From 3501be303eba9c6613ae4351027479f945d3fe2b Mon Sep 17 00:00:00 2001 From: Jambunathan K Date: Fri, 14 Sep 2012 02:11:03 +0530 Subject: [PATCH] org-e-odt.el: Pre-process LaTeX fragments Handle enumeration more robustly. Numbered OpenDocument formula no longer uses a table for typesetting of formula and it's number. Also some renaming and moving around. --- contrib/lisp/org-e-odt.el | 1092 ++++++++++++++++++++++++--------------------- 1 file changed, 587 insertions(+), 505 deletions(-) diff --git a/contrib/lisp/org-e-odt.el b/contrib/lisp/org-e-odt.el index 2fab446ab..2b4f6a257 100644 --- a/contrib/lisp/org-e-odt.el +++ b/contrib/lisp/org-e-odt.el @@ -84,7 +84,8 @@ (verse-block . org-e-odt-verse-block)) :export-block "ODT" :filters-alist ((:filter-parse-tree - . (org-e-odt--translate-description-lists + . (org-e-odt--translate-latex-fragments + org-e-odt--translate-description-lists org-e-odt--translate-list-tables))) :menu-entry (?o "Export to ODT" @@ -217,7 +218,7 @@ standard Emacs.") ("odf" . "OpenDocument Formula") ("odc" . "OpenDocument Chart"))) -(defvar org-e-odt-table-style-format +(defconst org-e-odt-table-style-format " @@ -261,28 +262,6 @@ according to the default face identified by the `htmlfontify'.") (defvar hfy-optimisations) (defvar org-e-odt-embedded-formulas-count 0) -(defvar org-e-odt-entity-frame-styles - '(("As-CharImage" "__Figure__" ("OrgInlineImage" nil "as-char")) - ("ParagraphImage" "__Figure__" ("OrgDisplayImage" nil "paragraph")) - ("PageImage" "__Figure__" ("OrgPageImage" nil "page")) - ("CaptionedAs-CharImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgInlineImage" nil "as-char")) - ("CaptionedParagraphImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgImageCaptionFrame" nil "paragraph")) - ("CaptionedPageImage" "__Figure__" - ("OrgCaptionedImage" - " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") - ("OrgPageImageCaptionFrame" nil "page")) - ("InlineFormula" "__MathFormula__" ("OrgInlineFormula" nil "as-char")) - ("DisplayFormula" "__MathFormula__" ("OrgDisplayFormula" nil "as-char")) - ("CaptionedDisplayFormula" "__MathFormula__" - ("OrgCaptionedFormula" nil "paragraph") - ("OrgFormulaCaptionFrame" nil "as-char")))) - (defvar org-e-odt-embedded-images-count 0) (defvar org-e-odt-image-size-probe-method (append (and (executable-find "identify") '(imagemagick)) ; See Bug#10675 @@ -301,7 +280,7 @@ according to the default face identified by the `htmlfontify'.") (defvar org-e-odt-max-image-size '(17.0 . 20.0) "Limiting dimensions for an embedded image.") -(defvar org-e-odt-label-styles +(defconst org-e-odt-label-styles '(("math-formula" "%c" "text" "(%n)") ("math-label" "(%n)" "text" "(%n)") ("category-and-value" "%e %n: %c" "category-and-value" "%e %n") @@ -327,34 +306,41 @@ specifiers - %e and %n. %e is replaced with the CATEGORY-NAME. `org-e-odt-format-label-reference'.") (defvar org-e-odt-category-map-alist - '(("__Table__" "Table" "value" "Table") - ("__Figure__" "Illustration" "value" "Figure") - ("__MathFormula__" "Text" "math-formula" "Equation") - ("__DvipngImage__" "Equation" "value" "Equation") - ("__Listing__" "Listing" "value" "Listing") + '(("__Table__" "Table" "value" "Table" org-e-odt--enumerable-p) + ("__Figure__" "Illustration" "value" "Figure" org-e-odt--enumerable-image-p) + ("__MathFormula__" "Text" "math-formula" "Equation" org-e-odt--enumerable-formula-p) + ("__DvipngImage__" "Equation" "value" "Equation" org-e-odt--enumerable-latex-image-p) + ("__Listing__" "Listing" "value" "Listing" org-e-odt--enumerable-p) ;; ("__Table__" "Table" "category-and-value") ;; ("__Figure__" "Figure" "category-and-value") ;; ("__DvipngImage__" "Equation" "category-and-value") ) "Map a CATEGORY-HANDLE to OD-VARIABLE and LABEL-STYLE. This is a list where each entry is of the form \\(CATEGORY-HANDLE -OD-VARIABLE LABEL-STYLE CATEGORY-NAME\\). CATEGORY_HANDLE -identifies the captionable entity in question. OD-VARIABLE is -the OpenDocument sequence counter associated with the entity. -These counters are declared within +OD-VARIABLE LABEL-STYLE CATEGORY-NAME ENUMERATOR-PREDICATE\\). + +CATEGORY_HANDLE identifies the captionable entity in question. + +OD-VARIABLE is the OpenDocument sequence counter associated with +the entity. These counters are declared within \"...\" block of -`org-e-odt-content-template-file'. LABEL-STYLE is a key into -`org-e-odt-label-styles' and specifies how a given entity should -be captioned and referenced. CATEGORY-NAME is used for -qualifying captions on export. You can modify the CATEGORY-NAME -used in the exported document by modifying -`org-export-dictionary'. For example, an embedded image in an -English document is captioned as \"Figure 1: Orgmode Logo\", by -default. If you want the image to be captioned as \"Illustration -1: Orgmode Logo\" instead, install an entry in +`org-e-odt-content-template-file'. + +LABEL-STYLE is a key into `org-e-odt-label-styles' and specifies +how a given entity should be captioned and referenced. + +CATEGORY-NAME is used for qualifying captions on export. You can +modify the CATEGORY-NAME used in the exported document by +modifying `org-export-dictionary'. For example, an embedded +image in an English document is captioned as \"Figure 1: Orgmode +Logo\", by default. If you want the image to be captioned as +\"Illustration 1: Orgmode Logo\" instead, install an entry in `org-export-dictionary' which translates \"Figure\" to \"Illustration\" when the language is \"en\" and encoding is -`:utf-8'.") +`:utf-8'. + +ENUMERATOR-PREDICATE is used for assigning a sequence number to +the entity. See `org-e-odt--enumerate'.") (defvar org-e-odt-manifest-file-entries nil) (defvar hfy-user-sheet-assoc) @@ -754,19 +740,24 @@ in order to mimic default behaviour: ;;;; Links +(defcustom org-e-odt-inline-formula-rules + '(("file" . "\\.\\(mathml\\|mml\\)\\'")) + "Rules characterizing formula files that can be inlined into HTML. + +A rule consists in an association whose key is the type of link +to consider, and value is a regexp that will be matched against +link's path." + :group 'org-export-e-odt + :type '(alist :key-type (string :tag "Type") + :value-type (regexp :tag "Path"))) + (defcustom org-e-odt-inline-image-rules '(("file" . "\\.\\(jpeg\\|jpg\\|png\\|gif\\)\\'")) "Rules characterizing image files that can be inlined into HTML. A rule consists in an association whose key is the type of link to consider, and value is a regexp that will be matched against -link's path. - -Note that, by default, the image extension *actually* allowed -depend on the way the HTML file is processed. When used with -pdflatex, pdf, jpg and png images are OK. When processing -through dvi to Postscript, only ps and eps are allowed. The -default we use here encompasses both." +link's path." :group 'org-export-e-odt :type '(alist :key-type (string :tag "Type") :value-type (regexp :tag "Path"))) @@ -990,163 +981,12 @@ style from the list." (desc (get-text-property 0 :description text))) (concat (and title (format "%s" - (org-e-odt-encode-plain-text title t))) + (org-e-odt--encode-plain-text title t))) (and desc (format "%s" - (org-e-odt-encode-plain-text desc t))))))))) + (org-e-odt--encode-plain-text desc t))))))))) -;;;; Inline Images - -(defun org-e-odt--copy-image-file (path) - "Returns the internal name of the file" - (let* ((image-type (file-name-extension path)) - (media-type (format "image/%s" image-type)) - (target-dir "Images/") - (target-file - (format "%s%04d.%s" target-dir - (incf org-e-odt-embedded-images-count) image-type))) - (message "Embedding %s as %s ..." - (substring-no-properties path) target-file) - - (when (= 1 org-e-odt-embedded-images-count) - (make-directory (concat org-e-odt-zip-dir target-dir)) - (org-e-odt-create-manifest-file-entry "" target-dir)) - - (copy-file path (concat org-e-odt-zip-dir target-file) 'overwrite) - (org-e-odt-create-manifest-file-entry media-type target-file) - target-file)) - -(defun org-e-odt--image-size (file &optional user-width - user-height scale dpi embed-as) - (let* ((--pixels-to-cms - (function (lambda (pixels dpi) - (let ((cms-per-inch 2.54) - (inches (/ pixels dpi))) - (* cms-per-inch inches))))) - (--size-in-cms - (function - (lambda (size-in-pixels dpi) - (and size-in-pixels - (cons (funcall --pixels-to-cms (car size-in-pixels) dpi) - (funcall --pixels-to-cms (cdr size-in-pixels) dpi)))))) - (dpi (or dpi org-e-odt-pixels-per-inch)) - (anchor-type (or embed-as "paragraph")) - (user-width (and (not scale) user-width)) - (user-height (and (not scale) user-height)) - (size - (and - (not (and user-height user-width)) - (or - ;; Use Imagemagick. - (and (executable-find "identify") - (let ((size-in-pixels - (let ((dim (shell-command-to-string - (format "identify -format \"%%w:%%h\" \"%s\"" - file)))) - (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim) - (cons (string-to-number (match-string 1 dim)) - (string-to-number (match-string 2 dim))))))) - (funcall --size-in-cms size-in-pixels dpi))) - ;; Use Emacs. - (let ((size-in-pixels - (ignore-errors ; Emacs could be in batch mode - (clear-image-cache) - (image-size (create-image file) 'pixels)))) - (funcall --size-in-cms size-in-pixels dpi)) - ;; Use hard-coded values. - (cdr (assoc-string anchor-type - org-e-odt-default-image-sizes-alist)) - ;; Error out. - (error "Cannot determine Image size. Aborting ...")))) - (width (car size)) (height (cdr size))) - (cond - (scale - (setq width (* width scale) height (* height scale))) - ((and user-height user-width) - (setq width user-width height user-height)) - (user-height - (setq width (* user-height (/ width height)) height user-height)) - (user-width - (setq height (* user-width (/ height width)) width user-width)) - (t (ignore))) - ;; ensure that an embedded image fits comfortably within a page - (let ((max-width (car org-e-odt-max-image-size)) - (max-height (cdr org-e-odt-max-image-size))) - (when (or (> width max-width) (> height max-height)) - (let* ((scale1 (/ max-width width)) - (scale2 (/ max-height height)) - (scale (min scale1 scale2))) - (setq width (* scale width) height (* scale height))))) - (cons width height))) - -(defun org-e-odt-link--inline-image (element info) - "Return HTML code for an inline image. -LINK is the link pointing to the inline image. INFO is a plist -used as a communication channel." - (let* ((src (cond - ((eq (org-element-type element) 'link) - (let* ((type (org-element-property :type element)) - (raw-path (org-element-property :path element))) - (cond ((member type '("http" "https")) - (concat type ":" raw-path)) - ((file-name-absolute-p raw-path) - (expand-file-name raw-path)) - (t raw-path)))) - ((member (org-element-type element) - '(latex-fragment latex-environment)) - (let* ((latex-frag (org-remove-indentation - (org-element-property :value element))) - (formula-link (org-e-odt-format-latex - latex-frag 'dvipng info))) - (and formula-link - (string-match "file:\\([^]]*\\)" formula-link) - (match-string 1 formula-link)))) - (t (error "what is this?")))) - (src-expanded (if (file-name-absolute-p src) src - (expand-file-name src (file-name-directory - (plist-get info :input-file))))) - (href (format - "\n" - (org-e-odt--copy-image-file src-expanded))) - ;; extract attributes from #+ATTR_ODT line. - (attr-from (case (org-element-type element) - (link (org-export-get-parent-element element)) - (t element))) - ;; convert attributes to a plist. - (attr-plist (org-export-read-attribute :attr_odt attr-from)) - ;; handle `:anchor', `:style' and `:attributes' properties. - (user-frame-anchor - (car (assoc-string (plist-get attr-plist :anchor) - '(("as-char") ("paragraph") ("page")) t))) - (user-frame-style - (and user-frame-anchor (plist-get attr-plist :style))) - (user-frame-attrs - (and user-frame-anchor (plist-get attr-plist :attributes))) - (user-frame-params - (list user-frame-style user-frame-attrs user-frame-anchor)) - ;; (embed-as (or embed-as user-frame-anchor "paragraph")) - ;; extrac - ;; handle `:width', `:height' and `:scale' properties. - (size (org-e-odt--image-size - src-expanded (plist-get attr-plist :width) - (plist-get attr-plist :height) - (plist-get attr-plist :scale) nil ;; embed-as - "paragraph" ; FIXME - )) - (width (car size)) (height (cdr size)) - (embed-as - (case (org-element-type element) - ((org-e-odt-standalone-image-p element info) "paragraph") - (latex-fragment "as-char") - (latex-environment "paragraph") - (t "paragraph"))) - (captions (org-e-odt-format-label element info 'definition)) - (caption (car captions)) (short-caption (cdr captions)) - (entity (concat (and caption "Captioned") embed-as "Image"))) - (org-e-odt-format-entity entity href width height - captions user-frame-params ))) - ;;;; Library wrappers (defun org-e-odt--zip-extract (archive members target) @@ -1304,7 +1144,6 @@ new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME (plist-get org-e-odt-automatic-styles object))))) (cons object-name style-name))) - ;;;; Checkbox (defun org-e-odt--checkbox (item) @@ -1317,7 +1156,6 @@ new entry in `org-e-odt-automatic-styles'. Return (OBJECT-NAME (off "[ ] ") (trans "[-] ")))))) - ;;; Template (defun org-e-odt-template (contents info) @@ -1615,13 +1453,14 @@ channel." "Transcode a DRAWER element from Org to ODT. CONTENTS holds the contents of the block. INFO is a plist holding contextual information." - (if (functionp org-e-odt-format-drawer-function) - (funcall org-e-odt-format-drawer-function - (org-element-property :drawer-name drawer) - contents) - ;; If there's no user defined function: simply display contents of - ;; the drawer. - contents)) + (let* ((name (org-element-property :drawer-name drawer)) + (output (if (functionp org-e-odt-format-drawer-function) + (funcall org-e-odt-format-drawer-function + name contents) + ;; If there's no user defined function: simply + ;; display contents of the drawer. + contents))) + output)) ;;;; Dynamic Block @@ -1920,16 +1759,17 @@ holding contextual information." (org-e-odt-format-headline--wrap inlinetask info format-function :contents contents))) ;; Otherwise, use a default template. - (t (format "\n%s" - "Text_20_body" - (org-e-odt--textbox - (concat - (format "\n%s" - "OrgInlineTaskHeading" - (org-e-odt-format-headline--wrap - inlinetask info)) - contents) - nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\""))))) + (t + (format "\n%s" + "Text_20_body" + (org-e-odt--textbox + (concat + (format "\n%s" + "OrgInlineTaskHeading" + (org-e-odt-format-headline--wrap + inlinetask info)) + contents) + nil nil "OrgInlineTaskFrame" " style:rel-width=\"100%\""))))) ;;;; Italic @@ -2012,67 +1852,19 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;; (when (or (not (> (length ad-return-value) 0)) ;; (get-text-property 0 'org-protected ad-return-value)) ;; (setq ad-return-value -;; (org-propertize (org-e-odt-encode-plain-text (ad-get-arg 0)) +;; (org-propertize (org-e-odt--encode-plain-text (ad-get-arg 0)) ;; 'org-protected t)))) -(defun org-e-odt-format-latex (latex-frag processing-type info) - (let* ((prefix (case processing-type - (dvipng "ltxpng/") - (mathml "ltxmathml/"))) - (input-file (plist-get info :input-file)) - (cache-subdir - (concat prefix (file-name-sans-extension - (file-name-nondirectory input-file)))) - (cache-dir (file-name-directory input-file)) - (display-msg (case processing-type - (dvipng "Creating LaTeX Image...") - (mathml "Creating MathML snippet...")))) - (with-temp-buffer - (insert latex-frag) - (org-format-latex cache-subdir cache-dir nil display-msg - nil nil processing-type) - (buffer-string)))) - (defun org-e-odt-latex-environment (latex-environment contents info) "Transcode a LATEX-ENVIRONMENT element from Org to ODT. CONTENTS is nil. INFO is a plist holding contextual information." - (let* ((latex-frag - (org-remove-indentation - (org-element-property :value latex-environment))) - (processing-type (plist-get info :LaTeX-fragments)) - (caption (org-element-property :caption latex-environment)) - (short-caption (and (cdr caption) - (org-export-data (cdr caption) info))) - (caption (and (car caption) (org-export-data (car caption) info))) - (label (org-element-property :name latex-environment)) - (attr nil) ; FIXME - (label (org-element-property :name latex-environment))) - - (when (memq processing-type '(t mathjax)) - (unless (and (fboundp 'org-format-latex-mathml-available-p) - (org-format-latex-mathml-available-p)) - (message "LaTeX to MathML converter not available. Trying dvinpng...") - (setq processing-type 'dvipng))) - - (when (eq processing-type 'dvipng) - (unless (and (org-check-external-command "latex" "" t) - (org-check-external-command "dvipng" "" t)) - (message "LaTeX to PNG converter not available. Using verbatim.") - (setq processing-type 'verbatim))) - - (case processing-type - ((t mathjax) - (org-e-odt-format-formula latex-environment info)) - (dvipng - (format "\n%s" - "Text_20_body" - (org-e-odt-link--inline-image latex-environment info))) - (t (org-e-odt-do-format-code latex-frag))))) + (let* ((latex-frag (org-remove-indentation + (org-element-property :value latex-environment)))) + (org-e-odt-do-format-code latex-frag))) ;;;; Latex Fragment - ;; (when latex-frag ; FIXME ;; (setq href (org-propertize href :title "LaTeX Fragment" ;; :description latex-frag))) @@ -2084,12 +1876,8 @@ CONTENTS is nil. INFO is a plist holding contextual information." CONTENTS is nil. INFO is a plist holding contextual information." (let* ((latex-frag (org-element-property :value latex-fragment)) (processing-type (plist-get info :LaTeX-fragments))) - (cond - ((member processing-type '(t mathjax)) - (org-e-odt-format-formula latex-fragment info)) - ((eq processing-type 'dvipng) - (org-e-odt-link--inline-image latex-fragment info)) - (t (org-e-odt-encode-plain-text latex-frag t))))) + (format "%s" + "OrgCode" (org-e-odt--encode-plain-text latex-frag t)))) ;;;; Line Break @@ -2102,17 +1890,10 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;;;; Link - - -;;;; Links :: Generic - -;; (org-lparse-link-description-is-image -;; (format "\n\n%s\n" -;; href desc)) - ;;;; Links :: Label references -(defun org-e-odt-enumerate-element (element info &optional predicate n) +(defun org-e-odt--enumerate (element info &optional predicate n) + (when predicate (assert (funcall predicate element info))) (let* ((--numbered-parent-headline-at-<=-n (function (lambda (element n info) @@ -2150,101 +1931,218 @@ CONTENTS is nil. INFO is a plist holding contextual information." tag)) (defun org-e-odt-format-label (element info op) + (assert (memq (org-element-type element) '(link table src-block paragraph))) (let* ((caption-from (case (org-element-type element) (link (org-export-get-parent-element element)) (t element))) - ;; get label and caption. + ;; Get label and caption. (label (org-element-property :name caption-from)) - (caption (org-element-property :caption caption-from)) + (caption (org-export-get-caption caption-from)) (short-caption (org-export-get-caption caption-from t)) - ;; transcode captions. - (caption (and caption (org-export-data (car caption) info))) + ;; Transcode captions. + (caption (and caption (org-export-data caption info))) (short-caption (and short-caption (org-export-data short-caption info)))) (when (or label caption) (let* ((default-category - (cond - ((eq (org-element-type element) 'table) - "__Table__") - ((org-e-odt-standalone-image-p element info) - "__Figure__") - ((member (org-element-type element) - '(latex-environment latex-fragment)) - (let ((processing-type (plist-get info :LaTeX-fragments))) - (cond - ((eq processing-type 'dvipng) "__DvipngImage__") - ((eq processing-type 'mathjax) "__MathFormula__") - ((eq processing-type 't) "__MathFormula__") - (t (error "Handle LaTeX:verbatim"))))) - ((eq (org-element-type element) 'src-block) - "__Listing__") - (t (error "Handle enumeration of %S" element)))) - (predicate - (cond - ((member (org-element-type element) - '(table latex-environment src-block)) - nil) - ((org-e-odt-standalone-image-p element info) - 'org-e-odt-standalone-image-p) - (t (error "Handle enumeration of %S" element)))) - (seqno (org-e-odt-enumerate-element - element info predicate)) ; FIXME - ;; handle label props. - (label-props (assoc default-category org-e-odt-category-map-alist)) - ;; identify opendocument counter - (counter (nth 1 label-props)) - ;; identify label style - (label-style (nth 2 label-props)) - ;; retrieve localized category sting - (category (org-export-translate (nth 3 label-props) :utf-8 info))) - (case op - (definition - ;; assign an internal label, if user has not provided one - (setq label (or label (format "%s-%s" default-category seqno))) - (setq label (org-export-solidify-link-text label)) - - (cons - (format-spec - (cadr (assoc-string label-style org-e-odt-label-styles t)) - `((?e . ,category) - (?n . ,(format - "%s" - label counter counter seqno)) - (?c . ,(or caption "")))) - short-caption)) - (reference - (assert label) - (setq label (org-export-solidify-link-text label)) - (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t))) - (fmt1 (car fmt)) - (fmt2 (cadr fmt))) - (format "%s" - fmt1 label (format-spec fmt2 `((?e . ,category) - (?n . ,seqno)))))) - (t (error "Unknow %S on label" op))))))) + (case (org-element-type element) + (table "__Table__") + (src-block "__Listing__") + ((link paragraph) + (cond + ((org-e-odt--enumerable-latex-image-p element info) + "__DvipngImage__") + ((org-e-odt--enumerable-image-p element info) + "__Figure__") + ((org-e-odt--enumerable-formula-p element info) + "__MathFormula__") + (t (error "Don't know how to format label for link: %S" + element)))) + (t (error "Don't know how to format label for element type: %s" + (org-element-type element))))) + seqno) + (assert default-category) + (destructuring-bind (counter label-style category predicate) + (assoc-default default-category org-e-odt-category-map-alist) + ;; Compute sequence number of the element. + (setq seqno (org-e-odt--enumerate element info predicate)) + ;; Localize category string. + (setq category (org-export-translate category :utf-8 info)) + (case op + ;; Case 1: Handle Label definition. + (definition + ;; Assign an internal label, if user has not provided one + (setq label (or label (format "%s-%s" default-category seqno))) + (setq label (org-export-solidify-link-text label)) + (cons + (format-spec + (cadr (assoc-string label-style org-e-odt-label-styles t)) + `((?e . ,category) + (?n . ,(format + "%s" + label counter counter seqno)) + (?c . ,(or caption "")))) + short-caption)) + ;; Case 2: Handle Label reference. + (reference + (assert label) + (setq label (org-export-solidify-link-text label)) + (let* ((fmt (cddr (assoc-string label-style org-e-odt-label-styles t))) + (fmt1 (car fmt)) + (fmt2 (cadr fmt))) + (format "%s" + fmt1 label (format-spec fmt2 `((?e . ,category) + (?n . ,seqno)))))) + (t (error "Unknow %S on label" op)))))))) + + +;;;; Links :: Inline Images + +(defun org-e-odt--copy-image-file (path) + "Returns the internal name of the file" + (let* ((image-type (file-name-extension path)) + (media-type (format "image/%s" image-type)) + (target-dir "Images/") + (target-file + (format "%s%04d.%s" target-dir + (incf org-e-odt-embedded-images-count) image-type))) + (message "Embedding %s as %s ..." + (substring-no-properties path) target-file) + + (when (= 1 org-e-odt-embedded-images-count) + (make-directory (concat org-e-odt-zip-dir target-dir)) + (org-e-odt-create-manifest-file-entry "" target-dir)) + + (copy-file path (concat org-e-odt-zip-dir target-file) 'overwrite) + (org-e-odt-create-manifest-file-entry media-type target-file) + target-file)) + +(defun org-e-odt--image-size (file &optional user-width + user-height scale dpi embed-as) + (let* ((--pixels-to-cms + (function (lambda (pixels dpi) + (let ((cms-per-inch 2.54) + (inches (/ pixels dpi))) + (* cms-per-inch inches))))) + (--size-in-cms + (function + (lambda (size-in-pixels dpi) + (and size-in-pixels + (cons (funcall --pixels-to-cms (car size-in-pixels) dpi) + (funcall --pixels-to-cms (cdr size-in-pixels) dpi)))))) + (dpi (or dpi org-e-odt-pixels-per-inch)) + (anchor-type (or embed-as "paragraph")) + (user-width (and (not scale) user-width)) + (user-height (and (not scale) user-height)) + (size + (and + (not (and user-height user-width)) + (or + ;; Use Imagemagick. + (and (executable-find "identify") + (let ((size-in-pixels + (let ((dim (shell-command-to-string + (format "identify -format \"%%w:%%h\" \"%s\"" + file)))) + (when (string-match "\\([0-9]+\\):\\([0-9]+\\)" dim) + (cons (string-to-number (match-string 1 dim)) + (string-to-number (match-string 2 dim))))))) + (funcall --size-in-cms size-in-pixels dpi))) + ;; Use Emacs. + (let ((size-in-pixels + (ignore-errors ; Emacs could be in batch mode + (clear-image-cache) + (image-size (create-image file) 'pixels)))) + (funcall --size-in-cms size-in-pixels dpi)) + ;; Use hard-coded values. + (cdr (assoc-string anchor-type + org-e-odt-default-image-sizes-alist)) + ;; Error out. + (error "Cannot determine Image size. Aborting ...")))) + (width (car size)) (height (cdr size))) + (cond + (scale + (setq width (* width scale) height (* height scale))) + ((and user-height user-width) + (setq width user-width height user-height)) + (user-height + (setq width (* user-height (/ width height)) height user-height)) + (user-width + (setq height (* user-width (/ height width)) width user-width)) + (t (ignore))) + ;; ensure that an embedded image fits comfortably within a page + (let ((max-width (car org-e-odt-max-image-size)) + (max-height (cdr org-e-odt-max-image-size))) + (when (or (> width max-width) (> height max-height)) + (let* ((scale1 (/ max-width width)) + (scale2 (/ max-height height)) + (scale (min scale1 scale2))) + (setq width (* scale width) height (* scale height))))) + (cons width height))) + +(defun org-e-odt-link--inline-image (element info) + "Return HTML code for an inline image. +LINK is the link pointing to the inline image. INFO is a plist +used as a communication channel." + (assert (eq (org-element-type element) 'link)) + (let* ((src (let* ((type (org-element-property :type element)) + (raw-path (org-element-property :path element))) + (cond ((member type '("http" "https")) + (concat type ":" raw-path)) + ((file-name-absolute-p raw-path) + (expand-file-name raw-path)) + (t raw-path)))) + (src-expanded (if (file-name-absolute-p src) src + (expand-file-name src (file-name-directory + (plist-get info :input-file))))) + (href (format + "\n" + (org-e-odt--copy-image-file src-expanded))) + ;; Extract attributes from #+ATTR_ODT line. + (attr-from (case (org-element-type element) + (link (org-export-get-parent-element element)) + (t element))) + ;; Convert attributes to a plist. + (attr-plist (org-export-read-attribute :attr_odt attr-from)) + ;; Handle `:anchor', `:style' and `:attributes' properties. + (user-frame-anchor + (car (assoc-string (plist-get attr-plist :anchor) + '(("as-char") ("paragraph") ("page")) t))) + (user-frame-style + (and user-frame-anchor (plist-get attr-plist :style))) + (user-frame-attrs + (and user-frame-anchor (plist-get attr-plist :attributes))) + (user-frame-params + (list user-frame-style user-frame-attrs user-frame-anchor)) + ;; (embed-as (or embed-as user-frame-anchor "paragraph")) + ;; extrac + ;; handle `:width', `:height' and `:scale' properties. + (size (org-e-odt--image-size + src-expanded (plist-get attr-plist :width) + (plist-get attr-plist :height) + (plist-get attr-plist :scale) nil ;; embed-as + "paragraph" ; FIXME + )) + (width (car size)) (height (cdr size)) + (embed-as (if (org-e-odt--standalone-link-p element info) "paragraph" + "as-char")) + (captions (org-e-odt-format-label element info 'definition)) + (caption (car captions)) (short-caption (cdr captions)) + (entity (concat (and caption "Captioned") embed-as "Image"))) + (org-e-odt--render-image/formula entity href width height + captions user-frame-params ))) + ;;;; Links :: Math formula -(defun org-e-odt-format-formula (element info) - (let* ((src (cond - ((eq (org-element-type element) 'link) ; FIXME - (let* ((type (org-element-property :type element)) - (raw-path (org-element-property :path element))) - (cond - ((file-name-absolute-p raw-path) - (expand-file-name raw-path)) - (t raw-path)))) - ((member (org-element-type element) - '(latex-fragment latex-environment)) - (let* ((latex-frag (org-remove-indentation - (org-element-property :value element))) - (formula-link (org-e-odt-format-latex - latex-frag 'mathml info))) - (and formula-link - (string-match "file:\\([^]]*\\)" formula-link) - (match-string 1 formula-link)))) - (t (error "what is this?")))) +(defun org-e-odt-link--inline-formula (element info) + (let* ((src (let* ((type (org-element-property :type element)) + (raw-path (org-element-property :path element))) + (cond + ((file-name-absolute-p raw-path) + (expand-file-name raw-path)) + (t raw-path)))) (full-src (if (file-name-absolute-p src) src (expand-file-name src (file-name-directory (plist-get info :input-file))))) @@ -2257,43 +2155,23 @@ CONTENTS is nil. INFO is a plist holding contextual information." (href (format "\n" " xlink:show=\"embed\" xlink:actuate=\"onLoad\"" - (file-name-directory (org-e-odt-copy-formula-file full-src)))) + (file-name-directory (org-e-odt--copy-formula-file full-src)))) (embed-as (if caption 'paragraph 'character)) width height) (cond ((eq embed-as 'character) - (org-e-odt-format-entity "InlineFormula" href width height)) + (org-e-odt--render-image/formula "InlineFormula" href width height)) (t - (let* ((equation (org-e-odt-format-entity + (let* ((equation (org-e-odt--render-image/formula "CaptionedDisplayFormula" href width height captions)) (label (let* ((org-e-odt-category-map-alist - '(("__Table__" "Table" "value") - ("__Figure__" "Illustration" "value") - ("__MathFormula__" "Text" "math-label") - ("__DvipngImage__" "Equation" "value") - ("__Listing__" "Listing" "value")))) - (car (org-e-odt-format-label caption-from info 'definition)))) - (formula-tree - (org-element-adopt-elements - (list 'table '(:type org :attr_odt (":style \"OrgEquation\""))) - (org-element-adopt-elements - (list 'table-row '(:type standard)) - (list 'table-cell nil "") (list 'table-cell nil "")) - (org-element-adopt-elements - (list 'table-row '(:type standard)) - (org-element-adopt-elements - (list 'table-cell nil) - (list 'export-block (list :type "ODT" :value equation))) - (org-element-adopt-elements - (list 'table-cell nil) - (list 'export-block (list :type "ODT" :value label)))))) - (formula-info - (org-export-collect-tree-properties - formula-tree (org-export-get-environment 'e-odt)))) - (org-export-data formula-tree formula-info)))))) - -(defun org-e-odt-copy-formula-file (src-file) + '(("__MathFormula__" "Text" "math-label" "Equation" + org-e-odt--enumerable-formula-p)))) + (car (org-e-odt-format-label caption-from info 'definition))))) + (concat equation "" label)))))) + +(defun org-e-odt--copy-formula-file (src-file) "Returns the internal name of the file" (let* ((target-dir (format "Formula-%04d/" (incf org-e-odt-embedded-formulas-count))) @@ -2322,94 +2200,189 @@ CONTENTS is nil. INFO is a plist holding contextual information." ;;;; Targets -(defun org-e-odt-format-entity (entity href width height &optional - captions user-frame-params) - (let* ((caption (car captions)) (short-caption (cdr captions)) - (entity-style (assoc-string entity org-e-odt-entity-frame-styles t)) - default-frame-params frame-params - (--merge-frame-params - (function - (lambda (default-frame-params user-frame-params) - (if (not user-frame-params) default-frame-params - (assert (= (length default-frame-params) 3)) - (assert (= (length user-frame-params) 3)) - (loop for user-frame-param in user-frame-params - for default-frame-param in default-frame-params - collect (or user-frame-param default-frame-param))))))) +(defun org-e-odt--render-image/formula (cfg-key href width height &optional + captions user-frame-params) + (let* ((frame-cfg-alist + ;; Each element of this alist is of the form (CFG-HANDLE + ;; INNER-FRAME-PARAMS OUTER-FRAME-PARAMS). + + ;; CFG-HANDLE is the key to the alist. + + ;; INNER-FRAME-PARAMS and OUTER-FRAME-PARAMS specify the + ;; frame params for INNER-FRAME and OUTER-FRAME + ;; respectively. See below. + + ;; Configurations that are meant to be applied to + ;; non-captioned image/formula specifies no + ;; OUTER-FRAME-PARAMS. + + ;; TERMINOLOGY + ;; =========== + ;; INNER-FRAME :: Frame that directly surrounds an + ;; image/formula. + + ;; OUTER-FRAME :: Frame that encloses the INNER-FRAME. This + ;; frame also contains the caption, if any. + + ;; FRAME-PARAMS :: List of the form (FRAME-STYLE-NAME + ;; FRAME-ATTRIBUTES FRAME-ANCHOR). Note + ;; that these are the last three arguments + ;; to `org-e-odt--frame'. + + ;; Note that an un-captioned image/formula requires just an + ;; INNER-FRAME, while a captioned image/formula requires + ;; both an INNER and an OUTER-FRAME. + '(("As-CharImage" ("OrgInlineImage" nil "as-char")) + ("ParagraphImage" ("OrgDisplayImage" nil "paragraph")) + ("PageImage" ("OrgPageImage" nil "page")) + ("CaptionedAs-CharImage" + ("OrgCaptionedImage" + " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") + ("OrgInlineImage" nil "as-char")) + ("CaptionedParagraphImage" + ("OrgCaptionedImage" + " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") + ("OrgImageCaptionFrame" nil "paragraph")) + ("CaptionedPageImage" + ("OrgCaptionedImage" + " style:rel-width=\"100%\" style:rel-height=\"scale\"" "paragraph") + ("OrgPageImageCaptionFrame" nil "page")) + ("InlineFormula" ("OrgInlineFormula" nil "as-char")) + ("DisplayFormula" ("OrgDisplayFormula" nil "as-char")) + ("CaptionedDisplayFormula" + ("OrgCaptionedFormula" nil "paragraph") + ("OrgFormulaCaptionFrame" nil "paragraph")))) + (caption (car captions)) (short-caption (cdr captions)) + ;; Retrieve inner and outer frame params, from configuration. + (frame-cfg (assoc-string cfg-key frame-cfg-alist t)) + (inner (nth 1 frame-cfg)) + (outer (nth 2 frame-cfg)) + ;; User-specified frame params (from #+ATTR_ODT spec) + (user user-frame-params) + (--merge-frame-params (function + (lambda (default user) + "Merge default and user frame params." + (if (not user) default + (assert (= (length default) 3)) + (assert (= (length user) 3)) + (loop for u in user + for d in default + collect (or u d))))))) (cond + ;; Case 1: Image/Formula has no caption. + ;; There is only one frame, one that surrounds the image + ;; or formula. ((not caption) - (setq default-frame-params (nth 2 entity-style)) - (setq frame-params (funcall --merge-frame-params - default-frame-params user-frame-params)) - (apply 'org-e-odt--frame href width height frame-params)) + ;; Merge user frame params with that from configuration. + (setq inner (funcall --merge-frame-params inner user)) + (apply 'org-e-odt--frame href width height inner)) + ;; Case 2: Image/Formula is captioned or labeled. + ;; There are two frames: The inner one surrounds the + ;; image or formula. The outer one contains the + ;; caption/sequence number. (t - (setq default-frame-params (nth 3 entity-style)) - (setq frame-params (funcall --merge-frame-params - default-frame-params user-frame-params)) + ;; Merge user frame params with outer frame params. + (setq outer (funcall --merge-frame-params outer user)) + ;; Short caption, if specified, goes as part of inner frame. + (setq inner (let ((frame-params (copy-sequence inner))) + (setcar (cdr frame-params) + (concat + (cadr frame-params) + (when short-caption + (format " draw:name=\"%s\" " short-caption)))) + frame-params)) (apply 'org-e-odt--textbox (format "\n%s" "Illustration" (concat - (apply 'org-e-odt--frame href width height - (let ((entity-style-1 (copy-sequence - (nth 2 entity-style)))) - (setcar (cdr entity-style-1) - (concat - (cadr entity-style-1) - (and short-caption - (format " draw:name=\"%s\" " - short-caption)))) - entity-style-1)) + (apply 'org-e-odt--frame href width height inner) caption)) - width height frame-params))))) - -(defun org-e-odt-standalone-image-p (element info) - "Test if ELEMENT is a standalone image for the purpose ODT export. + width height outer))))) + +(defun org-e-odt--enumerable-p (element info) + ;; Element should have a caption or label. + (or (org-element-property :caption element) + (org-element-property :name element))) + +(defun org-e-odt--enumerable-image-p (element info) + (org-e-odt--standalone-link-p + element info + ;; Paragraph should have a caption or label. It SHOULD NOT be a + ;; replacement element. (i.e., It SHOULD NOT be a result of LaTeX + ;; processing.) + (lambda (p) + (and (not (org-element-property :replaces p)) + (or (org-element-property :caption p) + (org-element-property :name p)))) + ;; Link should point to an image file. + (lambda (l) + (assert (eq (org-element-type l) 'link)) + (org-export-inline-image-p l org-e-odt-inline-image-rules)))) + +(defun org-e-odt--enumerable-latex-image-p (element info) + (org-e-odt--standalone-link-p + element info + ;; Paragraph should have a caption or label. It SHOULD also be a + ;; replacement element. (i.e., It SHOULD be a result of LaTeX + ;; processing.) + (lambda (p) + (and (org-element-property :replaces p) + (or (org-element-property :caption p) + (org-element-property :name p)))) + ;; Link should point to an image file. + (lambda (l) + (assert (eq (org-element-type l) 'link)) + (org-export-inline-image-p l org-e-odt-inline-image-rules)))) + +(defun org-e-odt--enumerable-formula-p (element info) + (org-e-odt--standalone-link-p + element info + ;; Paragraph should have a caption or label. + (lambda (p) + (or (org-element-property :caption p) + (org-element-property :name p))) + ;; Link should point to a MathML or ODF file. + (lambda (l) + (assert (eq (org-element-type l) 'link)) + (org-export-inline-image-p l org-e-odt-inline-formula-rules)))) + +(defun org-e-odt--standalone-link-p (element info &optional + paragraph-predicate + link-predicate) + "Test if ELEMENT is a standalone link for the purpose ODT export. INFO is a plist holding contextual information. -Return non-nil, if ELEMENT is of type paragraph and it's sole -content, save for whitespaces, is a link that qualifies as an -inline image. - -Return non-nil, if ELEMENT is of type link and it's containing -paragraph has no other content save for leading and trailing -whitespaces. - -Return nil, otherwise. - -Bind `org-e-odt-standalone-image-predicate' to constrain -paragraph further. For example, to check for only captioned -standalone images, do the following. - - \(setq org-e-odt-standalone-image-predicate - \(lambda \(paragraph\) - \(org-element-property :caption paragraph\)\)\) -" - (let ((--standalone-image-predicate - (function (lambda (paragraph) - (or (org-element-property :caption paragraph) - (org-element-property :name paragraph))))) - (paragraph (case (org-element-type element) - (paragraph element) - (link (and (org-export-inline-image-p - element org-e-odt-inline-image-rules) - (org-export-get-parent element))) - (t nil)))) - (when paragraph - (assert (eq (org-element-type paragraph) 'paragraph)) - (when (funcall --standalone-image-predicate paragraph) - (let ((contents (org-element-contents paragraph))) +Return non-nil, if ELEMENT is of type paragraph satisfying +PARAGRAPH-PREDICATE and it's sole content, save for whitespaces, +is a link that satisfies LINK-PREDICATE. + +Return non-nil, if ELEMENT is of type link satisfying +LINK-PREDICATE and it's containing paragraph satisfies +PARAGRAPH-PREDICATE inaddtion to having no other content save for +leading and trailing whitespaces. + +Return nil, otherwise." + (let ((p (case (org-element-type element) + (paragraph element) + (link (and (or (not link-predicate) + (funcall link-predicate element)) + (org-export-get-parent element))) + (t nil)))) + (when p + (assert (eq (org-element-type p) 'paragraph)) + (when (or (not paragraph-predicate) + (funcall paragraph-predicate p)) + (let ((contents (org-element-contents p))) (loop for x in contents with inline-image-count = 0 - always (cond - ((eq (org-element-type x) 'plain-text) - (not (org-string-nw-p x))) - ((eq (org-element-type x) 'link) - (when (org-export-inline-image-p - x org-e-odt-inline-image-rules) - (= (incf inline-image-count) 1))) - (t nil)))))))) - + always (case (org-element-type x) + (plain-text + (not (org-string-nw-p x))) + (link + (and (or (not link-predicate) + (funcall link-predicate x)) + (= (incf inline-image-count) 1))) + (t nil)))))))) (defun org-e-odt-get-previous-elements (blob info) (let ((parent (org-export-get-parent blob))) @@ -2423,7 +2396,6 @@ standalone images, do the following. (setq el (org-export-get-parent (org-export-get-parent el)))) ordinal))) - (defun org-e-odt-link (link desc info) "Transcode a LINK object from Org to ODT. @@ -2450,6 +2422,10 @@ INFO is a plist holding contextual information. See ((and (not desc) (org-export-inline-image-p link org-e-odt-inline-image-rules)) (org-e-odt-link--inline-image link info)) + ;; Formula file. + ((and (not desc) (org-export-inline-image-p + link org-e-odt-inline-formula-rules)) + (org-e-odt-link--inline-formula link info)) ;; Radio target: Transcode target's contents and use them as ;; link's description. ((string= type "radio") @@ -2527,10 +2503,10 @@ INFO is a plist holding contextual information. See (otherwise ;; (unless desc ;; (setq number (cond - ;; ((org-e-odt-standalone-image-p destination info) + ;; ((org-e-odt--standalone-link-p destination info) ;; (org-export-get-ordinal ;; (assoc 'link (org-element-contents destination)) - ;; info 'link 'org-e-odt-standalone-image-p)) + ;; info 'link 'org-e-odt--standalone-link-p)) ;; (t (org-export-get-ordinal destination info)))) ;; (setq desc (when number ;; (if (atom number) (number-to-string number) @@ -2613,7 +2589,7 @@ contextual information." ;;;; Plain Text -(defun org-e-odt-fill-tabs-and-spaces (line) +(defun org-e-odt--encode-tabs-and-spaces (line) (replace-regexp-in-string "\\([\t]\\|\\([ ]+\\)\\)" (lambda (s) @@ -2626,13 +2602,13 @@ contextual information." (t "")))))) line)) -(defun org-e-odt-encode-plain-text (text &optional no-whitespace-filling) +(defun org-e-odt--encode-plain-text (text &optional no-whitespace-filling) (mapc (lambda (pair) (setq text (replace-regexp-in-string (car pair) (cdr pair) text t t))) '(("&" . "&") ("<" . "<") (">" . ">"))) (if no-whitespace-filling text - (org-e-odt-fill-tabs-and-spaces text))) + (org-e-odt--encode-tabs-and-spaces text))) (defun org-e-odt--quotation-marks (text info) "Export quotation marks depending on language conventions. @@ -2653,7 +2629,7 @@ is a plist used as a communication channel." TEXT is the string to transcode. INFO is a plist holding contextual information." ;; Protect &, < and >. - (setq text (org-e-odt-encode-plain-text text t)) + (setq text (org-e-odt--encode-plain-text text t)) ;; Handle quotation marks (setq text (org-e-odt--quotation-marks text info)) ;; Convert special strings. @@ -2871,7 +2847,7 @@ and prefix with \"OrgSrc\". For example, (font-lock-fontify-buffer) (buffer-string)))) (fontifier (if use-htmlfontify-p 'org-e-odt-htmlfontify-string - 'org-e-odt-encode-plain-text)) + 'org-e-odt--encode-plain-text)) (par-style (if use-htmlfontify-p "OrgSrcBlock" "OrgFixedWidthBlock")) (i 0)) @@ -2923,23 +2899,18 @@ and prefix with \"OrgSrc\". For example, CONTENTS holds the contents of the item. INFO is a plist holding contextual information." (let* ((lang (org-element-property :language src-block)) - (caption (org-element-property :caption src-block)) - (short-caption (and (cdr caption) - (org-export-data (cdr caption) info))) - (caption (and (car caption) (org-export-data (car caption) info))) - (label (org-element-property :name src-block)) - (attributes (org-export-read-attribute :attr_odt src-block))) - (let* ((captions (org-e-odt-format-label src-block info 'definition)) - (caption (car captions)) (short-caption (cdr captions))) - (concat - (and caption - (format "\n%s" - "Listing" caption)) - (let ((--src-block (org-e-odt-format-code src-block info))) - (if (not (plist-get attributes :textbox)) --src-block - (format "\n%s" - "Text_20_body" - (org-e-odt--textbox --src-block nil nil nil)))))))) + (attributes (org-export-read-attribute :attr_odt src-block)) + (captions (org-e-odt-format-label src-block info 'definition)) + (caption (car captions)) (short-caption (cdr captions))) + (concat + (and caption + (format "\n%s" + "Listing" caption)) + (let ((--src-block (org-e-odt-format-code src-block info))) + (if (not (plist-get attributes :textbox)) --src-block + (format "\n%s" + "Text_20_body" + (org-e-odt--textbox --src-block nil nil nil))))))) ;;;; Statistics Cookie @@ -3109,8 +3080,8 @@ channel." (if (memq (org-element-type (car table-cell-contents)) org-element-all-elements) contents - (format "\n%s" - paragraph-style contents)))) + (format "\n%s" + paragraph-style contents)))) (let (s) (dotimes (i horiz-span s) (setq s (concat s "\n")))) @@ -3430,7 +3401,7 @@ contextual information." "\\(\\)?[ \t]*\n" "" contents)) ;; Replace tabs and spaces. - (setq contents (org-e-odt-fill-tabs-and-spaces contents)) + (setq contents (org-e-odt--encode-tabs-and-spaces contents)) ;; Surround it in a verse environment. (format "\n%s" "OrgVerse" contents)) @@ -3439,6 +3410,107 @@ contextual information." ;;; Filters +;;;; LaTeX fragments + +(defun org-e-odt--translate-latex-fragments (tree backend info) + (let ((processing-type (plist-get info :LaTeX-fragments)) + (count 0)) + ;; Normalize processing-type to one of dvipng, mathml or verbatim. + ;; If the desired converter is not available, force verbatim + ;; processing. + (case processing-type + ((t mathml) + (if (and (fboundp 'org-format-latex-mathml-available-p) + (org-format-latex-mathml-available-p)) + (setq processing-type 'mathml) + (message "LaTeX to MathML converter not available.") + (setq processing-type 'verbatim))) + (dvipng + (unless (and (org-check-external-command "latex" "" t) + (org-check-external-command "dvipng" "" t)) + (message "LaTeX to PNG converter not available.") + (setq processing-type 'verbatim))) + (otherwise + (message "Unknown LaTeX option. Forcing verbatim.") + (setq processing-type 'verbatim))) + + ;; Store normalized value for later use. + (when (plist-get info :LaTeX-fragments) + (plist-put info :LaTeX-fragments processing-type)) + (message "Formatting LaTeX using %s" processing-type) + + ;; Convert `latex-fragment's and `latex-environment's. + (when (memq processing-type '(mathml dvipng)) + (org-element-map + tree '(latex-fragment latex-environment) + (lambda (latex-*) + (incf count) + (let* ((latex-frag (org-element-property :value latex-*)) + (input-file (plist-get info :input-file)) + (cache-dir (file-name-directory input-file)) + (cache-subdir (concat + (case processing-type + (dvipng "ltxpng/") + (mathml "ltxmathml/")) + (file-name-sans-extension + (file-name-nondirectory input-file)))) + (display-msg + (case processing-type + (dvipng (format "Creating LaTeX Image %d..." count)) + (mathml (format "Creating MathML snippet %d..." count)))) + ;; Get an Org-style link to PNG image or the MathML + ;; file. + (org-link + (let ((link (with-temp-buffer + (insert latex-frag) + (org-format-latex cache-subdir cache-dir + nil display-msg + nil nil processing-type) + (buffer-substring-no-properties + (point-min) (point-max))))) + (if (not (string-match "file:\\([^]]*\\)" link)) + (message "LaTeX Conversion failed.") + link)))) + (when org-link + ;; Conversion succeeded. Parse above Org-style link to a + ;; `link' object. + (let* ((link (car (org-element-map (with-temp-buffer + (org-mode) + (insert org-link) + (org-element-parse-buffer)) + 'link 'identity)))) + ;; Orphan the link. + (org-element-put-property link :parent nil) + (let* ( + (replacement + (case (org-element-type latex-*) + ;; Case 1: LaTeX environment. + ;; Mimic a "standalone image or formula" by + ;; enclosing the `link' in a `paragraph'. + ;; Copy over original attributes, captions to + ;; the enclosing paragraph. + (latex-environment + (org-element-adopt-elements + (list 'paragraph + (list :style "OrgFormula" + :name (org-element-property :name + latex-*) + :caption (org-element-property :caption + latex-*))) + link)) + ;; Case 2: LaTeX fragment. + ;; No special action. + (latex-fragment link)))) + ;; Note down the object that link replaces. + (org-element-put-property replacement :replaces + (list (org-element-type latex-*) + (list :value latex-frag))) + ;; Replace now. + (org-element-set-element latex-* replacement)))))) + info))) + tree) + + ;;;; Description lists ;; This translator is necessary to handle indented tables in a uniform @@ -3965,6 +4037,16 @@ using `org-open-file'." (cons (concat "\\." (car desc) "\\'") 'archive-mode))) org-e-odt-file-extensions) + +;;; FIXME + +;;;; Links whose description is image + +;; (org-lparse-link-description-is-image +;; (format "\n\n%s\n" +;; href desc)) + + (provide 'org-e-odt) ;;; org-e-odt.el ends here -- 2.11.4.GIT