Reading view

There are new articles available, click to refresh the page.

中文 LaTeX 圈有没有类似的 Template 和 Gallery 集合

pythonee:

固然大学论文、试题集之类的排版是 TeX 的主要场景,但之前在网上偶遇过一些特色的模板,比如古籍、乐普、字体设计、技术书籍之类的,还有一些可爱的论文配图,但年代久远,收藏夹丢失了

很多新手都是从案例开始对 TeX 感兴趣的,我就是其中之一

再进阶的时候,就是碰到了字体、宏包开发这些高级话题

Last Week on My Mac: Ghosts in the machine

I can confirm that there are ghosts in Macs. I know because I have seen them, spectres of rock bands from well over 50 years ago, speaking to us from the past, a dozen years before the first Mac, and four years before Apple was even founded. The band in question is named Creedence Clearwater Revival, who split up in 1972. Their appearance on Macs has been sporadic, in the form of a mystery volume that seems to mount from nowhere, whose name starts with the distinctive neologism coined by CCR’s rhythm guitarist Tom Fogerty after his friend Credence Newball.

Last week it turned out that mystery volume is a cryptex, one of the 23 used to provide support for Apple Intelligence in macOS, iOS and iPadOS.

Cryptexes are both straightforward and rather strange. They’re basically just a cryptographically secured disk image, but when they’re loaded by APFS, rather than being mounted as a volume, they get grafted into the file system almost as if they had been firmlinked into it. Although they didn’t exactly impress when used for Rapid Security Responses (RSRs) in macOS Ventura, since then they’ve been put to better use adding flexibility to the Signed System Volume (SSV), an immutable snapshot of the System volume that’s sealed with cryptographic hashes.

While the SSV is a powerful way to secure the boot process, it’s also a little too rigid for some purposes. Not only do cryptexes provide a convenient way to deliver Safari and its supporting components, which previously had to be installed on the Data volume, but they are a flexible solution for large dyld caches, accommodating to the differing needs of Intel and Apple silicon Macs. Intel Macs only use those built for their own architecture, but Apple silicon Macs require support for both, with the Intel version available for use by Rosetta 2 when running translated x86 code.

What I hadn’t realised, and hadn’t seen reported elsewhere, was how the extras needed for Apple Intelligence, another single-platform feature, are also provided in cryptexes. Unlike those for the system, these aren’t grafted early during the boot process, so can be downloaded and installed when a user enables AI, and thereafter grafted after that user has logged in. Their contents then appear among the thousands of install-on-demand linguistics and other components in /System/Library/AssetsV2, as I described earlier this week.

Presumably they merit this special protection because of their access to Private Cloud Compute (PCC), consistent with Apple’s stringent policies and engineering to ensure the robustness of PCC. Indeed, as Apple describes, the PCC is apparently an enthusiastic user of cryptexes: “Additional software outside the base operating system can be delivered to the system only in the form of cryptexes, which contain their own Image4 manifest and trust cache.” Apple goes on to provide a detailed account of how cryptexes are handled by PCC. This illustrates how sophisticated their management can be, and explains why, despite their shaky introduction as RSRs, cryptexes are proliferating.

This could change when macOS 27 goes single-architecture next year, and there’s no need to cater for both chalk and cheese. But I suspect the advantages of augmenting the SSV with the flexibility of cryptexes will remain sufficiently attractive to ensure they are retained in macOS, as they already are in iOS and iPadOS.

Cryptexes are also remarkably unobtrusive, as has been apparent with the 23 currently used to support AI. That is until something unearthly happens deep inside the grafting mechanism in macOS and accidentally mounts a cryptex as a disk image, making it appear like a spectre in the Finder. In my case it must have occurred when I copied a cryptex from its hiding place among those files in /System/Library/AssetsV2 and mounted it to see what it contained. Exorcising this ghost required compressing the cryptex, trashing the copy I had made, and repeatedly trying to unmount it until it finally stopped appearing following startup.

But I still know how to summon the spirit of Creedence Clearwater Revival whenever I need to remind myself of the early 1970s. Now if someone would be kind enough to tell me which cryptex brings the spirit of Pink Floyd, I’ll leave you in peace.

Cryptexes, AI and Creedence Clearwater Revival

Somewhen around late versions of macOS Monterey, and certainly by the release of Ventura, macOS started to use cryptexes to load Safari and parts of the operating system including dyld caches, rather than installing them to the Data volume. Over a period of three months, cryptexes were also used to install Rapid Security Responses (RSRs) in an experiment that was quickly discontinued. What I hadn’t realised until recently was that they are also used to deliver much of the additional components required to support Apple Intelligence features in Apple silicon Macs. This article looks as how that works.

Cryptexes

These first appeared on Apple’s customised iPhone, its Security Research Device, which uses them to load a personalised trust cache and a disk image containing corresponding content. Without the cryptex, engineering those iPhones would have been extremely difficult. According to its entry in the File Formats Manual from five years ago (man cryptex), ‘A cryptex is a cryptographically-sealed archive which encapsulates a well-defined filesystem hierarchy. The host operating system recognizes the hierarchy of the cryptex and extends itself with the content of that hierarchy. The name cryptex is a portmanteau for “CRYPTographically-sealed EXtension”.’

In practice, a cryptex is a sealed disk image containing its own file system, mounted at a randomly chosen location within the root file system during the boot process. Prior to mounting the cryptex, macOS verifies it matches its seal, thus hasn’t been tampered with. Managing these cryptexes is the task of the cryptexd service with cryptexctl. Because cryptexes aren’t mounted in the usual way, they’re not visible in mount lists such as that produced by mount(8).

System cryptexes

Once kernel boot is well under way, APFS mounts containers and volumes in the current boot volume group, followed by others to be mounted at startup. When those are complete, it turns to mounting and grafting the three standard system cryptexes:

  • os.dmg, around 6 GB (macOS 15.5), containing system components such as dyld caches;
  • app.dmg, around 23 MB, containing Safari and supporting components;
  • os.clone.dmg, apparently a copy of os.dmg and the same size.

AI cryptex collection

About 5 seconds later, and over 14 seconds after APFS first started work, it checks and grafts a series of 23 cryptexes primarily involved with Apple Intelligence features. These are handled one at a time in succession, each reported in a sequence of log entries as follows (times in seconds after an arbitrary start).

First the Image4 file containing the cryptex is validated
9.434431 root_hash_execution_cb_mobile_asset:3066: image4_trust_evaluate: successfully validated the payload and the manifest

Then it’s grafted into the file system of the Data volume as a ‘PFK volume’. In this extract I omit the bulk of the cryptex’s name using […] for the sake of brevity.
9.434465 apfs_graft:695: disk3s5 Grafting on a PFK volume
9.434509 graft_dev_init:480: disk3 UC_[…]_Cryptex.dmg GRAFT (compiled @ Apr 22 2025 19:49:43)
9.434514 graft_dev_init:484: disk3 UC_[…]_Cryptex.dmg device_handle block size 4096 real block size 4096 block count 11264 features 0 internal VEK
9.434695 nx_mount:1308: UC_[…]_Cryptex.dmg initializing cache w/hash_size 512 and cache size 512
9.437484 nx_mount:1630: UC_[…]_Cryptex.dmg checkpoint search: largest xid 15, best xid 15 @ 7
9.437497 nx_mount:1657: UC_[…]_Cryptex.dmg stable checkpoint indices: desc 6 data 31
9.438117 er_state_obj_get_for_recovery:8420: UC_FM_LANGUAGE_INSTRUCT_3B_CONC No ER state object for volume RevivalB13M201388.UC_[…]_Cryptex - rolling is not happening, nothing to recover.
9.438124 apfs_log_op_with_proc:3263: UC_FM_LANGUAGE_INSTRUCT_3B_CONC grafting volume RevivalB13M201388.UC_[…]_Cryptex, requested by: mobileassetd (pid 457); parent: launchd (pid 1)

Note the volume name starts with Revival. Names of all other cryptex volumes in the AI collection start with the same code name, except for the PKI cryptex examined below, which uses Creedence instead. Perhaps these are a reference to Creedence Clearwater Revival?

