emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Matt Huszagh <huszaghmatt@gmail.com>
To: "emacs-orgmode@gnu.org" <emacs-orgmode@gnu.org>
Subject: Patch to align baseline of latex fragments and surrounding text
Date: Sun, 10 Oct 2021 16:23:51 -0700	[thread overview]
Message-ID: <874k9oxy48.fsf@gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1567 bytes --]


I've created a patch to align the baseline of latex image fragments to
the surrounding text. The patch consists of several parts. First, it
adds a customizable variable that can be set to a user supplied function
to compute the value of :ascent passed to `overlay-put'. It can also be
set to a symbol (e.g., 'center, which is the current setting and still
the default), or an integer (:ascent can take an integer
percentage). The patch also modifies `org--make-preview-overlay' to use
this new variable.

The other part of the patch is a new function that computes the correct
value for :ascent from an SVG file.

Unfortunately, this isn't a general-purpose solution to baseline text
alignment. It currently only works with SVG images and requires that
these SVG images encode the text baseline in the viewBox attribute (I've
explained in the function documentation how to achieve this).

I was not initially planning to include the function because it only
works in certain special cases (though if you setup your SVG image
generation as I've described in the documentation it should work
correctly for all of your LaTeX fragments). However, I ultimately
decided it was beneficial to include it for several reasons: (1) it
would not be obvious for many users how to write this function on their
own, (2) by including it, others can improve upon it, and (3) I tried to
minimize corner cases by leaving the default value as 'center and having
the function return 'center whenever it detects an incorrect :ascent

Let me know what you think!


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-org-make-preview-overlay-Add-ability-to-set-vertical.patch --]
[-- Type: text/x-patch, Size: 4968 bytes --]

From 6c33fa1875cc169616d878b59054d50980f741f3 Mon Sep 17 00:00:00 2001
From: Matt Huszagh <huszaghmatt@gmail.com>
Date: Sun, 10 Oct 2021 15:46:05 -0700
Subject: [PATCH] org--make-preview-overlay: Add ability to set vertical
 alignment of latex fragments

* lisp/org.el (org--match-text-baseline-ascent): Add function that
computes the value of :ascent to match the baseline of the fragment to
the surrounding text.
(org-latex-fragment-overlay-ascent): Add custom variable that allows a
function to be used to compute the value of :ascent.
(org--make-preview-overlay): Incorporate the custom variable.
 lisp/org.el | 89 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 80 insertions(+), 9 deletions(-)

diff --git a/lisp/org.el b/lisp/org.el
index 405f0f0f9..dbc288a3c 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -320,6 +320,74 @@ identifier."
   :version "24.1"
   :group 'org-id)
+(defun org--match-text-baseline-ascent (imagefile imagetype)
+  "Set :ascent to match the text baseline of an image to the surrounding text.
+IMAGEFILE is the path of the image file and IMAGETYPE is the
+image file type.
+This function currently only works for SVG images (defaulting to
+'center otherwise).  It also requires that the SVG's viewbox is
+correctly set according to the text baseline position.
+Specifically, it computes
+ascent = 100 * -min-y / height
+where min-y and height are taken from the viewbox.  If this
+computation returns a non-sensical value (below 0 or above 100),
+it will return 'center instead.
+It's possible to include text baseline information in the viewbox
+by using \\documentclass[preview]{standalone} in the input LaTeX
+file, compiling first to DVI and then converting this to an SVG
+image with dvisvgm.
+For example,
+(setq my-dvisvgm
+      '(my-dvisvgm :programs (\"latex\" \"dvisvgm\")
+                   :description \"dvi > svg\"
+                   :message \"you need to install latex and dvisvgm.\"
+                   :use-xcolor t
+                   :image-input-type \"dvi\"
+                   :image-output-type \"svg\"
+                   :latex-compiler (\"latex -output-directory=%o %f\")
+                   :image-converter (\"dvisvgm --no-fonts --exact-bbox -c %S -o %O %f\")))
+(add-to-list 'org-preview-latex-process-alist my-dvisvgm)
+(setq org-preview-latex-default-process 'my-dvisvgm)
+(setq org-format-latex-header
+  \"\\documentclass[preview]{standalone}
+  (if (eq imagetype 'svg)
+      (let* ((viewbox (split-string
+                       (xml-get-attribute (car (xml-parse-file imagefile)) 'viewBox)))
+             (min-y (string-to-number (nth 1 viewbox)))
+             (height (string-to-number (nth 3 viewbox)))
+             (ascent (round (* -100 (/ min-y height)))))
+        (if (or (< ascent 0) (> ascent 100))
+            'center
+          ascent))
+    'center))
+(defcustom org-latex-fragment-overlay-ascent 'center
+  "Value of :ascent used for LaTeX image fragments.
+Org uses `overlay-put' to overlay LaTeX image fragments on inline
+math.  `overlay-put' takes an :ascent parameter that can specify
+the vertical offset of this image fragment.  See the 'Image
+Descriptors' section of the elisp manual for more information.
+If this variable is a symbol or integer it will be passed
+directly to :ascent.  It can also be a function that takes the
+image file as an argument.  The function will be evaluated and
+its return value passed to :ascent.  The primary benefit of this
+option is to be able to compute the baseline of the latex
+fragment and to align it with the baseline of the surrounding
+  :type '(symbol function integer)
+  :group 'org)
 ;;; Version
@@ -15928,15 +15996,18 @@ Argument IMAGETYPE is the extension of the displayed image,
 as a string.  It defaults to \"png\"."
   (let ((ov (make-overlay beg end))
 	(imagetype (or (intern imagetype) 'png)))
-    (overlay-put ov 'org-overlay-type 'org-latex-overlay)
-    (overlay-put ov 'evaporate t)
-    (overlay-put ov
-		 'modification-hooks
-		 (list (lambda (o _flag _beg _end &optional _l)
-			 (delete-overlay o))))
-    (overlay-put ov
-		 'display
-		 (list 'image :type imagetype :file image :ascent 'center))))
+    (let ((ascent (if (functionp org-latex-fragment-overlay-ascent)
+                      (funcall org-latex-fragment-overlay-ascent image imagetype)
+                    org-latex-fragment-overlay-ascent)))
+      (overlay-put ov 'org-overlay-type 'org-latex-overlay)
+      (overlay-put ov 'evaporate t)
+      (overlay-put ov
+		   'modification-hooks
+		   (list (lambda (o _flag _beg _end &optional _l)
+			   (delete-overlay o))))
+      (overlay-put ov
+		   'display
+		   (list 'image :type imagetype :file image :ascent ascent)))))
 (defun org-clear-latex-preview (&optional beg end)
   "Remove all overlays with LaTeX fragment images in current buffer.

             reply	other threads:[~2021-10-10 23:24 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-10 23:23 Matt Huszagh [this message]
2021-10-10 23:29 ` Matt Huszagh
2021-12-03  2:32   ` Matt Huszagh
2021-12-09 20:59     ` Sébastien Miquel
2021-12-09 22:18       ` Matt Huszagh
2021-12-10 15:49         ` Sébastien Miquel
2021-12-11  4:53           ` [Patch] Align " Matt Huszagh
2022-07-30  9:55             ` Ihor Radchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874k9oxy48.fsf@gmail.com \
    --to=huszaghmatt@gmail.com \
    --cc=emacs-orgmode@gnu.org \


* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).