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.
------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins