Blender V2.61 - r43446

ImageBuff.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of VideoTexture library
00004 
00005 Copyright (c) 2007 The Zdeno Ash Miklas
00006 
00007 This program is free software; you can redistribute it and/or modify it under
00008 the terms of the GNU Lesser General Public License as published by the Free Software
00009 Foundation; either version 2 of the License, or (at your option) any later
00010 version.
00011 
00012 This program is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00015 
00016 You should have received a copy of the GNU Lesser General Public License along with
00017 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00018 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00019 http://www.gnu.org/copyleft/lesser.txt.
00020 -----------------------------------------------------------------------------
00021 */
00022 
00027 // implementation
00028 
00029 #include <PyObjectPlus.h>
00030 #include <structmember.h>
00031 
00032 #include "ImageBuff.h"
00033 #include "Exception.h"
00034 #include "ImageBase.h"
00035 #include "FilterSource.h"
00036 
00037 // use ImBuf API for image manipulation
00038 extern "C" {
00039 #include "IMB_imbuf_types.h"
00040 #include "IMB_imbuf.h"
00041 #include "bgl.h"
00042 };
00043 
00044 // default filter
00045 FilterRGB24 defFilter;
00046 
00047 // forward declaration;
00048 extern PyTypeObject ImageBuffType;
00049 
00050 static int ImageBuff_init (PyObject * pySelf, PyObject * args, PyObject * kwds)
00051 {
00052     short width = -1;
00053     short height = -1;
00054     unsigned char color = 0;
00055     PyObject *py_scale = Py_False;
00056     ImageBuff *image;
00057 
00058     PyImage * self = reinterpret_cast<PyImage*>(pySelf);
00059     // create source object
00060     if (self->m_image != NULL) 
00061         delete self->m_image;
00062     image = new ImageBuff();
00063     self->m_image = image;
00064 
00065     if (PyArg_ParseTuple(args, "hh|bO!:ImageBuff", &width, &height, &color, &PyBool_Type, &py_scale)) 
00066     {
00067         // initialize image buffer
00068         image->setScale(py_scale == Py_True);
00069         image->clear(width, height, color);
00070     }
00071     else
00072     {
00073         // check if at least one argument was passed
00074         if (width != -1 || height != -1)
00075             // yes and they didn't match => it's an error
00076             return -1;
00077         // empty argument list is okay
00078         PyErr_Clear();
00079     }
00080     // initialization succeded
00081     return 0;
00082 
00083 }
00084 
00085 ImageBuff::~ImageBuff (void)
00086 {
00087     if (m_imbuf)
00088         IMB_freeImBuf(m_imbuf);
00089 }
00090 
00091 
00092 // load image from buffer
00093 void ImageBuff::load (unsigned char * img, short width, short height)
00094 {
00095     // loading a new buffer implies to reset the imbuf if any, because the size may change
00096     if (m_imbuf)
00097     {
00098         IMB_freeImBuf(m_imbuf);
00099         m_imbuf = NULL;
00100     }
00101     // initialize image buffer
00102     init(width, height);
00103     // original size
00104     short orgSize[2] = {width, height};
00105     // is filter available
00106     if (m_pyfilter != NULL)
00107         // use it to process image
00108         convImage(*(m_pyfilter->m_filter), img, orgSize);
00109     else
00110         // otherwise use default filter
00111         convImage(defFilter, img, orgSize);
00112     // image is available
00113     m_avail = true;
00114 }
00115 
00116 void ImageBuff::clear (short width, short height, unsigned char color)
00117 {
00118     unsigned char *p;
00119     int size;
00120 
00121     // loading a new buffer implies to reset the imbuf if any, because the size may change
00122     if (m_imbuf)
00123     {
00124         IMB_freeImBuf(m_imbuf);
00125         m_imbuf = NULL;
00126     }
00127     // initialize image buffer
00128     init(width, height);
00129     // the width/height may be different due to scaling
00130     size = (m_size[0] * m_size[1]);
00131     // initialize memory with color for all channels
00132     memset(m_image, color, size*4);
00133     // and change the alpha channel
00134     p = &((unsigned char*)m_image)[3];
00135     for (; size>0; size--)
00136     {
00137         *p = 0xFF;
00138         p += 4;
00139     }
00140     // image is available
00141     m_avail = true;
00142 }
00143 
00144 // img must point to a array of RGBA data of size width*height
00145 void ImageBuff::plot (unsigned char * img, short width, short height, short x, short y, short mode)
00146 {
00147     struct ImBuf* tmpbuf;
00148 
00149     if (m_size[0] == 0 || m_size[1] == 0 || width <= 0 || height <= 0)
00150         return;
00151 
00152     if (!m_imbuf) {
00153         // allocate most basic imbuf, we will assign the rect buffer on the fly
00154         m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0);
00155     }
00156 
00157     tmpbuf = IMB_allocImBuf(width, height, 0, 0);
00158 
00159     // assign temporarily our buffer to the ImBuf buffer, we use the same format
00160     tmpbuf->rect = (unsigned int*)img;
00161     m_imbuf->rect = m_image;
00162     IMB_rectblend(m_imbuf, tmpbuf, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
00163     // remove so that MB_freeImBuf will free our buffer
00164     m_imbuf->rect = NULL;
00165     tmpbuf->rect = NULL;
00166     IMB_freeImBuf(tmpbuf);
00167 }
00168 
00169 void ImageBuff::plot (ImageBuff* img, short x, short y, short mode)
00170 {
00171     if (m_size[0] == 0 || m_size[1] == 0 || img->m_size[0] == 0 || img->m_size[1] == 0)
00172         return;
00173 
00174     if (!m_imbuf) {
00175         // allocate most basic imbuf, we will assign the rect buffer on the fly
00176         m_imbuf = IMB_allocImBuf(m_size[0], m_size[1], 0, 0);
00177     }
00178     if (!img->m_imbuf) {
00179         // allocate most basic imbuf, we will assign the rect buffer on the fly
00180         img->m_imbuf = IMB_allocImBuf(img->m_size[0], img->m_size[1], 0, 0);
00181     }
00182     // assign temporarily our buffer to the ImBuf buffer, we use the same format
00183     img->m_imbuf->rect = img->m_image;
00184     m_imbuf->rect = m_image;
00185     IMB_rectblend(m_imbuf, img->m_imbuf, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
00186     // remove so that MB_freeImBuf will free our buffer
00187     m_imbuf->rect = NULL;
00188     img->m_imbuf->rect = NULL;
00189 }
00190 
00191 
00192 // cast Image pointer to ImageBuff
00193 inline ImageBuff * getImageBuff (PyImage * self)
00194 { return static_cast<ImageBuff*>(self->m_image); }
00195 
00196 
00197 // python methods
00198 
00199 static bool testPyBuffer(Py_buffer* buffer, int width, int height, unsigned int pixsize)
00200 {
00201     if (buffer->itemsize != 1)
00202     {
00203         PyErr_SetString(PyExc_ValueError, "Buffer must be an array of bytes");
00204         return false;
00205     } 
00206     if (buffer->len != width*height*pixsize)
00207     {
00208         PyErr_SetString(PyExc_ValueError, "Buffer hasn't the correct size");
00209         return false;
00210     } 
00211     // multi dimension are ok as long as there is no hole in the memory
00212     Py_ssize_t size = buffer->itemsize;
00213     for (int i=buffer->ndim-1; i>=0 ; i--)
00214     {
00215         if (buffer->suboffsets != NULL && buffer->suboffsets[i] >= 0)
00216         {
00217             PyErr_SetString(PyExc_ValueError, "Buffer must be of one block");
00218             return false;
00219         }
00220         if (buffer->strides != NULL && buffer->strides[i] != size)
00221         {
00222             PyErr_SetString(PyExc_ValueError, "Buffer must be of one block");
00223             return false;
00224         }
00225         if (i > 0)
00226             size *= buffer->shape[i];
00227     }
00228     return true;
00229 }
00230 
00231 static bool testBGLBuffer(Buffer* buffer, int width, int height, unsigned int pixsize)
00232 {
00233     unsigned int size = BGL_typeSize(buffer->type);
00234     for (int i=0; i<buffer->ndimensions; i++)
00235     {
00236         size *= buffer->dimensions[i];
00237     }
00238     if (size != width*height*pixsize)
00239     {
00240         PyErr_SetString(PyExc_ValueError, "Buffer hasn't the correct size");
00241         return false;
00242     } 
00243     return true;
00244 }
00245 
00246 
00247 // load image
00248 static PyObject * load (PyImage * self, PyObject * args)
00249 {
00250     // parameters: string image buffer, its size, width, height
00251     Py_buffer buffer;
00252     Buffer *bglBuffer;
00253     short width;
00254     short height;
00255     unsigned int pixSize;
00256 
00257     // calc proper buffer size
00258     // use pixel size from filter
00259     if (self->m_image->getFilter() != NULL)
00260         pixSize = self->m_image->getFilter()->m_filter->firstPixelSize();
00261     else
00262         pixSize = defFilter.firstPixelSize();
00263 
00264     // parse parameters
00265     if (!PyArg_ParseTuple(args, "s*hh:load", &buffer, &width, &height))
00266     {
00267         PyErr_Clear();
00268         // check if it is BGL buffer
00269         if (!PyArg_ParseTuple(args, "O!hh:load", &BGL_bufferType, &bglBuffer, &width, &height))
00270         {
00271             // report error
00272             return NULL;
00273         }
00274         else
00275         {
00276             if (testBGLBuffer(bglBuffer, width, height, pixSize))
00277             {
00278                 try
00279                 {
00280                     // if correct, load image
00281                     getImageBuff(self)->load((unsigned char*)bglBuffer->buf.asvoid, width, height);
00282                 }
00283                 catch (Exception & exp)
00284                 {
00285                     exp.report();
00286                 }
00287             }
00288         }
00289     }
00290     else
00291     {
00292         // check if buffer size is correct
00293         if (testPyBuffer(&buffer, width, height, pixSize))
00294         {
00295             try 
00296             {
00297                 // if correct, load image
00298                 getImageBuff(self)->load((unsigned char*)buffer.buf, width, height);
00299             }
00300             catch (Exception & exp)
00301             {
00302                 exp.report();
00303             }
00304         }
00305         PyBuffer_Release(&buffer);
00306     }
00307     if (PyErr_Occurred())
00308         return NULL;
00309     Py_RETURN_NONE; 
00310 }
00311 
00312 static PyObject * plot (PyImage * self, PyObject * args)
00313 {
00314     PyImage * other;
00315     Buffer* bglBuffer;
00316     Py_buffer buffer;
00317     //unsigned char * buff;
00318     //unsigned int buffSize;
00319     short width;
00320     short height;
00321     short x, y;
00322     short mode = IMB_BLEND_COPY;
00323 
00324     if (PyArg_ParseTuple(args, "s*hhhh|h:plot", &buffer, &width, &height, &x, &y, &mode))
00325     {
00326         // correct decoding, verify that buffer size is correct
00327         // we need a continous memory buffer
00328         if (testPyBuffer(&buffer, width, height, 4))
00329         {
00330             getImageBuff(self)->plot((unsigned char*)buffer.buf, width, height, x, y, mode);
00331         }
00332         PyBuffer_Release(&buffer);
00333         if (PyErr_Occurred())
00334             return NULL;
00335         Py_RETURN_NONE; 
00336     }
00337     PyErr_Clear();
00338     // try the other format
00339     if (PyArg_ParseTuple(args, "O!hh|h:plot", &ImageBuffType, &other, &x, &y, &mode))
00340     {
00341         getImageBuff(self)->plot(getImageBuff(other), x, y, mode);
00342         Py_RETURN_NONE;
00343     }
00344     PyErr_Clear();
00345     // try the last format (BGL buffer)
00346     if (!PyArg_ParseTuple(args, "O!hhhh|h:plot", &BGL_bufferType, &bglBuffer, &width, &height, &x, &y, &mode))
00347     {
00348         PyErr_SetString(PyExc_TypeError, "Expecting ImageBuff or Py buffer or BGL buffer as first argument; width, height next; postion x, y and mode as last arguments");
00349         return NULL;
00350     }
00351     if (testBGLBuffer(bglBuffer, width, height, 4))
00352     {
00353         getImageBuff(self)->plot((unsigned char*)bglBuffer->buf.asvoid, width, height, x, y, mode);
00354     }
00355     if (PyErr_Occurred())
00356         return NULL;
00357     Py_RETURN_NONE; 
00358 }
00359 
00360 // methods structure
00361 static PyMethodDef imageBuffMethods[] =
00362 { 
00363     {"load", (PyCFunction)load, METH_VARARGS, "Load image from buffer"},
00364     {"plot", (PyCFunction)plot, METH_VARARGS, "update image buffer"},
00365     {NULL}
00366 };
00367 // attributes structure
00368 static PyGetSetDef imageBuffGetSets[] =
00369 {   // attributes from ImageBase class
00370     {(char*)"valid", (getter)Image_valid, NULL, (char*)"bool to tell if an image is available", NULL},
00371     {(char*)"image", (getter)Image_getImage, NULL, (char*)"image data", NULL},
00372     {(char*)"size", (getter)Image_getSize, NULL, (char*)"image size", NULL},
00373     {(char*)"scale", (getter)Image_getScale, (setter)Image_setScale, (char*)"fast scale of image (near neighbour)", NULL},
00374     {(char*)"flip", (getter)Image_getFlip, (setter)Image_setFlip, (char*)"flip image vertically", NULL},
00375     {(char*)"filter", (getter)Image_getFilter, (setter)Image_setFilter, (char*)"pixel filter", NULL},
00376     {NULL}
00377 };
00378 
00379 
00380 // define python type
00381 PyTypeObject ImageBuffType =
00382 { 
00383     PyVarObject_HEAD_INIT(NULL, 0)
00384     "VideoTexture.ImageBuff",   /*tp_name*/
00385     sizeof(PyImage),          /*tp_basicsize*/
00386     0,                         /*tp_itemsize*/
00387     (destructor)Image_dealloc, /*tp_dealloc*/
00388     0,                         /*tp_print*/
00389     0,                         /*tp_getattr*/
00390     0,                         /*tp_setattr*/
00391     0,                         /*tp_compare*/
00392     0,                         /*tp_repr*/
00393     0,                         /*tp_as_number*/
00394     0,                         /*tp_as_sequence*/
00395     0,                         /*tp_as_mapping*/
00396     0,                         /*tp_hash */
00397     0,                         /*tp_call*/
00398     0,                         /*tp_str*/
00399     0,                         /*tp_getattro*/
00400     0,                         /*tp_setattro*/
00401     &imageBufferProcs,         /*tp_as_buffer*/
00402     Py_TPFLAGS_DEFAULT,        /*tp_flags*/
00403     "Image source from image buffer",       /* tp_doc */
00404     0,                     /* tp_traverse */
00405     0,                     /* tp_clear */
00406     0,                     /* tp_richcompare */
00407     0,                     /* tp_weaklistoffset */
00408     0,                     /* tp_iter */
00409     0,                     /* tp_iternext */
00410     imageBuffMethods,    /* tp_methods */
00411     0,                   /* tp_members */
00412     imageBuffGetSets,          /* tp_getset */
00413     0,                         /* tp_base */
00414     0,                         /* tp_dict */
00415     0,                         /* tp_descr_get */
00416     0,                         /* tp_descr_set */
00417     0,                         /* tp_dictoffset */
00418     (initproc)ImageBuff_init,     /* tp_init */
00419     0,                         /* tp_alloc */
00420     Image_allocNew,           /* tp_new */
00421 };
00422