Home | History | Annotate | Download | only in Modules
      1 
      2 /* IMGFILE module - Interface to sgi libimage */
      3 
      4 /* XXX This module should be done better at some point. It should return
      5 ** an object of image file class, and have routines to manipulate these
      6 ** image files in a neater way (so you can get rgb images off a greyscale
      7 ** file, for instance, or do a straight display without having to get the
      8 ** image bits into python, etc).
      9 **
     10 ** Warning: this module is very non-reentrant (esp. the readscaled stuff)
     11 */
     12 
     13 #include "Python.h"
     14 
     15 #include <gl/image.h>
     16 
     17 #include "/usr/people/4Dgifts/iristools/include/izoom.h"
     18 
     19 /* Bunch of missing extern decls; keep gcc -Wall happy... */
     20 extern void i_seterror();
     21 extern void iclose();
     22 extern void filterzoom();
     23 extern void putrow();
     24 extern void getrow();
     25 
     26 static PyObject * ImgfileError; /* Exception we raise for various trouble */
     27 
     28 static int top_to_bottom;       /* True if we want top-to-bottom images */
     29 
     30 /* The image library does not always call the error hander :-(,
     31    therefore we have a global variable indicating that it was called.
     32    It is cleared by imgfile_open(). */
     33 
     34 static int error_called;
     35 
     36 
     37 /* The error handler */
     38 
     39 static void
     40 imgfile_error(char *str)
     41 {
     42     PyErr_SetString(ImgfileError, str);
     43     error_called = 1;
     44     return;     /* To imglib, which will return a failure indicator */
     45 }
     46 
     47 
     48 /* Open an image file and return a pointer to it.
     49    Make sure we raise an exception if we fail. */
     50 
     51 static IMAGE *
     52 imgfile_open(char *fname)
     53 {
     54     IMAGE *image;
     55     i_seterror(imgfile_error);
     56     error_called = 0;
     57     errno = 0;
     58     if ( (image = iopen(fname, "r")) == NULL ) {
     59         /* Error may already be set by imgfile_error */
     60         if ( !error_called ) {
     61             if (errno)
     62                 PyErr_SetFromErrno(ImgfileError);
     63             else
     64                 PyErr_SetString(ImgfileError,
     65                                 "Can't open image file");
     66         }
     67         return NULL;
     68     }
     69     return image;
     70 }
     71 
     72 static PyObject *
     73 imgfile_ttob(PyObject *self, PyObject *args)
     74 {
     75     int newval;
     76     PyObject *rv;
     77 
     78     if (!PyArg_ParseTuple(args, "i:ttob", &newval))
     79         return NULL;
     80     rv = PyInt_FromLong(top_to_bottom);
     81     top_to_bottom = newval;
     82     return rv;
     83 }
     84 
     85 static PyObject *
     86 imgfile_read(PyObject *self, PyObject *args)
     87 {
     88     char *fname;
     89     PyObject *rv;
     90     int xsize, ysize, zsize;
     91     char *cdatap;
     92     long *idatap;
     93     static short rs[8192], gs[8192], bs[8192];
     94     int x, y;
     95     IMAGE *image;
     96     int yfirst, ylast, ystep;
     97 
     98     if ( !PyArg_ParseTuple(args, "s:read", &fname) )
     99         return NULL;
    100 
    101     if ( (image = imgfile_open(fname)) == NULL )
    102         return NULL;
    103 
    104     if ( image->colormap != CM_NORMAL ) {
    105         iclose(image);
    106         PyErr_SetString(ImgfileError,
    107                         "Can only handle CM_NORMAL images");
    108         return NULL;
    109     }
    110     if ( BPP(image->type) != 1 ) {
    111         iclose(image);
    112         PyErr_SetString(ImgfileError,
    113                         "Can't handle imgfiles with bpp!=1");
    114         return NULL;
    115     }
    116     xsize = image->xsize;
    117     ysize = image->ysize;
    118     zsize = image->zsize;
    119     if ( zsize != 1 && zsize != 3) {
    120         iclose(image);
    121         PyErr_SetString(ImgfileError,
    122                         "Can only handle 1 or 3 byte pixels");
    123         return NULL;
    124     }
    125     if ( xsize > 8192 ) {
    126         iclose(image);
    127         PyErr_SetString(ImgfileError,
    128                         "Can't handle image with > 8192 columns");
    129         return NULL;
    130     }
    131 
    132     if ( zsize == 3 ) zsize = 4;
    133     rv = PyString_FromStringAndSize((char *)NULL, xsize*ysize*zsize);
    134     if ( rv == NULL ) {
    135         iclose(image);
    136         return NULL;
    137     }
    138     cdatap = PyString_AsString(rv);
    139     idatap = (long *)cdatap;
    140 
    141     if (top_to_bottom) {
    142         yfirst = ysize-1;
    143         ylast = -1;
    144         ystep = -1;
    145     } else {
    146         yfirst = 0;
    147         ylast = ysize;
    148         ystep = 1;
    149     }
    150     for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
    151         if ( zsize == 1 ) {
    152             getrow(image, rs, y, 0);
    153             for(x=0; x<xsize; x++ )
    154                 *cdatap++ = rs[x];
    155         } else {
    156             getrow(image, rs, y, 0);
    157             getrow(image, gs, y, 1);
    158             getrow(image, bs, y, 2);
    159             for(x=0; x<xsize; x++ )
    160                 *idatap++ = (rs[x] & 0xff)  |
    161                     ((gs[x] & 0xff)<<8) |
    162                     ((bs[x] & 0xff)<<16);
    163         }
    164     }
    165     iclose(image);
    166     if ( error_called ) {
    167         Py_DECREF(rv);
    168         return NULL;
    169     }
    170     return rv;
    171 }
    172 
    173 static IMAGE *glob_image;
    174 static long *glob_datap;
    175 static int glob_width, glob_z, glob_ysize;
    176 
    177 static void
    178 xs_get(short *buf, int y)
    179 {
    180     if (top_to_bottom)
    181         getrow(glob_image, buf, (glob_ysize-1-y), glob_z);
    182     else
    183         getrow(glob_image, buf, y, glob_z);
    184 }
    185 
    186 static void
    187 xs_put_c(short *buf, int y)
    188 {
    189     char *datap = (char *)glob_datap + y*glob_width;
    190     int width = glob_width;
    191 
    192     while ( width-- )
    193         *datap++ = (*buf++) & 0xff;
    194 }
    195 
    196 static void
    197 xs_put_0(short *buf, int y)
    198 {
    199     long *datap = glob_datap + y*glob_width;
    200     int width = glob_width;
    201 
    202     while ( width-- )
    203         *datap++ = (*buf++) & 0xff;
    204 }
    205 static void
    206 xs_put_12(short *buf, int y)
    207 {
    208     long *datap = glob_datap + y*glob_width;
    209     int width = glob_width;
    210 
    211     while ( width-- )
    212         *datap++ |= ((*buf++) & 0xff) << (glob_z*8);
    213 }
    214 
    215 static void
    216 xscale(IMAGE *image, int xsize, int ysize, int zsize,
    217        long *datap, int xnew, int ynew, int fmode, double blur)
    218 {
    219     glob_image = image;
    220     glob_datap = datap;
    221     glob_width = xnew;
    222     glob_ysize = ysize;
    223     if ( zsize == 1 ) {
    224         glob_z = 0;
    225         filterzoom(xs_get, xs_put_c, xsize, ysize,
    226                    xnew, ynew, fmode, blur);
    227     } else {
    228         glob_z = 0;
    229         filterzoom(xs_get, xs_put_0, xsize, ysize,
    230                    xnew, ynew, fmode, blur);
    231         glob_z = 1;
    232         filterzoom(xs_get, xs_put_12, xsize, ysize,
    233                    xnew, ynew, fmode, blur);
    234         glob_z = 2;
    235         filterzoom(xs_get, xs_put_12, xsize, ysize,
    236                    xnew, ynew, fmode, blur);
    237     }
    238 }
    239 
    240 
    241 static PyObject *
    242 imgfile_readscaled(PyObject *self, PyObject *args)
    243 {
    244     char *fname;
    245     PyObject *rv;
    246     int xsize, ysize, zsize;
    247     char *cdatap;
    248     long *idatap;
    249     static short rs[8192], gs[8192], bs[8192];
    250     int x, y;
    251     int xwtd, ywtd, xorig, yorig;
    252     float xfac, yfac;
    253     IMAGE *image;
    254     char *filter;
    255     double blur = 1.0;
    256     int extended;
    257     int fmode = 0;
    258     int yfirst, ylast, ystep;
    259 
    260     /*
    261     ** Parse args. Funny, since arg 4 and 5 are optional
    262     ** (filter name and blur factor). Also, 4 or 5 arguments indicates
    263     ** extended scale algorithm in stead of simple-minded pixel drop/dup.
    264     */
    265     extended = PyTuple_Size(args) >= 4;
    266     if ( !PyArg_ParseTuple(args, "sii|sd",
    267                            &fname, &xwtd, &ywtd, &filter, &blur) )
    268         return NULL;
    269 
    270     /*
    271     ** Check parameters, open file and check type, rows, etc.
    272     */
    273     if ( extended ) {
    274         if ( strcmp(filter, "impulse") == 0 )
    275             fmode = IMPULSE;
    276         else if ( strcmp( filter, "box") == 0 )
    277             fmode = BOX;
    278         else if ( strcmp( filter, "triangle") == 0 )
    279             fmode = TRIANGLE;
    280         else if ( strcmp( filter, "quadratic") == 0 )
    281             fmode = QUADRATIC;
    282         else if ( strcmp( filter, "gaussian") == 0 )
    283             fmode = GAUSSIAN;
    284         else {
    285             PyErr_SetString(ImgfileError, "Unknown filter type");
    286             return NULL;
    287         }
    288     }
    289 
    290     if ( (image = imgfile_open(fname)) == NULL )
    291         return NULL;
    292 
    293     if ( image->colormap != CM_NORMAL ) {
    294         iclose(image);
    295         PyErr_SetString(ImgfileError,
    296                         "Can only handle CM_NORMAL images");
    297         return NULL;
    298     }
    299     if ( BPP(image->type) != 1 ) {
    300         iclose(image);
    301         PyErr_SetString(ImgfileError,
    302                         "Can't handle imgfiles with bpp!=1");
    303         return NULL;
    304     }
    305     xsize = image->xsize;
    306     ysize = image->ysize;
    307     zsize = image->zsize;
    308     if ( zsize != 1 && zsize != 3) {
    309         iclose(image);
    310         PyErr_SetString(ImgfileError,
    311                         "Can only handle 1 or 3 byte pixels");
    312         return NULL;
    313     }
    314     if ( xsize > 8192 ) {
    315         iclose(image);
    316         PyErr_SetString(ImgfileError,
    317                         "Can't handle image with > 8192 columns");
    318         return NULL;
    319     }
    320 
    321     if ( zsize == 3 ) zsize = 4;
    322     rv = PyString_FromStringAndSize(NULL, xwtd*ywtd*zsize);
    323     if ( rv == NULL ) {
    324         iclose(image);
    325         return NULL;
    326     }
    327     PyFPE_START_PROTECT("readscaled", return 0)
    328     xfac = (float)xsize/(float)xwtd;
    329     yfac = (float)ysize/(float)ywtd;
    330     PyFPE_END_PROTECT(yfac)
    331     cdatap = PyString_AsString(rv);
    332     idatap = (long *)cdatap;
    333 
    334     if ( extended ) {
    335         xscale(image, xsize, ysize, zsize,
    336                idatap, xwtd, ywtd, fmode, blur);
    337     } else {
    338         if (top_to_bottom) {
    339             yfirst = ywtd-1;
    340             ylast = -1;
    341             ystep = -1;
    342         } else {
    343             yfirst = 0;
    344             ylast = ywtd;
    345             ystep = 1;
    346         }
    347         for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
    348             yorig = (int)(y*yfac);
    349             if ( zsize == 1 ) {
    350                 getrow(image, rs, yorig, 0);
    351                 for(x=0; x<xwtd; x++ ) {
    352                     *cdatap++ = rs[(int)(x*xfac)];
    353                 }
    354             } else {
    355                 getrow(image, rs, yorig, 0);
    356                 getrow(image, gs, yorig, 1);
    357                 getrow(image, bs, yorig, 2);
    358                 for(x=0; x<xwtd; x++ ) {
    359                     xorig = (int)(x*xfac);
    360                     *idatap++ = (rs[xorig] & 0xff)  |
    361                         ((gs[xorig] & 0xff)<<8) |
    362                         ((bs[xorig] & 0xff)<<16);
    363                 }
    364             }
    365         }
    366     }
    367     iclose(image);
    368     if ( error_called ) {
    369         Py_DECREF(rv);
    370         return NULL;
    371     }
    372     return rv;
    373 }
    374 
    375 static PyObject *
    376 imgfile_getsizes(PyObject *self, PyObject *args)
    377 {
    378     char *fname;
    379     PyObject *rv;
    380     IMAGE *image;
    381 
    382     if ( !PyArg_ParseTuple(args, "s:getsizes", &fname) )
    383         return NULL;
    384 
    385     if ( (image = imgfile_open(fname)) == NULL )
    386         return NULL;
    387     rv = Py_BuildValue("(iii)", image->xsize, image->ysize, image->zsize);
    388     iclose(image);
    389     return rv;
    390 }
    391 
    392 static PyObject *
    393 imgfile_write(PyObject *self, PyObject *args)
    394 {
    395     IMAGE *image;
    396     char *fname;
    397     int xsize, ysize, zsize, len;
    398     char *cdatap;
    399     long *idatap;
    400     short rs[8192], gs[8192], bs[8192];
    401     short r, g, b;
    402     long rgb;
    403     int x, y;
    404     int yfirst, ylast, ystep;
    405 
    406 
    407     if ( !PyArg_ParseTuple(args, "ss#iii:write",
    408                       &fname, &cdatap, &len, &xsize, &ysize, &zsize) )
    409         return NULL;
    410 
    411     if ( zsize != 1 && zsize != 3 ) {
    412         PyErr_SetString(ImgfileError,
    413                         "Can only handle 1 or 3 byte pixels");
    414         return NULL;
    415     }
    416     if ( len != xsize * ysize * (zsize == 1 ? 1 : 4) ) {
    417         PyErr_SetString(ImgfileError, "Data does not match sizes");
    418         return NULL;
    419     }
    420     if ( xsize > 8192 ) {
    421         PyErr_SetString(ImgfileError,
    422                         "Can't handle image with > 8192 columns");
    423         return NULL;
    424     }
    425 
    426     error_called = 0;
    427     errno = 0;
    428     image =iopen(fname, "w", RLE(1), 3, xsize, ysize, zsize);
    429     if ( image == 0 ) {
    430         if ( ! error_called ) {
    431             if (errno)
    432                 PyErr_SetFromErrno(ImgfileError);
    433             else
    434                 PyErr_SetString(ImgfileError,
    435                                 "Can't create image file");
    436         }
    437         return NULL;
    438     }
    439 
    440     idatap = (long *)cdatap;
    441 
    442     if (top_to_bottom) {
    443         yfirst = ysize-1;
    444         ylast = -1;
    445         ystep = -1;
    446     } else {
    447         yfirst = 0;
    448         ylast = ysize;
    449         ystep = 1;
    450     }
    451     for ( y=yfirst; y != ylast && !error_called; y += ystep ) {
    452         if ( zsize == 1 ) {
    453             for( x=0; x<xsize; x++ )
    454                 rs[x] = *cdatap++;
    455             putrow(image, rs, y, 0);
    456         } else {
    457             for( x=0; x<xsize; x++ ) {
    458                 rgb = *idatap++;
    459                 r = rgb & 0xff;
    460                 g = (rgb >> 8 ) & 0xff;
    461                 b = (rgb >> 16 ) & 0xff;
    462                 rs[x] = r;
    463                 gs[x] = g;
    464                 bs[x] = b;
    465             }
    466             putrow(image, rs, y, 0);
    467             putrow(image, gs, y, 1);
    468             putrow(image, bs, y, 2);
    469         }
    470     }
    471     iclose(image);
    472     if ( error_called )
    473         return NULL;
    474     Py_INCREF(Py_None);
    475     return Py_None;
    476 
    477 }
    478 
    479 
    480 static PyMethodDef imgfile_methods[] = {
    481     { "getsizes",       imgfile_getsizes, METH_VARARGS },
    482     { "read",           imgfile_read, METH_VARARGS },
    483     { "readscaled",     imgfile_readscaled, METH_VARARGS},
    484     { "write",          imgfile_write, METH_VARARGS },
    485     { "ttob",           imgfile_ttob, METH_VARARGS },
    486     { NULL,             NULL } /* Sentinel */
    487 };
    488 
    489 
    490 void
    491 initimgfile(void)
    492 {
    493     PyObject *m, *d;
    494 
    495     if (PyErr_WarnPy3k("the imgfile module has been removed in "
    496                        "Python 3.0", 2) < 0)
    497         return;
    498 
    499     m = Py_InitModule("imgfile", imgfile_methods);
    500     if (m == NULL)
    501         return;
    502     d = PyModule_GetDict(m);
    503     ImgfileError = PyErr_NewException("imgfile.error", NULL, NULL);
    504     if (ImgfileError != NULL)
    505         PyDict_SetItemString(d, "error", ImgfileError);
    506 }
    507 
    508 
    509 
    510