diff options
| author | Eli Zaretskii | 2024-06-01 16:43:18 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2024-06-01 16:43:18 +0300 |
| commit | d2dce513445d7235c9f751ea6d9b4847d62882e7 (patch) | |
| tree | 7f3aa5fcd3be7ca24f44c96f85ea8c1ab1ad41f4 | |
| parent | 7af5d6fc9a352d4f53f8e48a6bc9ae9a3bf235a3 (diff) | |
| download | emacs-d2dce513445d7235c9f751ea6d9b4847d62882e7.tar.gz emacs-d2dce513445d7235c9f751ea6d9b4847d62882e7.zip | |
Fix misc problems with thumbnails on MS-Windows
* lisp/image/image-dired-external.el (image-dired-pngcrush-thumb):
Fix deletion of intermediate file.
(image-dired-cmd-pngcrush-options)
(image-dired-cmd-create-standard-thumbnail-options): Use %u for
file:// URI.
(image-dired--file-URI): New function.
(image-dired-create-thumb-1, image-dired-create-thumb-2)
(image-dired-set-exif-data): Use it to generate correct URI on
MS-Windows.
* src/w32image.c (Fw32image_create_thumbnail): Copy the file names
before mirroring their slashes.
| -rw-r--r-- | lisp/image/image-dired-external.el | 36 | ||||
| -rw-r--r-- | src/w32image.c | 7 |
2 files changed, 30 insertions, 13 deletions
diff --git a/lisp/image/image-dired-external.el b/lisp/image/image-dired-external.el index 20438fa12e7..1fa94e06e02 100644 --- a/lisp/image/image-dired-external.el +++ b/lisp/image/image-dired-external.el | |||
| @@ -103,21 +103,24 @@ It optimizes the compression of PNG images. It also adds PNG textual chunks | |||
| 103 | with the information required by the Thumbnail Managing Standard." | 103 | with the information required by the Thumbnail Managing Standard." |
| 104 | :type '(choice (const :tag "Not Set" nil) file)) | 104 | :type '(choice (const :tag "Not Set" nil) file)) |
| 105 | 105 | ||
| 106 | ;; Note: the "-text" arguments below are according to specification in | ||
| 107 | ;; https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#CREATION | ||
| 106 | (defcustom image-dired-cmd-pngcrush-options | 108 | (defcustom image-dired-cmd-pngcrush-options |
| 107 | `("-q" | 109 | `("-q" |
| 108 | "-text" "b" "Description" "Thumbnail of file://%f" | 110 | "-text" "b" "Description" "Thumbnail of file://%u" |
| 109 | "-text" "b" "Software" ,(emacs-version) | 111 | "-text" "b" "Software" ,(string-replace "\n" " " (emacs-version)) |
| 110 | ;; "-text b \"Thumb::Image::Height\" \"%oh\" " | 112 | ;; "-text b \"Thumb::Image::Height\" \"%oh\" " |
| 111 | ;; "-text b \"Thumb::Image::Mimetype\" \"%mime\" " | 113 | ;; "-text b \"Thumb::Image::Mimetype\" \"%mime\" " |
| 112 | ;; "-text b \"Thumb::Image::Width\" \"%ow\" " | 114 | ;; "-text b \"Thumb::Image::Width\" \"%ow\" " |
| 113 | "-text" "b" "Thumb::MTime" "%m" | 115 | "-text" "b" "Thumb::MTime" "%m" |
| 114 | ;; "-text b \"Thumb::Size\" \"%b\" " | 116 | ;; "-text b \"Thumb::Size\" \"%b\" " |
| 115 | "-text" "b" "Thumb::URI" "file://%f" | 117 | "-text" "b" "Thumb::URI" "file://%u" |
| 116 | "%q" "%t") | 118 | "%q" "%t") |
| 117 | "Arguments for `image-dired-cmd-pngcrush-program'. | 119 | "Arguments for `image-dired-cmd-pngcrush-program'. |
| 118 | The value can use the same %-format specifiers as in | 120 | The value can use the same %-format specifiers as in |
| 119 | `image-dired-cmd-create-thumbnail-options', with \"%q\" for a | 121 | `image-dired-cmd-create-thumbnail-options', with \"%q\" standing for a |
| 120 | temporary file name (typically generated by pnqnq)." | 122 | temporary file name (typically generated by pnqnq), |
| 123 | and \"%u\" standing for a file URI corresponding to file in \"%f\"." | ||
| 121 | :version "26.1" | 124 | :version "26.1" |
| 122 | :type '(repeat (string :tag "Argument"))) | 125 | :type '(repeat (string :tag "Argument"))) |
| 123 | 126 | ||
| @@ -134,20 +137,22 @@ The value can use the same %-format specifiers as in | |||
| 134 | :type '(repeat (string :tag "Argument")) | 137 | :type '(repeat (string :tag "Argument")) |
| 135 | :link '(url-link "man:optipng(1)")) | 138 | :link '(url-link "man:optipng(1)")) |
| 136 | 139 | ||
| 140 | ;; Note: the "-set" arguments below are according to specification in | ||
| 141 | ;; https://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html#CREATION | ||
| 137 | (defcustom image-dired-cmd-create-standard-thumbnail-options | 142 | (defcustom image-dired-cmd-create-standard-thumbnail-options |
| 138 | (let ((opts (list | 143 | (let ((opts (list |
| 139 | "-size" "%wx%h" "%f[0]" | 144 | "-size" "%wx%h" "%f[0]" |
| 140 | "-set" "Thumb::MTime" "%m" | 145 | "-set" "Thumb::MTime" "%m" |
| 141 | "-set" "Thumb::URI" "file://%f" | 146 | "-set" "Thumb::URI" "file://%u" |
| 142 | "-set" "Description" "Thumbnail of file://%f" | 147 | "-set" "Description" "Thumbnail of file://%u" |
| 143 | "-set" "Software" (emacs-version) | 148 | "-set" "Software" (string-replace "\n" " " (emacs-version)) |
| 144 | "-thumbnail" "%wx%h>" "png:%t"))) | 149 | "-thumbnail" "%wx%h>" "png:%t"))) |
| 145 | (if (executable-find "gm") (cons "convert" opts) opts)) | 150 | (if (executable-find "gm") (cons "convert" opts) opts)) |
| 146 | "Options for creating thumbnails according to the Thumbnail Managing Standard. | 151 | "Options for creating thumbnails according to the Thumbnail Managing Standard. |
| 147 | Used with `image-dired-cmd-create-thumbnail-program', if that is available. | 152 | Used with `image-dired-cmd-create-thumbnail-program', if that is available. |
| 148 | The value can use the same %-format specifiers as in | 153 | The value can use the same %-format specifiers as in |
| 149 | `image-dired-cmd-create-thumbnail-options', with \"%m\" for file | 154 | `image-dired-cmd-create-thumbnail-options', with \"%m\" for file |
| 150 | modification time. | 155 | modification time and \"%u\" for the URI of the file in \"%f\". |
| 151 | On MS-Windows, if the `convert' command is not available, and | 156 | On MS-Windows, if the `convert' command is not available, and |
| 152 | `w32image-create-thumbnail' is used instead, the textual chunks | 157 | `w32image-create-thumbnail' is used instead, the textual chunks |
| 153 | specified by the \"-set\" options will not be injected, and instead | 158 | specified by the \"-set\" options will not be injected, and instead |
| @@ -196,6 +201,12 @@ and %v which is replaced by the tag value." | |||
| 196 | 201 | ||
| 197 | ;;; Util functions | 202 | ;;; Util functions |
| 198 | 203 | ||
| 204 | (defun image-dired--file-URI (file) | ||
| 205 | ;; https://en.wikipedia.org/wiki/File_URI_scheme | ||
| 206 | (if (memq system-type '(windows-nt ms-dos)) | ||
| 207 | (concat "/" file) | ||
| 208 | file)) | ||
| 209 | |||
| 199 | (defun image-dired--probe-thumbnail-cmd (cmd) | 210 | (defun image-dired--probe-thumbnail-cmd (cmd) |
| 200 | "Check whether CMD is usable for thumbnail creation." | 211 | "Check whether CMD is usable for thumbnail creation." |
| 201 | (cond | 212 | (cond |
| @@ -327,11 +338,11 @@ on MS-Windows cannot have too many concurrent sub-processes.") | |||
| 327 | (message "command %S %s" (process-command process) | 338 | (message "command %S %s" (process-command process) |
| 328 | (string-replace "\n" "" status)) | 339 | (string-replace "\n" "" status)) |
| 329 | (message "command %S failed with status %s" | 340 | (message "command %S failed with status %s" |
| 330 | process status)) | 341 | process status))) |
| 331 | (when (or (not (processp process)) | 342 | (when (or (not (processp process)) |
| 332 | (memq (process-status process) '(exit signal))) | 343 | (memq (process-status process) '(exit signal))) |
| 333 | (let ((temp (cdr (assq ?q spec)))) | 344 | (let ((temp (cdr (assq ?q spec)))) |
| 334 | (delete-file temp)))))) | 345 | (delete-file temp))))) |
| 335 | (proc | 346 | (proc |
| 336 | (if (eq system-type 'windows-nt) | 347 | (if (eq system-type 'windows-nt) |
| 337 | ;; See above for the reasons we don't use 'start-process' | 348 | ;; See above for the reasons we don't use 'start-process' |
| @@ -385,6 +396,7 @@ on MS-Windows cannot have too many concurrent sub-processes.") | |||
| 385 | (spec `((?s . ,size) (?w . ,size) (?h . ,size) | 396 | (spec `((?s . ,size) (?w . ,size) (?h . ,size) |
| 386 | (?m . ,modif-time) | 397 | (?m . ,modif-time) |
| 387 | (?f . ,original-file) | 398 | (?f . ,original-file) |
| 399 | (?u . ,(image-dired--file-URI original-file)) | ||
| 388 | (?q . ,thumbnail-nq8-file) | 400 | (?q . ,thumbnail-nq8-file) |
| 389 | (?t . ,thumbnail-file))) | 401 | (?t . ,thumbnail-file))) |
| 390 | (thumbnail-dir (file-name-directory thumbnail-file)) | 402 | (thumbnail-dir (file-name-directory thumbnail-file)) |
| @@ -471,6 +483,7 @@ file is created by Emacs itself." | |||
| 471 | (spec `((?s . ,size) (?w . ,size) (?h . ,size) | 483 | (spec `((?s . ,size) (?w . ,size) (?h . ,size) |
| 472 | (?m . ,modif-time) | 484 | (?m . ,modif-time) |
| 473 | (?f . ,original-file) | 485 | (?f . ,original-file) |
| 486 | (?u . ,(image-dired--file-URI original-file)) | ||
| 474 | (?q . ,thumbnail-nq8-file) | 487 | (?q . ,thumbnail-nq8-file) |
| 475 | (?t . ,thumbnail-file)))) | 488 | (?t . ,thumbnail-file)))) |
| 476 | (cond | 489 | (cond |
| @@ -611,6 +624,7 @@ default value at the prompt." | |||
| 611 | (let ((spec | 624 | (let ((spec |
| 612 | (list | 625 | (list |
| 613 | (cons ?f (expand-file-name file)) | 626 | (cons ?f (expand-file-name file)) |
| 627 | (cons ?u (image-dired--file-URI (expand-file-name file))) | ||
| 614 | (cons ?t tag-name) | 628 | (cons ?t tag-name) |
| 615 | (cons ?v tag-value)))) | 629 | (cons ?v tag-value)))) |
| 616 | (apply #'call-process image-dired-cmd-write-exif-data-program nil nil nil | 630 | (apply #'call-process image-dired-cmd-write-exif-data-program nil nil nil |
diff --git a/src/w32image.c b/src/w32image.c index 6daf42c1916..e71471f4a7c 100644 --- a/src/w32image.c +++ b/src/w32image.c | |||
| @@ -631,7 +631,8 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) | |||
| 631 | 631 | ||
| 632 | /* Create an image by reading from INPUT_FILE. */ | 632 | /* Create an image by reading from INPUT_FILE. */ |
| 633 | wchar_t input_file_w[MAX_PATH]; | 633 | wchar_t input_file_w[MAX_PATH]; |
| 634 | input_file = ENCODE_FILE (Fexpand_file_name (input_file, Qnil)); | 634 | input_file |
| 635 | = ENCODE_FILE (Fexpand_file_name (Fcopy_sequence (input_file), Qnil)); | ||
| 635 | unixtodos_filename (SSDATA (input_file)); | 636 | unixtodos_filename (SSDATA (input_file)); |
| 636 | filename_to_utf16 (SSDATA (input_file), input_file_w); | 637 | filename_to_utf16 (SSDATA (input_file), input_file_w); |
| 637 | GpImage *file_image; | 638 | GpImage *file_image; |
| @@ -652,7 +653,9 @@ Return non-nil if thumbnail creation succeeds, nil otherwise. */) | |||
| 652 | { | 653 | { |
| 653 | /* Save the thumbnail image to a file of specified TYPE. */ | 654 | /* Save the thumbnail image to a file of specified TYPE. */ |
| 654 | wchar_t thumb_file_w[MAX_PATH]; | 655 | wchar_t thumb_file_w[MAX_PATH]; |
| 655 | thumb_file = ENCODE_FILE (Fexpand_file_name (thumb_file, Qnil)); | 656 | thumb_file |
| 657 | = ENCODE_FILE (Fexpand_file_name (Fcopy_sequence (thumb_file), | ||
| 658 | Qnil)); | ||
| 656 | unixtodos_filename (SSDATA (thumb_file)); | 659 | unixtodos_filename (SSDATA (thumb_file)); |
| 657 | filename_to_utf16 (SSDATA (thumb_file), thumb_file_w); | 660 | filename_to_utf16 (SSDATA (thumb_file), thumb_file_w); |
| 658 | status = GdipSaveImageToFile (thumb_image, thumb_file_w, | 661 | status = GdipSaveImageToFile (thumb_image, thumb_file_w, |