The root hash of the cryptex file system is then authenticated
9.438156 graft_dev_blockmap_lut_switch_to_metadata_based_if_needed:1312: UC_FM_LANGUAGE_INSTRUCT_3B_CONC lut contains 26 extents, 3 of which contain metadata
9.438160 is_root_hash_authentication_required_osx:387: UC_FM_LANGUAGE_INSTRUCT_3B_CONC Release kext with internal build: 0, ARV disabled: 0, booting xid: 0
9.438164 is_root_hash_authentication_required_osx:418: UC_FM_LANGUAGE_INSTRUCT_3B_CONC strict graft, root hash authentication failure is required
9.438167 is_root_hash_authentication_required:557: UC_FM_LANGUAGE_INSTRUCT_3B_CONC Strict Graft, root hash authentication is required
9.438179 authenticate_root_hash:642: UC_FM_LANGUAGE_INSTRUCT_3B_CONC successfully validated on-disk root hash
9.438191 apfs_lookup_ge_jobj_id:5028: disk3s5 Found OBJID 0x66a1b8 type 3

The graft is then completed.
9.438195 apfs_graft:1045: disk3s5 Graft ino 6557986, jobj_id range 6725836+76
9.438396 apfs_graft:1138: disk3s5 successfully grafted ino 6557986 on dir 6725835, dev_name [UC_[…]_Cryptex.dmg]

Fortunately, these log entries provide the inode number for the location of the grafted cryptex, and that can be used in Mints to obtain its full path.

Among the AI cryptex collection is a secure public key infrastructure (PKI) trust store, located at
/System/Library/AssetsV2/com_apple_MobileAsset_PKITrustStore/purpose_auto/[…].asset/AssetData/Restore/SECUREPKITRUSTSTOREASSETS_SECUREPKITRUSTSTORE_Cryptex.dmg
In the log, this is recorded as being 4.2 MB in size, and that is the same size as reported for the .dmg file by the Finder. Disk images are in APFS (Case-sensitive) format, and might be identical to their equivalents provided for iOS and iPadOS.

When mounted, that disk image becomes a volume named Creedence11M6270.SECUREPKITRUSTSTOREASSETS_SECUREPKITRUSTSTORE_Cryptex. That contains many property lists, certificate data, a SystemRootCertificates keychain, and two property lists that are grafted into /System/Library/CoreServices.

The names of all 23 cryptex disk images included in the macOS 15.5 AI cryptex collection are given in the Appendix. All are given as being compiled at Apr 22 2025 19:49:43, the same as the system cryptexes, implying that they were installed as part of the macOS 15.5 update. The whole sequence of processing the AI cryptexes took 0.78 seconds to complete, and the total size of disk images mounted in that period was 7.2 GB, which is similar to the reported size of additional files required to support AI.

Conclusions

  • Apple silicon Macs running macOS 15.5 with AI enabled load 23 additional cryptexes to support AI, totalling 7.2 GB.
  • Those AI cryptexes are grafted into the Data volume, in paths starting /System/Library/AssetsV2.
  • All except one have volume names starting with Revival
  • One cryptex is a secure PKI trust store, whose volume name starts with Creedence instead.
  • These cryptexes are installed and updated as part of macOS updates, although they could also be installed or updated separately, for example when AI is enabled.
  • If a Mac shows an unusual mounted volume with a name starting with Creedence or Revival, that’s almost certainly the respective disk image, which should normally be hidden and not visible in the Finder.

Appendix

Disk image names for the AI cryptex collection in macOS 15.5 (Apple silicon):

  • UC_FM_LANGUAGE_INSTRUCT_3B_CONCISE_TONE_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROOFREADING_REVIEW_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_VISUAL_IMAGE_DIFFUSION_V1_BASE_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_BASE_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_IF_PLANNER_NLROUTER_BASE_EN_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAIL_REPLY_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_DRAFTS_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_SUMMARIZATION_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_AUTONAMING_MESSAGES_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_URGENCY_CLASSIFICATION_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_MESSAGES_REPLY_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROFESSIONAL_TONE_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_SAFETY_GUARDRAIL_BASE_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_CODE_GENERATE_SMALL_V1_BASE_GENERIC_H16_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAGIC_REWRITE_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_300M_BASE_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_CODE_GENERATE_SAFETY_GUARDRAIL_BASE_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • UC_FM_LANGUAGE_INSTRUCT_3B_FRIENDLY_TONE_DRAFT_GENERIC_GENERIC_H16S_Cryptex.dmg,
  • SECUREPKITRUSTSTOREASSETS_SECUREPKITRUSTSTORE_Cryptex.dmg.

