diff options
Diffstat (limited to 'lisp/image')
-rw-r--r-- | lisp/image/exif.el | 36 | ||||
-rw-r--r-- | lisp/image/gravatar.el | 6 | ||||
-rw-r--r-- | lisp/image/image-converter.el | 92 |
3 files changed, 98 insertions, 36 deletions
diff --git a/lisp/image/exif.el b/lisp/image/exif.el index 23f11bd87cc..b25968af536 100644 --- a/lisp/image/exif.el +++ b/lisp/image/exif.el @@ -58,6 +58,9 @@ ;; (:tag 306 :tag-name date-time :format 2 :format-type ascii ;; :value "2019:09:21 16:22:13") ;; ...) +;; +;; (exif-field 'date-time (exif-parse-file "test.jpg")) => +;; "2022:09:14 18:46:19" ;;; Code: @@ -65,6 +68,7 @@ (defvar exif-tag-alist '((11 processing-software) + (270 description) (271 make) (272 model) (274 orientation) @@ -73,7 +77,8 @@ (296 resolution-unit) (305 software) (306 date-time) - (315 artist)) + (315 artist) + (33432 copyright)) "Alist of tag values and their names.") (defconst exif--orientation @@ -95,7 +100,10 @@ mirrored or not.") "Parse FILE (a JPEG file) and return the Exif data, if any. The return value is a list of Exif items. -If the data is invalid, an `exif-error' is signaled." +If the data is invalid, an `exif-error' is signaled. + +Also see the `exif-field' convenience function to extract data +from the return value of this function." (with-temp-buffer (set-buffer-multibyte nil) (insert-file-contents-literally file) @@ -105,7 +113,10 @@ If the data is invalid, an `exif-error' is signaled." "Parse BUFFER (which should be a JPEG file) and return the Exif data, if any. The return value is a list of Exif items. -If the data is invalid, an `exif-error' is signaled." +If the data is invalid, an `exif-error' is signaled. + +Also see the `exif-field' convenience function to extract data +from the return value of this function." (setq buffer (or buffer (current-buffer))) (with-current-buffer buffer (if enable-multibyte-characters @@ -122,13 +133,20 @@ If the data is invalid, an `exif-error' is signaled." (when-let ((app1 (cdr (assq #xffe1 (exif--parse-jpeg))))) (exif--parse-exif-chunk app1)))))) +(defun exif-field (field data) + "Return raw FIELD from EXIF. +If FIELD is not present in the data, return nil. +FIELD is a symbol in the cdr of `exif-tag-alist'. +DATA is the result of calling `exif-parse-file'." + (plist-get (seq-find (lambda (e) + (eq field (plist-get e :tag-name))) + data) + :value)) + (defun exif-orientation (exif) "Return the orientation (in degrees) in EXIF. If the orientation isn't present in the data, return nil." - (let ((code (plist-get (cl-find 'orientation exif - :key (lambda (e) - (plist-get e :tag-name))) - :value))) + (let ((code (exif-field 'orientation exif))) (cadr (assq code exif--orientation)))) (defun exif--parse-jpeg () @@ -243,9 +261,9 @@ VALUE is an integer representing BYTES characters." (set-buffer-multibyte nil) (if le (dotimes (i bytes) - (insert (logand (lsh value (* i -8)) 255))) + (insert (logand (ash value (* i -8)) 255))) (dotimes (i bytes) - (insert (logand (lsh value (* (- (1- bytes) i) -8)) 255)))) + (insert (logand (ash value (* (- (1- bytes) i) -8)) 255)))) (insert 0) (buffer-string))) diff --git a/lisp/image/gravatar.el b/lisp/image/gravatar.el index 8ef8bd8eeed..8c49c1edf28 100644 --- a/lisp/image/gravatar.el +++ b/lisp/image/gravatar.el @@ -45,7 +45,7 @@ "Time to live in seconds for gravatar cache entries. If a requested gravatar has been cached for longer than this, it is retrieved anew. The default value is 30 days." - :type 'integer + :type 'natnum ;; Restricted :type to number of seconds. :version "27.1" :group 'gravatar) @@ -277,7 +277,7 @@ where GRAVATAR is either an image descriptor, or the symbol ;; Store the image in the cache. (when image (setf (gethash mail-address gravatar--cache) - (cons (time-convert (current-time) 'integer) + (cons (time-convert nil 'integer) image))) (prog1 (apply callback (if data image 'error) cbargs) @@ -286,7 +286,7 @@ where GRAVATAR is either an image descriptor, or the symbol (defun gravatar--prune-cache () (let ((expired nil) - (time (- (time-convert (current-time) 'integer) + (time (- (time-convert nil 'integer) ;; Twelve hours. (* 12 60 60)))) (maphash (lambda (key val) diff --git a/lisp/image/image-converter.el b/lisp/image/image-converter.el index d3d560f0219..9c2f24819a3 100644 --- a/lisp/image/image-converter.el +++ b/lisp/image/image-converter.el @@ -46,6 +46,16 @@ formats that are to be supported: Only the suffixes that map to :type 'symbol :version "27.1") +(defcustom image-convert-to-format "png" + "The image format to convert to. +This should be a string like \"png\" or \"ppm\" or some +other (preferably lossless) format that Emacs understands +natively. The converter chosen has to support the format, and if +not, conversion will fail." + :group 'image + :version "29.1" + :type 'string) + (defvar image-converter-regexp nil "A regexp that matches the file name suffixes that can be converted.") @@ -58,15 +68,21 @@ formats that are to be supported: Only the suffixes that map to (imagemagick :command "convert" :probe ("-list" "format"))) "List of supported image converters to try.") +(defvar image-converter--extra-converters (make-hash-table :test #'equal)) + +(defun image-converter-initialize () + "Determine the external image converter to be used. +This also determines which external formats we can parse." + (unless image-converter + (image-converter--find-converter))) + (defun image-convert-p (source &optional data-p) "Return `image-convert' if SOURCE is an image that can be converted. SOURCE can either be a file name or a string containing image data. In the latter case, DATA-P should be non-nil. If DATA-P is a string, it should be a MIME format string like \"image/gif\"." - ;; Find an installed image converter. - (unless image-converter - (image-converter--find-converter)) + (image-converter-initialize) ;; When image-converter was customized (when (and image-converter (not image-converter-regexp)) (when-let ((formats (image-converter--probe image-converter))) @@ -85,22 +101,23 @@ is a string, it should be a MIME format string like 'image-convert)) (defun image-convert (image &optional image-format) - "Convert IMAGE file to the PNG format. + "Convert IMAGE file to an image format Emacs understands. +This will usually be \"png\", but this is controlled by the +`image-convert-to-format' user option. + IMAGE can either be a file name or image data. To pass in image data, IMAGE should a string containing the image data, and IMAGE-FORMAT should be a symbol with a MIME format name like \"image/webp\". For instance: - (image-convert data-string 'image/bmp) + (image-convert data-string \\='image/bmp) IMAGE can also be an image object as returned by `create-image'. -This function converts the image to PNG, and the converted image -data is returned as a string." - ;; Find an installed image converter. - (unless image-converter - (image-converter--find-converter)) +This function converts the image the preferred format, and the +converted image data is returned as a string." + (image-converter-initialize) (unless image-converter (error "No external image converters available")) (when (and image-format @@ -108,19 +125,27 @@ data is returned as a string." (error "IMAGE-FORMAT should be a symbol like `image/png'")) (with-temp-buffer (set-buffer-multibyte nil) - (when-let ((err (image-converter--convert - image-converter - (if (listp image) - (plist-get (cdr image) :file) - image) - (if (listp image) - (plist-get (cdr image) :data-p) - image-format)))) - (error "%s" err)) + (let* ((source (if (listp image) + (plist-get (cdr image) :file) + image)) + (format (if (listp image) + (plist-get (cdr image) :data-p) + image-format)) + (type (if format + (image-converter--mime-type format) + (file-name-extension source))) + (extra-converter (gethash type image-converter--extra-converters))) + (if extra-converter + (funcall extra-converter source format) + (when-let ((err (image-converter--convert + image-converter source format))) + (error "%s" err)))) (if (listp image) ;; Return an image object that's the same as we were passed, ;; but ignore the :type value. - (apply #'create-image (buffer-string) 'png t + (apply #'create-image (buffer-string) + (intern image-convert-to-format) + t (cl-loop for (key val) on (cdr image) by #'cddr unless (eq key :type) append (list key val))) @@ -241,12 +266,15 @@ Only suffixes that map to `image-mode' are returned." (list (format "%s:-" (image-converter--mime-type image-format)) - "png:-"))))) + (concat image-convert-to-format + ":-")))))) ;; SOURCE is a file name. (apply #'call-process (car command) nil t nil (append (cdr command) - (list (expand-file-name source) "png:-"))))) + (list (expand-file-name source) + (concat image-convert-to-format + ":-")))))) ;; If the command failed, hopefully the buffer contains the ;; error message. (buffer-string)))) @@ -266,17 +294,33 @@ Only suffixes that map to `image-mode' are returned." (append (cdr command) (list "-i" "-" - "-c:v" "png" + "-c:v" image-convert-to-format "-f" "image2pipe" "-"))))) (apply #'call-process (car command) nil '(t nil) nil (append (cdr command) (list "-i" (expand-file-name source) - "-c:v" "png" "-f" "image2pipe" + "-c:v" image-convert-to-format + "-f" "image2pipe" "-"))))) "ffmpeg error when converting"))) +;;;###autoload +(defun image-converter-add-handler (suffix converter) + "Make Emacs use CONVERTER to parse image files that end with SUFFIX. +CONVERTER is a function with two parameters, where the first is +the file name or a string with the image data, and the second is +non-nil if the first parameter is image data. The converter +should output the image in the current buffer, converted to +`image-convert-to-format'." + (cl-pushnew suffix image-converter-file-name-extensions :test #'equal) + (setq image-converter-file-name-extensions + (sort image-converter-file-name-extensions #'string<)) + (setq image-converter-regexp + (concat "\\." (regexp-opt image-converter-file-name-extensions) "\\'")) + (setf (gethash suffix image-converter--extra-converters) converter)) + (provide 'image-converter) ;;; image-converter.el ends here |