org-latex-preview如何显示透明png

如果设置了小于100的alpha-background值,发现latex fragment是png的时候,图片透明区域并没有显示透明背景,而是显示了背景色。

类似的问题之前在emacs-dashboard的看到过,给的解决方案是加入

    (dashboard-image-extra-props '(:mask heuristic))

关于:mask heuristic的文档信息:

‘:mask MASK’ If MASK is ‘heuristic’ or ‘(heuristic BG)’, build a clipping mask for the image, so that the background of a frame is visible behind the image. If BG is not specified, or if BG is ‘t’, determine the background color of the image by looking at the four corners of the image, assuming the most frequently occurring color from the corners is the background color of the image. Otherwise, BG must be a list ‘(RED GREEN BLUE)’ specifying the color to assume for the background of the image.

If MASK is ‘nil’, remove a mask from the image, if it has one. Images in some formats include a mask which can be removed by specifying ‘:mask nil’.

例子如下:

看起来org-latex-preview没有做这个处理,还是说,有什么我不知道的办法可以做到这个呢?

1 个赞

我检查了org.el 9.7.11的代码,在第16729行的函数org--create-inline-image

的确没有这个处理,也没有提供任何可以插入这个处理的方法。

……我去提个补丁好了。

3 个赞

不太走运,我在最新的代码里发现这部分代码打算被重构了。

org-display-inline-images已经在9.8后被标记为obsoleted,想用org-link-preview替代它的功能,这意味着要从org-latex-preview向下传递property需要侵入这一堆正在重构的功能。

所以目前我能想到的解决方案只能是强行改变 org--create-inline-image 的行为,或者添加一个外部的绑定作为开关。因为org-link-preview有自己的处理队列,所以外部绑定可能还会引入同步的风险。

所以比较直接的方案是,重载org--create-inline-image

   (setq my-additional-props '(:mask heuristic))

   ;; function to override `org--create-inline-image' 
   (defun my-create-inline-image (file width)
   ;; ####################################################
   ;; copy what happen in `org--create-inline-image' here
   ;; ####################################################
   (when file-or-data
      (apply #'create-image
             file-or-data
             (and (image-type-available-p 'imagemagick)
                  width
                  'imagemagick)
             remote?
             :width width
             :max-width
             (pcase org-image-max-width
               (`fill-column (* fill-column (frame-char-width (selected-frame))))
               (`window (window-width nil t))
               ((pred integerp) org-image-max-width)
               ((pred floatp) (floor (* org-image-max-width (window-width nil t))))
               (`nil nil)
               (_ (error "Unsupported value of `org-image-max-width': %S"
                         org-image-max-width)))
             :scale 1
             my-additional-props))))
   ;; ...

   ;; then override it
   (advice-add 'org--create-inline-image :override #‘my-create-inline-image)

但是这个方案的坏处是这样之后org里面所有的png图片都会创建mask显示背景透明了,这在另一些场景下可能不是好事。

我比较社恐,没有给org的邮件列表发邮件,如果有maintainer看到,希望可以考虑下这方面的需求。

帮你 @yantar92

1 个赞

有时候我也遇到需要改源码的情况,推荐一个包 psearch 还挺好用的:

(setq my-additional-props nil)
(psearch-patch org--create-inline-image
  (psearch-replace '`(create-image . ,args)
                   '`(create-image ,@args my-additional-props)))

为了不影响其他场景,可以只 advice 一下必要的函数:

(define-advice org-latex-preview
    (:around (orig &rest arg) heuristic)
  (let ((my-additional-props '(:mask heuristic)))
    (apply orig arg)))
1 个赞

看上去有点激进,这种自动化侵入函数结构的方式会引入更大的不确定性。等价的少写代码的方式是自己去解析函数休。

丑陋的不是侵入方式,而是侵入行为本身。

1 个赞

前辈说的有道理,我用这个包主要是为了让自己看清楚我改动了哪里,日后包更新了,删除和维护自己的配置代码也比较方便。

我以前遇到不好 hack 的代码,也都是重载,但是很多时候需要像上面一样复制一大段函数,我用这个包就是为了少写代码 :rofl:

确实挺丑的,但是完美的东西很少,如果又要符合自己的个性化习惯,就更少了。而反馈上游、提PR、讨论跟进,都是需要消耗资源(时间、精力)的。

如果能满足自己当下的需求,我很多时候愿意忍受手段的不完美 :rofl:

况且,即使是 emacs 本身提供的 advice 机制,如果是 :around,也就完全绕过了原函数,也是一种侵入。其实 emacs 这么可定制化,不就是欢迎我们侵入:rofl:

这个手段前辈能介绍下吗?我学习一下。

1 个赞

psearch.el就是提供了这样的一个框架。如果函数是lambda,其实不需要像psearch这样解析代码,但如果它是bytecode或者closure就只能解析原来的代码了。

(defun symbol-definition (f &optional type)
  (let ((def (find-definition-noselect f type
                     (find-lisp-object-file-name f type))))
          (with-current-buffer (car def)
             (goto-char (cdr def))
             (eval-expression (sexp-at-point))))
  (symbol-function f))

sexp-at-point那一步已经拿到函数体代码了,我觉得不妨先做一步求值,因为不想管字符编码之类的问题。当然后面拿到的不一定是lambda,也可能是closure。

因为解析代码不可避所以从效率上说其实还不如抄出来。我的配置koishimacs是单个org文件的文学启动,故个人倾向于代码抄出来一把梭哈,其次能不侵入就不侵入。

1 个赞

有时候这是不可避免的,写代码如果要完美主义,那估计会疯掉

1 个赞

GNU ELPA - advice-patch 也是做类似工作的,不过功能更简单

1 个赞

所以我最后给的方案是付出最小的思考代价侵入 :wink:

愚昧而美好是纯洁 :innocent:,聪明而丑陋就是邪恶 :smiling_imp:了。

等待美好就得忍受愚昧,keep it in the simple and stupid way

今天测了一下发现改错了函数,org-link-previeworg-latex-preview走的路线不一样,latex预览png透明的方案如下:

    (defun my:org--make-preview-overlay (beg end image &optional imagetype)
      "Build an overlay between BEG and END using IMAGE file.
  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 :mask 'heuristic))))
    
    (advice-add 'org--make-preview-overlay :override #'my:org--make-preview-overlay)

这个要提交到org的话就简单多了 :blush:

1 个赞

Mailing list discussion: [Patch] Support png overlay background transparency in a transparent frame

3 个赞