Blender V2.61 - r43446
|
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