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

大概是这样了。灵活度还是很高的。

3 个赞

那导出怎么办?

什么导出怎么办?图片已经处理完了,导出后援引的自然是处理后的图片。

是这样的,一般希望在导出的文件中包含的是 300dpi 以上的高清晰图片。而且图像尺寸什么的在保存的时候就可以指定,完全没有必要再用 shell。

所以我想要的是——显示和最终使用的其实是两个不同的图像

问题是 Emacs 没有 Word 或者浏览器那样的排版渲染引擎啊,想要显示和导出都用同一个图像不太可能。


图片必须在 Emacs 中行内显示,然后才能在导出时包含进去嘛?或者说,有没有方法指定行内图片有的可以显示,有的不要显示?

只有满足后一个条件,才能做到你说的「既能在 Emacs 中显示分辨率小的图片,又能在导出时使用 300dpi 以上的高清图片」。


(org-display-inline-images &optional INCLUDE-LINKED REFRESH BEG END)

Display inline images.
Normally only links without a description part are inlined, because this
is how it will work for export.  When INCLUDE-LINKED is set, also links
with a description part will be inlined. 

必须得行内显示,导出时图片才能包含进去。

而且我搜了一下,并没有现有方法让单个行内图片 toggle 显示状态,只有个总开关 org-toggle-inline-images

所以,要满足你的需求,就得阅读下 org-mode 的源码,增加个特性:支持单个图片的显示状态切换。

1 个赞

确实,总之是不容易

谢谢你的建议,等有时间了看看能不能搞一个穷人版的实现

1 个赞

我刚尝试了下,org-mode 导出时使用的还是原图。所以,我楼上那个回答操作起来很麻烦 :persevere: 不要用了。

目前看来最简单的解决方案:就是修改 org-mode 增加个 #+attr_org: :geometry 100x200> 这样的属性。

以后有空,再考虑增加「控制单个行内图片显示的 独立开关 」的功能。

出于对 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 个赞

接上文:

考虑到 image.c 只支持了少数参数,那 imagemagick 这个 Photoshop 级的库放在那用不了绝大多数功能,岂不是很忧伤?

我搜索了一下,elisp 是能支持 shell 命令行执行的,也就说不一定非得用 C 绑定,直接调命令行就好。

比如:emacs - Inline PDF images in org-mode - Stack Overflow

看起来是重写了 org-display-inline-images 整个函数,然后调用 imagemagick 命令行。

(shell-command (format org-imagemagick-display-command
                           file org-image-actual-width org-image-actual-width file-thumb) nil nil)))

其中 org-imagemagick-display-command 是可以自定义的,这样就能使用 imagemagick 命令行的所有功能了。还不用跟上游的 C 代码打交道了,话说我又不会 C……

这个法子更好。缺点是要在目录下生成临时文件,不过并不影响我们的原图导出。很好很合适了。

2 个赞

这个方案真聪明.

请问您的kunth的文学编程文档在哪下载的呢

https://www.ctan.org/tex-archive/web/c_cpp/cweb

下載 cweb 的 tarball,unpack 后 make 就有了,要装 tex,cweb,等,建議从 texlive 下。