1

Using wanderlust in emacs-25.1.x, how can I specify the display size and position in the message buffer of attached images that are shown inline?

I want to display smaller versions of the images, and I'd like to arrange them in a grid at the bottom of the message.

I can't find anything in the wanderlust docs about this.

Thank you in advance.

More info added ...

OK. Here's what I have been able to determine so far. Images are displayed using the code in semi/mime-image.el. Near the top of that file is a static-cond which is used to select different methods for displaying images. The one that is selected by default makes use of the standard emacs 'insert-image' function. Here is its doc string:

(insert-image IMAGE &optional STRING AREA SLICE)

Insert IMAGE into current buffer at point. IMAGE is displayed by inserting STRING into the current buffer with a ‘display’ property whose value is the image. STRING defaults to a single space if you omit it. AREA is where to display the image. AREA nil or omitted means display it in the text area, a value of ‘left-margin’ means display it in the left marginal area, a value of ‘right-margin’ means display it in the right marginal area. SLICE specifies slice of IMAGE to insert. SLICE nil or omitted means insert whole image. SLICE is a list (X Y WIDTH HEIGHT) specifying the X and Y positions and WIDTH and HEIGHT of image area to insert. A float value 0.0 - 1.0 means relative to the width or height of the image; integer values are taken as pixel values.

So, even if I change how 'insert-image' is called, it can't be used to resize the image ... only to reposition it and display slices (subsets) of it.

In order to resize these images, I am going to have to add code to redefine new versions the 'mime-image-create' and 'mime-image-insert' functions that normally get defined in semi/mime-image.el.

I'm still not sure how to best do this. Perhaps I can use imagemagick's 'display' program to rescale the image text.

I'm investigating this, and I will continue to report my findings.

7
  • It may be that w3m kicks in to help display in-line images, but I'd need to check that to be sure . . .
    – lawlist
    Commented Apr 6, 2017 at 15:04
  • Concerning w3m: I haven't been able to get emacs-w3m to work under emacs-25. The latest emacs-w3m I could find is from 2005 or 2006, and it's incompatible with emacs-25. Therefore, I would assume that wl is not using w3m on my emacs-25.1 system.
    – HippoMan
    Commented Apr 6, 2017 at 17:37
  • ... but I'm wrong. :) I got w3m working with emacs-25 by using the cvs version of emacs-w3m.
    – HippoMan
    Commented Apr 6, 2017 at 17:48
  • To be clear, these are not technically "inline images". They are MIME attachments which are displayed inline, in the wanderlust message buffer. wl seems to use mime-view within the semi package to display these attachments. However, I couldn't find any code within the semi package which seems to have anything to do with the size and position of the images that are displayed withn the message buffer.
    – HippoMan
    Commented Apr 6, 2017 at 19:57
  • I figured out more info, and I added it to my original question, above.
    – HippoMan
    Commented Apr 6, 2017 at 20:34

2 Answers 2

1

Here is one idea using the built-in image-dired library and the external utility convert that is part of the ImageMagick suite. Emacs does not need to be built with ImageMagick support for this idea to work, but convert and its dependencies must be on the computer. I am only shrinking the image, not organizing the attachments in groups of four or anything fancy like that.

I have added support in mime-display-image for converting PDF full size to PNG thumbnails (first page only).

I found a mime-preview-condition in mime-view.el that conflicts with my new proposed condition, and I resolved the conflict by simply commenting it out. In a nutshell, I don't want mime-display-text/plain to be triggered when dealing with a PDF. If anyone sees a negative effect by commenting out those lines, please post a comment and let me know -- along with a suggested fix (if known).

NOTE: I added the -flatten argument to image-dired-cmd-create-thumbnail-options (in my own setup) in order to make transparent PNG background white. The user may choose to do the same. In my use case, I create PDF with pdflatex from TexLive and PDF converted to PNG without -flatten do not show up well in a buffer with a dark background.

(ctree-set-calist-strictly
  'mime-preview-condition
  '((type . application)
    (subtype . pdf)
    (body . visible)
    (body-presentation-method . mime-display-image)
    (image-format . pdf)))

