GNU bug report logs - #69602
29.1; Image :map should adjust with :scale and :rotation

Previous Next

Package: emacs;

Reported by: Joseph Turner <joseph <at> breatheoutbreathe.in>

Date: Thu, 7 Mar 2024 06:09:02 UTC

Severity: normal

Found in version 29.1

Done: Eli Zaretskii <eliz <at> gnu.org>

Bug is archived. No further changes may be made.

Full log


Message #23 received at 69602 <at> debbugs.gnu.org (full text, mbox):

From: Joseph Turner <joseph <at> breatheoutbreathe.in>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 69602 <at> debbugs.gnu.org, stephen.berman <at> gmx.net, juri <at> linkov.net
Subject: Re: bug#69602: 29.1; Image :map should adjust with :scale and
 :rotation
Date: Thu, 07 Mar 2024 05:53:11 -0800
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes:

>> From: Joseph Turner <joseph <at> breatheoutbreathe.in>
>> Cc: 69602 <at> debbugs.gnu.org, stephen.berman <at> gmx.net, juri <at> linkov.net
>> Date: Thu, 07 Mar 2024 00:08:57 -0800
>>
>> Eli Zaretskii <eliz <at> 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

[0001-Add-image-after-change-size-hooks-image-after-rotate.patch (text/x-diff, attachment)]

This bug report was last modified 1 year and 116 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.