Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 26a14a3

Browse files
committed
Forgot this file
svn path=/trunk/matplotlib/; revision=5472
1 parent 22e2a42 commit 26a14a3

1 file changed

Lines changed: 293 additions & 0 deletions

File tree

src/_png.cpp

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
#include <png.h>
2+
3+
// To remove a gcc warning
4+
#ifdef _POSIX_C_SOURCE
5+
#undef _POSIX_C_SOURCE
6+
#endif
7+
8+
// TODO: Un CXX-ify this module
9+
#include "CXX/Extensions.hxx"
10+
#include "numpy/arrayobject.h"
11+
#include "mplutils.h"
12+
13+
// the extension module
14+
class _png_module : public Py::ExtensionModule<_png_module>
15+
{
16+
public:
17+
_png_module()
18+
: Py::ExtensionModule<_png_module>( "_png" )
19+
{
20+
add_varargs_method("write_png", &_png_module::write_png,
21+
"write_png(buffer, width, height, fileobj, dpi=None)");
22+
add_varargs_method("read_png", &_png_module::write_png,
23+
"read_png(fileobj)");
24+
initialize("Module to write PNG files");
25+
}
26+
27+
virtual ~_png_module() {}
28+
29+
private:
30+
Py::Object write_png(const Py::Tuple& args);
31+
Py::Object read_png(const Py::Tuple& args);
32+
};
33+
34+
static void write_png_data(png_structp png_ptr, png_bytep data, png_size_t length) {
35+
printf("%x %x %d %x\n", png_ptr, data, *data, length);
36+
PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
37+
PyObject* write_method = PyObject_GetAttrString(py_file_obj, "write");
38+
PyObject* result = NULL;
39+
if (write_method)
40+
result = PyObject_CallFunction(write_method, (char *)"s#", data, length);
41+
Py_XDECREF(write_method);
42+
Py_XDECREF(result);
43+
}
44+
45+
static void flush_png_data(png_structp png_ptr) {
46+
PyObject* py_file_obj = (PyObject*)png_get_io_ptr(png_ptr);
47+
PyObject* flush_method = PyObject_GetAttrString(py_file_obj, "flush");
48+
PyObject* result = NULL;
49+
if (flush_method)
50+
result = PyObject_CallFunction(flush_method, (char *)"");
51+
Py_XDECREF(flush_method);
52+
Py_XDECREF(result);
53+
}
54+
55+
// this code is heavily adapted from the paint license, which is in
56+
// the file paint.license (BSD compatible) included in this
57+
// distribution. TODO, add license file to MANIFEST.in and CVS
58+
Py::Object _png_module::write_png(const Py::Tuple& args)
59+
{
60+
args.verify_length(4, 5);
61+
62+
FILE *fp = NULL;
63+
bool close_file = false;
64+
Py::Object buffer_obj = Py::Object(args[0]);
65+
PyObject* buffer = buffer_obj.ptr();
66+
if (!PyObject_CheckReadBuffer(buffer)) {
67+
throw Py::TypeError("First argument must be an rgba buffer.");
68+
}
69+
70+
const void* pixBufferPtr = NULL;
71+
Py_ssize_t pixBufferLength = 0;
72+
if (PyObject_AsReadBuffer(buffer, &pixBufferPtr, &pixBufferLength)) {
73+
throw Py::ValueError("Couldn't get data from read buffer.");
74+
}
75+
76+
png_byte* pixBuffer = (png_byte*)pixBufferPtr;
77+
int width = (int)Py::Int(args[1]);
78+
int height = (int)Py::Int(args[2]);
79+
80+
if (pixBufferLength < width * height * 4) {
81+
throw Py::ValueError("Buffer and width, height don't seem to match.");
82+
}
83+
84+
Py::Object py_fileobj = Py::Object(args[3]);
85+
if (py_fileobj.isString()) {
86+
std::string fileName = Py::String(py_fileobj);
87+
const char *file_name = fileName.c_str();
88+
if ((fp = fopen(file_name, "wb")) == NULL)
89+
throw Py::RuntimeError( Printf("Could not open file %s", file_name).str() );
90+
close_file = true;
91+
} else if (PyFile_CheckExact(py_fileobj.ptr())) {
92+
fp = PyFile_AsFile(py_fileobj.ptr());
93+
}
94+
else {
95+
PyObject* write_method = PyObject_GetAttrString(py_fileobj.ptr(), "write");
96+
if (!(write_method && PyCallable_Check(write_method))) {
97+
Py_XDECREF(write_method);
98+
throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
99+
}
100+
Py_XDECREF(write_method);
101+
}
102+
103+
png_bytep *row_pointers = NULL;
104+
png_structp png_ptr = NULL;
105+
png_infop info_ptr = NULL;
106+
107+
try {
108+
struct png_color_8_struct sig_bit;
109+
png_uint_32 row;
110+
111+
row_pointers = new png_bytep[height];
112+
for (row = 0; row < (png_uint_32)height; ++row) {
113+
row_pointers[row] = pixBuffer + row * width * 4;
114+
}
115+
116+
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
117+
if (png_ptr == NULL) {
118+
throw Py::RuntimeError("Could not create write struct");
119+
}
120+
121+
info_ptr = png_create_info_struct(png_ptr);
122+
if (info_ptr == NULL) {
123+
throw Py::RuntimeError("Could not create info struct");
124+
}
125+
126+
if (setjmp(png_ptr->jmpbuf)) {
127+
throw Py::RuntimeError("Error building image");
128+
}
129+
130+
if (fp) {
131+
png_init_io(png_ptr, fp);
132+
} else {
133+
png_set_write_fn(png_ptr, (void*)py_fileobj.ptr(),
134+
&write_png_data, &flush_png_data);
135+
}
136+
png_set_IHDR(png_ptr, info_ptr,
137+
width, height, 8,
138+
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
139+
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
140+
141+
// Save the dpi of the image in the file
142+
if (args.size() == 5) {
143+
double dpi = Py::Float(args[4]);
144+
size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0));
145+
png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER);
146+
}
147+
148+
// this a a color image!
149+
sig_bit.gray = 0;
150+
sig_bit.red = 8;
151+
sig_bit.green = 8;
152+
sig_bit.blue = 8;
153+
/* if the image has an alpha channel then */
154+
sig_bit.alpha = 8;
155+
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
156+
157+
png_write_info(png_ptr, info_ptr);
158+
png_write_image(png_ptr, row_pointers);
159+
png_write_end(png_ptr, info_ptr);
160+
} catch (...) {
161+
if (fp && close_file) fclose(fp);
162+
delete [] row_pointers;
163+
/* Changed calls to png_destroy_write_struct to follow
164+
http://www.libpng.org/pub/png/libpng-manual.txt.
165+
This ensures the info_ptr memory is released.
166+
*/
167+
if (png_ptr && info_ptr) png_destroy_write_struct(&png_ptr, &info_ptr);
168+
throw;
169+
}
170+
171+
png_destroy_write_struct(&png_ptr, &info_ptr);
172+
delete [] row_pointers;
173+
if (fp && close_file) fclose(fp);
174+
175+
return Py::Object();
176+
}
177+
178+
179+
Py::Object
180+
_png_module::read_png(const Py::Tuple& args) {
181+
182+
args.verify_length(1);
183+
std::string fname = Py::String(args[0]);
184+
185+
png_byte header[8]; // 8 is the maximum size that can be checked
186+
187+
FILE *fp = fopen(fname.c_str(), "rb");
188+
if (!fp)
189+
throw Py::RuntimeError(Printf("_image_module::readpng could not open PNG file %s for reading", fname.c_str()).str());
190+
191+
if (fread(header, 1, 8, fp) != 8)
192+
throw Py::RuntimeError("_image_module::readpng: error reading PNG header");
193+
if (png_sig_cmp(header, 0, 8))
194+
throw Py::RuntimeError("_image_module::readpng: file not recognized as a PNG file");
195+
196+
197+
/* initialize stuff */
198+
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
199+
200+
if (!png_ptr)
201+
throw Py::RuntimeError("_image_module::readpng: png_create_read_struct failed");
202+
203+
png_infop info_ptr = png_create_info_struct(png_ptr);
204+
if (!info_ptr)
205+
throw Py::RuntimeError("_image_module::readpng: png_create_info_struct failed");
206+
207+
if (setjmp(png_jmpbuf(png_ptr)))
208+
throw Py::RuntimeError("_image_module::readpng: error during init_io");
209+
210+
png_init_io(png_ptr, fp);
211+
png_set_sig_bytes(png_ptr, 8);
212+
213+
png_read_info(png_ptr, info_ptr);
214+
215+
png_uint_32 width = info_ptr->width;
216+
png_uint_32 height = info_ptr->height;
217+
218+
// convert misc color types to rgb for simplicity
219+
if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY ||
220+
info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
221+
png_set_gray_to_rgb(png_ptr);
222+
else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
223+
png_set_palette_to_rgb(png_ptr);
224+
225+
226+
int bit_depth = info_ptr->bit_depth;
227+
if (bit_depth == 16) png_set_strip_16(png_ptr);
228+
229+
230+
png_set_interlace_handling(png_ptr);
231+
png_read_update_info(png_ptr, info_ptr);
232+
233+
bool rgba = info_ptr->color_type == PNG_COLOR_TYPE_RGBA;
234+
if ( (info_ptr->color_type != PNG_COLOR_TYPE_RGB) && !rgba) {
235+
std::cerr << "Found color type " << (int)info_ptr->color_type << std::endl;
236+
throw Py::RuntimeError("_image_module::readpng: cannot handle color_type");
237+
}
238+
239+
/* read file */
240+
if (setjmp(png_jmpbuf(png_ptr)))
241+
throw Py::RuntimeError("_image_module::readpng: error during read_image");
242+
243+
png_bytep *row_pointers = new png_bytep[height];
244+
png_uint_32 row;
245+
246+
for (row = 0; row < height; row++)
247+
row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)];
248+
249+
png_read_image(png_ptr, row_pointers);
250+
251+
252+
253+
int dimensions[3];
254+
dimensions[0] = height; //numrows
255+
dimensions[1] = width; //numcols
256+
dimensions[2] = 4;
257+
258+
PyArrayObject *A = (PyArrayObject *) PyArray_FromDims(3, dimensions, PyArray_FLOAT);
259+
260+
261+
for (png_uint_32 y = 0; y < height; y++) {
262+
png_byte* row = row_pointers[y];
263+
for (png_uint_32 x = 0; x < width; x++) {
264+
265+
png_byte* ptr = (rgba) ? &(row[x*4]) : &(row[x*3]);
266+
size_t offset = y*A->strides[0] + x*A->strides[1];
267+
//if ((y<10)&&(x==10)) std::cout << "r = " << ptr[0] << " " << ptr[0]/255.0 << std::endl;
268+
*(float*)(A->data + offset + 0*A->strides[2]) = (float)(ptr[0]/255.0f);
269+
*(float*)(A->data + offset + 1*A->strides[2]) = (float)(ptr[1]/255.0f);
270+
*(float*)(A->data + offset + 2*A->strides[2]) = (float)(ptr[2]/255.0f);
271+
*(float*)(A->data + offset + 3*A->strides[2]) = rgba ? (float)(ptr[3]/255.0f) : 1.0f;
272+
}
273+
}
274+
275+
//free the png memory
276+
png_read_end(png_ptr, info_ptr);
277+
png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
278+
fclose(fp);
279+
for (row = 0; row < height; row++)
280+
delete [] row_pointers[row];
281+
delete [] row_pointers;
282+
return Py::asObject((PyObject*)A);
283+
}
284+
285+
extern "C"
286+
DL_EXPORT(void)
287+
init_png(void)
288+
{
289+
import_array();
290+
291+
static _png_module* _png = NULL;
292+
_png = new _png_module;
293+
}

0 commit comments

Comments
 (0)