Revision: 4716
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4716&view=rev
Author:   mdboom
Date:     2007-12-12 12:06:30 -0800 (Wed, 12 Dec 2007)

Log Message:
-----------
Save images to Svg files without writing the image data out as a
temporary file.

Modified Paths:
--------------
    branches/transforms/lib/matplotlib/backends/backend_svg.py
    branches/transforms/src/_image.cpp

Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_svg.py  2007-12-12 
19:15:46 UTC (rev 4715)
+++ branches/transforms/lib/matplotlib/backends/backend_svg.py  2007-12-12 
20:06:30 UTC (rev 4716)
@@ -245,30 +245,33 @@
 
         h,w = im.get_size_out()
 
+        self._svgwriter.write (
+            '<image x="%s" y="%s" width="%s" height="%s" '
+            '%s xlink:href="'%(x/trans[0], (self.height-y)/trans[3]-h, w, h, 
transstr)
+            )
+
         if rcParams['svg.image_inline']:
-            filename = os.path.join (tempfile.gettempdir(),
-                                    tempfile.gettempprefix() + '.png'
-                                    )
+            class Base64Writer(object):
+                def __init__(self, write_method):
+                    self._write_method = write_method
+                    self._buffer = ''
+                def write(self, data):
+                    self._buffer += data
+                    while len(self._buffer) >= 64:
+                        self._write_method(base64.encodestring(buffer[:64]))
+                        self._write_method('\n')
+                        self._buffer = self._buffer[64:]
+                def flush(self):
+                    self._write_method(base64.encodestring(self._buffer))
+                    self._write_method('\n')
 
-            verbose.report ('Writing temporary image file for inlining: %s' % 
filename)
-            # im.write_png() accepts a filename, not file object, would be
-            # good to avoid using files and write to mem with StringIO
+            self._svgwriter.write("data:image/png;base64,\n")
+            base64writer = Base64Writer(self._svgwriter.write)
 
-            # JDH: it *would* be good, but I don't know how to do this
-            # since libpng seems to want a FILE* and StringIO doesn't seem
-            # to provide one.  I suspect there is a way, but I don't know
-            # it
-
             im.flipud_out()
-            im.write_png(filename)
+            im.write_png(base64writer)
             im.flipud_out()
-
-            imfile = file (filename, 'rb')
-            image64 = base64.encodestring (imfile.read())
-            imfile.close()
-            os.remove(filename)
-            hrefstr = 'data:image/png;base64,\n' + image64
-
+            base64writer.flush()
         else:
             self._imaged[self.basename] = self._imaged.get(self.basename,0) + 1
             filename = '%s.image%d.png'%(self.basename, 
self._imaged[self.basename])
@@ -276,12 +279,9 @@
             im.flipud_out()
             im.write_png(filename)
             im.flipud_out()
-            hrefstr = filename
+            self._svgwriter.write(filename)
 
-        self._svgwriter.write (
-            '<image x="%s" y="%s" width="%s" height="%s" '
-            'xlink:href="%s" %s/>\n'%(x/trans[0], (self.height-y)/trans[3]-h, 
w, h, hrefstr, transstr)
-            )
+        self._svgwriter.write('"/>\n')
 
     def draw_text(self, gc, x, y, s, prop, angle, ismath):
         if ismath:

Modified: branches/transforms/src/_image.cpp
===================================================================
--- branches/transforms/src/_image.cpp  2007-12-12 19:15:46 UTC (rev 4715)
+++ branches/transforms/src/_image.cpp  2007-12-12 20:06:30 UTC (rev 4716)
@@ -575,7 +575,25 @@
 
 }
 
+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* result = NULL;
+  if (write_method)
+    result = PyObject_CallFunction(write_method, "s#", data, length);
+  Py_XDECREF(write_method);
+  Py_XDECREF(result);
+}
 
+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, "flush");
+  PyObject* result = NULL;
+  if (flush_method)
+    result = PyObject_CallFunction(flush_method, "");
+  Py_XDECREF(flush_method);
+  Py_XDECREF(result);
+}
 
 // this code is heavily adapted from the paint license, which is in
 // the file paint.license (BSD compatible) included in this
@@ -593,79 +611,90 @@
 
   args.verify_length(1);
 
-  std::pair<agg::int8u*,bool> bufpair = _get_output_buffer();
+  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 {
+    PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write");
+    if (!(write_method && PyCallable_Check(write_method))) {
+      Py_XDECREF(write_method);
+      throw Py::TypeError("Object does not appear to be a path or a Python 
file-like object");
+    }
+    Py_XDECREF(write_method);
+  }
 
-  std::string fileName = Py::String(args[0]);
-  const char *file_name = fileName.c_str();
-  FILE *fp;
   png_structp png_ptr;
   png_infop info_ptr;
-  struct        png_color_8_struct sig_bit;
+  struct png_color_8_struct sig_bit;
   png_uint_32 row=0;
 
   //todo: allocate on heap
-  png_bytep *row_pointers = new png_bytep[rowsOut];
+  png_bytep *row_pointers = NULL;
+  std::pair<agg::int8u*,bool> bufpair;
+  bufpair.first = NULL;
+  bufpair.second = false;
 
-  for (row = 0; row < rowsOut; ++row)
-    row_pointers[row] = bufpair.first + row * colsOut * 4;
+  try {
+    row_pointers = new png_bytep[rowsOut];
+    if (!row_pointers)
+      throw Py::RuntimeError("Out of memory");
 
-  fp = fopen(file_name, "wb");
-  if (fp == NULL) {
-    if (bufpair.second) delete [] bufpair.first;
-    delete [] row_pointers;
-    throw Py::RuntimeError(Printf("Could not open file %s", file_name).str());
-  }
+    bufpair = _get_output_buffer();
+    for (row = 0; row < rowsOut; ++row)
+      row_pointers[row] = bufpair.first + row * colsOut * 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");
 
-  png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-  if (png_ptr == NULL) {
-    if (bufpair.second) delete [] bufpair.first;
-    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)
+      throw Py::RuntimeError("Could not create info struct");
 
-  info_ptr = png_create_info_struct(png_ptr);
-  if (info_ptr == NULL) {
-    if (bufpair.second) delete [] bufpair.first;
-    fclose(fp);
+    if (setjmp(png_ptr->jmpbuf))
+      throw Py::RuntimeError("Error building image");
+
+    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,
+                 colsOut, rowsOut, 8,
+                 PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+    // 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);
     png_destroy_write_struct(&png_ptr, &info_ptr);
-    delete [] row_pointers;
-    throw Py::RuntimeError("Could not create info struct");
-  }
-
-  if (setjmp(png_ptr->jmpbuf)) {
+  } catch (...) {
     if (bufpair.second) delete [] bufpair.first;
-    fclose(fp);
+    if (fp) fclose(fp);
     png_destroy_write_struct(&png_ptr, &info_ptr);
     delete [] row_pointers;
-    throw Py::RuntimeError("Error building image");
+    throw;
   }
 
-  png_init_io(png_ptr, fp);
-  png_set_IHDR(png_ptr, info_ptr,
-              colsOut, rowsOut, 8,
-              PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
-              PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
-
-  // 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);
-  png_destroy_write_struct(&png_ptr, &info_ptr);
-  fclose(fp);
-
+  if (fp) fclose(fp);
   delete [] row_pointers;
+  if (bufpair.second) delete [] bufpair.first;
 
-  if (bufpair.second) delete [] bufpair.first;
   return Py::Object();
 }
 


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

-------------------------------------------------------------------------
SF.Net email is sponsored by:
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services
for just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to