bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#69602: 29.1; Image :map should adjust with :scale and :rotation


From: Joseph Turner
Subject: bug#69602: 29.1; Image :map should adjust with :scale and :rotation
Date: Thu, 07 Mar 2024 05:53:11 -0800

Eli Zaretskii <eliz@gnu.org> writes:

>> From: Joseph Turner <joseph@breatheoutbreathe.in>
>> Cc: 69602@debbugs.gnu.org, stephen.berman@gmx.net, juri@linkov.net
>> Date: Thu, 07 Mar 2024 00:08:57 -0800
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
> I hoped :map allows its value to be a form that is evaluated when the
> image is being processed, in which case that form could call
> image-compute-scaling-factor when it produces the coordinates.

Thanks!  Would this require a change in C?

> If that doesn't work, then...
>
>> When creating an image, we set its :map property according to the return
>> value of `image-compute-scaling-factor'.  Once the image is inserted into
>> the buffer, the user may run `image-increase-size' or `image-rotate',
>> which changes how the image is displayed but not its :map.
>>
>> Now, we need to rerun `image-compute-scaling-factor' and recompute :map.

What I said here is wrong.  `image-compute-scaling-factor' is not
useful for recomputing :map, but `image--current-scaling' is.

>> However, there is no hook which runs after the user runs those commands,
>> so AFAICT there's no way for our code to know when to recompute :map.
>
> ...AFAIU, when an image is rescaled, we call
> image-transform-properties to produce the updated image properties.

There are two ways to rescale an image, `image-transform-properties'
(defined in image-mode.el; works only on file-backed images in
image-mode) and `image--change-size' (defined in image.el; works
on any image object in any mode).

For now, I'd like to focus on improving `image.el'.

> So I guess you'd like that function to recompute the coordinates in
> :map according to the transform?
>
> IOW, I don't understand why you think the problem can only be solved
> in C: AFAIK almost all of the machinery that performs image transforms
> is implemented in Lisp, and each time an image is rescaled, we
> basically re-process the image descriptor anew.

The attached patch adds two hooks in `image.el' which allow packages to
recompute an image's map after it's rescaled or rotated.

The following demonstrates `image-after-change-size-hooks':

(progn
  (defun image--scale-map (map factor)
    "Scale MAP by FACTOR, destructively modifying it."
    (when (and factor (/= 1 factor))
      (pcase-dolist (`(,`(,type . ,coords) ,_id ,_plist) map)
        (pcase-exhaustive type
          ('rect
           (setf (caar coords) (round (* (caar coords) factor)))
           (setf (cdar coords) (round (* (cdar coords) factor)))
           (setf (cadr coords) (round (* (cadr coords) factor)))
           (setf (cddr coords) (round (* (cddr coords) factor))))
          ('circle
           (setf (caar coords) (round (* (caar coords) factor)))
           (setf (cdar coords) (round (* (cdar coords) factor)))
           (setf (cdr coords) (round (* (cdr coords) factor))))
          ('poly
           (dotimes (i (length coords))
             (aset coords i
                   (round (* (aref coords i) factor))))))))
    map)

  (defun image-rescale-image-map ()
    "Recalculate and set :map property of image at point.
Assumes that image has an :unscaled-map property."
    (when-let* ((image (image--get-imagemagick-and-warn))
                (unscaled-image (image--image-without-parameters image))
                (unscaled-map (image-property image :unscaled-map))
                (scale (image--current-scaling image unscaled-image)))
      (setf (image-property image :map)
            (image--scale-map (copy-tree unscaled-map t) scale))))

  (with-current-buffer (get-buffer-create "*image-properties-test*")
    (let* ((svg-string "<?xml version=\"1.0\" encoding=\"UTF-8\" 
standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n 
\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\";>\n<!-- Generated by 
graphviz version 2.43.0 (0)\n -->\n<!-- Title: orggraphview Pages: 1 -->\n<svg 
width=\"128pt\" height=\"128pt\"\n viewBox=\"0.00 0.00 127.59 127.59\" 
xmlns=\"http://www.w3.org/2000/svg\"; 
xmlns:xlink=\"http://www.w3.org/1999/xlink\";>\n<g id=\"graph0\" class=\"graph\" 
transform=\"scale(1 1) rotate(0) translate(4 
123.59)\">\n<title>orggraphview</title>\n<polygon fill=\"white\" 
stroke=\"transparent\" points=\"-4,4 -4,-123.59 123.59,-123.59 123.59,4 
-4,4\"/>\n<!-- a -->\n<g id=\"node1\" class=\"node\">\n<title>a</title>\n<g 
id=\"a_node1\"><a xlink:href=\"1\" xlink:title=\"Hover me!\">\n<ellipse 
fill=\"none\" stroke=\"black\" cx=\"59.79\" cy=\"-59.79\" rx=\"59.59\" 
ry=\"59.59\"/>\n<text text-anchor=\"middle\" x=\"59.79\" y=\"-56.09\" 
font-family=\"Times,serif\" font-size=\"14.00\" fill=\"#000000\">Hover 
me!</text>\n</a>\n</g>\n</g>\n</g>\n</svg>\n")
           (scale 0.75)  ; Adjust initial image scale
           (unscaled-map '(((circle (85 . 85) . 80) "1" (help-echo 
"Surprise!"))))
           (map (image--scale-map (copy-tree unscaled-map t) scale))
           (image
            (create-image svg-string 'svg t
                          :scale scale :map map :unscaled-map unscaled-map)))
      (add-hook 'image-after-change-size-hooks #'image-rescale-image-map nil t)
      (erase-buffer)
      (insert-image image)
      (goto-char (point-min))
      (pop-to-buffer (current-buffer)))))

After applying the attached patch, evaluate the above form, press "i +"
and "i -" repeatedly to see the image and its map scale together.

Thanks!

Joseph

Attachment: 0001-Add-image-after-change-size-hooks-image-after-rotate.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]