;; Comment out the following lines in `mime-view.el':
;;    (ctree-set-calist-strictly
;;      'mime-preview-condition
;;      '((body . visible)
;;        (body-presentation-method . mime-display-text/plain)))

(defun mime-display-image (entity situation)
  (message "Decoding image ...")
  (condition-case err
    (let* ((format (cdr (assq 'image-format situation)))
           (image
             (unless (eq format 'pdf)
               (mime-image-create (mime-entity-content entity) format 'data))))
      (if (and (null image) (not (eq format 'pdf)))
          (message "Invalid glyph!")
        (save-excursion
          ;;; (insert-image image)
          (let* ((buffer (current-buffer))
                 (basename (mime-entity-filename entity))
                 ;;; `temporary-file-directory' `should` already have a forward
                 ;;;  trailing slash.  Use the `wl-temporary-file-directory'?
                 (tmp-dir
                   (concat
                     (file-name-as-directory temporary-file-directory)
                      "wanderlust/"))
                 (wl-extract-dir (concat tmp-dir "full-size/"))
                 (wl-thumbnails (concat tmp-dir "thumbnails/"))
                 (curr-file (concat wl-extract-dir basename))
                 (image-dired-dir wl-thumbnails)
                 (image-dired-thumb-width 200)
                 (image-dired-thumb-height 200))
            (when (or image (eq format 'pdf))
              ;;; `image-dired' will create the thumbnail directory.
              (unless (and (file-exists-p wl-extract-dir)
                           (file-directory-p wl-extract-dir))
                (make-directory wl-extract-dir 'parents))
              (mime-write-entity-content entity curr-file))
            (cond
              ((string-match (image-file-name-regexp) curr-file)
                (let ((thumb-name (image-dired-thumb-name curr-file)))
                  (if (and (not (file-exists-p thumb-name))
                           (not (= 0 (image-dired-create-thumb
                                        curr-file thumb-name))))
                      (message "Thumb could not be created for file %s"
                               curr-file)
                    (image-dired-insert-thumbnail
                      thumb-name curr-file buffer))))
              ((string-match "\\.\\(PDF\\)\\'" curr-file)
                (let* ((absolute-basename (file-name-sans-extension curr-file))
                       (png-filename (concat absolute-basename ".png"))
                       (pdf-first-page-filename (concat curr-file "[0]"))
                       (thumb-name (image-dired-thumb-name png-filename)))
                  (if (and (not (file-exists-p thumb-name))
                           (not (= 0 (image-dired-create-thumb
                                       pdf-first-page-filename thumb-name))))
                      (message "Thumb could not be created for file %s"
                               pdf-first-page-filename)
                    (image-dired-insert-thumbnail
                      thumb-name pdf-first-page-filename buffer))))
              (t
                ;;; catch-all / fall-back is the default behavior.
                (message "%s does not match `image-file-name-regexp'" curr-file)
                (insert-image image))))
          (insert "\n")
          (message "Decoding image ... done."))))
   (error nil err)))
1
  • Thank you. I wasn't paying attention, and I didn't notice this a few minutes ago when I entered my own solution, above. It looks like we're using similar methods, although I'm lazy and letting image+ do the Imagemagick and temp-file work :).
    – HippoMan
    Commented Apr 9, 2017 at 14:30
0

I found a way to do all of this. The "image+" package can be used to perform resizing of images and other manipulation:

https://github.com/mhayashi1120/Emacs-imagex

It utilizes temp files and some Imagemagick facilities.

With the help of this package, I now have come up with a way to (1) resize images, and (2) arrange them in a grid at the bottom of the message.

I did this by overriding the 'mime-display-image' function in 'semi/mime-image.el', as follows ...

(defvar my-images-per-line 3
  "*Number of images per line.")
(defvar my-max-image-width (truncate (/ (window-pixel-width) (1+ my-images-per-line)))
  "*Maximum image width.")
(defvar my-max-image-height (truncate (/ (window-pixel-height) 3.5))
  "*Maximum image height.")

(defun my-mime-display-image (entity situation)
  (message "Decoding image...")
  (condition-case err
      (let ((format (cdr (assq 'image-format situation)))
            (nimages 0)
            image
            size
            image-w
            image-h
            w-factor
            h-factor
            resize-factor
            current-point
            end-point)
        (setq image (mime-image-create (mime-entity-content entity)
                                       format 'data))
        (if (null image)
            (message "Invalid glyph!")
          (save-excursion
            (save-restriction
              ;; Count the number of images that are already entered
              ;; into this buffer.
              (widen)
              (setq current-point (point-min))
              (setq end-point (point-max))
              (while (<= current-point end-point)
                (when (get-char-property current-point 'display)
                  (setq nimages (1+ nimages)))
                (setq current-point (1+ current-point))))
            (setq size (image-size image t))
            (setq image-w (car size))
            (setq image-h (cdr size))
            (setq w-factor (/ (float my-max-image-width) image-w))
            (setq h-factor (/ (float my-max-image-height) image-h))
            (setq resize-factor (min w-factor h-factor))
            ;; Enter a single newline if it's the first image to be entered.
            ;; Enter 3 newlines if we've already entered 'my-images-per-line'
            ;; images on the current line.
            (when (= (% nimages my-images-per-line) 0)
              (insert-char ?\n (if (< nimages 1) 1 3)))
            ;; Always precede each image with a few spaces.
            (insert-char ?\s 3)
            (setq current-point (point))
            (mime-image-insert image)
            ;; If resize-factor is not close to 1.00, use the image+
            ;; module to resize the image. It operates on the image
            ;; located at the current point.
            ;; For image+, see https://github.com/mhayashi1120/Emacs-imagex
            (when (> (abs (- resize-factor 1.00)) 0.05)
              (goto-char current-point)
              (imagex-sticky-mode 1)
              (imagex-sticky--zoom resize-factor))
            (message "Decoding image...done")
            )))
        (error nil err)))
(advice-add 'mime-display-image :override #'my-mime-display-image)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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