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