25003
|
1 ;;; image.el --- image API
|
|
2
|
37035
|
3 ;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
|
42316
|
4
|
|
5 ;; Maintainer: FSF
|
25309
|
6 ;; Keywords: multimedia
|
25003
|
7
|
|
8 ;; This file is part of GNU Emacs.
|
|
9
|
|
10 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
11 ;; it under the terms of the GNU General Public License as published by
|
|
12 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
13 ;; any later version.
|
|
14
|
|
15 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
18 ;; GNU General Public License for more details.
|
|
19
|
|
20 ;; You should have received a copy of the GNU General Public License
|
|
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
23 ;; Boston, MA 02111-1307, USA.
|
|
24
|
|
25 ;;; Commentary:
|
|
26
|
|
27 ;;; Code:
|
|
28
|
32166
|
29
|
|
30 (defgroup image ()
|
|
31 "Image support."
|
|
32 :group 'multimedia)
|
|
33
|
|
34
|
25003
|
35 (defconst image-type-regexps
|
38746
|
36 '(("\\`/[\t\n\r ]*\\*.*XPM.\\*/" . xpm)
|
38709
|
37 ("\\`P[1-6]" . pbm)
|
|
38 ("\\`GIF8" . gif)
|
|
39 ("\\`\211PNG\r\n" . png)
|
38746
|
40 ("\\`[\t\n\r ]*#define" . xbm)
|
38884
|
41 ("\\`\\(MM\0\\*\\|II\\*\0\\)" . tiff)
|
38746
|
42 ("\\`[\t\n\r ]*%!PS" . postscript)
|
38732
|
43 ("\\`\xff\xd8" . (image-jpeg-p . jpeg)))
|
25003
|
44 "Alist of (REGEXP . IMAGE-TYPE) pairs used to auto-detect image types.
|
|
45 When the first bytes of an image file match REGEXP, it is assumed to
|
38732
|
46 be of image type IMAGE-TYPE if IMAGE-TYPE is a symbol. If not a symbol,
|
|
47 IMAGE-TYPE must be a pair (PREDICATE . TYPE). PREDICATE is called
|
|
48 with one argument, a string containing the image data. If PREDICATE returns
|
|
49 a non-nil value, TYPE is the image's type ")
|
|
50
|
|
51
|
|
52 (defun image-jpeg-p (data)
|
46810
|
53 "Value is non-nil if DATA, a string, consists of JFIF image data.
|
|
54 We accept the tag Exif because that is the same format."
|
38732
|
55 (when (string-match "\\`\xff\xd8" data)
|
|
56 (catch 'jfif
|
|
57 (let ((len (length data)) (i 2))
|
|
58 (while (< i len)
|
|
59 (when (/= (aref data i) #xff)
|
|
60 (throw 'jfif nil))
|
|
61 (setq i (1+ i))
|
|
62 (when (>= (+ i 2) len)
|
|
63 (throw 'jfif nil))
|
|
64 (let ((nbytes (+ (lsh (aref data (+ i 1)) 8)
|
38776
|
65 (aref data (+ i 2))))
|
|
66 (code (aref data i)))
|
|
67 (when (and (>= code #xe0) (<= code #xef))
|
38732
|
68 ;; APP0 LEN1 LEN2 "JFIF\0"
|
38776
|
69 (throw 'jfif
|
46810
|
70 (string-match "JFIF\\|Exif" (substring data i (+ i nbytes)))))
|
38746
|
71 (setq i (+ i 1 nbytes))))))))
|
25003
|
72
|
|
73
|
|
74 ;;;###autoload
|
27073
|
75 (defun image-type-from-data (data)
|
|
76 "Determine the image type from image data DATA.
|
|
77 Value is a symbol specifying the image type or nil if type cannot
|
|
78 be determined."
|
|
79 (let ((types image-type-regexps)
|
|
80 type)
|
|
81 (while (and types (null type))
|
|
82 (let ((regexp (car (car types)))
|
|
83 (image-type (cdr (car types))))
|
38732
|
84 (when (or (and (symbolp image-type)
|
|
85 (string-match regexp data))
|
|
86 (and (consp image-type)
|
|
87 (funcall (car image-type) data)
|
|
88 (setq image-type (cdr image-type))))
|
27073
|
89 (setq type image-type))
|
|
90 (setq types (cdr types))))
|
|
91 type))
|
|
92
|
|
93
|
|
94 ;;;###autoload
|
25003
|
95 (defun image-type-from-file-header (file)
|
|
96 "Determine the type of image file FILE from its first few bytes.
|
|
97 Value is a symbol specifying the image type, or nil if type cannot
|
|
98 be determined."
|
|
99 (unless (file-name-directory file)
|
27073
|
100 (setq file (expand-file-name file data-directory)))
|
25003
|
101 (setq file (expand-file-name file))
|
|
102 (let ((header (with-temp-buffer
|
43834
|
103 (set-buffer-multibyte nil)
|
25003
|
104 (insert-file-contents-literally file nil 0 256)
|
27073
|
105 (buffer-string))))
|
|
106 (image-type-from-data header)))
|
25003
|
107
|
|
108
|
|
109 ;;;###autoload
|
|
110 (defun image-type-available-p (type)
|
|
111 "Value is non-nil if image type TYPE is available.
|
|
112 Image types are symbols like `xbm' or `jpeg'."
|
28958
|
113 (and (boundp 'image-types) (not (null (memq type image-types)))))
|
25003
|
114
|
|
115
|
|
116 ;;;###autoload
|
27073
|
117 (defun create-image (file-or-data &optional type data-p &rest props)
|
|
118 "Create an image.
|
|
119 FILE-OR-DATA is an image file name or image data.
|
25003
|
120 Optional TYPE is a symbol describing the image type. If TYPE is omitted
|
27073
|
121 or nil, try to determine the image type from its first few bytes
|
|
122 of image data. If that doesn't work, and FILE-OR-DATA is a file name,
|
34378
5ae7af279df7
(create-image): Doc fix; spotted by Per Cederqvist <ceder@lysator.liu.se>.
Eli Zaretskii <eliz@gnu.org>
diff
changeset
|
123 use its file extension as image type.
|
27073
|
124 Optional DATA-P non-nil means FILE-OR-DATA is a string containing image data.
|
25003
|
125 Optional PROPS are additional image attributes to assign to the image,
|
31635
|
126 like, e.g. `:mask MASK'.
|
25003
|
127 Value is the image created, or nil if images of type TYPE are not supported."
|
27075
|
128 (when (and (not data-p) (not (stringp file-or-data)))
|
|
129 (error "Invalid image file name `%s'" file-or-data))
|
27073
|
130 (cond ((null data-p)
|
|
131 ;; FILE-OR-DATA is a file name.
|
|
132 (unless (or type
|
|
133 (setq type (image-type-from-file-header file-or-data)))
|
|
134 (let ((extension (file-name-extension file-or-data)))
|
|
135 (unless extension
|
|
136 (error "Cannot determine image type"))
|
|
137 (setq type (intern extension)))))
|
|
138 (t
|
|
139 ;; FILE-OR-DATA contains image data.
|
|
140 (unless type
|
|
141 (setq type (image-type-from-data file-or-data)))))
|
|
142 (unless type
|
|
143 (error "Cannot determine image type"))
|
25003
|
144 (unless (symbolp type)
|
27073
|
145 (error "Invalid image type `%s'" type))
|
25003
|
146 (when (image-type-available-p type)
|
27073
|
147 (append (list 'image :type type (if data-p :data :file) file-or-data)
|
|
148 props)))
|
25003
|
149
|
|
150
|
|
151 ;;;###autoload
|
29470
|
152 (defun put-image (image pos &optional string area)
|
25617
|
153 "Put image IMAGE in front of POS in the current buffer.
|
25003
|
154 IMAGE must be an image created with `create-image' or `defimage'.
|
25816
|
155 IMAGE is displayed by putting an overlay into the current buffer with a
|
|
156 `before-string' STRING that has a `display' property whose value is the
|
29470
|
157 image. STRING is defaulted if you omit it.
|
25003
|
158 POS may be an integer or marker.
|
|
159 AREA is where to display the image. AREA nil or omitted means
|
|
160 display it in the text area, a value of `left-margin' means
|
|
161 display it in the left marginal area, a value of `right-margin'
|
25816
|
162 means display it in the right marginal area."
|
29626
|
163 (unless string (setq string "x"))
|
25617
|
164 (let ((buffer (current-buffer)))
|
29470
|
165 (unless (eq (car-safe image) 'image)
|
25617
|
166 (error "Not an image: %s" image))
|
|
167 (unless (or (null area) (memq area '(left-margin right-margin)))
|
|
168 (error "Invalid area %s" area))
|
25816
|
169 (setq string (copy-sequence string))
|
25617
|
170 (let ((overlay (make-overlay pos pos buffer))
|
25816
|
171 (prop (if (null area) image (list (list 'margin area) image))))
|
|
172 (put-text-property 0 (length string) 'display prop string)
|
25617
|
173 (overlay-put overlay 'put-image t)
|
|
174 (overlay-put overlay 'before-string string))))
|
25003
|
175
|
|
176
|
|
177 ;;;###autoload
|
29470
|
178 (defun insert-image (image &optional string area)
|
25003
|
179 "Insert IMAGE into current buffer at point.
|
25816
|
180 IMAGE is displayed by inserting STRING into the current buffer
|
29470
|
181 with a `display' property whose value is the image. STRING is
|
|
182 defaulted if you omit it.
|
25003
|
183 AREA is where to display the image. AREA nil or omitted means
|
|
184 display it in the text area, a value of `left-margin' means
|
|
185 display it in the left marginal area, a value of `right-margin'
|
25816
|
186 means display it in the right marginal area."
|
29626
|
187 ;; Use a space as least likely to cause trouble when it's a hidden
|
|
188 ;; character in the buffer.
|
|
189 (unless string (setq string " "))
|
29470
|
190 (unless (eq (car-safe image) 'image)
|
25003
|
191 (error "Not an image: %s" image))
|
|
192 (unless (or (null area) (memq area '(left-margin right-margin)))
|
|
193 (error "Invalid area %s" area))
|
29607
|
194 (if area
|
|
195 (setq image (list (list 'margin area) image))
|
|
196 ;; Cons up a new spec equal but not eq to `image' so that
|
|
197 ;; inserting it twice in a row (adjacently) displays two copies of
|
|
198 ;; the image. Don't try to avoid this by looking at the display
|
|
199 ;; properties on either side so that we DTRT more often with
|
|
200 ;; cut-and-paste. (Yanking killed image text next to another copy
|
|
201 ;; of it loses anyway.)
|
|
202 (setq image (cons 'image (cdr image))))
|
25816
|
203 (let ((start (point)))
|
|
204 (insert string)
|
|
205 (add-text-properties start (point)
|
48130
|
206 `(display ,image rear-nonsticky (display)))))
|
26007
|
207
|
25003
|
208
|
|
209 ;;;###autoload
|
|
210 (defun remove-images (start end &optional buffer)
|
|
211 "Remove images between START and END in BUFFER.
|
|
212 Remove only images that were put in BUFFER with calls to `put-image'.
|
|
213 BUFFER nil or omitted means use the current buffer."
|
|
214 (unless buffer
|
|
215 (setq buffer (current-buffer)))
|
|
216 (let ((overlays (overlays-in start end)))
|
|
217 (while overlays
|
|
218 (let ((overlay (car overlays)))
|
|
219 (when (overlay-get overlay 'put-image)
|
25857
|
220 (delete-overlay overlay)))
|
|
221 (setq overlays (cdr overlays)))))
|
25003
|
222
|
|
223
|
|
224 ;;;###autoload
|
28721
|
225 (defun find-image (specs)
|
|
226 "Find an image, choosing one of a list of image specifications.
|
25003
|
227
|
29470
|
228 SPECS is a list of image specifications.
|
25003
|
229
|
|
230 Each image specification in SPECS is a property list. The contents of
|
|
231 a specification are image type dependent. All specifications must at
|
27059
6bb2a4a0413e
* image.el (defimage): Images with the :data keyword should be considered valid as well.
William M. Perry <wmperry@aventail.com>
diff
changeset
|
232 least contain the properties `:type TYPE' and either `:file FILE' or
|
6bb2a4a0413e
* image.el (defimage): Images with the :data keyword should be considered valid as well.
William M. Perry <wmperry@aventail.com>
diff
changeset
|
233 `:data DATA', where TYPE is a symbol specifying the image type,
|
6bb2a4a0413e
* image.el (defimage): Images with the :data keyword should be considered valid as well.
William M. Perry <wmperry@aventail.com>
diff
changeset
|
234 e.g. `xbm', FILE is the file to load the image from, and DATA is a
|
29470
|
235 string containing the actual image data. The specification whose TYPE
|
|
236 is supported, and FILE exists, is used to construct the image
|
|
237 specification to be returned. Return nil if no specification is
|
|
238 satisfied.
|
|
239
|
|
240 The image is looked for first on `load-path' and then in `data-directory'."
|
25003
|
241 (let (image)
|
|
242 (while (and specs (null image))
|
|
243 (let* ((spec (car specs))
|
27073
|
244 (type (plist-get spec :type))
|
27059
6bb2a4a0413e
* image.el (defimage): Images with the :data keyword should be considered valid as well.
William M. Perry <wmperry@aventail.com>
diff
changeset
|
245 (data (plist-get spec :data))
|
27921
|
246 (file (plist-get spec :file))
|
|
247 found)
|
27073
|
248 (when (image-type-available-p type)
|
|
249 (cond ((stringp file)
|
27921
|
250 (let ((path load-path))
|
|
251 (while (and (not found) path)
|
|
252 (let ((try-file (expand-file-name file (car path))))
|
|
253 (when (file-readable-p try-file)
|
|
254 (setq found try-file)))
|
|
255 (setq path (cdr path)))
|
|
256 (unless found
|
29470
|
257 (let ((try-file (expand-file-name file data-directory)))
|
|
258 (if (file-readable-p try-file)
|
|
259 (setq found try-file))))
|
|
260 (if found
|
|
261 (setq image
|
30952
|
262 (cons 'image (plist-put (copy-sequence spec)
|
|
263 :file found))))))
|
27075
|
264 ((not (null data))
|
27073
|
265 (setq image (cons 'image spec)))))
|
|
266 (setq specs (cdr specs))))
|
28721
|
267 image))
|
|
268
|
|
269
|
|
270 ;;;###autoload
|
|
271 (defmacro defimage (symbol specs &optional doc)
|
|
272 "Define SYMBOL as an image.
|
|
273
|
|
274 SPECS is a list of image specifications. DOC is an optional
|
|
275 documentation string.
|
|
276
|
|
277 Each image specification in SPECS is a property list. The contents of
|
|
278 a specification are image type dependent. All specifications must at
|
|
279 least contain the properties `:type TYPE' and either `:file FILE' or
|
|
280 `:data DATA', where TYPE is a symbol specifying the image type,
|
|
281 e.g. `xbm', FILE is the file to load the image from, and DATA is a
|
|
282 string containing the actual image data. The first image
|
|
283 specification whose TYPE is supported, and FILE exists, is used to
|
|
284 define SYMBOL.
|
|
285
|
|
286 Example:
|
|
287
|
|
288 (defimage test-image ((:type xpm :file \"~/test1.xpm\")
|
|
289 (:type xbm :file \"~/test1.xbm\")))"
|
|
290 `(defvar ,symbol (find-image ',specs) ,doc))
|
25003
|
291
|
|
292
|
|
293 (provide 'image)
|
|
294
|
25872
|
295 ;;; image.el ends here
|