|
From: <md...@us...> - 2009-10-26 14:19:19
|
Revision: 7909
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7909&view=rev
Author: mdboom
Date: 2009-10-26 14:19:04 +0000 (Mon, 26 Oct 2009)
Log Message:
-----------
Support Python file-like objects in readpng
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/image.py
trunk/matplotlib/lib/matplotlib/tests/test_image.py
trunk/matplotlib/src/_png.cpp
Modified: trunk/matplotlib/lib/matplotlib/image.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/image.py 2009-10-25 23:29:31 UTC (rev 7908)
+++ trunk/matplotlib/lib/matplotlib/image.py 2009-10-26 14:19:04 UTC (rev 7909)
@@ -938,10 +938,15 @@
-def imread(fname):
+def imread(fname, format=None):
"""
- Return image file in *fname* as :class:`numpy.array`.
+ Return image file in *fname* as :class:`numpy.array`. *fname* may
+ be a string path or a Python file-like object.
+ If *format* is provided, will try to read file of that type,
+ otherwise the format is deduced from the filename. If nothing can
+ be deduced, PNG is tried.
+
Return value is a :class:`numpy.array`. For grayscale images, the
return array is MxN. For RGB images, the return value is MxNx3.
For RGBA images the return value is MxNx4.
@@ -959,12 +964,16 @@
image = Image.open( fname )
return pil_to_array(image)
+ handlers = {'png' :_png.read_png, }
+ if format is None:
+ if cbook.is_string_like(fname):
+ basename, ext = os.path.splitext(fname)
+ ext = ext.lower()[1:]
+ else:
+ ext = 'png'
+ else:
+ ext = format
- handlers = {'png' :_png.read_png,
- }
- basename, ext = os.path.splitext(fname)
- ext = ext.lower()[1:]
-
if ext not in handlers.keys():
im = pilread()
if im is None:
@@ -972,6 +981,13 @@
return im
handler = handlers[ext]
+
+ # To handle Unicode filenames, we pass a file object to the PNG
+ # reader extension, since Python handles them quite well, but it's
+ # tricky in C.
+ if cbook.is_string_like(fname):
+ fname = open(fname, 'rb')
+
return handler(fname)
Modified: trunk/matplotlib/lib/matplotlib/tests/test_image.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/tests/test_image.py 2009-10-25 23:29:31 UTC (rev 7908)
+++ trunk/matplotlib/lib/matplotlib/tests/test_image.py 2009-10-26 14:19:04 UTC (rev 7909)
@@ -4,6 +4,9 @@
import matplotlib.pyplot as plt
from nose.tools import assert_raises
+import cStringIO
+import os
+
@image_comparison(baseline_images=['image_interps'])
def test_image_interps():
'make the basic nearest, bilinear and bicubic interps'
@@ -26,6 +29,24 @@
fig.savefig('image_interps')
+def test_image_python_io():
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ ax.plot([1,2,3])
+ buffer = cStringIO.StringIO()
+ fig.savefig(buffer)
+ buffer.seek(0)
+ plt.imread(buffer)
+
+def test_image_unicode_io():
+ fig = plt.figure()
+ ax = fig.add_subplot(111)
+ ax.plot([1,2,3])
+ fname = u"\u0a3a\u0a3a.png"
+ fig.savefig(fname)
+ plt.imread(fname)
+ os.remove(fname)
+
if __name__=='__main__':
import nose
nose.runmodule(argv=['-s','--with-doctest'], exit=False)
Modified: trunk/matplotlib/src/_png.cpp
===================================================================
--- trunk/matplotlib/src/_png.cpp 2009-10-25 23:29:31 UTC (rev 7908)
+++ trunk/matplotlib/src/_png.cpp 2009-10-26 14:19:04 UTC (rev 7909)
@@ -130,12 +130,12 @@
png_init_io(png_ptr, fp);
} else {
png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(),
- &write_png_data, &flush_png_data);
+ &write_png_data, &flush_png_data);
}
png_set_IHDR(png_ptr, info_ptr,
- width, height, 8,
- PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+ width, height, 8,
+ PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
// Save the dpi of the image in the file
if (args.size() == 5) {
@@ -157,14 +157,14 @@
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
} catch (...) {
- if (fp && close_file) fclose(fp);
- delete [] row_pointers;
- /* Changed calls to png_destroy_write_struct to follow
- http://www.libpng.org/pub/png/libpng-manual.txt.
- This ensures the info_ptr memory is released.
- */
- if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
- throw;
+ if (fp && close_file) fclose(fp);
+ delete [] row_pointers;
+ /* Changed calls to png_destroy_write_struct to follow
+ http://www.libpng.org/pub/png/libpng-manual.txt.
+ This ensures the info_ptr memory is released.
+ */
+ if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
+ throw;
}
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -174,39 +174,85 @@
return Py::Object();
}
+static void _read_png_data(PyObject* py_file_obj, png_bytep data, png_size_t length) {
+ PyObject* read_method = PyObject_GetAttrString(py_file_obj, "read");
+ PyObject* result = NULL;
+ char *buffer;
+ Py_ssize_t bufflen;
+ if (read_method)
+ result = PyObject_CallFunction(read_method, (char *)"i", length);
+ if (PyString_AsStringAndSize(result, &buffer, &bufflen) == 0) {
+ if (bufflen == (Py_ssize_t)length) {
+ memcpy(data, buffer, length);
+ }
+ }
+ Py_XDECREF(read_method);
+ Py_XDECREF(result);
+}
+static void read_png_data(png_structp png_ptr, png_bytep data, png_size_t length) {
+ PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
+ _read_png_data(py_file_obj, data, length);
+}
+
Py::Object
_png_module::read_png(const Py::Tuple& args) {
args.verify_length(1);
- std::string fname = Py::String(args[0]);
+ png_byte header[8]; // 8 is the maximum size that can be checked
+ FILE* fp = NULL;
+ bool close_file = false;
- png_byte header[8]; // 8 is the maximum size that can be checked
+ Py::Object py_fileobj = Py::Object(args[0]);
+ if (py_fileobj.isString()) {
+ std::string fileName = Py::String(py_fileobj);
+ const char *file_name = fileName.c_str();
+ if ((fp = fopen(file_name, "rb")) == NULL)
+ throw Py::RuntimeError( Printf("Could not open file %s for reading", file_name).str() );
+ close_file = true;
+ } else if (PyFile_CheckExact(py_fileobj.ptr())) {
+ fp = PyFile_AsFile(py_fileobj.ptr());
+ } else {
+ PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read");
+ if (!(read_method && PyCallable_Check(read_method))) {
+ Py_XDECREF(read_method);
+ throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
+ }
+ Py_XDECREF(read_method);
+ }
- FILE *fp = fopen(fname.c_str(), "rb");
- if (!fp)
- throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str());
-
- if (fread(header, 1, 8, fp) != 8)
- throw Py::RuntimeError("_image_module::readpng: error reading PNG header");
- if (png_sig_cmp(header, 0, 8))
+ if (fp) {
+ if (fread(header, 1, 8, fp) != 8) {
+ throw Py::RuntimeError("_image_module::readpng: error reading PNG header");
+ }
+ } else {
+ _read_png_data(py_fileobj.ptr(), header, 8);
+ }
+ if (png_sig_cmp(header, 0, 8)) {
throw Py::RuntimeError("_image_module::readpng: file not recognized as a PNG file");
+ }
-
/* initialize stuff */
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
+ if (!png_ptr) {
throw Py::RuntimeError("_image_module::readpng: png_create_read_struct failed");
+ }
png_infop info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
+ if (!info_ptr) {
throw Py::RuntimeError("_image_module::readpng: png_create_info_struct failed");
+ }
- if (setjmp(png_jmpbuf(png_ptr)))
+ if (setjmp(png_jmpbuf(png_ptr))) {
throw Py::RuntimeError("_image_module::readpng: error during init_io");
+ }
- png_init_io(png_ptr, fp);
+ if (fp) {
+ png_init_io(png_ptr, fp);
+ } else {
+ png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data);
+ }
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
@@ -272,26 +318,28 @@
for (png_uint_32 y = 0; y < height; y++) {
png_byte* row = row_pointers[y];
- for (png_uint_32 x = 0; x < width; x++) {
- size_t offset = y*A->strides[0] + x*A->strides[1];
- if (bit_depth == 16) {
- png_uint_16* ptr = &reinterpret_cast<png_uint_16*> (row)[x * dimensions[2]];
+ for (png_uint_32 x = 0; x < width; x++) {
+ size_t offset = y*A->strides[0] + x*A->strides[1];
+ if (bit_depth == 16) {
+ png_uint_16* ptr = &reinterpret_cast<png_uint_16*> (row)[x * dimensions[2]];
for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
- *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
- } else {
- png_byte* ptr = &(row[x * dimensions[2]]);
- for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
- {
- *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
- }
- }
+ *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
+ } else {
+ png_byte* ptr = &(row[x * dimensions[2]]);
+ for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
+ {
+ *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
+ }
+ }
}
}
//free the png memory
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
- fclose(fp);
+ if (close_file) {
+ fclose(fp);
+ }
for (row = 0; row < height; row++)
delete [] row_pointers[row];
delete [] row_pointers;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|