The 0.5 release happened on 2/15, not on 2/14. :-)
[python/dscho.git] / Modules / imgfile.c
blob65976c10cd60f6c4e816d9cbb8fb1dd629ddf98f
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission.
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* IMGFILE module - Interface to sgi libimage */
34 /* XXX This modele should be done better at some point. It should return
35 ** an object of image file class, and have routines to manipulate these
36 ** image files in a neater way (so you can get rgb images off a greyscale
37 ** file, for instance, or do a straight display without having to get the
38 ** image bits into python, etc).
40 ** Warning: this module is very non-reentrant (esp. the readscaled stuff)
43 #include "Python.h"
45 #include <gl/image.h>
47 #include "/usr/people/4Dgifts/iristools/include/izoom.h"
49 /* Bunch of missing extern decls; keep gcc -Wall happy... */
50 extern void i_seterror();
51 extern void iclose();
52 extern void filterzoom();
53 extern void putrow();
54 extern void getrow();
56 static PyObject * ImgfileError; /* Exception we raise for various trouble */
58 static int top_to_bottom; /* True if we want top-to-bottom images */
60 /* The image library does not always call the error hander :-(,
61 therefore we have a global variable indicating that it was called.
62 It is cleared by imgfile_open(). */
64 static int error_called;
67 /* The error handler */
69 static void
70 imgfile_error(str)
71 char *str;
73 PyErr_SetString(ImgfileError, str);
74 error_called = 1;
75 return; /* To imglib, which will return a failure indicator */
79 /* Open an image file and return a pointer to it.
80 Make sure we raise an exception if we fail. */
82 static IMAGE *
83 imgfile_open(fname)
84 char *fname;
86 IMAGE *image;
87 i_seterror(imgfile_error);
88 error_called = 0;
89 errno = 0;
90 if ( (image = iopen(fname, "r")) == NULL ) {
91 /* Error may already be set by imgfile_error */
92 if ( !error_called ) {
93 if (errno)
94 PyErr_SetFromErrno(ImgfileError);
95 else
96 PyErr_SetString(ImgfileError,
97 "Can't open image file");
99 return NULL;
101 return image;
104 static PyObject *
105 imgfile_ttob(self, args)
106 PyObject *self;
107 PyObject *args;
109 int newval;
110 PyObject *rv;
112 if (!PyArg_Parse(args, "i", &newval))
113 return NULL;
114 rv = PyInt_FromLong(top_to_bottom);
115 top_to_bottom = newval;
116 return rv;
119 static PyObject *
120 imgfile_read(self, args)
121 PyObject *self;
122 PyObject *args;
124 char *fname;
125 PyObject *rv;
126 int xsize, ysize, zsize;
127 char *cdatap;
128 long *idatap;
129 static short rs[8192], gs[8192], bs[8192];
130 int x, y;
131 IMAGE *image;
132 int yfirst, ylast, ystep;
134 if ( !PyArg_Parse(args, "s", &fname) )
135 return NULL;
137 if ( (image = imgfile_open(fname)) == NULL )
138 return NULL;
140 if ( image->colormap != CM_NORMAL ) {
141 iclose(image);
142 PyErr_SetString(ImgfileError,
143 "Can only handle CM_NORMAL images");
144 return NULL;
146 if ( BPP(image->type) != 1 ) {
147 iclose(image);
148 PyErr_SetString(ImgfileError,
149 "Can't handle imgfiles with bpp!=1");
150 return NULL;
152 xsize = image->xsize;
153 ysize = image->ysize;
154 zsize = image->zsize;
155 if ( zsize != 1 && zsize != 3) {
156 iclose(image);
157 PyErr_SetString(ImgfileError,
158 "Can only handle 1 or 3 byte pixels");
159 return NULL;
161 if ( xsize > 8192 ) {
162 iclose(image);
163 PyErr_SetString(ImgfileError,
164 "Can't handle image with > 8192 columns");
165 return NULL;
168 if ( zsize == 3 ) zsize = 4;
169 rv = PyString_FromStringAndSize((char *)NULL, xsize*ysize*zsize);
170 if ( rv == NULL ) {
171 iclose(image);
172 return NULL;
174 cdatap = PyString_AsString(rv);
175 idatap = (long *)cdatap;
177 if (top_to_bottom) {
178 yfirst = ysize-1;
179 ylast = -1;
180 ystep = -1;
181 } else {
182 yfirst = 0;
183 ylast = ysize;
184 ystep = 1;
186 for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
187 if ( zsize == 1 ) {
188 getrow(image, rs, y, 0);
189 for(x=0; x<xsize; x++ )
190 *cdatap++ = rs[x];
191 } else {
192 getrow(image, rs, y, 0);
193 getrow(image, gs, y, 1);
194 getrow(image, bs, y, 2);
195 for(x=0; x<xsize; x++ )
196 *idatap++ = (rs[x] & 0xff) |
197 ((gs[x] & 0xff)<<8) |
198 ((bs[x] & 0xff)<<16);
201 iclose(image);
202 if ( error_called ) {
203 Py_DECREF(rv);
204 return NULL;
206 return rv;
209 static IMAGE *glob_image;
210 static long *glob_datap;
211 static int glob_width, glob_z, glob_ysize;
213 static void
214 xs_get(buf, y)
215 short *buf;
216 int y;
218 if (top_to_bottom)
219 getrow(glob_image, buf, (glob_ysize-1-y), glob_z);
220 else
221 getrow(glob_image, buf, y, glob_z);
224 static void
225 xs_put_c(buf, y)
226 short *buf;
227 int y;
229 char *datap = (char *)glob_datap + y*glob_width;
230 int width = glob_width;
232 while ( width-- )
233 *datap++ = (*buf++) & 0xff;
236 static void
237 xs_put_0(buf, y)
238 short *buf;
239 int y;
241 long *datap = glob_datap + y*glob_width;
242 int width = glob_width;
244 while ( width-- )
245 *datap++ = (*buf++) & 0xff;
247 static void
248 xs_put_12(buf, y)
249 short *buf;
250 int y;
252 long *datap = glob_datap + y*glob_width;
253 int width = glob_width;
255 while ( width-- )
256 *datap++ |= ((*buf++) & 0xff) << (glob_z*8);
259 static void
260 xscale(image, xsize, ysize, zsize, datap, xnew, ynew, fmode, blur)
261 IMAGE *image;
262 int xsize, ysize, zsize;
263 long *datap;
264 int xnew, ynew;
265 int fmode;
266 double blur;
268 glob_image = image;
269 glob_datap = datap;
270 glob_width = xnew;
271 glob_ysize = ysize;
272 if ( zsize == 1 ) {
273 glob_z = 0;
274 filterzoom(xs_get, xs_put_c, xsize, ysize,
275 xnew, ynew, fmode, blur);
276 } else {
277 glob_z = 0;
278 filterzoom(xs_get, xs_put_0, xsize, ysize,
279 xnew, ynew, fmode, blur);
280 glob_z = 1;
281 filterzoom(xs_get, xs_put_12, xsize, ysize,
282 xnew, ynew, fmode, blur);
283 glob_z = 2;
284 filterzoom(xs_get, xs_put_12, xsize, ysize,
285 xnew, ynew, fmode, blur);
290 static PyObject *
291 imgfile_readscaled(self, args)
292 PyObject *self;
293 PyObject *args;
295 char *fname;
296 PyObject *rv;
297 int xsize, ysize, zsize;
298 char *cdatap;
299 long *idatap;
300 static short rs[8192], gs[8192], bs[8192];
301 int x, y;
302 int xwtd, ywtd, xorig, yorig;
303 float xfac, yfac;
304 int cnt;
305 IMAGE *image;
306 char *filter;
307 double blur;
308 int extended;
309 int fmode = 0;
310 int yfirst, ylast, ystep;
313 ** Parse args. Funny, since arg 4 and 5 are optional
314 ** (filter name and blur factor). Also, 4 or 5 arguments indicates
315 ** extended scale algorithm in stead of simple-minded pixel drop/dup.
317 extended = 0;
318 cnt = PyTuple_Size(args);
319 if ( cnt == 5 ) {
320 extended = 1;
321 if ( !PyArg_Parse(args, "(siisd)",
322 &fname, &xwtd, &ywtd, &filter, &blur) )
323 return NULL;
324 } else if ( cnt == 4 ) {
325 extended = 1;
326 if ( !PyArg_Parse(args, "(siis)",
327 &fname, &xwtd, &ywtd, &filter) )
328 return NULL;
329 blur = 1.0;
330 } else if ( !PyArg_Parse(args, "(sii)", &fname, &xwtd, &ywtd) )
331 return NULL;
334 ** Check parameters, open file and check type, rows, etc.
336 if ( extended ) {
337 if ( strcmp(filter, "impulse") == 0 )
338 fmode = IMPULSE;
339 else if ( strcmp( filter, "box") == 0 )
340 fmode = BOX;
341 else if ( strcmp( filter, "triangle") == 0 )
342 fmode = TRIANGLE;
343 else if ( strcmp( filter, "quadratic") == 0 )
344 fmode = QUADRATIC;
345 else if ( strcmp( filter, "gaussian") == 0 )
346 fmode = GAUSSIAN;
347 else {
348 PyErr_SetString(ImgfileError, "Unknown filter type");
349 return NULL;
353 if ( (image = imgfile_open(fname)) == NULL )
354 return NULL;
356 if ( image->colormap != CM_NORMAL ) {
357 iclose(image);
358 PyErr_SetString(ImgfileError,
359 "Can only handle CM_NORMAL images");
360 return NULL;
362 if ( BPP(image->type) != 1 ) {
363 iclose(image);
364 PyErr_SetString(ImgfileError,
365 "Can't handle imgfiles with bpp!=1");
366 return NULL;
368 xsize = image->xsize;
369 ysize = image->ysize;
370 zsize = image->zsize;
371 if ( zsize != 1 && zsize != 3) {
372 iclose(image);
373 PyErr_SetString(ImgfileError,
374 "Can only handle 1 or 3 byte pixels");
375 return NULL;
377 if ( xsize > 8192 ) {
378 iclose(image);
379 PyErr_SetString(ImgfileError,
380 "Can't handle image with > 8192 columns");
381 return NULL;
384 if ( zsize == 3 ) zsize = 4;
385 rv = PyString_FromStringAndSize(NULL, xwtd*ywtd*zsize);
386 if ( rv == NULL ) {
387 iclose(image);
388 return NULL;
390 PyFPE_START_PROTECT("readscaled", return 0)
391 xfac = (float)xsize/(float)xwtd;
392 yfac = (float)ysize/(float)ywtd;
393 PyFPE_END_PROTECT(yfac)
394 cdatap = PyString_AsString(rv);
395 idatap = (long *)cdatap;
397 if ( extended ) {
398 xscale(image, xsize, ysize, zsize,
399 idatap, xwtd, ywtd, fmode, blur);
400 } else {
401 if (top_to_bottom) {
402 yfirst = ywtd-1;
403 ylast = -1;
404 ystep = -1;
405 } else {
406 yfirst = 0;
407 ylast = ywtd;
408 ystep = 1;
410 for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
411 yorig = (int)(y*yfac);
412 if ( zsize == 1 ) {
413 getrow(image, rs, yorig, 0);
414 for(x=0; x<xwtd; x++ ) {
415 *cdatap++ = rs[(int)(x*xfac)];
417 } else {
418 getrow(image, rs, yorig, 0);
419 getrow(image, gs, yorig, 1);
420 getrow(image, bs, yorig, 2);
421 for(x=0; x<xwtd; x++ ) {
422 xorig = (int)(x*xfac);
423 *idatap++ = (rs[xorig] & 0xff) |
424 ((gs[xorig] & 0xff)<<8) |
425 ((bs[xorig] & 0xff)<<16);
430 iclose(image);
431 if ( error_called ) {
432 Py_DECREF(rv);
433 return NULL;
435 return rv;
438 static PyObject *
439 imgfile_getsizes(self, args)
440 PyObject *self;
441 PyObject *args;
443 char *fname;
444 PyObject *rv;
445 IMAGE *image;
447 if ( !PyArg_Parse(args, "s", &fname) )
448 return NULL;
450 if ( (image = imgfile_open(fname)) == NULL )
451 return NULL;
452 rv = Py_BuildValue("(iii)", image->xsize, image->ysize, image->zsize);
453 iclose(image);
454 return rv;
457 static PyObject *
458 imgfile_write(self, args)
459 PyObject *self;
460 PyObject *args;
462 IMAGE *image;
463 char *fname;
464 int xsize, ysize, zsize, len;
465 char *cdatap;
466 long *idatap;
467 short rs[8192], gs[8192], bs[8192];
468 short r, g, b;
469 long rgb;
470 int x, y;
471 int yfirst, ylast, ystep;
474 if ( !PyArg_Parse(args, "(ss#iii)",
475 &fname, &cdatap, &len, &xsize, &ysize, &zsize) )
476 return NULL;
478 if ( zsize != 1 && zsize != 3 ) {
479 PyErr_SetString(ImgfileError,
480 "Can only handle 1 or 3 byte pixels");
481 return NULL;
483 if ( len != xsize * ysize * (zsize == 1 ? 1 : 4) ) {
484 PyErr_SetString(ImgfileError, "Data does not match sizes");
485 return NULL;
487 if ( xsize > 8192 ) {
488 PyErr_SetString(ImgfileError,
489 "Can't handle image with > 8192 columns");
490 return NULL;
493 error_called = 0;
494 errno = 0;
495 image =iopen(fname, "w", RLE(1), 3, xsize, ysize, zsize);
496 if ( image == 0 ) {
497 if ( ! error_called ) {
498 if (errno)
499 PyErr_SetFromErrno(ImgfileError);
500 else
501 PyErr_SetString(ImgfileError,
502 "Can't create image file");
504 return NULL;
507 idatap = (long *)cdatap;
509 if (top_to_bottom) {
510 yfirst = ysize-1;
511 ylast = -1;
512 ystep = -1;
513 } else {
514 yfirst = 0;
515 ylast = ysize;
516 ystep = 1;
518 for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
519 if ( zsize == 1 ) {
520 for( x=0; x<xsize; x++ )
521 rs[x] = *cdatap++;
522 putrow(image, rs, y, 0);
523 } else {
524 for( x=0; x<xsize; x++ ) {
525 rgb = *idatap++;
526 r = rgb & 0xff;
527 g = (rgb >> 8 ) & 0xff;
528 b = (rgb >> 16 ) & 0xff;
529 rs[x] = r;
530 gs[x] = g;
531 bs[x] = b;
533 putrow(image, rs, y, 0);
534 putrow(image, gs, y, 1);
535 putrow(image, bs, y, 2);
538 iclose(image);
539 if ( error_called )
540 return NULL;
541 Py_INCREF(Py_None);
542 return Py_None;
547 static PyMethodDef imgfile_methods[] = {
548 { "getsizes", imgfile_getsizes },
549 { "read", imgfile_read },
550 { "readscaled", imgfile_readscaled, 1},
551 { "write", imgfile_write },
552 { "ttob", imgfile_ttob },
553 { NULL, NULL } /* Sentinel */
557 void
558 initimgfile()
560 PyObject *m, *d;
561 m = Py_InitModule("imgfile", imgfile_methods);
562 d = PyModule_GetDict(m);
563 ImgfileError = PyErr_NewException("imgfile.error", NULL, NULL);
564 if (ImgfileError != NULL)
565 PyDict_SetItemString(d, "error", ImgfileError);