Given in the order that they are grafted.

Boot disk structure in macOS, iOS and iPadOS, and AI cryptexes

Volume structure of internal startup disks has grown increasingly complex during the transition from Intel to Apple silicon Macs. There also seems to be little information on iOS and iPadOS to compare against. This article briefly reviews structures of macOS 15 Sequoia on Apple silicon, iOS 18 and iPadOS 18.

Information for macOS is derived from the diskutil command tool, and from APFS entries in the log when booting a Mac mini M4 Pro in macOS 15.5. That for iOS is drawn from APFS entries in the log when booting an iPhone 15 Pro in iOS 18.5. That for iPadOS is drawn from APFS entries in the log when booting an iPad Pro 11-inch (4th generation)(Wi-Fi) in iPadOS 18.5. All three had Apple Intelligence enabled prior to booting. iOS and iPadOS logs were obtained from sysdiagnoses, and all logs were read using LogUI.

macOS 15 (Apple silicon)

The boot volume group consists of six volumes in a single container (partition). Two other containers are normally hidden from the user:

  • the first container of around 524 MB is reserved for preboot and secure boot support.
  • another container of about 5.4 GB is used for fallback recovery frOS, and in Big Sur was the primary recovery system, until the introduction of paired recovery volumes in macOS 12 Monterey.

The boot volume group contains:

  • System, left unmounted after booting from its Signed System Volume (SSV) snapshot;
  • Data, the only encrypted volume in the group, with numerous cryptexes grafted into it, and firmlinked to the SSV at multiple points;
  • paired, primary Recovery, containing a disk image of the Recovery system;
  • VM, the backing store for virtual memory;
  • Preboot, for early stages in the secure boot process, with cryptexes grafted into it;
  • Update, used as a working volume for macOS updates.

There are two groups of cryptexes grafted onto those volumes:

  • system cryptexes, including the large SystemCryptex or os.dmg of about 4.3 GB mainly containing dyld caches, and the smaller AppCryptex or app.dmg containing Safari and supporting components;
  • PFK volumes containing support components for Apple Intelligence features. These are numerous, and some are listed in the Appendix at the end.

If you’re wondering what a PFK volume might be, so am I. But this is what Google’s AI had to say: “Mac PFK” likely refers to a combination of MAC knives and Practical Fishkeeping (PFK) magazine. MAC knives are known for their high-quality, sharp blades and are popular among chefs and home cooks. Practical Fishkeeping is a magazine focused on fishkeeping, covering various aspects of the hobby.

These are summarised, without the help of Practical Fishkeeping, in this diagram.

iPadOS 18

In contrast to macOS since Big Sur, iPadOS and iOS only appear to have two containers (partitions) on their internal storage. The first is presumed to be similar in purpose to that in macOS, in supporting preboot and secure boot, although there is a xART volume in the boot volume group. In iPadOS, this container is smaller, at around 367 MB.

The boot volume group contains a slightly different range of volumes:

  • there is no Recovery volume;
  • there is no VM volume, as iPadOS doesn’t ordinarily support swapping/paging, although M-series models can in certain circumstances;
  • User, a second encrypted volume, appears unique to iPadOS;
  • xART and Hardware volumes are additional.

Cryptexes appear similar, with both system cryptexes and PFK volumes.

These are summarised below.

iOS 18

This is similar to iPadOS, with a first container/partition of around 351 MB, and the following differences in the boot volume group:

  • there is no User volume, and no Update volume;
  • Baseband Data is additional.

Cryptexes appear similar, with both system cryptexes and PFK volumes.

These are summarised below.

