emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* Patch to align baseline of latex fragments and surrounding text
@ 2021-10-10 23:23 Matt Huszagh
  2021-10-10 23:29 ` Matt Huszagh
  0 siblings, 1 reply; 2+ messages in thread
From: Matt Huszagh @ 2021-10-10 23:23 UTC (permalink / raw)
  To: emacs-orgmode

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

Hello,

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
value.

Let me know what you think!

Best
Matt


[-- 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}
+  [PACKAGES]
+  [DEFAULT-PACKAGES]\")"
+  (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
+text."
+  :type '(symbol function integer)
+  :group 'org)
+
 ;;; Version
 (org-check-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.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Patch to align baseline of latex fragments and surrounding text
  2021-10-10 23:23 Patch to align baseline of latex fragments and surrounding text Matt Huszagh
@ 2021-10-10 23:29 ` Matt Huszagh
  0 siblings, 0 replies; 2+ messages in thread
From: Matt Huszagh @ 2021-10-10 23:29 UTC (permalink / raw)
  To: emacs-orgmode

Matt Huszagh <huszaghmatt@gmail.com> writes:

> 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
> value.

I should also mention that I've tested this for different image scaling
factors (`:image-size-adjust' in `org-preview-latex-process-alist') and
it works regardless of the scale factor. That is, the baseline will be
correctly aligned irrespective of the scale factor you set (though
obviously the text median
(https://en.wikipedia.org/wiki/Baseline_(typography))) will only match
the surrounding text for the correct scaling factor.

Matt


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-10-10 23:30 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-10 23:23 Patch to align baseline of latex fragments and surrounding text Matt Huszagh
2021-10-10 23:29 ` Matt Huszagh

Code repositories for project(s) associated with this inbox:

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

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 NNTP newsgroup(s).