From: <md...@us...> - 2007-12-12 20:06:44
|
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. |