dataImage.c // dataImage.c
/************************************************************************
dumpImage.c: Tcl command "dumpImage" that returns a binary
array of scan-lined RGBA values of an image data.
Rev. 0.3. Feb. 18, 2011 zhuo. varname to reuse the memory area
Rev. 0.2. Feb. 18, 2011 zhuo.
Rev. 0.1. Feb. 13, 2011 zhuo
Tcl command to be implemented:
dumpImage ?-format Format? ?-reverse? imgName ?varName?
Return value: When varName is not specified, it returns a binary
array of scan-lined RGBA values of an image data.
When varName is specified, the values are overwritten.
Format : A string consisting of "r", "g", "b", "a", or "0".
r : red, g : green, b : blue, a : alpha, 0 : zero.
It specifies the order of the output stream.
Example:
"r" : generates only red channel values,
"rgb" : generates red, green, and blue values for each
pixel.
"rgb0" : red, green, blue followed by zero.
"rgba" : by default.
-reverse : When specified, the scan starts from the bottom line.
Reference:
handling binary data
http://www.geocities.co.jp/SiliconValley/4137/dir4/tapi40.html
C function
http://www.geocities.co.jp/SiliconValley/4137/dir4/tapi41.html
Access to Photo
http://www.geocities.co.jp/SiliconValley/4137/dir4/tkcmfg.html
***********************************************************************/
#include <tcl.h>
#include <tk.h>
#include <string.h>
typedef struct {
/* system argument */
Tcl_Interp* interp;
int objc;
Tcl_Obj* CONST * objv;
/* argument */
char* strFormat;
char* strImageName;
char* strVarName;
int reverse;
/* format parameters */
int formatLen;
int* formatOffsets;
/* image data */
Tk_PhotoImageBlock imageBlock;
/* output */
enum { ExistingVar, NonexistingVar, ReturnValue } outStyle;
unsigned char* pOutBin;
} DumpImage;
static void init( DumpImage* d, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[] ) {
d->interp = interp;
d->objc = objc;
d->objv = objv;
d->strFormat = "rgb";
d->strImageName = "";
d->strVarName = "";
d->reverse = 0;
d->formatLen = 0;
d->formatOffsets = 0;
d->pOutBin = NULL;
}
static int setArgParams( DumpImage* d ) {
int argCnt = 0;
if ( d->objc < 2 ) {
Tcl_WrongNumArgs( d->interp, 1, d->objv, "?-format format? ?-reverse? imageName ?varName?" );
return TCL_ERROR;
}
/* parse arguments and options */
while ( --(d->objc) >= 1 ) {
char * pArg = Tcl_GetString( *++(d->objv) );
if ( ! strcmp( pArg, "-format" ) ) {
if ( --(d->objc) < 1 ) {
Tcl_AddErrorInfo( d->interp, "-format option needs a format string." );
return TCL_ERROR;
}
d->strFormat = Tcl_GetString( *++(d->objv) );
} else if ( ! strcmp( pArg, "-reverse" ) ) {
d->reverse = 1;
} else if ( *pArg == '-' ) {
Tcl_AddErrorInfo( d->interp, "unknown option encountered." );
return TCL_ERROR;
} else {
switch ( ++argCnt ) {
case 1:
d->strImageName = pArg;
break;
case 2:
d->strVarName = pArg;
break;
default:
Tcl_AddErrorInfo( d->interp, "extra argument specified." );
return TCL_ERROR;
}
}
}
return TCL_OK;
}
static int setImageBlock( DumpImage* d ) {
Tk_PhotoHandle imageHandle = 0;
if ( !strcmp( d->strImageName, "" ) ) {
Tcl_AddErrorInfo( d->interp, "image name not specified." );
return TCL_ERROR;
}
if ( ! (imageHandle = Tk_FindPhoto( d->interp, d->strImageName )) ) {
Tcl_AddErrorInfo( d->interp, "the image name does not exist." );
return TCL_ERROR;
}
Tk_PhotoGetImage( imageHandle, &(d->imageBlock) );
return TCL_OK;
}
static int setFormatOffsets( DumpImage* d ) {
int idx;
d->formatLen = strlen( d->strFormat );
d->formatOffsets = (int*)Tcl_Alloc( sizeof(int) * d->formatLen );
if ( ! d->formatOffsets ) {
Tcl_AddErrorInfo( d->interp, "internal memory full." );
return TCL_ERROR;
}
for ( idx = 0; idx < d->formatLen; ++idx ) {
switch ( d->strFormat[idx] ) {
case 'r' :
d->formatOffsets[idx] = d->imageBlock.offset[ 0 ];
break;
case 'g' :
d->formatOffsets[idx] = d->imageBlock.offset[ 1 ];
break;
case 'b' :
d->formatOffsets[idx] = d->imageBlock.offset[ 2 ];
break;
case 'a' :
d->formatOffsets[idx] = d->imageBlock.offset[ 3 ];
break;
case '0' :
d->formatOffsets[idx] = -1;
break;
default :
Tcl_AddErrorInfo( d->interp, "invalid format character encountered." );
return TCL_ERROR;
}
}
return TCL_OK;
}
static int setOutputArea( DumpImage* d ) {
unsigned int len = sizeof(char) * d->imageBlock.width * d->imageBlock.height * d->formatLen;
/* When varname is specified, and when it exists, prepare overwriting the existing area. */
if ( *(d->strVarName) != '\0' ) {
Tcl_Obj* pObj = Tcl_GetVar2Ex( d->interp, d->strVarName, NULL, 0 );
if ( pObj ) {
d->pOutBin = Tcl_SetByteArrayLength( pObj, len );
d->outStyle = ExistingVar;
return TCL_OK;
}
}
/* When varname not specified, or non-existent */
d->outStyle = ( *(d->strVarName) == '\0' ) ? ReturnValue : NonexistingVar;
d->pOutBin = (unsigned char*)Tcl_Alloc( len );
if ( ! (d->pOutBin) ) {
Tcl_AddErrorInfo( d->interp, "internal memory full." );
return TCL_ERROR;
}
return TCL_OK;
}
static int scan( DumpImage* d ) {
const int width = d->imageBlock.width;
const int height = d->imageBlock.height;
const int pixelSize = d->imageBlock.pixelSize;
const int* const fmtOffs = d->formatOffsets;
const int fmtLen = d->formatLen;
int linePitch = d->imageBlock.pitch;
unsigned char* pLineTop = d->imageBlock.pixelPtr;
int lineCount;
unsigned char* pOutCur = d->pOutBin;
Tcl_Obj* pOutObj;
if ( d->reverse ) {
pLineTop += (height - 1) * linePitch;
linePitch *= -1;
}
for ( lineCount = height; --lineCount >= 0; pLineTop += linePitch ) {
unsigned char* pLineCur;
unsigned char* pLineEnd;
for ( pLineCur = pLineTop, pLineEnd = pLineTop + width * pixelSize;
pLineCur < pLineEnd;
pLineCur += pixelSize ) {
int fmtIdx;
for ( fmtIdx = 0; fmtIdx < fmtLen; ++fmtIdx ) {
*pOutCur++ = (fmtOffs[ fmtIdx ] < 0) ? 0 :
pLineCur[ fmtOffs[ fmtIdx ] ];
}
}
}
if ( d->outStyle == ExistingVar ) {
return TCL_OK;
}
pOutObj = Tcl_NewByteArrayObj( d->pOutBin, width * height * fmtLen );
if ( d->outStyle == ReturnValue ) {
Tcl_SetObjResult( d->interp, pOutObj );
} else {
Tcl_SetVar2Ex( d->interp, d->strVarName, 0, pOutObj, 0 );
}
return TCL_OK;
}
static void final( DumpImage* d ) {
if ( d->formatOffsets ) Tcl_Free( (char*)(d->formatOffsets) );
}
static int dumpImageCmd(ClientData data, Tcl_Interp* interp,
int objc, Tcl_Obj* CONST objv[]){
DumpImage d;
int status = TCL_ERROR;
init( &d, interp, objc, objv );
if ( (setArgParams( &d ) == TCL_OK) &&
(setImageBlock( &d ) == TCL_OK) &&
(setFormatOffsets( &d ) == TCL_OK) &&
(setOutputArea( &d ) == TCL_OK) &&
(scan( &d ) == TCL_OK) ) {
status = TCL_OK;
}
final( &d );
return status;
}
/*
TIPS: The DLLEXPORT function name below must
consist of only alphabet letters (not numbers)
and must be capitalized.
*/
DLLEXPORT int Dumpimage_Init(Tcl_Interp* interp){
#ifdef USE_TCL_STUBS
Tcl_InitStubs( interp, "8.1", 0 );
#endif
#ifdef USE_TK_STUBS
Tk_InitStubs( interp, "8.1", 0 );
#endif
Tcl_CreateObjCommand(interp, "dumpImage", dumpImageCmd, NULL, NULL);
return Tcl_PkgProvide(interp, "dumpImage", "0.1");
}
|