总结
假设我们得到
- 页面上某个点相对于页面左上角的绝对坐标,以及
- 某些内容的 LaTeX 代码,比如显示的未编号方程式。
如何在 LaTeX 文档中定位此内容,以便最紧的盒子它周围是否位于页面上给定的绝对坐标处?
这里的关键是盒子确实应该最紧的,同样地TexText
设法找到它所生成内容的最紧密的盒子Inkscape
:
由于我不能确定以上内容不是XY问题,下面我也将解释我是什么真的正在嘗試做。
TL;DR 就我而言真的尝试做(可能与主题无关)
给定一个由 Inkscape 生成的 SVG 文件,其中包含一个或多个由 TexText 创建的物体,如何将其转换为 PDF,使得在该 PDF 中,由 TexText 创建的内容是可搜索的并且使用字体而不是轮廓,就像它是从普通 LaTeX 文档生成的一样?
该 PDF 中的其他内容应该与我们平常从 SVG 生成 PDF 时的内容相同(例如,使用命令行命令inkscape --export-type="pdf" <name of SVG>
)。
(我知道 Inkscape 选项“省略 PDF 中的文本并生成 LaTeX 文件”。不幸的是,它不能用于处理 TexText。)
介绍
假设我们得到一个 Inkscape 生成的 SVG 文件,其中包含一个或多个由 TexText 生成的对象(通过引擎pdfLaTeX
)。对于每个 TexText 生成的对象,我想生成一个 LaTeX 文件。这个 LaTeX 文件在编译时(通过pdfLaTeX
或LuaLaTeX
)应该生成一个与 Inkscape 生成的页面大小相同的页面,但只包含视觉上与所考虑的 TexText 生成的对象相同,包括其大小(这很容易)及其页面上的精确位置(到目前为止,我还做不到)。此外,Inkscape+TexText 生成的 PDF 不可搜索,并且使用轮廓而不是字体,而 LaTeX 生成的 PDF 应该(与 LaTeX 一样)可搜索,并且使用字体而不是轮廓。
(最终,我希望能够通过脚本等自动生成 LaTeX 文件python
。但我不是在要求 Python 脚本;我只问 LaTeX 部分。)
为什么有人想这样做
我的主要动机如下。当我们将 Inkscape 生成的 SVG 文件转换为 PDF 时,TexText 生成的部分不可搜索。这与 TexText 将 pdfLaTeX 渲染的内容转换为 SVG 轮廓有关。
现在,即使 PDF 不可搜索且使用轮廓而不是字体,原则上也有办法使用 OCR 将这种不可搜索的 PDF 转换为可搜索的 PDF(例如参见这里)然而,玩过tessaract
和其他几个免费的OCR引擎,我还没有找到办法做到这一点可靠地 和 自动地。
此外,在 PDF 文档中,可能存在一些理由(与可搜索性问题无关)更喜欢使用字体而不是轮廓。例如,如果文本很多,那么使用字体的 PDF 文件将比使用轮廓的 PDF 文件小得多。
Inkscape 实际上有一个功能非常接近我想要的。也就是说,可以将 LaTeX 代码以纯文本形式直接写入 Inkscape。代码不会在 Inkscape 中呈现。但是我们可以将项目的副本保存为 PDF使用选项“省略 PDF 中的文本并生成 LaTeX 文件”(参见这里)。然后,Inkscape 会生成一个省略了所有文本的 PDF 文件和一个辅助 LaTeX 文件。最后,PDF 将使用 包含在 LaTeX 文档中\includegraphics
,而我们最初在 Inkscape 中作为文本包含的 LaTeX 代码将放入\put
命令中,这些命令会将结果放在包含的 PDF 之上。这确实是我想要的情况:LaTeX 正常生成 LaTeX 内容,生成的 PDF 将可搜索并使用字体,并且 LaTeX 生成的内容将放在我们最初在 Inkscape 中放置的位置。
但我确实希望能够使用 TexText,这样我就能立即看到最终产品的样子。
开始的方法
事实证明,当使用 TexText 时,Inkscape 生成的 SVG 文件不仅包含轮廓,还包含我们输入到 TexText 中的 LaTeX 代码、包含用于呈现此代码的 LaTeX 前言的文件的位置、X- 和是-TexText 渲染对象的坐标和放大倍数。当然,SVG 还包含画布大小。
我们的想法是,可以编写一个 Python 代码来提取所有这些信息,然后自动地,为 SVG 文件中的每个 TexText 生成的对象生成一个 LaTeX 文档。此文档在编译时应生成一个 PDF,其大小与 Inkscape 生成的 PDF 相同,但仅包含该 TexText 对象的内容,现在可搜索并使用实际字体。此外,内容应与 Inkscape 生成的 PDF 中的对应内容大小相同且位于相同的位置。
换句话说,我希望能够在 LaTeX 中模拟 TexText 的行为。
有关 TexText 在 Inkscape 中的行为的一些相关细节
当你在 TexText 中输入一些内容并保存时,Inkscape 会将其显示在一个框中,非常紧密围绕渲染的内容,无论它是公式还是文本。例如,如果我们在 TexText 中输入以下内容(假设我们加载了amsmath
TexText 的 LaTeX 代码),
\begin{align*}
\sqrt{1+x^{2}}&=\sin x \\
\frac{1}{1+x^{2}}&=e^{-1-\frac{1}{x}}
\end{align*}
我们在 Inkscape 中得到以下输出:
请注意,界定 TexText 生成内容的(可移动且可调整大小的)框是非常紧密;例如,左上角与平方根符号的最上端和最左边的范围对齐。
(据我所知,TexText 在 SVG 级别完成了这种“紧密限制”,即只有在 LaTeX 代码被渲染并转换为 SVG 之后。但我实际上并不知道。)
如果我们现在手动设置X- 和是-将此对象的坐标设置为 0 和 0,
平方根的最上边缘与画布顶部边缘完美对齐,其最左边缘与画布左边缘对齐:
更一般地,我们输入的数字X- 和是-TexText 生成对象的坐标将是非常紧密 TexText 生成内容的边界框。
我希望能在 LaTeX 中做什么
我希望能够在 LaTeX 中模拟 Inkscape+TexText 的行为,包括定位相对于页面的左上角。我们可以假设以下内容作为输入信息
- 页面大小
- LaTeX 代码(放入 TexText 中)
- 这(x,y)内容左上角的坐标,相对于页面的左上角
- TexText的放大倍数设置。
这些都是可以从 Inkscape 生成的 SVG 文件中轻松提取为纯文本的内容。以下是不能最容易提取的是 TexText 渲染对象的宽度和高度。一旦我们“选择”(在 Inkscape 的意义上)对象,这些在 Inkscape 中可见(在“W:”和“H:”旁边)。但这些数字不会在 SVG 文件中显示。相反,Inkscape 必须在运行时计算它们。像这样的信息——不会明确出现在 SVG 文件中,而必须由 Inkscape 在运行时生成——我假设我们无法提供给我们的 LaTeX 代码。(您可能会认为\widthof
并\heightof
会在 LaTeX 中给我们这些数字。但是,特别是对于由生成的方程式,例如align
,这两个命令将返回通常为不是非常紧密。
我尝试这样做
创建与 Inkscape 画布大小完全相同的页面非常简单。对于一般对象(文本或方程式,包括由 eg 生成的对象align
,如上例所示)的绝对定位,到目前为止,我一直尝试\put
在环境内picture
使用,就像 Inkscape 在我们使用选项“忽略 PDF 中的文本并生成 LaTeX 文件”保存为 PDF 时所做的那样(见上文)。但是,接下来的步骤我还没能完全弄清楚。
以上面的例子为例,以 生成的两个方程为例align
。我得到的最接近的结果是这样的。我将 TexText 中的 LaTeX 代码放入零宽度的 中。(如果我们使用minipage
而不是 ,那么零宽度已经不起作用了,例如……但让我们继续当前示例。)然后,我将那个小页面放入环境中的修改版本中。这是一个 MWE。它将尝试将方程式放在页面的左上角,就像我们在 Inkscape 中对 TexText 所做的那样:align
\[…\]
\put
picture
\documentclass{article}
\usepackage{amsmath}
\usepackage{newtxtext}
\usepackage{newtxmath}
\usepackage{calc}
% The following two numbers can be automatically read from SVG.
% By Inkscape's default, they are in mm.
\newcommand{\DocWidth}{162.81847}
\newcommand{\DocHeight}{109.87428}
\usepackage[papersize={\DocWidth mm,\DocHeight mm},margin=0mm]{geometry}
% for a cheap way to use 'calc' to do simple arithmetic with *numbers*
% rather than lengths, turn numbers into lengths---in pt---and then
% strip the lengths.
\makeatletter
\newcommand{\mymath}{\strip@pt\dimexpr}
\makeatother
% e.g. '\mymath (12pt + 2pt)/7*11/10' returns '2.2'
\setlength{\parindent}{0pt}
% Since we'll need to know the height of our content, let's save the content
% into a macro
\newcommand\mnpgA{%
\begin{minipage}[t]{0pt}
% here enter the exact same LaTeX code as was entered into
% TexText, which can be automatically read from SVG
\begin{align*}
\sqrt{1+x^{2}}&=\sin x \\
\frac{1}{1+x^{2}}&=e^{-1-\frac{1}{x}}
\end{align*}
\end{minipage}
}
% measure the height
\newlength{\HeightOfMinipage}
\setlength{\HeightOfMinipage}{\heightof{\mnpgA}}
% I want the positioning to be relative to the upper left corner,
% whereas by default it is relative to the lower left corner.
% So I define a new command that does the necessary calculations.
% This is where we use the height we just measured.
\newcommand{\mmPerPt}{0.35145980351459803515} % = (25.4 mm/inch)/(72.27 pt/inch)
%
\newcommand{\putt}[3]{\put(#1,\mymath \DocHeight pt-\mmPerPt\HeightOfMinipage-#2 pt){#3}}
% Remember, \put takes its position arguments as pure numbers,
% expecting them to be in millimeters. (Actually, it will
% take them to be multiples of \unitlength, and the latter will
% be set to 1mm in this document.)
% But our cheap calculator \mymath does computations with lengths
% in pt, before stripping the pt.
\begin{document}
%
% let's make the vertical space around displayed equations
% as small as we can
\setlength{\abovedisplayskip}{0pt}
\setlength{\belowdisplayskip}{0pt}
\setlength{\abovedisplayshortskip}{0pt}
\setlength{\belowdisplayshortskip}{0pt}
%
\thispagestyle{empty}
\setlength{\unitlength}{1mm}
%
\begin{picture}(\DocWidth,\DocHeight)
\putt{0}{0}{\mnpgA}
\end{picture}
%
\end{document}
不幸的是,输出不太正确。让我们放大左上角:
请注意,页面顶部和平方根顶部之间有间隙,页面左边缘和平方根最左点之间也有间隙。但在我们上面看到的 Inkscape+TexText 生成的 PDF 中,没有这样的间隙。
不太理想的方法:通过中间 EPS 文件
上述方法的障碍实际上是,围绕感兴趣内容的不可见框并不完全紧密。我们可以尝试通过以下方式使其紧密:
我们可以像往常一样生成感兴趣内容的 PDF。在这个初始 PDF 中,内容周围的不可见框不一定是完全紧密的。接下来,我们使用 将此 PDF 文件转换为 EPS pdftops -eps
。此 EPS 具有与其生成源 PDF 一样大的边界框。然后我们将其应用于ps2eps
EPS 文件,这将生成另一个 EPS 文件。第二个 EPS 文件将具有紧密的边界框围绕内容;这就是我们想要的。最后,我们使用 将此第二个 EPS 文件转换回 PDF ps2pdf -dEPSCrop
,以便生成的 PDF 中可见页面的大小与 EPS 中可见页面的大小完全相同。最终的 PDF 紧密地限制了内容。然后可以使用 和 将其包含并精确定位在页面\put
上\includegraphics
。
这种方法的一个缺点是它需要 LaTeX 之外的额外步骤。但更严重的是,结果仍然不总是完美的;通常,边界框要么太紧,要么太松。例如,看看使用此过程完成的以下示例(本例中的 LaTeX 内容只是我们迄今为止考虑的两个方程中的较低者)。我们放大左上角:
注意上面的“1”的顶部已被剪裁。同时,页面左边缘和分数线左边缘之间有一个小间隙。
或者,你也可以直接将 EPS 文件放入\includegraphics
pdfLaTeX 中,然后将其转换为 PDF。结果如下。同样,效果不错,但并不完美;顶部和左侧都有小间隙。
概括
我如何在 LaTeX 中模拟我描述的 Inkscape+TexText 行为?该解决方案应该适用于各种 LaTeX 内容:align
、、、混合纯文本和方程式……任何可以在 TexText 中输入(并正常工作)的内容。我希望能够只输入与我在 TexText 中输入的相同的 LaTeX 代码,并且\[…\]
$…$
X- 和是- 坐标和放大倍数,并使结果处于与 Inkscape+TexText 生成的 PDF 中完全相同的位置。此外,解决方案应该是可以(相当)容易在 Python 中自动化的东西。(意思是,给定一个 SVG,Python 脚本将生成与 SVG 中 TexText 生成的对象一样多的 LaTeX 文档,以便每个 LaTeX 文档都会给出具有上述属性的 PDF。)与 Inkscape+TexText 生成的 PDF 不同,LaTeX 生成的 PDF 应该是可搜索的,并使用字体而不是轮廓。
我在这里不是在问 Python 代码,只是问如何让故事中的 LaTeX 部分发挥作用。如果有额外的帮助LuaLaTeX
,也可以使用它们。
我可能忽略了一种完全不同的方法,但就我目前尝试的方法而言,问题是我不知道如何将任意的 LaTeX 内容放入一个完全密封的隐形盒子里,TexText 似乎知道如何去做(也许在 SVG 级别,但我不确定)。