340d8a3ae70350f38fdc412bc7bfdffda22b3c4f
[muse-el.git] / lisp / muse-latex2png.el
blob340d8a3ae70350f38fdc412bc7bfdffda22b3c4f
1 ;; muse-latex2png.el --- generate PNG images from inline LaTeX code
3 ;; Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
5 ;; Author: Michael Olson <mwolson@gnu.org>
6 ;; Created: 12-Oct-2005
8 ;; This file is part of Emacs Muse. It is not part of GNU Emacs.
10 ;; Emacs Muse is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published
12 ;; by the Free Software Foundation; either version 3, or (at your
13 ;; option) any later version.
15 ;; Emacs Muse is distributed in the hope that it will be useful, but
16 ;; WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 ;; General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with Emacs Muse; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 ;; Boston, MA 02110-1301, USA.
25 ;;; Commentary:
27 ;; This was taken from latex2png.el, by Ganesh Swami <ganesh AT
28 ;; iamganesh DOT com>, which was made for emacs-wiki. It has since
29 ;; been extensively rewritten for Muse.
31 ;;; To do
33 ;; Remove stale image files. This could be done by making a function
34 ;; for `muse-before-publish-hook' that deletes according to
35 ;; (muse-page-name).
37 ;;; Code
39 (require 'muse-publish)
41 (defgroup muse-latex2png nil
42 "Publishing LaTeX formulas as PNG files."
43 :group 'muse-publish)
45 (defcustom muse-latex2png-img-dest "./latex"
46 "The folder where the generated images will be placed.
47 This is relative to the current publishing directory."
48 :type 'string
49 :group 'muse-latex2png)
51 (defcustom muse-latex2png-scale-factor 2.5
52 "The scale factor to be used for sizing the resulting LaTeX output."
53 :type 'number
54 :group 'muse-latex2png)
56 (defcustom muse-latex2png-fg "Black"
57 "The foreground color."
58 :type 'string
59 :group 'muse-latex2png)
61 (defcustom muse-latex2png-bg "Transparent"
62 "The background color."
63 :type 'string
64 :group 'muse-latex2png)
66 (defcustom muse-latex2png-template
67 "\\documentclass{article}
68 \\usepackage{fullpage}
69 \\usepackage{amssymb}
70 \\usepackage[usenames]{color}
71 \\usepackage{amsmath}
72 \\usepackage{latexsym}
73 \\usepackage[mathscr]{eucal}
74 %preamble%
75 \\pagestyle{empty}
76 \\begin{document}
77 {%code%}
78 \\end{document}\n"
79 "The LaTeX template to use."
80 :type 'string
81 :group 'muse-latex2png)
83 (defun muse-latex2png-move2pubdir (file prefix pubdir)
84 "Move FILE to the PUBDIR folder.
86 This is done so that the resulting images do not clutter your
87 main publishing directory.
89 Old files with PREFIX in the name are deleted."
90 (when file
91 (if (file-exists-p file)
92 (progn
93 (unless (file-directory-p pubdir)
94 (message "Creating latex directory %s" pubdir)
95 (make-directory pubdir))
96 (copy-file file (expand-file-name (file-name-nondirectory file)
97 pubdir)
99 (delete-file file)
100 (concat muse-latex2png-img-dest "/" (file-name-nondirectory file)))
101 (message "Cannot find %s!" file))))
103 (defun muse-latex2png (code prefix preamble)
104 "Convert the LaTeX CODE into a png file beginning with PREFIX.
105 PREAMBLE indicates extra packages and definitions to include."
106 (unless preamble
107 (setq preamble ""))
108 (unless prefix
109 (setq prefix "muse-latex2png"))
110 (let* ((tmpdir (cond ((boundp 'temporary-file-directory)
111 temporary-file-directory)
112 ((fboundp 'temp-directory)
113 (temp-directory))
114 (t "/tmp")))
115 (texfile (expand-file-name
116 (concat prefix "__" (format "%d" (abs (sxhash code))))
117 tmpdir))
118 (defalt-directory default-directory))
119 (with-temp-file (concat texfile ".tex")
120 (insert muse-latex2png-template)
121 (goto-char (point-min))
122 (while (search-forward "%preamble%" nil t)
123 (replace-match preamble nil t))
124 (goto-char (point-min))
125 (while (search-forward "%code%" nil t)
126 (replace-match code nil t)))
127 (setq default-directory tmpdir)
128 (call-process "latex" nil nil nil texfile)
129 (if (file-exists-p (concat texfile ".dvi"))
130 (progn
131 (call-process
132 "dvipng" nil nil nil
133 "-E"
134 "-fg" muse-latex2png-fg
135 "-bg" muse-latex2png-bg
136 "-T" "tight"
137 "-x" (format "%s" (* muse-latex2png-scale-factor 1000))
138 "-y" (format "%s" (* muse-latex2png-scale-factor 1000))
139 "-o" (concat texfile ".png")
140 (concat texfile ".dvi"))
141 (if (file-exists-p (concat texfile ".png"))
142 (progn
143 (delete-file (concat texfile ".dvi"))
144 (delete-file (concat texfile ".tex"))
145 (delete-file (concat texfile ".aux"))
146 (delete-file (concat texfile ".log"))
147 (concat texfile ".png"))
148 (message "Failed to create png file")
149 nil))
150 (message (concat "Failed to create dvi file " texfile))
151 nil)))
153 (defun muse-latex2png-region (beg end attrs)
154 "Generate an image for the Latex code between BEG and END.
155 If a Muse page is currently being published, replace the given
156 region with the appropriate markup that displays the image.
157 Otherwise, just return the path of the generated image.
159 Valid keys for the ATTRS alist are as follows.
161 prefix: The prefix given to the image file.
162 preamble: Extra text to add to the Latex preamble.
163 inline: Display image as inline, instead of a block."
164 (let ((end-marker (set-marker (make-marker) (1+ end)))
165 (pubdir (expand-file-name
166 muse-latex2png-img-dest
167 (file-name-directory muse-publishing-current-output-path))))
168 (save-restriction
169 (narrow-to-region beg end)
170 (let* ((text (buffer-substring-no-properties beg end))
171 ;; the prefix given to the image file.
172 (prefix (cdr (assoc "prefix" attrs)))
173 ;; preamble (for extra options)
174 (preamble (cdr (assoc "preamble" attrs)))
175 ;; display inline or as a block
176 (display (car (assoc "inline" attrs))))
177 (when muse-publishing-p
178 (delete-region beg end)
179 (goto-char (point-min)))
180 (unless (file-directory-p pubdir)
181 (make-directory pubdir))
182 (let ((path (muse-latex2png-move2pubdir
183 (muse-latex2png text prefix preamble)
184 prefix pubdir)))
185 (when path
186 (when muse-publishing-p
187 (muse-insert-markup
188 (if (muse-style-derived-p "html")
189 (concat "<img src=\"" path
190 "\" alt=\"latex2png equation\" "
191 (if display (concat "class=\"latex-inline\"")
192 (concat "class=\"latex-display\""))
193 (if (muse-style-derived-p "xhtml")
194 " />"
195 ">")
196 (muse-insert-markup "<!-- " text "-->"))
197 (let ((ext (or (file-name-extension path) ""))
198 (path (muse-path-sans-extension path)))
199 (muse-markup-text 'image path ext))))
200 (goto-char (point-max)))
201 path))))))
203 (defun muse-publish-latex-tag (beg end attrs)
204 "If the current style is not Latex-based, generate an image for the
205 given Latex code. Otherwise, don't do anything to the region.
206 See `muse-latex2png-region' for valid keys for ATTRS."
207 (unless (assoc "prefix" attrs)
208 (setq attrs (cons (cons "prefix"
209 (concat "latex2png-" (muse-page-name)))
210 attrs)))
211 (if (or (muse-style-derived-p "latex") (muse-style-derived-p "context"))
212 (muse-publish-mark-read-only beg end)
213 (muse-latex2png-region beg end attrs)))
215 (put 'muse-publish-latex-tag 'muse-dangerous-tag t)
217 (defun muse-publish-math-tag (beg end)
218 "Surround the given region with \"$\" characters. Then, if the
219 current style is not Latex-based, generate an image for the given
220 Latex math code.
222 If 6 or more spaces come before the tag, and the end of the tag
223 is at the end of a line, then surround the region with the
224 equivalent of \"$$\" instead. This causes the region to be
225 centered in the published output, among other things."
226 (let* ((centered (and (re-search-backward
227 (concat "^[" muse-regexp-blank "]\\{6,\\}\\=")
228 nil t)
229 (save-excursion
230 (save-match-data
231 (goto-char end)
232 (looking-at (concat "[" muse-regexp-blank "]*$"))))
233 (prog1 t
234 (replace-match "")
235 (when (and (or (muse-style-derived-p "latex")
236 (muse-style-derived-p "context"))
237 (not (bobp)))
238 (backward-char 1)
239 (if (bolp)
240 (delete-char 1)
241 (forward-char 1)))
242 (setq beg (point)))))
243 (tag-beg (if centered
244 (if (muse-style-derived-p "context")
245 "\\startformula " "\\[ ")
246 "$"))
247 (tag-end (if centered
248 (if (muse-style-derived-p "context")
249 " \\stopformula" " \\]")
250 "$"))
251 (attrs (nconc (list (cons "prefix"
252 (concat "latex2png-" (muse-page-name))))
253 (if centered nil
254 '(("inline" . t))))))
255 (goto-char beg)
256 (muse-insert-markup tag-beg)
257 (goto-char end)
258 (muse-insert-markup tag-end)
259 (if (or (muse-style-derived-p "latex") (muse-style-derived-p "context"))
260 (muse-publish-mark-read-only beg (point))
261 (muse-latex2png-region beg (point) attrs))))
263 (put 'muse-publish-math-tag 'muse-dangerous-tag t)
265 ;;; Insinuate with muse-publish
267 (add-to-list 'muse-publish-markup-tags
268 '("latex" t t nil muse-publish-latex-tag)
271 (add-to-list 'muse-publish-markup-tags
272 '("math" t nil nil muse-publish-math-tag)
275 (provide 'muse-latex2png)
276 ;;; muse-latex2png.el ends here