最近在尝试给 Org-mode 加一个用 Typst 做公式预览的功能,但是过程中遇到了一个问题,即生成的 SVG 显示出来的样子特别小:

(上下为作为对比的普通文本大小)
在 emacs -Q
下也是如此。目前不太清楚这个问题要怎么排查解决,所以来请教坛友。
P.S. 关于这个使用 Typst 做公式预览的功能,思路上就是以 .typ 文件作为中间文件,用 Typst 生成 SVG。流程是先把 :latex-compiler
设为一个从 tex 生成 typ 文件的脚本,把 org-latex-preview 生成的 tex 文件预处理一下、去掉 hardcode 的 LaTeX headers,再加上 Typst 的 headers;然后用 Typst 从这个 .typ 文件生成 SVG。当然这么做有很多缺点,不过作为一个原型来说暂且可行。
实现如下:
(add-to-list 'org-preview-latex-process-alist
'(typst :programs ("typst")
:description "Use Typst to generate svg"
:message "you need to install the programs: python and typst."
:image-input-type "typ"
:image-output-type "svg"
:image-size-adjust (1.0 . 1.0)
:post-clean
(".typ")
:latex-compiler
("python ~/src/latex2typst.py %f %O")
:latex-header ""
:image-converter
("typst compile %f %O")
))
其中的 latex2typst.py 的内容如下:
import sys
import re
def extract_rgb_values(text):
pattern = r'\\definecolor\{(fg|bg)\}\{rgb\}\{(.+?)\}'
matches = re.findall(pattern, text)
color_dict = {}
for match in matches:
color_name = match[0]
color_values = match[1].split(',')
color_values = [float(value) * 100 for value in color_values]
color_dict[color_name] = color_values
return (color_dict['fg'], color_dict['bg'])
if len(sys.argv) > 2:
input_filename = sys.argv[1]
output_filename = sys.argv[2]
else:
print("Please specify input and ouput filenames")
sys.exit(1)
with open(input_filename) as f:
contents = f.read()
fg, bg = extract_rgb_values(contents)
index = contents.find('\\color{fg}')
formula = contents[index+len('\\color{fg}')+1:-19]
if formula.startswith('$$'):
formula = formula[1:-1]
def typst_header(fg, bg):
fg_str = ','.join([str(value) + "%" for value in fg])
bg_str = ','.join([str(value) + "%" for value in bg])
return f"""#set text(fill: rgb({fg_str}))
#set page(width: auto, height: auto, margin: 4pt, fill: rgb({bg_str}))
"""
if index != -1:
with open(output_filename, 'w') as f:
f.write(typst_header(fg, bg))
f.write(formula)
5 个赞
Roife
2
调整 image-size-adjust
会有效果吗,或者考虑直接生成 png?
0WD0
4
我用了另外一种解决方案,我希望混用 latex 和 typst 公式,就给 org-create-forula-image 加了一个 advice
默认情况下尝试用 typst 编译,如果有报错再退回到 latex
我这里设置的是 $ 包围的尝试用 typst 的数学模式编译;
$$ 包围的用 typst 的 markup 模式编译
\( \[ \begin 这种包围的直接认为是 latex
(defvar org-typst-scale-ratio 180)
(defvar org-typst-debug nil
"Enable debug messages for org Typst advice.")
(defun org-typst--debug (fmt &rest args)
(when org-typst-debug
(apply #'message (concat "[org-typst] " fmt) args)))
(defun org-create-formula-image--typst-advice (orig-fun string tofile options buffer &optional processing-type)
"Advice for `org-create-formula-image' to add Typst support.
When PROCESSING-TYPE is 'latex and STRING is $ delimited, first try
compiling with Typst. If successful, return the SVG output directly.
Otherwise, fall back to the original LaTeX processing.
ORIG-FUN is the original function.
STRING, TOFILE, OPTIONS, BUFFER, and PROCESSING-TYPE are the original arguments."
(org-typst--debug "Enter advice: processing-type=%S tofile=%S" processing-type tofile)
(if (and (eq processing-type org-preview-latex-default-process)
(numberp (string-match-p "\\`\\s-*\\$" string))
(numberp (string-match-p "\\$\\s-*\\'" string)))
(let* ((tmpdir temporary-file-directory)
(typst-filebase (make-temp-name (expand-file-name "orgtypst" tmpdir)))
(typst-file (concat typst-filebase ".typ"))
(svg-file (concat typst-filebase ".svg"))
(typst-content (replace-regexp-in-string "\\`\\s-*\\$\\s-*\\|\\s-*\\$\\s-*\\'" "" string))
(normal-type (and (numberp (string-match-p "\\`\\s-*\\$" typst-content)) (numberp (string-match-p "\\$\\s-*\\'" typst-content))))
(scale (plist-get options :scale))
(fg-raw (plist-get options (if buffer :foreground :html-foreground)))
(bg-raw (plist-get options (if buffer :background :html-background)))
(fg (cond
((null fg-raw) nil)
((eq fg-raw 'default) nil)
((stringp fg-raw) fg-raw)
(t nil)))
(bg (cond
((null bg-raw) nil)
((eq bg-raw 'default) nil)
((string= bg-raw "Transparent") "Transparent")
((stringp bg-raw) bg-raw)
(t "Transparent"))))
(org-typst--debug "Typst candidate: tmpdir=%S typst=%S svg=%S" tmpdir typst-file svg-file)
(org-typst--debug "Scale=%S fg=%S bg=%S" scale fg bg)
(condition-case err
(progn
(org-typst--debug "Writing Typst file...")
(with-temp-file typst-file
(let ((page-fill (cond
((or (null bg) (string= bg "Transparent")) "#none")
(t (format "rgb(\"%s\")" bg)))))
(insert (format "#set page(width: auto, height: auto, margin: 0pt, fill: %s)\n" page-fill)))
(when fg
(insert (format "#set text(fill: rgb(\"%s\"))\n" fg)))
(let ((real-content (if normal-type
(replace-regexp-in-string "\\`\\s-*\\$\\s-*\\|\\s-*\\$\\s-*\\'" "" typst-content)
(format "$ %s $" typst-content))))
(insert (format "#scale(x:%f*%d%%,y:%f*%d%%,reflow:true)[\n %s \n]" scale org-typst-scale-ratio scale org-typst-scale-ratio real-content))))
(org-typst--debug "Typst file written: %s (len=%d)" typst-file (nth 7 (file-attributes typst-file)))
(with-current-buffer (get-buffer-create "*typst-formula*")
(let ((inhibit-read-only t))
(erase-buffer)
(insert-file-contents typst-file)))
(org-typst--debug "Running typst compile...")
(let* ((compile-buf (get-buffer-create "*typst-compile*"))
(exit-code (call-process "typst" nil compile-buf nil
"compile" typst-file svg-file)))
(org-typst--debug "Typst exit-code=%s svg-exists=%s" exit-code (file-exists-p svg-file))
(when org-typst-debug
(org-typst--debug "Typst output:\n%s"
(with-current-buffer compile-buf
(buffer-substring-no-properties (point-min) (point-max)))))
(if (and (eq exit-code 0) (file-exists-p svg-file))
(progn
(org-typst--debug "Typst success; copying %s -> %s" svg-file tofile)
(copy-file svg-file tofile 'replace)
(when (file-exists-p typst-file) (delete-file typst-file))
(when (file-exists-p svg-file) (delete-file svg-file))
(org-typst--debug "Typst cleanup done; returning %s" tofile)
tofile)
(org-typst--debug "Typst failed; cleaning up and falling back to LaTeX")
(when (file-exists-p typst-file) (delete-file typst-file))
(when (file-exists-p svg-file) (delete-file svg-file))
(funcall orig-fun string tofile options buffer processing-type))))
(error
(org-typst--debug "Error: %s" (error-message-string err))
(when (file-exists-p typst-file) (delete-file typst-file))
(when (file-exists-p svg-file) (delete-file svg-file))
(org-typst--debug "Fallback to LaTeX due to error")
(funcall orig-fun string tofile options buffer processing-type))))
(org-typst--debug "Not a Typst candidate; using original function")
(funcall orig-fun string tofile options buffer processing-type)))
(after! org
(advice-add 'org-create-formula-image :around #'org-create-formula-image--typst-advice))