0

I am trying to make jabber.el support images sent from e.g. Conversations.

I download the image using url-retrieve-synchonously and call create-image to get an image which I can then use with insert-image. This works as expected.

I would like, however, to put a :max-width and :max-height on the image. I can add them in the create-image call, but because create-image automatically inserts a :width and a :height image property, the max-values are ignored, as the manual explains:

The :max-width and :max-height keywords are used for scaling if the size of the image of the image exceeds these values. If :width is set it will have precedence over max-width, and if :height is set it will have precedence over max-height

The documentation says that I can remove image properties with setf, by setting them to nil:

Function: image-property image property

Return the value of property in image. Properties can be set by using setf. Setting a property to nil will remove the property from the image.

This, however, I can't make work - if I setf a property to nil, the key is deleted, but the value isn't, and the image object seems to be messed up.

Example (simplified):

(defun my-fetch-image (url)
  "Retun filename of image downloaded from url"
  (url-copy-file url "/tmp/test.jpg")
  (create-image "/tmp/test.jpg"))

(setq my-image (my-fetch-image "https://koldfront.dk/photo/pics/2018/09/snapshot-22-142810-s.jpg"))

Now, my-image looks like this: (image :type imagemagick :file "/tmp/test.jpg" :scale 1.2019047619047618 :width 288 :height 400)

And when I try to remove width and height:

(setf (image-property my-image :width) nil)
(setf (image-property my-image :height) nil)

I am left with my-image looking like this: (image :type imagemagick :file "/tmp/test.jpg" :scale 1.2019047619047618 288 :height 400)

As you can see :width got removed, but the value 288 is still there, and :height 400 is untouched.

I'm sure I haven't understood how to use setf, but I can't find any examples to go by, and my guesses don't yield the result I'm after, either.

  • I am using GNU Emacs 26.1 – asjo Apr 14 at 1:06
1

Update: The following statement is incorrect, I can reproduce the issue, and I believe it's a bug of image--set-property.

I can't reproduce with Emacs 26.1 and 26.2 from emacs -Q, the following produces the expected result, unlike yours:

;; So `setf' can know how to macroexpand `image-property'
(require 'image)

(let ((my-image '(image :type imagemagick
                        :file "/tmp/test.jpg"
                        :scale 1.2019047619047618
                        :width 288
                        :height 400)))
  (setf (image-property my-image :width) nil)
  my-image)

;; =>

(image :type imagemagick
       :file "/tmp/test.jpg"
       :scale 1.2019047619047618 288
       :height 400)

setf is a macro, so you can macroexpand it to understand what's it doing, for example, (setf (point) 1) expands to (goto-char 1). (Personally, I use M-x macrostep-expand from a third-party package, however, nowadays Emacs provides the builtin emacs-lisp-macroexpand command.).

  • Uhm, the result you show is the same result as I get. Notice the "288" efter the floating point value in your output? That's the value of the :width your call to setf removed. – asjo Apr 14 at 11:25
  • If you add another setf call to remove the :height, I bet it won't be gone for you either. – asjo Apr 14 at 11:26
  • 1
    @asjo Oops, you're right, I missed the number 288. There is a bug in image--set-property, (setcdr image (cddr image)) should be (setcdr image (cdddr image)), i.e., change cddr into cdddr. – xuchunyang Apr 14 at 12:28
  • 1
    @asjo No, I've not. I think you should. – xuchunyang Apr 15 at 4:23
  • 1
    Thanks for the help analyzing this, I have reported the bug now: debbugs.gnu.org/35285 – asjo Apr 15 at 10:40
0

So far, the workaround I have found is:

            (let ((width (image-property image :width))
                  (height (image-property image :height)))
              (setf (image-property image :width) nil)
              (setf (image-property image width) nil)
              (setf (image-property image :height) nil)
              (setf (image-property image height) nil))

This can't be the right way‽

0

For what's worth, since it's bug of Emacs, before it gets fixed, you can roll your own, something like the following (I wrote it mainly for fun and some practice):

(defun my-image-delete-properties (image &rest props)
  (cl-loop for (k v) on (cdr image) by #'cddr
           unless (memq k props)
           nconc (list k v) into properties
           finally return (cons (car image) properties)))

(let ((my-image '(image :type imagemagick
                        :file "/tmp/test.jpg"
                        :scale 1.2019047619047618
                        :width 288
                        :height 400)))
  (my-image-delete-properties my-image :width :height))
;; => (image :type imagemagick
;;           :file "/tmp/test.jpg"
;;           :scale 1.2019047619047618)

Unlike (setf (image-property image :width) nil), the above doesn't change image in-place (it is usually a good idea), if you want that, you can try the following instead:

(defun my-image-delete-properties (image &rest props)
  (cl-loop for (k v) on (cdr image) by #'cddr
           unless (memq k props)
           nconc (list k v) into properties
           finally return (setcdr image properties))
  image)

(let ((my-image '(image :type imagemagick
                        :file "/tmp/test.jpg"
                        :scale 1.2019047619047618
                        :width 288
                        :height 400)))
  (my-image-delete-properties my-image :width :height)
  my-image)
;; => (image :type imagemagick
;;           :file "/tmp/test.jpg"
;;           :scale 1.2019047619047618)

By the way, there is org-plist-delete for deleting a property from a plist, it doesn't change the argument in-place as well, like the first my-image-delete-properties.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.