Skip to content
This repository
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 205 lines (179 sloc) 7.37 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
;;; image-file.el --- support for visiting image files
;;
;; Copyright (C) 2000-2013 Free Software Foundation, Inc.
;;
;; Author: Miles Bader <miles@gnu.org>
;; Keywords: multimedia

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; Defines a file-name-handler hook that transforms visited (or
;; inserted) image files so that they are displayed by Emacs as
;; images. This is done by putting a `display' text-property on the
;; image data, with the image-data still present underneath; if the
;; resulting buffer file is saved to another name it will correctly save
;; the image data to the new file.

;;; Code:

(require 'image)


;;;###autoload
(defcustom image-file-name-extensions
  (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg"))
  "A list of image-file filename extensions.
Filenames having one of these extensions are considered image files,
in addition to those matching `image-file-name-regexps'.

See `auto-image-file-mode'; if `auto-image-file-mode' is enabled,
setting this variable directly does not take effect unless
`auto-image-file-mode' is re-enabled; this happens automatically when
the variable is set using \\[customize]."
  :type '(repeat string)
  :set (lambda (sym val)
(set-default sym val)
(when auto-image-file-mode
;; Re-initialize the image-file handler
(auto-image-file-mode t)))
  :initialize 'custom-initialize-default
  :group 'image)

;;;###autoload
(defcustom image-file-name-regexps nil
  "List of regexps matching image-file filenames.
Filenames matching one of these regexps are considered image files,
in addition to those with an extension in `image-file-name-extensions'.

See function `auto-image-file-mode'; if `auto-image-file-mode' is
enabled, setting this variable directly does not take effect unless
`auto-image-file-mode' is re-enabled; this happens automatically when
the variable is set using \\[customize]."
  :type '(repeat regexp)
  :set (lambda (sym val)
(set-default sym val)
(when auto-image-file-mode
;; Re-initialize the image-file handler
(auto-image-file-mode t)))
  :initialize 'custom-initialize-default
  :group 'image)


;;;###autoload
(defun image-file-name-regexp ()
  "Return a regular expression matching image-file filenames."
  (let ((exts-regexp
(and image-file-name-extensions
(concat "\\."
(regexp-opt (nconc (mapcar #'upcase
image-file-name-extensions)
image-file-name-extensions)
t)
"\\'"))))
    (if image-file-name-regexps
(mapconcat 'identity
(if exts-regexp
(cons exts-regexp image-file-name-regexps)
image-file-name-regexps)
"\\|")
      exts-regexp)))


;;;###autoload
(defun insert-image-file (file &optional visit beg end replace)
  "Insert the image file FILE into the current buffer.
Optional arguments VISIT, BEG, END, and REPLACE are interpreted as for
the command `insert-file-contents'."
  (let ((rval
(image-file-call-underlying #'insert-file-contents-literally
'insert-file-contents
file visit beg end replace)))
    ;; Turn the image data into a real image, but only if the whole file
    ;; was inserted
    (when (and (or (null beg) (zerop beg)) (null end))
      (let* ((ibeg (point))
(iend (+ (point) (cadr rval)))
(visitingp (and visit (= ibeg (point-min)) (= iend (point-max))))
(data
(string-make-unibyte
(buffer-substring-no-properties ibeg iend)))
(image
(create-image data nil t))
(props
`(display ,image
yank-handler
(image-file-yank-handler nil t)
intangible ,image
rear-nonsticky (display intangible)
;; This a cheap attempt to make the whole buffer
;; read-only when we're visiting the file (as
;; opposed to just inserting it).
,@(and visitingp
'(read-only t front-sticky (read-only))))))
(add-text-properties ibeg iend props)
(when visitingp
;; Inhibit the cursor when the buffer contains only an image,
;; because cursors look very strange on top of images.
(setq cursor-type nil)
;; This just makes the arrow displayed in the right fringe
;; area look correct when the image is wider than the window.
(setq truncate-lines t))))
    rval))

;; We use a yank-handler to make yanked images unique, so that
;; yanking two copies of the same image next to each other are
;; recognized as two different images.
(defun image-file-yank-handler (string)
  "Yank handler for inserting an image into a buffer."
  (let ((len (length string))
(image (get-text-property 0 'display string)))
    (remove-text-properties 0 len yank-excluded-properties string)
    (if (consp image)
(add-text-properties 0
(or (next-single-property-change 0 'image-counter string)
(length string))
`(display
,(cons (car image) (cdr image))
yank-handler
,(cons 'image-file-yank-handler '(nil t)))
string))
    (insert string)))

(put 'image-file-handler 'safe-magic t)
(defun image-file-handler (operation &rest args)
  "Filename handler for inserting image files.
OPERATION is the operation to perform, on ARGS.
See `file-name-handler-alist' for details."
  (if (and (eq operation 'insert-file-contents)
auto-image-file-mode)
      (apply #'insert-image-file args)
    ;; We don't handle OPERATION, use another handler or the default
    (apply #'image-file-call-underlying operation operation args)))

(defun image-file-call-underlying (function operation &rest args)
  "Call FUNCTION with `image-file-handler' and OPERATION inhibited.
Optional argument ARGS are the arguments to call FUNCTION with."
  (let ((inhibit-file-name-handlers
(cons 'image-file-handler
(and (eq inhibit-file-name-operation operation)
inhibit-file-name-handlers)))
(inhibit-file-name-operation operation))
    (apply function args)))


;;;###autoload
(define-minor-mode auto-image-file-mode
  "Toggle visiting of image files as images (Auto Image File mode).
With a prefix argument ARG, enable Auto Image File mode if ARG is
positive, and disable it otherwise. If called from Lisp, enable
the mode if ARG is omitted or nil.

An image file is one whose name has an extension in
`image-file-name-extensions', or matches a regexp in
`image-file-name-regexps'."
  :global t
  :group 'image
  ;; Remove existing handler
  (let ((existing-entry
(rassq 'image-file-handler file-name-handler-alist)))
    (when existing-entry
      (setq file-name-handler-alist
(delq existing-entry file-name-handler-alist))))
  ;; Add new handler, if enabled
  (when auto-image-file-mode
    (push (cons (image-file-name-regexp) 'image-file-handler)
file-name-handler-alist)))


(provide 'image-file)

;;; image-file.el ends here
Something went wrong with that request. Please try again.