Conclusions

  • Volume structure of internal startup disks differs considerably between macOS, iPadOS and iOS.
  • As would be expected, iPadOS and iOS are most similar, but even they have substantial differences.
  • They each run their systems from a Signed System Volume firmlinked to an encrypted Data volume.
  • They each graft on two sets of cryptexes, one supplementing the system with dyld caches and Safari, the other providing components for AI.
  • There are now at least 24 cryptexes used to support AI.

I welcome corrections and explanations, please.

Appendix: Some PFK volumes from cryptexes

  • UC_FM_LANGUAGE_INSTRUCT_300M_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_300M_BAUC_FM_LANGUAGE_INSTRUCT_300M_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_DRAFTS_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_CONCISE_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAIL_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAIL_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_BASE_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROFESSIONAL_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_SUMMARIZATION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_PROOFREADING_REVIEW_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_HANDWRITING_SYNTHESIS_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_EVENT_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MESSAGES_REPLY_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_AUTONAMING_MESSAGES_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_URGENCY_CLASSIFICATION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_FRIENDLY_TONE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_HANDWRITING_SYNTHESIS_MULTILINGUAL_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_VISUAL_IMAGE_DIFFUSION_V1_BASE_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_MULTILINGUAL_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • SECUREPKITRUSTSTOREASSETS_SECUREPKITRUSTSTORE_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_TEXT_PERSON_EXTRACTION_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_FM_LANGUAGE_INSTRUCT_3B_MAGIC_REWRITE_DRAFT_GENERIC_GENERIC_H14G_Cryptex.dmg
  • UC_IF_PLANNER_NLROUTER_BASE_EN_GENERIC_H14G_Cryptex.dmg

Source: iPadOS 18.5, configured with AI enabled for British English.

使用 TikZ 在 Hexo 博客中愉快地画图

一转眼就到 2024 年了!大家新年快乐!

前段时间在写文章时,需要一些配图,于是就使用了 TikZ 来绘制。TikZ 是一个强大的 宏包,可以使用代码的形式绘制出各种各样精美的矢量图。

如果你的阅读器看不到上面的 SVG 格式图片,可以点这里查看 PNG 格式。example-tikz-graph

上面的图对应的 TikZ 代码可以在这里找到。然而画是画爽了,想把它贴到博客里时却犯了难——目前竟然没有什么好办法可以直接在博客里使用 TikZ!

TL;DR

咱们废话不多说,直接上结果:我写了一个 Hexo 插件,可以直接把 Markdown 源码里的 TikZ 代码渲染成 SVG 矢量图,然后在博客构建时嵌入到页面 HTML 中,用起来就和 MathJax 写数学公式一样简单。

而且最重要的是渲染完全在构建时完成,浏览器上无需运行任何 JavaScript。同时构建机上也无需安装 环境,因为其底层运行的是 WebAssembly。

👉 prinsss/hexo-filter-tikzjax: Server side PGF/TikZ renderer plugin for Hexo.

npm install hexo-filter-tikzjax

注意:插件安装成功后,需要运行 hexo clean 清除已有的缓存。

安装插件后,只需要在博客文章中添加 TikZ 代码块:

---title: '使用 TikZ 在 Hexo 博客中愉快地画图'tikzjax: true---Markdown text here...```​​tikz\begin{document}  \begin{tikzpicture}    % Your TikZ code here...    % The graph below is from https://tikz.dev/library-3d  \end{tikzpicture}\end{document}```

插件就会自动把代码渲染成对应的图片,非常方便:

TikZ 教程

不做过多介绍。贴几个链接,有兴趣的可以学学:

比如这就是我在写文章时画的图,全部用 TikZ 代码生成,画起来改起来都很方便。

原理

在本插件之前,主流的在网页上渲染 TikZ 绘图的方式是使用 TikZJax。TikZJax 有点类似 MathJax,都是通过 JavaScript 去渲染 语法。

<link rel="stylesheet" type="text/css" href="https://tikzjax.com/v1/fonts.css"><script src="https://tikzjax.com/v1/tikzjax.js"></script><script type="text/tikz">  \begin{tikzpicture}    \draw (0,0) circle (1in);  \end{tikzpicture}</script>

