Applied [#7076] Updated Python Image API to use float buffers in getPixelF/setPixelF
and added an image.updateDisplay() function to update imbuf->rect from imbuf->rect_float also corrected some docstrings and epydocs
This commit is contained in:
@@ -38,6 +38,7 @@
|
||||
#include "BKE_library.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_idprop.h"
|
||||
#include "BKE_utildefines.h"
|
||||
#include "BIF_drawimage.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "DNA_space_types.h" /* FILE_MAXDIR = 160 */
|
||||
@@ -106,6 +107,7 @@ static PyObject *Image_setStart( BPy_Image * self, PyObject * args );
|
||||
static PyObject *Image_setEnd( BPy_Image * self, PyObject * args );
|
||||
static PyObject *Image_setSpeed( BPy_Image * self, PyObject * args );
|
||||
static PyObject *Image_reload( BPy_Image * self );
|
||||
static PyObject *Image_updateDisplay( BPy_Image * self );
|
||||
static PyObject *Image_glLoad( BPy_Image * self );
|
||||
static PyObject *Image_glFree( BPy_Image * self );
|
||||
static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args );
|
||||
@@ -126,11 +128,11 @@ static PyObject *Image_makeCurrent( BPy_Image * self );
|
||||
static PyMethodDef BPy_Image_methods[] = {
|
||||
/* name, method, flags, doc */
|
||||
{"getPixelF", ( PyCFunction ) Image_getPixelF, METH_VARARGS,
|
||||
"(int, int) - Get pixel color as floats 0.0-1.0 returns [r,g,b,a]"},
|
||||
"(int, int) - Get pixel color as floats returns [r,g,b,a]"},
|
||||
{"getPixelI", ( PyCFunction ) Image_getPixelI, METH_VARARGS,
|
||||
"(int, int) - Get pixel color as ints 0-255 returns [r,g,b,a]"},
|
||||
{"setPixelF", ( PyCFunction ) Image_setPixelF, METH_VARARGS,
|
||||
"(int, int, [f r,f g,f b,f a]) - Set pixel color using floats 0.0-1.0"},
|
||||
"(int, int, [f r,f g,f b,f a]) - Set pixel color using floats"},
|
||||
{"setPixelI", ( PyCFunction ) Image_setPixelI, METH_VARARGS,
|
||||
"(int, int, [i r, i g, i b, i a]) - Set pixel color using ints 0-255"},
|
||||
{"getMaxXY", ( PyCFunction ) Image_getMaxXY, METH_NOARGS,
|
||||
@@ -159,6 +161,8 @@ static PyMethodDef BPy_Image_methods[] = {
|
||||
"() - Return Image object's bind code value"},
|
||||
{"reload", ( PyCFunction ) Image_reload, METH_NOARGS,
|
||||
"() - Reload the image from the filesystem"},
|
||||
{"updateDisplay", ( PyCFunction ) Image_updateDisplay, METH_NOARGS,
|
||||
"() - Update the display image from the floating point buffer (if it exists)"},
|
||||
{"glLoad", ( PyCFunction ) Image_glLoad, METH_NOARGS,
|
||||
"() - Load the image data in OpenGL texture memory.\n\
|
||||
The bindcode (int) is returned."},
|
||||
@@ -199,7 +203,7 @@ static PyMethodDef BPy_Image_methods[] = {
|
||||
static char M_Image_doc[] = "The Blender Image module\n\n";
|
||||
|
||||
static char M_Image_New_doc[] =
|
||||
"() - return a new Image object";
|
||||
"(name, width, height, depth) - all args are optional, return a new Image object";
|
||||
|
||||
static char M_Image_Get_doc[] =
|
||||
"(name) - return the image with the name 'name', \
|
||||
@@ -243,7 +247,7 @@ static PyObject *M_Image_New( PyObject * self, PyObject * args)
|
||||
if (width > 5000 || height > 5000 || width < 1 || height < 1)
|
||||
return ( EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"Image width and height must be between 1 and 5000" ) );
|
||||
image = BKE_add_image_size(width, height, name, 0, 0, color);
|
||||
image = BKE_add_image_size(width, height, name, depth==128 ? 1 : 0, 0, color);
|
||||
if( !image )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
||||
"couldn't create PyObject Image_Type" ) );
|
||||
@@ -382,27 +386,25 @@ static PyObject *M_Image_Load( PyObject * self, PyObject * value )
|
||||
/**
|
||||
* getPixelF( x, y )
|
||||
* returns float list of pixel colors in rgba order.
|
||||
* returned values are floats normalized to 0.0 - 1.0.
|
||||
* blender images are all 4x8 bit at the moment apr-2005
|
||||
*/
|
||||
* returned values are floats , in the full range of the float image source.
|
||||
*/
|
||||
|
||||
static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args )
|
||||
{
|
||||
|
||||
PyObject *attr;
|
||||
ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
|
||||
char *pixel; /* image data */
|
||||
int index; /* offset into image data */
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
|
||||
int pixel_size = 4; /* each pixel is 4 x 32 bit float */
|
||||
int i;
|
||||
|
||||
if( !PyArg_ParseTuple( args, "ii", &x, &y ) )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected 2 integers" );
|
||||
|
||||
if( !ibuf || !ibuf->rect ) /* loading didn't work */
|
||||
if( !ibuf || (!ibuf->rect_float && !ibuf->rect)) /* loading didn't work */
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't load image data in Blender" );
|
||||
|
||||
@@ -428,15 +430,26 @@ static PyObject *Image_getPixelF( BPy_Image * self, PyObject * args )
|
||||
"couldn't allocate memory for color list" );
|
||||
|
||||
index = ( x + y * ibuf->x ) * pixel_size;
|
||||
|
||||
pixel = ( char * ) ibuf->rect;
|
||||
for (i=0; i<4; i++) {
|
||||
PyList_SetItem( attr, i, PyFloat_FromDouble( ( ( double ) pixel[index+i] ) / 255.0 ));
|
||||
|
||||
/* if a float buffer exists, use it, otherwise convert the 8bpc buffer to float values */
|
||||
if (ibuf->rect_float) {
|
||||
float *pixelf; /* image data */
|
||||
|
||||
pixelf = ibuf->rect_float;
|
||||
for (i=0; i<4; i++) {
|
||||
PyList_SetItem( attr, i, PyFloat_FromDouble( (double)pixelf[index+i] ) );
|
||||
}
|
||||
} else {
|
||||
char *pixelc; /* image data */
|
||||
|
||||
pixelc = ( char * ) ibuf->rect;
|
||||
for (i=0; i<4; i++) {
|
||||
PyList_SetItem( attr, i, PyFloat_FromDouble( ( ( double ) pixelc[index+i] ) / 255.0 ));
|
||||
}
|
||||
}
|
||||
return attr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getPixelI( x, y )
|
||||
* returns integer list of pixel colors in rgba order.
|
||||
@@ -497,12 +510,11 @@ static PyObject *Image_getPixelI( BPy_Image * self, PyObject * args )
|
||||
static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args )
|
||||
{
|
||||
ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
|
||||
char *pixel; /* image data */
|
||||
float *pixel; /* image data */
|
||||
int index; /* offset into image data */
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int a = 0;
|
||||
int pixel_size = 4; /* each pixel is 4 x 8-bits packed in unsigned int */
|
||||
int pixel_size = 4; /* each pixel is 4 x 32 bit float */
|
||||
float p[4];
|
||||
|
||||
if( !PyArg_ParseTuple
|
||||
@@ -510,7 +522,7 @@ static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"expected 2 integers and an array of 4 floats" );
|
||||
|
||||
if( !ibuf || !ibuf->rect ) /* didn't work */
|
||||
if( !ibuf ) /* didn't work */
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't load image data in Blender" );
|
||||
|
||||
@@ -522,28 +534,16 @@ static PyObject *Image_setPixelF( BPy_Image * self, PyObject * args )
|
||||
|| y > ( ibuf->y - 1 )
|
||||
|| x < ibuf->xorig || y < ibuf->yorig )
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"x or y is out of ruange" );
|
||||
|
||||
for( a = 0; a < 4; a++ ) {
|
||||
if( p[a] > 1.0 || p[a] < 0.0 )
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"r, g, b, or a is out of range" );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
assumption: from looking at source, skipx is often not set,
|
||||
so we calc ourselves
|
||||
*/
|
||||
"x or y is out of range" );
|
||||
|
||||
/* if no float buffer already exists, add it */
|
||||
if (!ibuf->rect_float) imb_addrectfloatImBuf(ibuf);
|
||||
|
||||
index = ( x + y * ibuf->x ) * pixel_size;
|
||||
|
||||
pixel = ( char * ) ibuf->rect;
|
||||
|
||||
pixel[index] = ( char ) ( p[0] * 255.0 );
|
||||
pixel[index + 1] = ( char ) ( p[1] * 255.0 );
|
||||
pixel[index + 2] = ( char ) ( p[2] * 255.0 );
|
||||
pixel[index + 3] = ( char ) ( p[3] * 255.0 );
|
||||
pixel = ibuf->rect_float + index;
|
||||
|
||||
QUATCOPY(pixel, p);
|
||||
|
||||
ibuf->userflags |= IB_BITMAPDIRTY;
|
||||
Py_RETURN_NONE;
|
||||
@@ -821,8 +821,11 @@ static PyObject *Image_getDepth( BPy_Image * self )
|
||||
if( !ibuf ) /* didn't work */
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't load image data in Blender" );
|
||||
|
||||
return PyInt_FromLong( (long)ibuf->depth );
|
||||
if (ibuf->rect_float) {
|
||||
return PyInt_FromLong( (long)128 );
|
||||
} else {
|
||||
return PyInt_FromLong( (long)ibuf->depth );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -865,6 +868,21 @@ static PyObject *Image_reload( BPy_Image * self )
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *Image_updateDisplay( BPy_Image * self )
|
||||
{
|
||||
ImBuf *ibuf= BKE_image_get_ibuf(self->image, NULL);
|
||||
|
||||
if( !ibuf ) /* didn't work */
|
||||
return EXPP_ReturnPyObjError( PyExc_RuntimeError,
|
||||
"couldn't load image data in Blender" );
|
||||
|
||||
IMB_rect_from_float(ibuf);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PyObject *Image_glFree( BPy_Image * self )
|
||||
{
|
||||
Image *image = self->image;
|
||||
|
||||
@@ -394,7 +394,7 @@ PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
|
||||
{
|
||||
ID *id = NULL;
|
||||
char *name=NULL, *filename=NULL, *data_type=NULL;
|
||||
int img_width=256, img_height=256;
|
||||
int img_width=256, img_height=256, img_depth=32;
|
||||
float color[] = {0, 0, 0, 1};
|
||||
short data_code = 0;
|
||||
int user_count = 0;
|
||||
@@ -456,8 +456,8 @@ PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
|
||||
|
||||
/* New Data */
|
||||
if (self->type == ID_IM) {
|
||||
/* Image, accepts width and height*/
|
||||
if( !PyArg_ParseTuple( args, "|sii", &name, &img_width, &img_height ) )
|
||||
/* Image, accepts width and height, depth */
|
||||
if( !PyArg_ParseTuple( args, "|siii", &name, &img_width, &img_height, &img_depth ) )
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"one string and two ints expected as arguments" );
|
||||
CLAMP(img_width, 4, 5000);
|
||||
@@ -538,7 +538,7 @@ PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
|
||||
break;
|
||||
case ID_IM:
|
||||
{
|
||||
id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", 0, 0, color);
|
||||
id = (ID *)BKE_add_image_size(img_width, img_height, name?name:"Image", img_depth==128 ? 1:0, 0, color);
|
||||
if( !id )
|
||||
return ( EXPP_ReturnPyObjError( PyExc_MemoryError,
|
||||
"couldn't create PyObject Image_Type" ) );
|
||||
@@ -562,14 +562,14 @@ PyObject *LibBlockSeq_new(BPy_LibBlockSeq *self, PyObject * args, PyObject *kwd)
|
||||
break;
|
||||
case ID_VF:
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"Cannot create new fonts, use the load() function to load from a file" );
|
||||
"Cannot create new fonts, use the new(name, filename) function to load from a file" );
|
||||
case ID_TXT:
|
||||
id = (ID *)add_empty_text( name?name:"Text" );
|
||||
user_count = 1;
|
||||
break;
|
||||
case ID_SO:
|
||||
return EXPP_ReturnPyObjError( PyExc_TypeError,
|
||||
"Cannot create new sounds, use the load() function to load from a file" );
|
||||
"Cannot create new sounds, use the new(name, filename) function to load from a file" );
|
||||
case ID_GR:
|
||||
id = (ID *)add_group( name?name:"Group" );
|
||||
user_count = 1;
|
||||
|
||||
@@ -192,6 +192,16 @@ class Armature:
|
||||
@note: Must have called makeEditable() first.
|
||||
@rtype: None
|
||||
"""
|
||||
def copy():
|
||||
"""
|
||||
Return a copy of this armature.
|
||||
@rtype: Armature
|
||||
"""
|
||||
def __copy__():
|
||||
"""
|
||||
Return a copy of this armature.
|
||||
@rtype: Armature
|
||||
"""
|
||||
|
||||
import id_generics
|
||||
Armature.__doc__ += id_generics.attributes
|
||||
|
||||
@@ -121,6 +121,12 @@ class Group:
|
||||
@rtype: Group
|
||||
@return: a copy of this group
|
||||
"""
|
||||
def copy ():
|
||||
"""
|
||||
Make a copy of this group
|
||||
@rtype: Group
|
||||
@return: a copy of this group
|
||||
"""
|
||||
|
||||
import id_generics
|
||||
Group.__doc__ += id_generics.attributes
|
||||
|
||||
@@ -48,7 +48,7 @@ def New (name, width, height, depth):
|
||||
@type height: int
|
||||
@param height: The height of the new Image object, between 1 and 5000.
|
||||
@type depth: int
|
||||
@param depth: The colour depth of the new Image object. (8:Grey, 24:RGB, 32:RGBA). (Not implimented yet, all new images will be 24bit)
|
||||
@param depth: The colour depth of the new Image object. (32:RGBA 8bit channels, 128:RGBA 32bit high dynamic range float channels).
|
||||
@rtype: Blender Image
|
||||
@return: A new Blender Image object.
|
||||
"""
|
||||
@@ -83,7 +83,7 @@ class Image:
|
||||
@type filename: string
|
||||
@ivar size: The [width, height] dimensions of the image (in pixels).
|
||||
@type size: list
|
||||
@ivar depth: The pixel depth of the image. [8, 16, 18, 24, 32]
|
||||
@ivar depth: The pixel depth of the image, read only. [8, 16, 18, 24, 32, 128 (for 32bit float color channels)]
|
||||
@type depth: int
|
||||
@ivar xrep: Texture tiling: the number of repetitions in the x (horizontal)
|
||||
axis. [1, 16].
|
||||
@@ -137,14 +137,14 @@ class Image:
|
||||
|
||||
def getDepth():
|
||||
"""
|
||||
Get the pixel depth of this image.
|
||||
Get the pixel depth of this image. [8,16,24,32,128 for 32bit float images]
|
||||
@rtype: int
|
||||
"""
|
||||
|
||||
def getPixelF(x, y):
|
||||
"""
|
||||
Get the the colors of the current pixel in the form [r,g,b,a].
|
||||
Returned values are floats normalized to 0.0 - 1.0.
|
||||
For float image types, returned values can be greater then the useual [0.0, 1.0] range.
|
||||
Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
|
||||
@returns: [ r, g, b, a]
|
||||
@rtype: list of 4 floats
|
||||
@@ -229,6 +229,12 @@ class Image:
|
||||
@returns: None
|
||||
"""
|
||||
|
||||
def updateDisplay():
|
||||
"""
|
||||
Update the display image from the floating point buffer (if it exists)
|
||||
@returns: None
|
||||
"""
|
||||
|
||||
def glLoad():
|
||||
"""
|
||||
Load this image's data into OpenGL texture memory, if it is not already
|
||||
@@ -306,7 +312,7 @@ class Image:
|
||||
def setPixelF(x, y, (r, g, b,a )):
|
||||
"""
|
||||
Set the the colors of the current pixel in the form [r,g,b,a].
|
||||
Color values must be floats in the range 0.0 - 1.0.
|
||||
For float image types, returned values can be greater then the useual [0.0, 1.0] range.
|
||||
Pixel coordinates are in the range from 0 to N-1. See L{getMaxXY}
|
||||
@type x: int
|
||||
@type y: int
|
||||
|
||||
Reference in New Issue
Block a user