分享一篇文章:org-mode 下 latex 预览随文本一起缩放

文章链接:Scaling Latex previews in Emacs | Karthinks

org-mode 下的 latex 预览,默认不会随文本一起缩放。

此文介绍了一种方法,使之成为可能。

实测确实有用。附上 recipe 以作备份。

(defun my/text-scale-adjust-latex-previews ()
  "Adjust the size of latex preview fragments when changing the
buffer's text scale."
  (pcase major-mode
    ('latex-mode
     (dolist (ov (overlays-in (point-min) (point-max)))
       (if (eq (overlay-get ov 'category)
               'preview-overlay)
           (my/text-scale--resize-fragment ov))))
    ('org-mode
     (dolist (ov (overlays-in (point-min) (point-max)))
       (if (eq (overlay-get ov 'org-overlay-type)
               'org-latex-overlay)
           (my/text-scale--resize-fragment ov))))))

(defun my/text-scale--resize-fragment (ov)
  (overlay-put
   ov 'display
   (cons 'image
         (plist-put
          (cdr (overlay-get ov 'display))
          :scale (+ 1.0 (* 0.25 text-scale-mode-amount))))))

(add-hook 'text-scale-mode-hook #'my/text-scale-adjust-latex-previews)
2 个赞

emacs 里面的图片显示一般有 overlay 和 text-property 两种方式,其中 org-mode 的 LaTeX 和图片预览采用的是 overlay 的形式,而 text-scale-mode 只修改纯文本的显示,所以默认不修改图片的缩放。

这个问题其实可以更通用地解决,下面是我的方案:

;;; adjust image size while adjusting the font size
(defvar eli/image-scale-mode-step 1.2
  "Image scale factor.")

(defun eli/set-image-original-scale-factor (beg end img)
  "Set original scale factors."
  (let* ((ovs (overlays-in beg end))
         (original-scale))
    (dolist (ov ovs)
      (when-let ((scale (overlay-get ov 'original-scale)))
        (setq original-scale scale)))
    (unless original-scale
      (let ((ov (make-overlay beg end)))
        (setq original-scale (or (image-property img :scale) 1.0))
        (overlay-put ov 'original-scale original-scale)))
    original-scale))

(defun eli/delete-image-scale-factor-overlay ()
  "Delete all scale factors overlays."
  (let ((ovs (overlays-in (point-min) (point-max))))
    (mapc (lambda (ov)
            (when (overlay-get ov 'original-scale)
              (delete-overlay ov)))
          ovs)))

(defun eli/overlay-image-scale ()
  "Displaying buffer images(overlay property) in a larger/smaller size."
  (let* ((latex-ovs (cl-remove-if-not
                     (lambda (o) (or (eq (overlay-get o 'org-overlay-type) 'org-latex-overlay)
                                     (eq (overlay-get o 'category) 'preview-overlay)))
                     (overlays-in (point-min) (point-max))))
         (ovs (append org-inline-image-overlays latex-ovs)))
    (dolist (ov ovs)
      (let* ((img (overlay-get ov 'display))
             (width (image-property img :width))
             (original-width (or (image-property img :original-width)
                                 (image--set-property img
                                                      :original-width width)))
             (beg (overlay-start ov))
             (original-scale
              (eli/set-image-original-scale-factor beg (1+ beg) img)))
        (when (and (not width)
                   original-width)
          (image--set-property img :width original-width))
        (image--set-property img
                             :scale
                             (* original-scale
                                (expt eli/image-scale-mode-step
                                      text-scale-mode-amount)))))))

(defun eli/property-image-scale ()
  "Displaying buffer images(text property) in a larger/smaller size."
  (save-excursion
    (goto-char (point-min))
    (while (not (eobp))
      (when-let* ((img (get-text-property (point) 'display))
                  (original-scale
                   (eli/set-image-original-scale-factor (point)
                                                        (1+ (point))
                                                        img)))
        (when (and img (eq (car-safe img) 'image))
          (image--set-property img
                               :scale
                               (* original-scale
                                  (expt
                                   eli/image-scale-mode-step
                                   text-scale-mode-amount)))))
      (goto-char (next-single-property-change (point)
                                              'display nil (point-max))))))

(defun eli/image-scale (arg)
  "Displaying buffer images in a larger/smaller size."
  (eli/overlay-image-scale)
  (eli/property-image-scale)
  (when (< arg 0)
    (eli/delete-image-scale-factor-overlay)))

(advice-add 'text-scale-mode :after #'eli/image-scale)
6 个赞

谢谢你,我刚刚正在搜怎么与文本一起缩放图片,此方案刚好解决了我两个问题。