重新思考了一下 orgmode 文学编程

出于对 org-mode 图片缩放的好奇心,我试图查看下其内部是咋实现的。以下是我的发现:

第一步,当然是让 Emacs 描述 org-toggle-inline-image 函数。我只对图片如何处理和显示感兴趣,很自然的,目光就集中到了 org-display-inline-images 函数上。

org-display-inline-images 显然是个很重要的函数:

	(let ((re (concat "\\[\\[\\(\\(file:\\)\\|\\([./~]\\)\\)\\([^]\n]+?"
			  (substring (org-image-file-name-regexp) 0 -2)
			  "\\)\\]" (if include-linked "" "\\]")))

以上这里很明显用了正则去匹配图片。

	      (setq attrwidth (if (or (listp org-image-actual-width)
				      (null org-image-actual-width))

到这也知道,控制图片大小的设置 org-image-actual-width 从哪来的了。

				      (when (re-search-backward
					     "#\\+attr.*:width[ \t]+\\([^ ]+\\)"

再看这句,之前还奇怪为啥要在图片上方加 #+attr_org: :width 100 属性设置,还在想有没有 :height 100 这样的属性。看到这里,大概明白了。没有其它了,控制图片就只有这么一个宽度属性设置。

接下来当然是生成图片,关键就这一句:

(setq img (save-match-data (create-image file type nil :width width)))

接下来的代码看起来像是用 overlay 绘制图片,不过这个我们暂时不关心。我们比较关心的是 imagemagick 是如何根据此处读到的 width 来创建「缩略图」的,到底保存在临时文件还是内存之中?能不能依样画葫芦创建个 :height:geometry 的属性?

第三步,去看下 create-image 函数。

我们发现 create-image 函数出奇的简单,几乎没有提供有用的信息。不过它在注释里这样提到:

Optional PROPS are additional image attributes to assign to the image,
like, e.g. `:mask MASK'.

也就是说,除了我们已知的 width ,它其实还可以使用 mask 等一堆参数。那么这些参数是从何处来的?还有哪些参数可以用?

在下面的注释里还有这么一句:

;; It is x_find_image_file in image.c that sets the search path.

难不成在 C 语言写的 image.c 文件之中?

事到如今,我们硬着头皮到 image.c 文件中找找看吧。

打开 Emacs 在 GitHub 的仓库,一搜之下竟然还真有 image.c 这个文件!打开看看,10024 lines……没事,估计多半是用了 imagemagick 的 C 绑定,关键词搜 imagemagick。跳转了几次,看到了这个:emacs/image.c at d73d1384aa6d647a930b4dfe3e91505da4ffee21 · emacs-mirror/emacs · GitHub

这熟悉的字眼,这契合度……感觉就是这里定义的啊。有熟悉的 :width:mask,还有其它 :crop:background:max-height:max-width 等等。显然,这里对 imagemagick 进行了简单的封装,只支持这些关键词处理。但是 :max-width 已经足够满足我们的需求了!

接下来,去 org-display-inline-images 函数里修改下,读取 :max-width 的值,在 create-image 函数调用中启用可选参数 :max-width 100,就能做到让图片最大显示宽度为 100 了!

到这里,按说我应该写 elisp 验证了,也许还能给 org-mode 提个 PR。不过我基本从没学过 elisp,恐怕写不出超过 3 行的代码 :sweat_smile:

@et2010 ,及论坛内其它感兴趣的童鞋继续吧 :rofl:

8 个赞