然而这样做的问题是,太重了。在网页上动态加载 TikZJax,需要加载 955KB 的 JavaScript + 454KB 的 WebAssembly + 1.1MB 的内存数据,如果再另外安装一些宏包,最终打包产物大小甚至可以达到 5MB+。

对于一些有加载性能要求的网站,这显然是难以接受的。

那怎么办呢?答案就是 SSR / SSG,把渲染过程搬到服务端/构建时去做。这很适合博客这样的场景,尤其是静态博客,只需要构建时渲染一下,把生成的图片塞到 HTML 里就完事了,完全不需要客户端 JavaScript 参与,加载速度大幅提升。

因为 TikZJax 底层跑的是 WebAssembly,而 Node.js 也支持运行 WebAssembly,所以很自然地我就想,能不能把它的渲染流程直接搬到 Node.js 里面去做?

说干就干。于是就有了 node-tikzjax,一个 TikZJax 的移植版,可以在纯 Node.js 环境下运行,无需安装第三方依赖或者 环境。轻量化的特性很适合拿来做服务端渲染,也支持在 Cloudflare Worker 等 Runtime 上运行,非常好用。

hexo-filter-tikzjax 则是 node-tikzjax 的一个上层封装,主要就是在渲染 Hexo 博客文章时提取 Markdown 源码中的 TikZ 代码,交给 node-tikzjax 执行并渲染出 SVG 图片,然后将其内联插入到最终的 HTML 文件中。

如果是其他博客框架,也可以用类似的原理实现 TikZ 静态渲染的接入。

局限性

因为 node-tikzjax 并不是完整的 环境,所以不是所有宏包都可以使用。目前支持在 \usepackage{} 中直接使用的宏包有:

  • chemfig
  • tikz-cd
  • circuitikz
  • pgfplots
  • array
  • amsmath
  • amstext
  • amsfonts
  • amssymb
  • tikz-3dplot

如果希望添加其他宏包,可以参考 extractTexFilesToMemory 这里的代码添加。

如果在使用插件的过程中 TikZ 代码编译失败了,可以通过 hexo s --debug 或者 hexo g --debug 开启调试模式,查看 引擎的输出排查问题:

This is e-TeX, Version 3.14159265-2.6 (preloaded format=latex 2022.5.1)**entering extended mode(input.texLaTeX2e <2020-02-02> patch level 2("tikz-cd.sty" (tikzlibrarycd.code.tex (tikzlibrarymatrix.code.tex)(tikzlibraryquotes.code.tex) (pgflibraryarrows.meta.code.tex)))No file input.aux.ABD: EveryShipout initializing macros [1] [2] (input.aux) )Output written on input.dvi (2 pages, 25300 bytes).Transcript written on input.log.

或者也可以在这个 Live Demo 中输入你的 TikZ 代码,提交后可在控制台查看报错。

致谢

首先要感谢 @kisonecat 开发的 web2js 项目,这是一个 Pascal 到 WebAssembly 的编译器,使我们可以在 JavaScript 中运行 引擎,也是下面所有项目的基石。

这里有作者关于构建基于 Web 的 引擎的一篇文章,可以拜读一下:Both TEX and DVI viewers inside the web browser

感谢 @drgrice1 对 TikZJax 和 dvi2html 的修改,TA 的 fork 中包含了很多有用的新功能,并且修复了一些原始代码中的问题。

感谢 @artisticat1 对 TikZJax 的修改,这是基于上述 @drgrice1 的 fork 的又一个 fork,也添加了一些有用的功能。本插件依赖的 node-tikzjax,其底层使用的 WebAssembly 二进制和其他文件就是从这个仓库中获取的。

感谢 @artisticat1 开发的 obsidian-tikzjax 插件,这是本项目的灵感来源。本项目和该插件底层共享同一套 引擎,使用语法也很类似,基本可以在 Obsidian 和 Hexo 之间无缝切换(实际上也是我开发这个的原因 😹)。

如有任何问题,请在 GitHub 上提交 issue。祝使用愉快!

❌