Attachment "tip611.patch" to
ticket [2058b607]
added by
chw
2021-09-03 08:52:20.
Index: generic/tkImgPhoto.c
==================================================================
--- generic/tkImgPhoto.c
+++ generic/tkImgPhoto.c
@@ -195,10 +195,13 @@
static int MatchStringFormat(Tcl_Interp *interp, Tcl_Obj *data,
Tcl_Obj *formatString,
Tk_PhotoImageFormat **imageFormatPtr,
int *widthPtr, int *heightPtr, int *oldformat);
static const char * GetExtension(const char *path);
+static int ImgPhotoRotateReflect(Tcl_Interp *interp,
+ PhotoModel *modelPtr, int rotate,
+ int reflectX, int reflectY);
/*
*----------------------------------------------------------------------
*
* PhotoFormatThreadExitProc --
@@ -390,17 +393,18 @@
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
{
static const char *const photoOptions[] = {
- "blank", "cget", "configure", "copy", "data", "get", "put",
- "read", "redither", "transparency", "write", NULL
+ "blank", "cget", "configure", "copy", "data",
+ "get", "put", "read", "redither", "reflect",
+ "rotate", "transparency", "write", NULL
};
enum PhotoOptions {
PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
- PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_TRANS,
- PHOTO_WRITE
+ PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_REFLECT,
+ PHOTO_ROTATE, PHOTO_TRANS, PHOTO_WRITE
};
PhotoModel *modelPtr = clientData;
int result, index, x, y, width, height, dataWidth, dataHeight, listObjc;
struct SubcommandOptions options;
@@ -1162,10 +1166,48 @@
Tk_ImageChanged(modelPtr->tkMaster, x, y,
(modelPtr->width - x), (modelPtr->height - y),
modelPtr->width, modelPtr->height);
}
return TCL_OK;
+
+ case PHOTO_REFLECT: {
+ static const char *const reflectOptions[] = {
+ "horizontal", "vertical", NULL
+ };
+ enum transOptions {
+ REFLECT_H, REFLECT_V
+ };
+ int index;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "horizontal|vertical");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[2], reflectOptions, "option",
+ 0, &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ return ImgPhotoRotateReflect(interp, modelPtr, 0,
+ index == 0, index != 0);
+ }
+
+ case PHOTO_ROTATE: {
+ int rotate;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "direction");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIntFromObj(interp, objv[2], &rotate) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (rotate) {
+ return ImgPhotoRotateReflect(interp, modelPtr,
+ (rotate < 0) ? 270 : 90, 0, 0);
+ }
+ return TCL_OK;
+ }
case PHOTO_TRANS: {
static const char *const photoTransOptions[] = {
"get", "set", NULL
};
@@ -4087,10 +4129,113 @@
Tk_PhotoGetImage(clientData, &block);
block.pixelPtr += y * block.pitch + x * block.pixelSize;
return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ImgPhotoRotateReflect --
+ *
+ * This function rotates and/or reflects a photo image.
+ *
+ * Results:
+ * Returns a standard Tcl return value.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+ImgPhotoRotateReflect(
+ Tcl_Interp *interp, /* Interpreter. */
+ PhotoModel *modelPtr, /* Pointer to data structure describing
+ * overall photo image to (re)configure. */
+ int rotate, /* Rotation in degrees CCW. */
+ int reflectX, /* When true, reflect along X axis. */
+ int reflectY) /* When true, reflect along Y axis. */
+{
+ Tk_PhotoHandle photo = (Tk_PhotoHandle) modelPtr;
+ Tk_PhotoImageBlock block;
+ int width, height;
+ unsigned char *pixelPtr;
+
+ Tk_PhotoGetImage(photo, &block);
+ pixelPtr = (unsigned char *)
+ attemptckalloc((unsigned) block.height * block.pitch);
+ if (pixelPtr == NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, -1));
+ Tcl_SetErrorCode(interp, "TK", "MALLOC", NULL);
+ return TCL_ERROR;
+ }
+ memcpy(pixelPtr, block.pixelPtr, block.height * block.pitch);
+ block.pixelPtr = pixelPtr;
+ rotate = rotate % 360;
+ if (rotate < 45) {
+ rotate = 0;
+ } else if (rotate < 135) {
+ rotate = 90;
+ } else if (rotate < 225) {
+ rotate = 180;
+ } else if (rotate < 315) {
+ rotate = 270;
+ } else {
+ rotate = 0;
+ }
+ if (reflectX && reflectY) {
+ rotate = (rotate + 180) % 360;
+ }
+ width = block.width;
+ height = block.height;
+ switch (rotate) {
+ case 270: /* = 90 CW */
+ block.pitch = block.pixelSize;
+ block.pixelPtr += width * block.pixelSize * (height - 1);
+ block.pixelSize *= -width;
+ block.width = height;
+ block.height = width;
+ break;
+ case 180: /* = 180 CW */
+ block.pitch = -block.pitch;
+ block.pixelPtr += (width * height - 1) * block.pixelSize;
+ block.pixelSize = -block.pixelSize;
+ break;
+ case 90: /* = 270 CW */
+ block.pitch = -block.pixelSize;
+ block.pixelPtr += (width - 1) * block.pixelSize;
+ block.pixelSize *= width;
+ block.width = height;
+ block.height = width;
+ break;
+ }
+ if (reflectX) {
+ block.pixelPtr += (block.width - 1) * block.pixelSize;
+ block.pixelSize = -block.pixelSize;
+ }
+ if (reflectY) {
+ block.pixelPtr += block.pitch * (block.height - 1);
+ block.pitch = -block.pitch;
+ }
+ if (ImgPhotoSetSize(modelPtr, block.width, block.height) != TCL_OK) {
+ ckfree((char *) pixelPtr);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, -1));
+ Tcl_SetErrorCode(interp, "TK", "MALLOC", NULL);
+ return TCL_ERROR;
+ }
+ if (Tk_PhotoPutBlock(interp, photo, &block, 0, 0, block.width,
+ block.height, TK_PHOTO_COMPOSITE_SET) != TCL_OK) {
+ ckfree((char *) pixelPtr);
+ return TCL_ERROR;
+ }
+ ckfree((char *) pixelPtr);
+ return TCL_OK;
+}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoPutBlock_NoComposite, Tk_PhotoPutZoomedBlock_NoComposite --