Revision: 4237
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4237&view=rev
Author:   mdboom
Date:     2007-11-12 12:27:33 -0800 (Mon, 12 Nov 2007)

Log Message:
-----------
[ 1448342 ] FigureCanvasAgg.print_figure fails with StringIO 'file'
Added support to write png to an arbitrary Python file-like object in
the agg backend.  Will continue to use faster C-only calls if the
file-like object is in fact a file.
Also, clean up exception handling in write_png.

Modified Paths:
--------------
    trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
    trunk/matplotlib/src/_backend_agg.cpp

Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py     2007-11-12 
20:08:11 UTC (rev 4236)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py     2007-11-12 
20:27:33 UTC (rev 4237)
@@ -415,5 +415,5 @@
         
     def print_png(self, filename, *args, **kwargs):
         self.draw()
-        self.get_renderer()._renderer.write_png(str(filename), 
self.figure.dpi.get())
+        self.get_renderer()._renderer.write_png(filename, 
self.figure.dpi.get())
         

Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp       2007-11-12 20:08:11 UTC (rev 
4236)
+++ trunk/matplotlib/src/_backend_agg.cpp       2007-11-12 20:27:33 UTC (rev 
4237)
@@ -2256,7 +2256,22 @@
   
 }
 
+static void write_png_data(png_structp png_ptr, png_bytep data, png_size_t 
length) {
+  PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
+  PyObject* write_method = PyObject_GetAttrString(py_file_obj, "write");
+  PyObject_CallFunction(write_method, "s#", data, length);
+    
+  // MGDTODO: Check NULL on failure
+}
 
+static void flush_png_data(png_structp png_ptr) {
+  PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
+  PyObject* flush_method = PyObject_GetAttrString(py_file_obj, "write");
+  if (flush_method) {
+    PyObject_CallFunction(flush_method, "");
+  }
+}
+
 // this code is heavily adapted from the paint license, which is in
 // the file paint.license (BSD compatible) included in this
 // distribution.  TODO, add license file to MANIFEST.in and CVS
@@ -2267,97 +2282,96 @@
   
   args.verify_length(1, 2);
   
-  FILE *fp;
-  Py::Object o = Py::Object(args[0]);
-  bool fpclose = true;
-  if (o.isString()) {
-    std::string fileName = Py::String(o);
+  FILE *fp = NULL;
+  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, "wb")) == NULL)
       throw Py::RuntimeError( Printf("Could not open file %s", 
file_name).str() );
   }
   else {
-    if ((fp = PyFile_AsFile(o.ptr())) == NULL)
-      throw Py::TypeError("Could not convert object to file pointer");
-    fpclose = false;
+    if ((fp = PyFile_AsFile(py_fileobj.ptr())) == NULL) {
+      PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), 
"write");
+      if (!(write_method && PyCallable_Check(write_method)))
+       throw Py::TypeError("Object does not appear to be a Python file-like 
object");
+    }
   }
+
+  png_bytep *row_pointers = NULL;
+  png_structp png_ptr = NULL;
+  png_infop info_ptr = NULL;
   
-  png_structp png_ptr;
-  png_infop info_ptr;
-  struct        png_color_8_struct sig_bit;
-  png_uint_32 row;
+  try {
+    struct        png_color_8_struct sig_bit;
+    png_uint_32 row;
+    
+    row_pointers = new png_bytep[height];
+    for (row = 0; row < height; ++row) {
+      row_pointers[row] = pixBuffer + row * width * 4;
+    }
   
-  png_bytep *row_pointers = new png_bytep[height];
-  for (row = 0; row < height; ++row) {
-    row_pointers[row] = pixBuffer + row * width * 4;
-  }
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (png_ptr == NULL) {
+      throw Py::RuntimeError("Could not create write struct");
+    }
   
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL) {
+      throw Py::RuntimeError("Could not create info struct");
+    }
   
-  if (fp == NULL) {
-    delete [] row_pointers;
-    throw Py::RuntimeError("Could not open file");
-  }
+    if (setjmp(png_ptr->jmpbuf)) {
+      throw Py::RuntimeError("Error building image");
+    }
   
-  
-  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-  if (png_ptr == NULL) {
-    if (fpclose) fclose(fp);
-    delete [] row_pointers;
-    throw Py::RuntimeError("Could not create write struct");
-  }
-  
-  info_ptr = png_create_info_struct(png_ptr);
-  if (info_ptr == NULL) {
-    if (fpclose) fclose(fp);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-    delete [] row_pointers;
-    throw Py::RuntimeError("Could not create info struct");
-  }
-  
-  if (setjmp(png_ptr->jmpbuf)) {
-    if (fpclose) fclose(fp);
-    png_destroy_write_struct(&png_ptr, &info_ptr);
-    delete [] row_pointers;
-    throw Py::RuntimeError("Error building image");
-  }
-  
-  png_init_io(png_ptr, fp);
-  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);
+    if (fp) {
+      png_init_io(png_ptr, fp);
+    } else {
+      png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(), 
+                      &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);
 
-  // Save the dpi of the image in the file
-  if (args.size() == 2) {
-    double dpi = Py::Float(args[1]);
-    size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0));
-    png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, 
PNG_RESOLUTION_METER);
+    // Save the dpi of the image in the file
+    if (args.size() == 2) {
+      double dpi = Py::Float(args[1]);
+      size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0));
+      png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, 
PNG_RESOLUTION_METER);
+    }
+    
+    // this a a color image!
+    sig_bit.gray = 0;
+    sig_bit.red = 8;
+    sig_bit.green = 8;
+    sig_bit.blue = 8;
+    /* if the image has an alpha channel then */
+    sig_bit.alpha = 8;
+    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+    
+    png_write_info(png_ptr, info_ptr);
+    png_write_image(png_ptr, row_pointers);
+    png_write_end(png_ptr, info_ptr);
+    
+    /* 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.
+    */
+    
+  } catch (...) {
+      if (fp) fclose(fp);
+      delete [] row_pointers;
+      if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
+      throw;
   }
   
-  // this a a color image!
-  sig_bit.gray = 0;
-  sig_bit.red = 8;
-  sig_bit.green = 8;
-  sig_bit.blue = 8;
-  /* if the image has an alpha channel then */
-  sig_bit.alpha = 8;
-  png_set_sBIT(png_ptr, info_ptr, &sig_bit);
-  
-  png_write_info(png_ptr, info_ptr);
-  png_write_image(png_ptr, row_pointers);
-  png_write_end(png_ptr, info_ptr);
-  
-  /* 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.
-  */
-  
   png_destroy_write_struct(&png_ptr, &info_ptr);
-  
   delete [] row_pointers;
-  
-  if (fpclose) fclose(fp);
-  
+  if (fp) fclose(fp);
+
   return Py::Object();
 }
 


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to