Tk Source Code

Artifact [3fe926ad]
Login

Artifact 3fe926ad7c971aff1782df315f47f9a9d03fab160e6f4a34bb4e83d3599868a1:

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