From e25c6211a88d0b05aad035c481f3a7cee3d0eb16 Mon Sep 17 00:00:00 2001 From: Timo Taipalus Date: Thu, 6 Jan 2022 10:28:38 +0200 Subject: [PATCH] Add support for image flipping (Bug#47095) * lisp/image.el (image-map): Keybindings for flipping functions. (image-flip-horizontally): New function that toggles image flipping property. (image-flip-vertically): New function that toggles image flipping property and rotates image 180 degrees. * src/image.c (syms_of_image): Add property. (image_set_transform): Modify image rotation code to also horizontally flip the image when the property is set. * etc/NEWS: Add description. * doc/lispref/display.texi (Image Descriptors): Document :flip. --- doc/lispref/display.texi | 6 ++++++ etc/NEWS | 4 ++++ lisp/image.el | 18 ++++++++++++++++++ src/image.c | 31 +++++++++++++++++++++++++++---- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 1b08eda200..488af2a866 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -5596,6 +5596,12 @@ Image Descriptors values rotate clockwise, negative values counter-clockwise. Rotation is performed after scaling and cropping. +@item :flip @var{flip} +If this is @code{t}, the image will be horizontally flipped. +Currently it has no effect if the image type is @code{imagemagick}. +Vertical flipping can be achieved by rotating the image 180 degrees +and toggling this value. + @item :transform-smoothing @var{smooth} If this is @code{t}, any image transform will have smoothing applied; if @code{nil}, no smoothing will be applied. The exact algorithm used diff --git a/etc/NEWS b/etc/NEWS index 9c892b285d..231beae5d1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -599,6 +599,10 @@ This controls whether or not to show a message when opening certain image formats saying how to edit it as text. The default is to show this message for SVG and XPM. ++++ +*** New commands: 'image-flip-horizontally' and 'image-flip-vertically'. +These commands horizontally and vertically flip the image under point. + ** Image-Dired +++ diff --git a/lisp/image.el b/lisp/image.el index c9165f7781..53358888c2 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -181,6 +181,8 @@ image-map (define-key map [C-wheel-up] 'image-mouse-increase-size) (define-key map [C-mouse-4] 'image-mouse-increase-size) (define-key map "r" 'image-rotate) + (define-key map "h" 'image-flip-horizontally) + (define-key map "v" 'image-flip-vertically) (define-key map "o" 'image-save) map)) @@ -1249,6 +1251,22 @@ image-save (write-region (point-min) (point-max) (read-file-name "Write image to file: "))))) +(defun image-flip-horizontally () + "Horizontally flip the image under point." + (interactive) + (let ((image (image--get-image))) + (image-flush image) + (setf (image-property image :flip) + (not (image-property image :flip))))) + +(defun image-flip-vertically () + "Vertically flip the image under point." + (interactive) + (let ((image (image--get-image))) + (image-rotate 180) + (setf (image-property image :flip) + (not (image-property image :flip))))) + (provide 'image) ;;; image.el ends here diff --git a/src/image.c b/src/image.c index e7d347b782..61771ee4cf 100644 --- a/src/image.c +++ b/src/image.c @@ -2408,6 +2408,11 @@ image_set_transform (struct frame *f, struct image *img) double rotation = 0.0; compute_image_rotation (img, &rotation); + /* Determine flipping. */ + bool flip; + Lisp_Object m = image_spec_value (img->spec, QCflip, NULL); + flip = !NILP (m); + #ifndef HAVE_HAIKU # if defined USE_CAIRO || defined HAVE_XRENDER || defined HAVE_NS /* We want scale up operations to use a nearest neighbor filter to @@ -2447,14 +2452,25 @@ image_set_transform (struct frame *f, struct image *img) /* Perform rotation transformation. */ int rotate_flag = -1; - if (rotation == 0) + if (rotation == 0 && !flip) rotate_flag = 0; else { # if (defined USE_CAIRO || defined HAVE_XRENDER \ || defined HAVE_NTGUI || defined HAVE_NS) int cos_r, sin_r; - if (rotation == 90) + if (rotation == 0) + { + /* FLIP is always true here. As this will rotate by 0 + degrees, it has no visible effect. Applying only + translation matrix to the image would be sufficient for + horizontal flipping, but writing special handling for + this case would increase code complexity somewhat. */ + cos_r = 1; + sin_r = 0; + rotate_flag = 1; + } + else if (rotation == 90) { width = img->height; height = img->width; @@ -2495,9 +2511,14 @@ image_set_transform (struct frame *f, struct image *img) matrix3x3 v; matrix3x3_mult (rot, u, v); - /* 3. Translate back. */ + /* 3. Translate back. Flip horizontally if requested. */ t[2][0] = width * -.5; t[2][1] = height * -.5; + if (flip) + { + t[0][0] = -t[0][0]; + t[2][0] = -t[2][0]; + } matrix3x3_mult (t, v, matrix); # else /* 1. Translate so (0, 0) is in the center of the image. */ @@ -2515,9 +2536,10 @@ image_set_transform (struct frame *f, struct image *img) matrix3x3 v; matrix3x3_mult (u, rot, v); - /* 3. Translate back. */ + /* 3. Translate back. Flip horizontally if requested. */ t[2][0] = width * .5; t[2][1] = height * .5; + if (flip) t[0][0] = -t[0][0]; matrix3x3_mult (v, t, matrix); # endif img->width = width; @@ -11365,6 +11387,7 @@ syms_of_image (void) DEFSYM (QCtransform_smoothing, ":transform-smoothing"); DEFSYM (QCcolor_adjustment, ":color-adjustment"); DEFSYM (QCmask, ":mask"); + DEFSYM (QCflip, ":flip"); /* Other symbols. */ DEFSYM (Qlaplace, "laplace"); -- 2.32.0 (Apple Git-132)