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