diff options
| author | Lars Ingebrigtsen | 2019-11-19 11:47:19 +0100 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2019-11-19 11:47:25 +0100 |
| commit | 067a42f8dd2ce19de3203605ee8c1c08aa192580 (patch) | |
| tree | b316871e26d62bad39e8d9068f7884b401a57f0d | |
| parent | 49192e9510fe3c491b8c759a639bbe8bccf35856 (diff) | |
| download | emacs-067a42f8dd2ce19de3203605ee8c1c08aa192580.tar.gz emacs-067a42f8dd2ce19de3203605ee8c1c08aa192580.zip | |
Allow eww to display exotic images like webp
* lisp/image.el (image-type): Allow passing in the image type.
(create-image): Make conversion work with data in addition to files.
* lisp/image/image-converter.el (image-convert-p): Allow taking
working on data in addition to files (bug#38036).
(image-convert): Ditto.
(image-converter--convert): Extend signature to say whether we're
getting a file or data.
(image-converter--convert-magick): Convert data.
(image-converter--convert): Ditto.
| -rw-r--r-- | lisp/image.el | 38 | ||||
| -rw-r--r-- | lisp/image/image-converter.el | 105 |
2 files changed, 102 insertions, 41 deletions
diff --git a/lisp/image.el b/lisp/image.el index ad2ee6c6071..5f24475ce5b 100644 --- a/lisp/image.el +++ b/lisp/image.el | |||
| @@ -369,8 +369,10 @@ be determined." | |||
| 369 | ;; If nothing seems to be supported, return first type that matched. | 369 | ;; If nothing seems to be supported, return first type that matched. |
| 370 | (or first (setq first type)))))))) | 370 | (or first (setq first type)))))))) |
| 371 | 371 | ||
| 372 | (declare-function image-convert-p "image-converter.el" (file)) | 372 | (declare-function image-convert-p "image-converter.el" |
| 373 | (declare-function image-convert "image-converter.el" (image)) | 373 | (source &optional image-format)) |
| 374 | (declare-function image-convert "image-converter.el" | ||
| 375 | (image &optional image-format)) | ||
| 374 | 376 | ||
| 375 | ;;;###autoload | 377 | ;;;###autoload |
| 376 | (defun image-type (source &optional type data-p) | 378 | (defun image-type (source &optional type data-p) |
| @@ -380,12 +382,20 @@ Optional TYPE is a symbol describing the image type. If TYPE is omitted | |||
| 380 | or nil, try to determine the image type from its first few bytes | 382 | or nil, try to determine the image type from its first few bytes |
| 381 | of image data. If that doesn't work, and SOURCE is a file name, | 383 | of image data. If that doesn't work, and SOURCE is a file name, |
| 382 | use its file extension as image type. | 384 | use its file extension as image type. |
| 383 | Optional DATA-P non-nil means SOURCE is a string containing image data." | 385 | |
| 386 | Optional DATA-P non-nil means SOURCE is a string containing image | ||
| 387 | data. If DATA-P is a symbol with a name on the format | ||
| 388 | `image/jpeg', that may be used as a hint to determine the image | ||
| 389 | type if we can't otherwise guess it." | ||
| 384 | (when (and (not data-p) (not (stringp source))) | 390 | (when (and (not data-p) (not (stringp source))) |
| 385 | (error "Invalid image file name `%s'" source)) | 391 | (error "Invalid image file name `%s'" source)) |
| 386 | (unless type | 392 | (unless type |
| 387 | (setq type (if data-p | 393 | (setq type (if data-p |
| 388 | (image-type-from-data source) | 394 | (or (image-type-from-data source) |
| 395 | (and image-use-external-converter | ||
| 396 | (progn | ||
| 397 | (require 'image-converter) | ||
| 398 | (image-convert-p source data-p)))) | ||
| 389 | (or (image-type-from-file-header source) | 399 | (or (image-type-from-file-header source) |
| 390 | (image-type-from-file-name source) | 400 | (image-type-from-file-name source) |
| 391 | (and image-use-external-converter | 401 | (and image-use-external-converter |
| @@ -457,14 +467,18 @@ Images should not be larger than specified by `max-image-size'. | |||
| 457 | Image file names that are not absolute are searched for in the | 467 | Image file names that are not absolute are searched for in the |
| 458 | \"images\" sub-directory of `data-directory' and | 468 | \"images\" sub-directory of `data-directory' and |
| 459 | `x-bitmap-file-path' (in that order)." | 469 | `x-bitmap-file-path' (in that order)." |
| 460 | ;; It is x_find_image_file in image.c that sets the search path. | 470 | (let ((data-format |
| 461 | (setq type (image-type file-or-data type data-p)) | 471 | ;; Pass the image format, if any, if this is data. |
| 462 | ;; If we have external image conversion switched on (for exotic, | 472 | (and data-p (or (plist-get props :format) t)))) |
| 463 | ;; non-native image formats), then we convert the file. | 473 | ;; It is x_find_image_file in image.c that sets the search path. |
| 464 | (when (eq type 'image-convert) | 474 | (setq type (ignore-error unknown-image-type |
| 465 | (setq file-or-data (image-convert file-or-data) | 475 | (image-type file-or-data type data-format))) |
| 466 | type 'png | 476 | ;; If we have external image conversion switched on (for exotic, |
| 467 | data-p t)) | 477 | ;; non-native image formats), then we convert the file. |
| 478 | (when (eq type 'image-convert) | ||
| 479 | (setq file-or-data (image-convert file-or-data data-format) | ||
| 480 | type 'png | ||
| 481 | data-p t))) | ||
| 468 | (when (image-type-available-p type) | 482 | (when (image-type-available-p type) |
| 469 | (append (list 'image :type type (if data-p :data :file) file-or-data) | 483 | (append (list 'image :type type (if data-p :data :file) file-or-data) |
| 470 | (and (not (plist-get props :scale)) | 484 | (and (not (plist-get props :scale)) |
diff --git a/lisp/image/image-converter.el b/lisp/image/image-converter.el index 2e09976c011..dedccadcf46 100644 --- a/lisp/image/image-converter.el +++ b/lisp/image/image-converter.el | |||
| @@ -48,43 +48,58 @@ installed on the system." | |||
| 48 | (imagemagick :command "convert" :probe ("-list" "format"))) | 48 | (imagemagick :command "convert" :probe ("-list" "format"))) |
| 49 | "List of supported image converters to try.") | 49 | "List of supported image converters to try.") |
| 50 | 50 | ||
| 51 | (defun image-convert-p (file) | 51 | (defun image-convert-p (source &optional data-p) |
| 52 | "Return `image-convert' if FILE is an image file that can be converted." | 52 | "Return `image-convert' if SOURCE is an image that can be converted. |
| 53 | SOURCE can either be a file name or a string containing image | ||
| 54 | data. In the latter case, DATA-P should be non-nil. If DATA-P | ||
| 55 | is a string, it should be a MIME format string like | ||
| 56 | \"image/gif\"." | ||
| 53 | ;; Find an installed image converter. | 57 | ;; Find an installed image converter. |
| 54 | (unless image-converter | 58 | (unless image-converter |
| 55 | (image-converter--find-converter)) | 59 | (image-converter--find-converter)) |
| 56 | (and image-converter | 60 | (and image-converter |
| 57 | (string-match image-converter-regexp file) | 61 | (or (and (not data-p) |
| 62 | (string-match image-converter-regexp source)) | ||
| 63 | (and data-p | ||
| 64 | (symbolp data-p) | ||
| 65 | (string-match "/" (symbol-name data-p)) | ||
| 66 | (string-match | ||
| 67 | image-converter-regexp | ||
| 68 | (concat "foo." (image-converter--mime-type data-p))))) | ||
| 58 | 'image-convert)) | 69 | 'image-convert)) |
| 59 | 70 | ||
| 60 | (defun image-convert (image) | 71 | (defun image-convert (image &optional image-format) |
| 61 | "Convert IMAGE file to the PNG format. | 72 | "Convert IMAGE file to the PNG format. |
| 62 | IMAGE can either be a file name, which will make the return value | 73 | IMAGE can either be a file name, which will make the return value |
| 63 | a string with the image data. It can also be an image object as | 74 | a string with the image data. |
| 64 | returned by `create-image'. If so, it has to be an image object | 75 | |
| 65 | where created with DATA-P nil (i.e., it has to refer to a file)." | 76 | If IMAGE-FORMAT is non-nil, IMAGE is a string containing the |
| 77 | image data, and IMAGE-FORMAT is a symbol with a MIME format name | ||
| 78 | like \"image/webp\". | ||
| 79 | |||
| 80 | IMAGE can also be an image object as returned by `create-image'." | ||
| 66 | ;; Find an installed image converter. | 81 | ;; Find an installed image converter. |
| 67 | (unless image-converter | 82 | (unless image-converter |
| 68 | (image-converter--find-converter)) | 83 | (image-converter--find-converter)) |
| 69 | (unless image-converter | 84 | (unless image-converter |
| 70 | (error "No external image converters available")) | 85 | (error "No external image converters available")) |
| 71 | (when (and (listp image) | ||
| 72 | (not (plist-get (cdr image) :file))) | ||
| 73 | (error "Only images that refer to files can be converted")) | ||
| 74 | (with-temp-buffer | 86 | (with-temp-buffer |
| 75 | (set-buffer-multibyte nil) | 87 | (set-buffer-multibyte nil) |
| 76 | (when-let ((err (image-converter--convert | 88 | (when-let ((err (image-converter--convert |
| 77 | image-converter | 89 | image-converter |
| 78 | (if (listp image) | 90 | (if (listp image) |
| 79 | (plist-get (cdr image) :file) | 91 | (plist-get (cdr image) :file) |
| 80 | image)))) | 92 | image) |
| 93 | (if (listp image) | ||
| 94 | (plist-get (cdr image) :data-p) | ||
| 95 | image-format)))) | ||
| 81 | (error "%s" err)) | 96 | (error "%s" err)) |
| 82 | (if (listp image) | 97 | (if (listp image) |
| 83 | ;; Return an image object that's the same as we were passed, | 98 | ;; Return an image object that's the same as we were passed, |
| 84 | ;; but ignore the :type and :file values. | 99 | ;; but ignore the :type value. |
| 85 | (apply #'create-image (buffer-string) 'png t | 100 | (apply #'create-image (buffer-string) 'png t |
| 86 | (cl-loop for (key val) on (cdr image) by #'cddr | 101 | (cl-loop for (key val) on (cdr image) by #'cddr |
| 87 | unless (memq key '(:type :file)) | 102 | unless (eq key :type) |
| 88 | append (list key val))) | 103 | append (list key val))) |
| 89 | (buffer-string)))) | 104 | (buffer-string)))) |
| 90 | 105 | ||
| @@ -159,33 +174,65 @@ where created with DATA-P nil (i.e., it has to refer to a file)." | |||
| 159 | image-converter-regexp (concat "\\." (regexp-opt formats) "\\'")) | 174 | image-converter-regexp (concat "\\." (regexp-opt formats) "\\'")) |
| 160 | (throw 'done image-converter))))) | 175 | (throw 'done image-converter))))) |
| 161 | 176 | ||
| 162 | (cl-defmethod image-converter--convert ((type (eql graphicsmagick)) file) | 177 | (cl-defmethod image-converter--convert ((type (eql graphicsmagick)) source |
| 178 | image-format) | ||
| 163 | "Convert using GraphicsMagick." | 179 | "Convert using GraphicsMagick." |
| 164 | (image-converter--convert-magick type file)) | 180 | (image-converter--convert-magick type source image-format)) |
| 165 | 181 | ||
| 166 | (cl-defmethod image-converter--convert ((type (eql imagemagick)) file) | 182 | (cl-defmethod image-converter--convert ((type (eql imagemagick)) source |
| 183 | image-format) | ||
| 167 | "Convert using ImageMagick." | 184 | "Convert using ImageMagick." |
| 168 | (image-converter--convert-magick type file)) | 185 | (image-converter--convert-magick type source image-format)) |
| 186 | |||
| 187 | (defun image-converter--mime-type (image-format) | ||
| 188 | (and (symbolp image-format) | ||
| 189 | (cadr (split-string (symbol-name image-format) "/")))) | ||
| 169 | 190 | ||
| 170 | (defun image-converter--convert-magick (type file) | 191 | (defun image-converter--convert-magick (type source image-format) |
| 171 | (let ((command (image-converter--value type :command))) | 192 | (let ((command (image-converter--value type :command))) |
| 172 | (unless (zerop (apply #'call-process (car command) | 193 | (unless (zerop (if image-format |
| 173 | nil t nil | 194 | ;; We have the image data in SOURCE. |
| 174 | (append (cdr command) | 195 | (progn |
| 175 | (list (expand-file-name file) "png:-")))) | 196 | (insert source) |
| 197 | (apply #'call-process-region (point-min) (point-max) | ||
| 198 | (car command) t t nil | ||
| 199 | (append | ||
| 200 | (cdr command) | ||
| 201 | (list (format "%s:-" | ||
| 202 | (image-converter--mime-type | ||
| 203 | image-format)) | ||
| 204 | "png:-")))) | ||
| 205 | ;; SOURCE is a file name. | ||
| 206 | (apply #'call-process (car command) | ||
| 207 | nil t nil | ||
| 208 | (append (cdr command) | ||
| 209 | (list (expand-file-name source) "png:-"))))) | ||
| 176 | ;; If the command failed, hopefully the buffer contains the | 210 | ;; If the command failed, hopefully the buffer contains the |
| 177 | ;; error message. | 211 | ;; error message. |
| 178 | (buffer-string)))) | 212 | (buffer-string)))) |
| 179 | 213 | ||
| 180 | (cl-defmethod image-converter--convert ((type (eql ffmpeg)) file) | 214 | (cl-defmethod image-converter--convert ((type (eql ffmpeg)) source |
| 215 | image-format) | ||
| 181 | "Convert using ffmpeg." | 216 | "Convert using ffmpeg." |
| 182 | (let ((command (image-converter--value type :command))) | 217 | (let ((command (image-converter--value type :command))) |
| 183 | (unless (zerop (apply #'call-process | 218 | (unless (zerop (if image-format |
| 184 | (car command) | 219 | (progn |
| 185 | nil '(t nil) nil | 220 | (insert source) |
| 186 | (append (cdr command) | 221 | (apply #'call-process-region |
| 187 | (list "-i" (expand-file-name file) | 222 | (point-min) (point-max) (car command) |
| 188 | "-c:v" "png" "-f" "image2pipe" "-")))) | 223 | t '(t nil) nil |
| 224 | (append | ||
| 225 | (cdr command) | ||
| 226 | (list "-i" "-" | ||
| 227 | "-c:v" "png" | ||
| 228 | "-f" "image2pipe" "-")))) | ||
| 229 | (apply #'call-process | ||
| 230 | (car command) | ||
| 231 | nil '(t nil) nil | ||
| 232 | (append (cdr command) | ||
| 233 | (list "-i" (expand-file-name source) | ||
| 234 | "-c:v" "png" "-f" "image2pipe" | ||
| 235 | "-"))))) | ||
| 189 | "ffmpeg error when converting"))) | 236 | "ffmpeg error when converting"))) |
| 190 | 237 | ||
| 191 | (provide 'image-converter) | 238 | (provide 'image-converter) |