image-file.el 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. ;;; image-file.el --- support for visiting image files
  2. ;;
  3. ;; Copyright (C) 2000-2012 Free Software Foundation, Inc.
  4. ;;
  5. ;; Author: Miles Bader <miles@gnu.org>
  6. ;; Keywords: multimedia
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; Defines a file-name-handler hook that transforms visited (or
  20. ;; inserted) image files so that they are displayed by Emacs as
  21. ;; images. This is done by putting a `display' text-property on the
  22. ;; image data, with the image-data still present underneath; if the
  23. ;; resulting buffer file is saved to another name it will correctly save
  24. ;; the image data to the new file.
  25. ;;; Code:
  26. (require 'image)
  27. ;;;###autoload
  28. (defcustom image-file-name-extensions
  29. (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg"))
  30. "A list of image-file filename extensions.
  31. Filenames having one of these extensions are considered image files,
  32. in addition to those matching `image-file-name-regexps'.
  33. See `auto-image-file-mode'; if `auto-image-file-mode' is enabled,
  34. setting this variable directly does not take effect unless
  35. `auto-image-file-mode' is re-enabled; this happens automatically when
  36. the variable is set using \\[customize]."
  37. :type '(repeat string)
  38. :set (lambda (sym val)
  39. (set-default sym val)
  40. (when auto-image-file-mode
  41. ;; Re-initialize the image-file handler
  42. (auto-image-file-mode t)))
  43. :initialize 'custom-initialize-default
  44. :group 'image)
  45. ;;;###autoload
  46. (defcustom image-file-name-regexps nil
  47. "List of regexps matching image-file filenames.
  48. Filenames matching one of these regexps are considered image files,
  49. in addition to those with an extension in `image-file-name-extensions'.
  50. See function `auto-image-file-mode'; if `auto-image-file-mode' is
  51. enabled, setting this variable directly does not take effect unless
  52. `auto-image-file-mode' is re-enabled; this happens automatically when
  53. the variable is set using \\[customize]."
  54. :type '(repeat regexp)
  55. :set (lambda (sym val)
  56. (set-default sym val)
  57. (when auto-image-file-mode
  58. ;; Re-initialize the image-file handler
  59. (auto-image-file-mode t)))
  60. :initialize 'custom-initialize-default
  61. :group 'image)
  62. ;;;###autoload
  63. (defun image-file-name-regexp ()
  64. "Return a regular expression matching image-file filenames."
  65. (let ((exts-regexp
  66. (and image-file-name-extensions
  67. (concat "\\."
  68. (regexp-opt (nconc (mapcar #'upcase
  69. image-file-name-extensions)
  70. image-file-name-extensions)
  71. t)
  72. "\\'"))))
  73. (if image-file-name-regexps
  74. (mapconcat 'identity
  75. (if exts-regexp
  76. (cons exts-regexp image-file-name-regexps)
  77. image-file-name-regexps)
  78. "\\|")
  79. exts-regexp)))
  80. ;;;###autoload
  81. (defun insert-image-file (file &optional visit beg end replace)
  82. "Insert the image file FILE into the current buffer.
  83. Optional arguments VISIT, BEG, END, and REPLACE are interpreted as for
  84. the command `insert-file-contents'."
  85. (let ((rval
  86. (image-file-call-underlying #'insert-file-contents-literally
  87. 'insert-file-contents
  88. file visit beg end replace)))
  89. ;; Turn the image data into a real image, but only if the whole file
  90. ;; was inserted
  91. (when (and (or (null beg) (zerop beg)) (null end))
  92. (let* ((ibeg (point))
  93. (iend (+ (point) (cadr rval)))
  94. (visitingp (and visit (= ibeg (point-min)) (= iend (point-max))))
  95. (data
  96. (string-make-unibyte
  97. (buffer-substring-no-properties ibeg iend)))
  98. (image
  99. (create-image data nil t))
  100. (props
  101. `(display ,image
  102. yank-handler
  103. (image-file-yank-handler nil t)
  104. intangible ,image
  105. rear-nonsticky (display intangible)
  106. ;; This a cheap attempt to make the whole buffer
  107. ;; read-only when we're visiting the file (as
  108. ;; opposed to just inserting it).
  109. ,@(and visitingp
  110. '(read-only t front-sticky (read-only))))))
  111. (add-text-properties ibeg iend props)
  112. (when visitingp
  113. ;; Inhibit the cursor when the buffer contains only an image,
  114. ;; because cursors look very strange on top of images.
  115. (setq cursor-type nil)
  116. ;; This just makes the arrow displayed in the right fringe
  117. ;; area look correct when the image is wider than the window.
  118. (setq truncate-lines t))))
  119. rval))
  120. ;; We use a yank-handler to make yanked images unique, so that
  121. ;; yanking two copies of the same image next to each other are
  122. ;; recognized as two different images.
  123. (defun image-file-yank-handler (string)
  124. "Yank handler for inserting an image into a buffer."
  125. (let ((len (length string))
  126. (image (get-text-property 0 'display string)))
  127. (remove-text-properties 0 len yank-excluded-properties string)
  128. (if (consp image)
  129. (add-text-properties 0
  130. (or (next-single-property-change 0 'image-counter string)
  131. (length string))
  132. `(display
  133. ,(cons (car image) (cdr image))
  134. yank-handler
  135. ,(cons 'image-file-yank-handler '(nil t)))
  136. string))
  137. (insert string)))
  138. (put 'image-file-handler 'safe-magic t)
  139. (defun image-file-handler (operation &rest args)
  140. "Filename handler for inserting image files.
  141. OPERATION is the operation to perform, on ARGS.
  142. See `file-name-handler-alist' for details."
  143. (if (and (eq operation 'insert-file-contents)
  144. auto-image-file-mode)
  145. (apply #'insert-image-file args)
  146. ;; We don't handle OPERATION, use another handler or the default
  147. (apply #'image-file-call-underlying operation operation args)))
  148. (defun image-file-call-underlying (function operation &rest args)
  149. "Call FUNCTION with `image-file-handler' and OPERATION inhibited.
  150. Optional argument ARGS are the arguments to call FUNCTION with."
  151. (let ((inhibit-file-name-handlers
  152. (cons 'image-file-handler
  153. (and (eq inhibit-file-name-operation operation)
  154. inhibit-file-name-handlers)))
  155. (inhibit-file-name-operation operation))
  156. (apply function args)))
  157. ;;;###autoload
  158. (define-minor-mode auto-image-file-mode
  159. "Toggle visiting of image files as images (Auto Image File mode).
  160. With a prefix argument ARG, enable Auto Image File mode if ARG is
  161. positive, and disable it otherwise. If called from Lisp, enable
  162. the mode if ARG is omitted or nil.
  163. An image file is one whose name has an extension in
  164. `image-file-name-extensions', or matches a regexp in
  165. `image-file-name-regexps'."
  166. :global t
  167. :group 'image
  168. ;; Remove existing handler
  169. (let ((existing-entry
  170. (rassq 'image-file-handler file-name-handler-alist)))
  171. (when existing-entry
  172. (setq file-name-handler-alist
  173. (delq existing-entry file-name-handler-alist))))
  174. ;; Add new handler, if enabled
  175. (when auto-image-file-mode
  176. (push (cons (image-file-name-regexp) 'image-file-handler)
  177. file-name-handler-alist)))
  178. (provide 'image-file)
  179. ;;; image-file.el ends here