Richard Suchenwirth 2010-03-23 - I needed a fast photo image rotation quite badly at work, which would rotate fairly large images (say 2000 * 3000 pixels) by 90 degrees, in place. So after a long while, I did some C coding again, and some hours later, there it was: implementing a single command
rphoto imname ccw
where imname is the name of a photo image, and ccw is 1 for counter-clockwise, 0 for clockwise. This is a standalone extension, but come to think, wouldn't it be nice to have this functionality as an option for image copy ? :^)
/* rphoto.c - extension to make Tk photo images rotatable by 90 degrees */
/* $Id: rphoto.c,v 1.2 2010/03/23 15:07:30 suchenwi Exp $ */
#include <tk.h>
#define RPHOTO_VERSION "1.0"
#ifdef __WIN32__
# include <windows.h>
# ifndef DECLSPEC_EXPORT
# define DECLSPEC_EXPORT __declspec(dllexport)
# endif /* DECLSPEC_EXPORT */
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) {
return TRUE;
}
#else
# define DECLSPEC_EXPORT
#endif
/*------------------------------------------------------------- Worker function*/
static int rphoto(Tk_PhotoHandle imgin, int ccw) {
/* Rotate a photo image by 90 degrees in place.
ccw: 1 for counter-clockwise, 0 for clockwise */
Tk_PhotoImageBlock inblock;
int rc;
int width, height;
int i, j, k, ii, jj;
unsigned char *cp, aByte;
Tk_PhotoImageBlock pixel;
unsigned char *buf;
rc = Tk_PhotoGetImage(imgin, &inblock);
if(rc != 1) return TCL_ERROR;
width = inblock.width;
height = inblock.height;
buf = malloc(width * height * 4);
if(buf == NULL) return TCL_ERROR;
pixel.pixelPtr = buf;
pixel.width = height;
pixel.height = width;
pixel.pitch = height * 4;
pixel.pixelSize = 4;
pixel.offset[0] = 0;
pixel.offset[1] = 1;
pixel.offset[2] = 2;
pixel.offset[3] = 3;
for(i = 0; i < height; i++) {
ii = (ccw? i: height-i-1);
for (j = 0; j < width; j++) {
jj = (ccw? width-j-1: j);
for (k = 0; k < inblock.pixelSize; k++) {
aByte = *(inblock.pixelPtr
+ ii * inblock.pitch
+ jj * inblock.pixelSize
+ inblock.offset[k]);
cp = pixel.pixelPtr
+ j * pixel.pitch
+ i * pixel.pixelSize
+ pixel.offset[k];
*cp = aByte;
}
}
}
Tk_PhotoSetSize(imgin, height, width); /* swapped */
Tk_PhotoPutBlock(imgin, &pixel, 0, 0, height, width, TK_PHOTO_COMPOSITE_SET);
free(buf);
Tk_PhotoSetSize(imgin, 0, 0); /* allow resizing by others */
return TCL_OK;
}
/*------------------------------------------------------------ Command wrapper */
static int rphotoCmd(ClientData clientdata, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]) {
Tk_PhotoHandle imgin;
int ccw;
int rc;
Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
if(objc != 3) {
Tcl_WrongNumArgs(interp, 1, objv, "imgin imgout ccw");
return TCL_ERROR;
}
imgin = Tk_FindPhoto(interp,Tcl_GetStringFromObj(objv[1], NULL));
if (imgin == NULL) {
Tcl_SetStringObj(resultPtr, "input image does not exist",-1);
return TCL_ERROR;
}
rc = Tcl_GetIntFromObj(interp,objv[2],&ccw);
if(rc != TCL_OK) return TCL_ERROR;
rc = rphoto(imgin, ccw);
if(rc != TCL_OK) {
Tcl_SetStringObj(resultPtr, "out of memory",-1);
return TCL_ERROR;
}
return TCL_OK;
}
/* --------------------------------------------- Package & command registration */
EXTERN_C int DECLSPEC_EXPORT Rphoto_Init(Tcl_Interp* interp) {
int r;
const char *tkversion;
#ifdef USE_TCL_STUBS
Tcl_InitStubs(interp, "8.3", 0);
#endif
#ifdef USE_TK_STUBS
Tk_InitStubs(interp, "8.3", 0);
#endif
tkversion = Tcl_PkgRequire(interp, "Tk", "8.4", 0);
if (tkversion == NULL) return TCL_ERROR;
r = Tcl_PkgProvide(interp, "rphoto", RPHOTO_VERSION);
Tcl_CreateObjCommand(interp, "rphoto", (Tcl_ObjCmdProc *)rphotoCmd,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
return r;
}
EXTERN_C int DECLSPEC_EXPORT Rphoto_SafeInit(Tcl_Interp* interp) {
/* We don't need to be specially safe so... */
return Rphoto_Init(interp);
}..\tcc -v -o photorot.dll -Ic:/Programme/Tcl/Include -DUSE_TCL_STUBS -L c:/Programme/Tcl/lib -shared -rdynamic photorot.c tcc version 0.9.25 -> photorot.c photorot.c:37: warning: assignment makes pointer from integer without a cast photorot.c:46: field not found: offset2
Shouldn't it be
offset[2]
??? I also couldn't locate offsetk...?
RS 2010-09-14 If you look at the source of this page (with the Edit link), you see that
offset[2] and offset[k]
are correct there, but the code prettifier seems to play some silly games with it :/