Fix handling of comments in NetPBM image files.
[bpt/emacs.git] / lisp / image.el
CommitLineData
7840ced1
GM
1;;; image.el --- image API
2
ab422c4d 3;; Copyright (C) 1998-2013 Free Software Foundation, Inc.
634f4a67
PJ
4
5;; Maintainer: FSF
04799cf5 6;; Keywords: multimedia
bd78fa1d 7;; Package: emacs
7840ced1
GM
8
9;; This file is part of GNU Emacs.
10
eb3fa2cf 11;; GNU Emacs is free software: you can redistribute it and/or modify
7840ced1 12;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
7840ced1
GM
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
eb3fa2cf 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
7840ced1
GM
23
24;;; Commentary:
25
26;;; Code:
27
77f6105c
MB
28
29(defgroup image ()
30 "Image support."
31 :group 'multimedia)
32
110683ad 33(defalias 'image-refresh 'image-flush)
77f6105c 34
4fde92ef 35(defconst image-type-header-regexps
62564fc7 36 `(("\\`/[\t\n\r ]*\\*.*XPM.\\*/" . xpm)
0e7690de
CB
37 ("\\`P[1-6]\\\(?:\
38\\(?:\\(?:#[^\r\n]*[\r\n]\\)?[[:space:]]\\)+\
39\\(?:\\(?:#[^\r\n]*[\r\n]\\)?[0-9]\\)+\
40\\)\\{2\\}" . pbm)
3205431d 41 ("\\`GIF8[79]a" . gif)
6642c904 42 ("\\`\x89PNG\r\n\x1a\n" . png)
fa4354c1
AS
43 ("\\`[\t\n\r ]*#define \\([a-z0-9_]+\\)_width [0-9]+\n\
44#define \\1_height [0-9]+\n\\(\
45#define \\1_x_hot [0-9]+\n\
46#define \\1_y_hot [0-9]+\n\\)?\
47static \\(unsigned \\)?char \\1_bits" . xbm)
6642c904
JB
48 ("\\`\\(?:MM\0\\*\\|II\\*\0\\)" . tiff)
49 ("\\`[\t\n\r ]*%!PS" . postscript)
d30a05d1 50 ("\\`\xff\xd8" . jpeg) ; used to be (image-jpeg-p . jpeg)
62564fc7
JL
51 (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
52 (comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\r\n]*<\\)")))
53 (concat "\\(?:<\\?xml[ \t\r\n]+[^>]*>\\)?[ \t\r\n]*<"
54 comment-re "*"
55 "\\(?:!DOCTYPE[ \t\r\n]+[^>]*>[ \t\r\n]*<[ \t\r\n]*" comment-re "*\\)?"
56 "[Ss][Vv][Gg]"))
57 . svg)
58 )
6642c904 59 "Alist of (REGEXP . IMAGE-TYPE) pairs used to auto-detect image types.
7840ced1 60When the first bytes of an image file match REGEXP, it is assumed to
6642c904
JB
61be of image type IMAGE-TYPE if IMAGE-TYPE is a symbol. If not a symbol,
62IMAGE-TYPE must be a pair (PREDICATE . TYPE). PREDICATE is called
63with one argument, a string containing the image data. If PREDICATE returns
64a non-nil value, TYPE is the image's type.")
8a8ef149 65
5fd62452 66(defvar image-type-file-name-regexps
4fde92ef
KS
67 '(("\\.png\\'" . png)
68 ("\\.gif\\'" . gif)
69 ("\\.jpe?g\\'" . jpeg)
70 ("\\.bmp\\'" . bmp)
71 ("\\.xpm\\'" . xpm)
72 ("\\.pbm\\'" . pbm)
73 ("\\.xbm\\'" . xbm)
74 ("\\.ps\\'" . postscript)
62564fc7
JL
75 ("\\.tiff?\\'" . tiff)
76 ("\\.svgz?\\'" . svg)
77 )
4fde92ef
KS
78 "Alist of (REGEXP . IMAGE-TYPE) pairs used to identify image files.
79When the name of an image file match REGEXP, it is assumed to
80be of image type IMAGE-TYPE.")
81
a9bb04bb
CY
82;; We rely on `auto-mode-alist' to detect xbm and xpm files, instead
83;; of content autodetection. Their contents are just C code, so it is
84;; easy to generate false matches.
6642c904
JB
85(defvar image-type-auto-detectable
86 '((pbm . t)
a9bb04bb 87 (xbm . nil)
6642c904
JB
88 (bmp . maybe)
89 (gif . maybe)
90 (png . maybe)
a9bb04bb 91 (xpm . nil)
6642c904
JB
92 (jpeg . maybe)
93 (tiff . maybe)
62564fc7 94 (svg . maybe)
6642c904
JB
95 (postscript . nil))
96 "Alist of (IMAGE-TYPE . AUTODETECT) pairs used to auto-detect image files.
97\(See `image-type-auto-detected-p').
98
99AUTODETECT can be
100 - t always auto-detect.
101 - nil never auto-detect.
102 - maybe auto-detect only if the image type is available
103 (see `image-type-available-p').")
4fde92ef 104
c6b7ccaa 105(defvar image-format-suffixes
8259030d
LMI
106 '((image/x-icon "ico"))
107 "Alist of MIME Content-Type headers to file name suffixes.
108This is used as a hint by the ImageMagick library when detecting
c6b7ccaa 109image types. If `create-image' is called with a :format
8259030d
LMI
110matching found in this alist, the ImageMagick library will be
111told that the data would have this suffix if saved to a file.")
112
45448e64
SM
113(defcustom image-load-path
114 (list (file-name-as-directory (expand-file-name "images" data-directory))
115 'data-directory 'load-path)
5fc5ac38 116 "List of locations in which to search for image files.
93a75651
CY
117If an element is a string, it defines a directory to search.
118If an element is a variable symbol whose value is a string, that
119value defines a directory to search.
120If an element is a variable symbol whose value is a list, the
7a4bc7be
XF
121value is used as a list of directories to search.
122
123Subdirectories are not automatically included in the search."
45448e64
SM
124 :type '(repeat (choice directory variable))
125 :initialize 'custom-initialize-delay)
dada660a 126
5248a565 127
20c65d08 128(defun image-load-path-for-library (library image &optional path no-error)
ae77c7ff 129 "Return a suitable search path for images used by LIBRARY.
7c565097 130
40db64d2 131It searches for IMAGE in `image-load-path' (excluding
c0696e1b
BW
132\"`data-directory'/images\") and `load-path', followed by a path
133suitable for LIBRARY, which includes \"../../etc/images\" and
134\"../etc/images\" relative to the library file itself, and then
135in \"`data-directory'/images\".
7c565097 136
5248a565
BW
137Then this function returns a list of directories which contains
138first the directory in which IMAGE was found, followed by the
68ba6c49 139value of `load-path'. If PATH is given, it is used instead of
5248a565 140`load-path'.
20c65d08 141
5248a565 142If NO-ERROR is non-nil and a suitable path can't be found, don't
68ba6c49 143signal an error. Instead, return a list of directories as before,
5248a565 144except that nil appears in place of the image directory.
7c565097
BW
145
146Here is an example that uses a common idiom to provide
147compatibility with versions of Emacs that lack the variable
148`image-load-path':
149
9f036d33
BW
150 ;; Shush compiler.
151 (defvar image-load-path)
5248a565
BW
152
153 (let* ((load-path (image-load-path-for-library \"mh-e\" \"mh-logo.xpm\"))
9f036d33
BW
154 (image-load-path (cons (car load-path)
155 (when (boundp 'image-load-path)
156 image-load-path))))
5248a565 157 (mh-tool-bar-folder-buttons-init))"
7c565097
BW
158 (unless library (error "No library specified"))
159 (unless image (error "No image specified"))
c0696e1b
BW
160 (let (image-directory image-directory-load-path)
161 ;; Check for images in image-load-path or load-path.
162 (let ((img image)
163 (dir (or
164 ;; Images in image-load-path.
165 (image-search-load-path image)
166 ;; Images in load-path.
167 (locate-library image)))
168 parent)
169 ;; Since the image might be in a nested directory (for
170 ;; example, mail/attach.pbm), adjust `image-directory'
171 ;; accordingly.
172 (when dir
173 (setq dir (file-name-directory dir))
174 (while (setq parent (file-name-directory img))
175 (setq img (directory-file-name parent)
176 dir (expand-file-name "../" dir))))
177 (setq image-directory-load-path dir))
178
44e97401 179 ;; If `image-directory-load-path' isn't Emacs's image directory,
c0696e1b
BW
180 ;; it's probably a user preference, so use it. Then use a
181 ;; relative setting if possible; otherwise, use
182 ;; `image-directory-load-path'.
7c565097 183 (cond
c0696e1b
BW
184 ;; User-modified image-load-path?
185 ((and image-directory-load-path
186 (not (equal image-directory-load-path
187 (file-name-as-directory
188 (expand-file-name "images" data-directory)))))
189 (setq image-directory image-directory-load-path))
7c565097
BW
190 ;; Try relative setting.
191 ((let (library-name d1ei d2ei)
192 ;; First, find library in the load-path.
193 (setq library-name (locate-library library))
194 (if (not library-name)
195 (error "Cannot find library %s in load-path" library))
196 ;; And then set image-directory relative to that.
197 (setq
198 ;; Go down 2 levels.
c0696e1b
BW
199 d2ei (file-name-as-directory
200 (expand-file-name
201 (concat (file-name-directory library-name) "../../etc/images")))
7c565097 202 ;; Go down 1 level.
c0696e1b
BW
203 d1ei (file-name-as-directory
204 (expand-file-name
205 (concat (file-name-directory library-name) "../etc/images"))))
7c565097
BW
206 (setq image-directory
207 ;; Set it to nil if image is not found.
208 (cond ((file-exists-p (expand-file-name image d2ei)) d2ei)
209 ((file-exists-p (expand-file-name image d1ei)) d1ei)))))
44e97401 210 ;; Use Emacs's image directory.
c0696e1b
BW
211 (image-directory-load-path
212 (setq image-directory image-directory-load-path))
20c65d08 213 (no-error
20c65d08 214 (message "Could not find image %s for library %s" image library))
7c565097
BW
215 (t
216 (error "Could not find image %s for library %s" image library)))
217
5248a565
BW
218 ;; Return an augmented `path' or `load-path'.
219 (nconc (list image-directory)
220 (delete image-directory (copy-sequence (or path load-path))))))
221
7c565097 222
b4ac6e8c
GM
223;; Used to be in image-type-header-regexps, but now not used anywhere
224;; (since 2009-08-28).
8a8ef149 225(defun image-jpeg-p (data)
9b78a6a3
RS
226 "Value is non-nil if DATA, a string, consists of JFIF image data.
227We accept the tag Exif because that is the same format."
24c23999
JB
228 (setq data (ignore-errors (string-to-unibyte data)))
229 (when (and data (string-match-p "\\`\xff\xd8" data))
8a8ef149
GM
230 (catch 'jfif
231 (let ((len (length data)) (i 2))
232 (while (< i len)
233 (when (/= (aref data i) #xff)
234 (throw 'jfif nil))
235 (setq i (1+ i))
236 (when (>= (+ i 2) len)
237 (throw 'jfif nil))
238 (let ((nbytes (+ (lsh (aref data (+ i 1)) 8)
4a9bf8a4
GM
239 (aref data (+ i 2))))
240 (code (aref data i)))
241 (when (and (>= code #xe0) (<= code #xef))
8a8ef149 242 ;; APP0 LEN1 LEN2 "JFIF\0"
71296446 243 (throw 'jfif
24c23999
JB
244 (string-match-p "JFIF\\|Exif"
245 (substring data i (min (+ i nbytes) len)))))
3bdbead3 246 (setq i (+ i 1 nbytes))))))))
7840ced1
GM
247
248
249;;;###autoload
162dec01
GM
250(defun image-type-from-data (data)
251 "Determine the image type from image data DATA.
252Value is a symbol specifying the image type or nil if type cannot
7840ced1 253be determined."
4fde92ef 254 (let ((types image-type-header-regexps)
7840ced1 255 type)
4fde92ef 256 (while types
7840ced1 257 (let ((regexp (car (car types)))
6642c904 258 (image-type (cdr (car types))))
4fde92ef 259 (if (or (and (symbolp image-type)
24c23999 260 (string-match-p regexp data))
4fde92ef
KS
261 (and (consp image-type)
262 (funcall (car image-type) data)
263 (setq image-type (cdr image-type))))
264 (setq type image-type
265 types nil)
266 (setq types (cdr types)))))
267 type))
268
269
270;;;###autoload
6642c904 271(defun image-type-from-buffer ()
4fde92ef 272 "Determine the image type from data in the current buffer.
6642c904
JB
273Value is a symbol specifying the image type or nil if type cannot
274be determined."
4fde92ef
KS
275 (let ((types image-type-header-regexps)
276 type
277 (opoint (point)))
278 (goto-char (point-min))
279 (while types
280 (let ((regexp (car (car types)))
6642c904 281 (image-type (cdr (car types)))
4fde92ef
KS
282 data)
283 (if (or (and (symbolp image-type)
24c23999 284 (looking-at-p regexp))
4fde92ef
KS
285 (and (consp image-type)
286 (funcall (car image-type)
287 (or data
288 (setq data
289 (buffer-substring
290 (point-min)
291 (min (point-max)
292 (+ (point-min) 256))))))
293 (setq image-type (cdr image-type))))
6642c904 294 (setq type image-type
4fde92ef
KS
295 types nil)
296 (setq types (cdr types)))))
297 (goto-char opoint)
dce04f7f 298 (and type
67645389 299 (boundp 'image-types)
dce04f7f
CY
300 (memq type image-types)
301 type)))
7840ced1
GM
302
303
162dec01
GM
304;;;###autoload
305(defun image-type-from-file-header (file)
306 "Determine the type of image file FILE from its first few bytes.
307Value is a symbol specifying the image type, or nil if type cannot
308be determined."
4fde92ef
KS
309 (unless (or (file-readable-p file)
310 (file-name-absolute-p file))
311 (setq file (image-search-load-path file)))
312 (and file
313 (file-readable-p file)
314 (with-temp-buffer
315 (set-buffer-multibyte nil)
316 (insert-file-contents-literally file nil 0 256)
6642c904 317 (image-type-from-buffer))))
4fde92ef
KS
318
319
320;;;###autoload
321(defun image-type-from-file-name (file)
322 "Determine the type of image file FILE from its name.
323Value is a symbol specifying the image type, or nil if type cannot
324be determined."
ea1d4aac 325 (let (type first)
11fef14a
GM
326 (catch 'found
327 (dolist (elem image-type-file-name-regexps first)
328 (when (string-match-p (car elem) file)
329 (if (image-type-available-p (setq type (cdr elem)))
330 (throw 'found type)
331 ;; If nothing seems to be supported, return first type that matched.
332 (or first (setq first type))))))))
162dec01 333
7840ced1 334;;;###autoload
7d88e015 335(defun image-type (source &optional type data-p)
e7968373 336 "Determine and return image type.
7d88e015 337SOURCE is an image file name or image data.
7840ced1 338Optional TYPE is a symbol describing the image type. If TYPE is omitted
162dec01 339or nil, try to determine the image type from its first few bytes
7d88e015 340of image data. If that doesn't work, and SOURCE is a file name,
9ea8de1b 341use its file extension as image type.
7d88e015
CY
342Optional DATA-P non-nil means SOURCE is a string containing image data."
343 (when (and (not data-p) (not (stringp source)))
344 (error "Invalid image file name `%s'" source))
162dec01 345 (unless type
7d88e015
CY
346 (setq type (if data-p
347 (image-type-from-data source)
348 (or (image-type-from-file-header source)
349 (image-type-from-file-name source))))
350 (or type (error "Cannot determine image type")))
28681e35 351 (or (memq type (and (boundp 'image-types) image-types))
7d88e015 352 (error "Invalid image type `%s'" type))
e7968373
KS
353 type)
354
6642c904 355
82ff1d13
GM
356(if (fboundp 'image-metadata) ; eg not --without-x
357 (define-obsolete-function-alias 'image-extension-data
358 'image-metadata' "24.1"))
359
2e288d54
JB
360(define-obsolete-variable-alias
361 'image-library-alist
362 'dynamic-library-alist "24.1")
aa360da1 363
e7968373
KS
364;;;###autoload
365(defun image-type-available-p (type)
366 "Return non-nil if image type TYPE is available.
367Image types are symbols like `xbm' or `jpeg'."
368 (and (fboundp 'init-image-library)
d07ff9db 369 (init-image-library type)))
e7968373
KS
370
371
6642c904
JB
372;;;###autoload
373(defun image-type-auto-detected-p ()
4837b516 374 "Return t if the current buffer contains an auto-detectable image.
7d88e015
CY
375This function is intended to be used from `magic-fallback-mode-alist'.
376
377The buffer is considered to contain an auto-detectable image if
378its beginning matches an image type in `image-type-header-regexps',
1e83e2ca
GM
379and that image type is present in `image-type-auto-detectable' with a
380non-nil value. If that value is non-nil, but not t, then the image type
381must be available."
6642c904
JB
382 (let* ((type (image-type-from-buffer))
383 (auto (and type (cdr (assq type image-type-auto-detectable)))))
d567be22 384 (and auto
7d88e015 385 (or (eq auto t) (image-type-available-p type)))))
6642c904
JB
386
387
e7968373
KS
388;;;###autoload
389(defun create-image (file-or-data &optional type data-p &rest props)
390 "Create an image.
391FILE-OR-DATA is an image file name or image data.
392Optional TYPE is a symbol describing the image type. If TYPE is omitted
393or nil, try to determine the image type from its first few bytes
394of image data. If that doesn't work, and FILE-OR-DATA is a file name,
395use its file extension as image type.
396Optional DATA-P non-nil means FILE-OR-DATA is a string containing image data.
397Optional PROPS are additional image attributes to assign to the image,
398like, e.g. `:mask MASK'.
399Value is the image created, or nil if images of type TYPE are not supported.
400
2467875c
GM
401Images should not be larger than specified by `max-image-size'.
402
403Image file names that are not absolute are searched for in the
404\"images\" sub-directory of `data-directory' and
405`x-bitmap-file-path' (in that order)."
406 ;; It is x_find_image_file in image.c that sets the search path.
e7968373 407 (setq type (image-type file-or-data type data-p))
7840ced1 408 (when (image-type-available-p type)
162dec01
GM
409 (append (list 'image :type type (if data-p :data :file) file-or-data)
410 props)))
7840ced1
GM
411
412
413;;;###autoload
cedbd8d0 414(defun put-image (image pos &optional string area)
1571b5ff 415 "Put image IMAGE in front of POS in the current buffer.
7840ced1 416IMAGE must be an image created with `create-image' or `defimage'.
46655c94
GM
417IMAGE is displayed by putting an overlay into the current buffer with a
418`before-string' STRING that has a `display' property whose value is the
cedbd8d0 419image. STRING is defaulted if you omit it.
12dc863d 420The overlay created will have the `put-image' property set to t.
7840ced1 421POS may be an integer or marker.
7840ced1
GM
422AREA is where to display the image. AREA nil or omitted means
423display it in the text area, a value of `left-margin' means
424display it in the left marginal area, a value of `right-margin'
46655c94 425means display it in the right marginal area."
0ad550ba 426 (unless string (setq string "x"))
1571b5ff 427 (let ((buffer (current-buffer)))
cedbd8d0 428 (unless (eq (car-safe image) 'image)
1571b5ff
GM
429 (error "Not an image: %s" image))
430 (unless (or (null area) (memq area '(left-margin right-margin)))
431 (error "Invalid area %s" area))
46655c94 432 (setq string (copy-sequence string))
1571b5ff 433 (let ((overlay (make-overlay pos pos buffer))
46655c94
GM
434 (prop (if (null area) image (list (list 'margin area) image))))
435 (put-text-property 0 (length string) 'display prop string)
1571b5ff 436 (overlay-put overlay 'put-image t)
bc72b5d9
LMI
437 (overlay-put overlay 'before-string string)
438 overlay)))
7840ced1
GM
439
440
441;;;###autoload
5af275e0 442(defun insert-image (image &optional string area slice)
7840ced1 443 "Insert IMAGE into current buffer at point.
46655c94 444IMAGE is displayed by inserting STRING into the current buffer
0f0a88b9 445with a `display' property whose value is the image. STRING
913c8291 446defaults to a single space if you omit it.
7840ced1
GM
447AREA is where to display the image. AREA nil or omitted means
448display it in the text area, a value of `left-margin' means
449display it in the left marginal area, a value of `right-margin'
5af275e0
KS
450means display it in the right marginal area.
451SLICE specifies slice of IMAGE to insert. SLICE nil or omitted
452means insert whole image. SLICE is a list (X Y WIDTH HEIGHT)
453specifying the X and Y positions and WIDTH and HEIGHT of image area
454to insert. A float value 0.0 - 1.0 means relative to the width or
455height of the image; integer values are taken as pixel values."
0ad550ba
DL
456 ;; Use a space as least likely to cause trouble when it's a hidden
457 ;; character in the buffer.
458 (unless string (setq string " "))
cedbd8d0 459 (unless (eq (car-safe image) 'image)
7840ced1
GM
460 (error "Not an image: %s" image))
461 (unless (or (null area) (memq area '(left-margin right-margin)))
462 (error "Invalid area %s" area))
0dc91c57
DL
463 (if area
464 (setq image (list (list 'margin area) image))
465 ;; Cons up a new spec equal but not eq to `image' so that
466 ;; inserting it twice in a row (adjacently) displays two copies of
467 ;; the image. Don't try to avoid this by looking at the display
468 ;; properties on either side so that we DTRT more often with
469 ;; cut-and-paste. (Yanking killed image text next to another copy
470 ;; of it loses anyway.)
471 (setq image (cons 'image (cdr image))))
46655c94
GM
472 (let ((start (point)))
473 (insert string)
474 (add-text-properties start (point)
5af275e0
KS
475 `(display ,(if slice
476 (list (cons 'slice slice) image)
477 image) rear-nonsticky (display)))))
478
479
f22c36d3 480;;;###autoload
5af275e0 481(defun insert-sliced-image (image &optional string area rows cols)
b48bc937
KS
482 "Insert IMAGE into current buffer at point.
483IMAGE is displayed by inserting STRING into the current buffer
913c8291
GM
484with a `display' property whose value is the image. The default
485STRING is a single space.
b48bc937
KS
486AREA is where to display the image. AREA nil or omitted means
487display it in the text area, a value of `left-margin' means
488display it in the left marginal area, a value of `right-margin'
489means display it in the right marginal area.
68ba6c49 490The image is automatically split into ROWS x COLS slices."
5af275e0
KS
491 (unless string (setq string " "))
492 (unless (eq (car-safe image) 'image)
493 (error "Not an image: %s" image))
494 (unless (or (null area) (memq area '(left-margin right-margin)))
495 (error "Invalid area %s" area))
496 (if area
497 (setq image (list (list 'margin area) image))
498 ;; Cons up a new spec equal but not eq to `image' so that
499 ;; inserting it twice in a row (adjacently) displays two copies of
500 ;; the image. Don't try to avoid this by looking at the display
501 ;; properties on either side so that we DTRT more often with
502 ;; cut-and-paste. (Yanking killed image text next to another copy
503 ;; of it loses anyway.)
504 (setq image (cons 'image (cdr image))))
505 (let ((x 0.0) (dx (/ 1.0001 (or cols 1)))
506 (y 0.0) (dy (/ 1.0001 (or rows 1))))
507 (while (< y 1.0)
508 (while (< x 1.0)
509 (let ((start (point)))
510 (insert string)
511 (add-text-properties start (point)
512 `(display ,(list (list 'slice x y dx dy) image)
513 rear-nonsticky (display)))
514 (setq x (+ x dx))))
515 (setq x 0.0
516 y (+ y dy))
82dc617b 517 (insert (propertize "\n" 'line-height t)))))
5af275e0 518
10e2102e 519
7840ced1
GM
520
521;;;###autoload
522(defun remove-images (start end &optional buffer)
523 "Remove images between START and END in BUFFER.
524Remove only images that were put in BUFFER with calls to `put-image'.
525BUFFER nil or omitted means use the current buffer."
526 (unless buffer
527 (setq buffer (current-buffer)))
528 (let ((overlays (overlays-in start end)))
529 (while overlays
530 (let ((overlay (car overlays)))
531 (when (overlay-get overlay 'put-image)
0c898dd9
DL
532 (delete-overlay overlay)))
533 (setq overlays (cdr overlays)))))
7840ced1 534
4fde92ef
KS
535(defun image-search-load-path (file &optional path)
536 (unless path
537 (setq path image-load-path))
538 (let (element found filename)
5fc5ac38 539 (while (and (not found) (consp path))
93a75651 540 (setq element (car path))
5fc5ac38 541 (cond
93a75651 542 ((stringp element)
5fc5ac38
CY
543 (setq found
544 (file-readable-p
4fde92ef 545 (setq filename (expand-file-name file element)))))
93a75651
CY
546 ((and (symbolp element) (boundp element))
547 (setq element (symbol-value element))
548 (cond
549 ((stringp element)
550 (setq found
551 (file-readable-p
4fde92ef 552 (setq filename (expand-file-name file element)))))
93a75651 553 ((consp element)
4fde92ef 554 (if (setq filename (image-search-load-path file element))
93a75651 555 (setq found t))))))
5fc5ac38 556 (setq path (cdr path)))
4fde92ef 557 (if found filename)))
7840ced1
GM
558
559;;;###autoload
349c034d
GM
560(defun find-image (specs)
561 "Find an image, choosing one of a list of image specifications.
7840ced1 562
cedbd8d0 563SPECS is a list of image specifications.
7840ced1
GM
564
565Each image specification in SPECS is a property list. The contents of
566a specification are image type dependent. All specifications must at
bc283707
WP
567least contain the properties `:type TYPE' and either `:file FILE' or
568`:data DATA', where TYPE is a symbol specifying the image type,
569e.g. `xbm', FILE is the file to load the image from, and DATA is a
cedbd8d0
DL
570string containing the actual image data. The specification whose TYPE
571is supported, and FILE exists, is used to construct the image
572specification to be returned. Return nil if no specification is
573satisfied.
574
8646a62e
CY
575The image is looked for in `image-load-path'.
576
577Image files should not be larger than specified by `max-image-size'."
7840ced1
GM
578 (let (image)
579 (while (and specs (null image))
580 (let* ((spec (car specs))
581 (type (plist-get spec :type))
162dec01 582 (data (plist-get spec :data))
7f228379
GM
583 (file (plist-get spec :file))
584 found)
162dec01
GM
585 (when (image-type-available-p type)
586 (cond ((stringp file)
4fde92ef 587 (if (setq found (image-search-load-path file))
5fc5ac38
CY
588 (setq image
589 (cons 'image (plist-put (copy-sequence spec)
590 :file found)))))
f64ae86c 591 ((not (null data))
162dec01
GM
592 (setq image (cons 'image spec)))))
593 (setq specs (cdr specs))))
349c034d
GM
594 image))
595
596
597;;;###autoload
598(defmacro defimage (symbol specs &optional doc)
18c9f8a2 599 "Define SYMBOL as an image, and return SYMBOL.
349c034d
GM
600
601SPECS is a list of image specifications. DOC is an optional
602documentation string.
603
604Each image specification in SPECS is a property list. The contents of
605a specification are image type dependent. All specifications must at
606least contain the properties `:type TYPE' and either `:file FILE' or
607`:data DATA', where TYPE is a symbol specifying the image type,
608e.g. `xbm', FILE is the file to load the image from, and DATA is a
609string containing the actual image data. The first image
610specification whose TYPE is supported, and FILE exists, is used to
611define SYMBOL.
612
613Example:
614
615 (defimage test-image ((:type xpm :file \"~/test1.xpm\")
616 (:type xbm :file \"~/test1.xbm\")))"
fd8e7a80 617 (declare (doc-string 3))
349c034d 618 `(defvar ,symbol (find-image ',specs) ,doc))
7840ced1 619
0608aa45
KS
620\f
621;;; Animated image API
7840ced1 622
99e619b6
GM
623(defvar image-default-frame-delay 0.1
624 "Default interval in seconds between frames of a multi-frame image.
625Only used if the image does not specify a value.")
626
ed8d7fca
GM
627(defun image-multi-frame-p (image)
628 "Return non-nil if IMAGE contains more than one frame.
629The actual return value is a cons (NIMAGES . DELAY), where NIMAGES is
630the number of frames (or sub-images) in the image and DELAY is the delay
631in seconds that the image specifies between each frame. DELAY may be nil,
632in which case you might want to use `image-default-frame-delay'."
9019d095
GM
633 (when (fboundp 'image-metadata)
634 (let* ((metadata (image-metadata image))
635 (images (plist-get metadata 'count))
636 (delay (plist-get metadata 'delay)))
637 (when (and images (> images 1))
638 (if (or (not (numberp delay)) (< delay 0))
639 (setq delay image-default-frame-delay))
640 (cons images delay)))))
ed8d7fca 641
dd8620de
GM
642(defun image-animated-p (image)
643 "Like `image-multi-frame-p', but returns nil if no delay is specified."
644 (let ((multi (image-multi-frame-p image)))
645 (and (cdr multi) multi)))
646
647(make-obsolete 'image-animated-p 'image-multi-frame-p "24.4")
0608aa45 648
eea14f31 649;; "Destructively"?
18af70d0
CY
650(defun image-animate (image &optional index limit)
651 "Start animating IMAGE.
652Animation occurs by destructively altering the IMAGE spec list.
653
654With optional INDEX, begin animating from that animation frame.
655LIMIT specifies how long to animate the image. If omitted or
656nil, play the animation until the end. If t, loop forever. If a
657number, play until that number of seconds has elapsed."
ed8d7fca 658 (let ((animation (image-multi-frame-p image))
1100a63c
CY
659 timer)
660 (when animation
18af70d0
CY
661 (if (setq timer (image-animate-timer image))
662 (cancel-timer timer))
1100a63c
CY
663 (run-with-timer 0.2 nil 'image-animate-timeout
664 image (or index 0) (car animation)
665 0 limit))))
0608aa45
KS
666
667(defun image-animate-timer (image)
668 "Return the animation timer for image IMAGE."
669 ;; See cancel-function-timers
670 (let ((tail timer-list) timer)
671 (while tail
672 (setq timer (car tail)
673 tail (cdr tail))
72eac303
PE
674 (if (and (eq (timer--function timer) 'image-animate-timeout)
675 (eq (car-safe (timer--args timer)) image))
0608aa45
KS
676 (setq tail nil)
677 (setq timer nil)))
678 timer))
679
99e619b6
GM
680(defconst image-minimum-frame-delay 0.01
681 "Minimum interval in seconds between frames of an animated image.")
682
dc504515
GM
683(defun image-current-frame (image)
684 "The current frame number of IMAGE, indexed from 0."
685 (or (plist-get (cdr image) :index) 0))
bb9dfee1 686
dc504515 687(defun image-show-frame (image n &optional nocheck)
c0211c4e
GM
688 "Show frame N of IMAGE.
689Frames are indexed from 0. Optional argument NOCHECK non-nil means
690do not check N is within the range of frames present in the image."
691 (unless nocheck
692 (if (< n 0) (setq n 0)
ed8d7fca 693 (setq n (min n (1- (car (image-multi-frame-p image)))))))
c0211c4e 694 (plist-put (cdr image) :index n)
c0211c4e
GM
695 (force-window-update))
696
3a2ddc2d
GM
697(defun image-animate-get-speed (image)
698 "Return the speed factor for animating IMAGE."
699 (or (plist-get (cdr image) :speed) 1))
700
701(defun image-animate-set-speed (image value &optional multiply)
702 "Set the speed factor for animating IMAGE to VALUE.
703With optional argument MULTIPLY non-nil, treat VALUE as a
704multiplication factor for the current value."
705 (plist-put (cdr image) :speed
706 (if multiply
707 (* value (image-animate-get-speed image))
708 value)))
709
eea14f31 710;; FIXME? The delay may not be the same for different sub-images,
ed8d7fca 711;; hence we need to call image-multi-frame-p to return it.
eea14f31
GM
712;; But it also returns count, so why do we bother passing that as an
713;; argument?
1100a63c 714(defun image-animate-timeout (image n count time-elapsed limit)
e8cbec34
CY
715 "Display animation frame N of IMAGE.
716N=0 refers to the initial animation frame.
717COUNT is the total number of frames in the animation.
e8cbec34
CY
718TIME-ELAPSED is the total time that has elapsed since
719`image-animate-start' was called.
18af70d0 720LIMIT determines when to stop. If t, loop forever. If nil, stop
e8cbec34 721 after displaying the last animation frame. Otherwise, stop
eea14f31 722 after LIMIT seconds have elapsed.
3a2ddc2d
GM
723The minimum delay between successive frames is `image-minimum-frame-delay'.
724
725If the image has a non-nil :speed property, it acts as a multiplier
726for the animation speed. A negative value means to animate in reverse."
dc504515 727 (image-show-frame image n t)
3a2ddc2d
GM
728 (let* ((speed (image-animate-get-speed image))
729 (time (float-time))
ed8d7fca 730 (animation (image-multi-frame-p image))
1100a63c
CY
731 ;; Subtract off the time we took to load the image from the
732 ;; stated delay time.
3a2ddc2d
GM
733 (delay (max (+ (* (or (cdr animation) image-default-frame-delay)
734 (/ 1 (abs speed)))
ed8d7fca 735 time (- (float-time)))
99e619b6 736 image-minimum-frame-delay))
1100a63c 737 done)
3a2ddc2d
GM
738 (setq n (if (< speed 0)
739 (1- n)
740 (1+ n)))
741 (if limit
742 (cond ((>= n count) (setq n 0))
743 ((< n 0) (setq n (1- count))))
744 (and (or (>= n count) (< n 0)) (setq done t)))
e8cbec34 745 (setq time-elapsed (+ delay time-elapsed))
18af70d0
CY
746 (if (numberp limit)
747 (setq done (>= time-elapsed limit)))
e8cbec34
CY
748 (unless done
749 (run-with-timer delay nil 'image-animate-timeout
1100a63c 750 image n count time-elapsed limit))))
0608aa45
KS
751
752\f
60b5f187 753(defvar imagemagick-types-inhibit)
95f520b5 754(defvar imagemagick-enabled-types)
60b5f187
GM
755
756(defun imagemagick-filter-types ()
757 "Return a list of the ImageMagick types to be treated as images, or nil.
758This is the result of `imagemagick-types', including only elements
95f520b5 759that match `imagemagick-enabled-types' and do not match
60b5f187
GM
760`imagemagick-types-inhibit'."
761 (when (fboundp 'imagemagick-types)
95f520b5 762 (cond ((null imagemagick-enabled-types) nil)
60b5f187 763 ((eq imagemagick-types-inhibit t) nil)
60b5f187
GM
764 (t
765 (delq nil
766 (mapcar
767 (lambda (type)
768 (unless (memq type imagemagick-types-inhibit)
95f520b5 769 (if (eq imagemagick-enabled-types t) type
43f5c7ae 770 (catch 'found
95f520b5 771 (dolist (enable imagemagick-enabled-types nil)
43f5c7ae
GM
772 (if (cond ((symbolp enable) (eq enable type))
773 ((stringp enable)
774 (string-match enable
775 (symbol-name type))))
776 (throw 'found type)))))))
60b5f187
GM
777 (imagemagick-types)))))))
778
c505aaeb
CY
779(defvar imagemagick--file-regexp nil
780 "File extension regexp for ImageMagick files, if any.
781This is the extension installed into `auto-mode-alist' and
782`image-type-file-name-regexps' by `imagemagick-register-types'.")
3de25479
JV
783
784;;;###autoload
ce07fa9a 785(defun imagemagick-register-types ()
d66c4c7c 786 "Register file types that can be handled by ImageMagick.
c505aaeb 787This function is called at startup, after loading the init file.
60b5f187 788It registers the ImageMagick types returned by `imagemagick-filter-types'.
5319014e
CY
789
790Registered image types are added to `auto-mode-alist', so that
791Emacs visits them in Image mode. They are also added to
792`image-type-file-name-regexps', so that the `image-type' function
793recognizes these files as having image type `imagemagick'.
d66c4c7c 794
32d72c2f 795If Emacs is compiled without ImageMagick support, this does nothing."
d66c4c7c 796 (when (fboundp 'imagemagick-types)
60b5f187
GM
797 (let* ((types (mapcar (lambda (type) (downcase (symbol-name type)))
798 (imagemagick-filter-types)))
799 (re (if types (concat "\\." (regexp-opt types) "\\'")))
32d72c2f
GM
800 (ama-elt (car (member (cons imagemagick--file-regexp 'image-mode)
801 auto-mode-alist)))
802 (itfnr-elt (car (member (cons imagemagick--file-regexp 'imagemagick)
803 image-type-file-name-regexps))))
804 (if (not re)
805 (setq auto-mode-alist (delete ama-elt auto-mode-alist)
806 image-type-file-name-regexps
807 (delete itfnr-elt image-type-file-name-regexps))
808 (if ama-elt
809 (setcar ama-elt re)
810 (push (cons re 'image-mode) auto-mode-alist))
811 (if itfnr-elt
812 (setcar itfnr-elt re)
72834e10
CY
813 ;; Append to `image-type-file-name-regexps', so that we
814 ;; preferentially use specialized image libraries.
815 (add-to-list 'image-type-file-name-regexps
816 (cons re 'imagemagick) t)))
c505aaeb
CY
817 (setq imagemagick--file-regexp re))))
818
041df390
CY
819(defcustom imagemagick-types-inhibit
820 '(C HTML HTM INFO M TXT PDF)
95f520b5 821 "List of ImageMagick types that should never be treated as images.
c505aaeb 822This should be a list of symbols, each of which should be one of
95f520b5 823the ImageMagick types listed by `imagemagick-types'. The listed
c505aaeb
CY
824image types are not registered by `imagemagick-register-types'.
825
826If the value is t, inhibit the use of ImageMagick for images.
827
87eb79c2
GM
828If you change this without using customize, you must call
829`imagemagick-register-types' afterwards.
830
c505aaeb
CY
831If Emacs is compiled without ImageMagick support, this variable
832has no effect."
833 :type '(choice (const :tag "Support all ImageMagick types" nil)
834 (const :tag "Disable all ImageMagick types" t)
835 (repeat symbol))
32d72c2f 836 :initialize 'custom-initialize-default
c505aaeb
CY
837 :set (lambda (symbol value)
838 (set-default symbol value)
839 (imagemagick-register-types))
2a1e2476 840 :version "24.3"
c505aaeb 841 :group 'image)
3de25479 842
95f520b5 843(defcustom imagemagick-enabled-types
47b36b94 844 '(3FR ART ARW AVS BMP BMP2 BMP3 CAL CALS CMYK CMYKA CR2 CRW
041df390
CY
845 CUR CUT DCM DCR DCX DDS DJVU DNG DPX EXR FAX FITS GBR GIF
846 GIF87 GRB HRZ ICB ICO ICON J2C JNG JP2 JPC JPEG JPG JPX K25
847 KDC MIFF MNG MRW MSL MSVG MTV NEF ORF OTB PBM PCD PCDS PCL
848 PCT PCX PDB PEF PGM PICT PIX PJPEG PNG PNG24 PNG32 PNG8 PNM
849 PPM PSD PTIF PWP RAF RAS RBG RGB RGBA RGBO RLA RLE SCR SCT
850 SFW SGI SR2 SRF SUN SVG SVGZ TGA TIFF TIFF64 TILE TIM TTF
851 UYVY VDA VICAR VID VIFF VST WBMP WPG X3F XBM XC XCF XPM XV
852 XWD YCbCr YCbCrA YUV)
32d72c2f 853 "List of ImageMagick types to treat as images.
95f520b5
CY
854Each list element should be a string or symbol, representing one
855of the image types returned by `imagemagick-types'. If the
856element is a string, it is handled as a regexp that enables all
857matching types.
32d72c2f 858
95f520b5
CY
859The value of `imagemagick-enabled-types' may also be t, meaning
860to enable all types that ImageMagick supports.
32d72c2f
GM
861
862The variable `imagemagick-types-inhibit' overrides this variable.
863
eda82a31 864If you change this without using customize, you must call
32d72c2f
GM
865`imagemagick-register-types' afterwards.
866
867If Emacs is compiled without ImageMagick support, this variable
868has no effect."
869 :type '(choice (const :tag "Support all ImageMagick types" t)
870 (const :tag "Disable all ImageMagick types" nil)
871 (repeat :tag "List of types"
872 (choice (symbol :tag "type")
873 (regexp :tag "regexp"))))
874 :initialize 'custom-initialize-default
875 :set (lambda (symbol value)
876 (set-default symbol value)
877 (imagemagick-register-types))
2a1e2476 878 :version "24.3"
32d72c2f
GM
879 :group 'image)
880
881(imagemagick-register-types)
882
7840ced1
GM
883(provide 'image)
884
e43367a0 885;;; image.el ends here