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 :/