在此主题,@David Carlisle 告诉我们如何使用 luatex 读取 png 图像的一些属性。唉,图像库似乎无法获取该colorspace
属性。总是报告nil
。
如果我可以从文件中读取两个字节(在已知位置),并将这些字节作为纯文本 00 到 FF 分配给 LaTeX 变量,那么我知道从那里该做什么。
我看过此主题,这似乎相关,但它并没有提供我需要的东西。
因此,这是我的一般问题:Lua 代码如何做到这一点:
1) 打开任意二进制文件(部分)。虽然我考虑的是 PNG,但我假设可以使用任何文件类型。该方法必须是跨平台的。
2) 仅选择从偏移量 P 到偏移量 Q 的字节,其中 P 和 Q 通过 LaTeX 宏作为变量提供。可能多达几百个字节,但可能要少得多。
3) 使用代码 0 到 F 将字节表示为纯文本字符串。因此,如果要求十个字节,则字符串可能看起来A9003405BC
没有空格或返回。
4)将字符串分配给 LaTeX 宏,以便通过普通 LaTeX 进行后续处理。
我为什么想知道:在我的 LuaLaTeX 应用程序中,图像的使用受到限制。我了解图像规范,但(不是程序员)对诸如此类的事情感到困惑LuaTeX 手册。
为什么其他人应该关心:在我看来,Lua 的功能在 LuaLaTeX 中没有得到充分利用,可能是因为大多数用户都在做一次性项目,不想学习另一种编程语言。我的要求是模块化的,具有普遍适用性。
请注意,当所需信息不在特定字节偏移处时,也可以使用 1-4 的解决方案,只要它位于文件开头附近的某个位置即可。然后,可以使用普通的 LaTeX 方法解析纯文本字符串以获取值。
编辑:看了下面大卫的回答,我有一些问题:
所需代码如下(伪代码,这不起作用):
\newcommand\getsomebytes[3]{ % filename, start, end
\directlua{
local inp = assert(io.open("#1", "rb"))
local data = inp:read("*all")
\gdef\heretheyare{string.byte(data,#2,#3)}
}
}
然后,在文档主体中,我将使用:
\getsomebytes{filename.png}{4}{56} % bytes from 4 to 56 here
这不会打印任何内容,但会将结果以\heretheyare
纯文本形式存储在宏中(数字而不是字母也可以,只要字符串可以通过 LaTeX 字符串方法(例如来自包)进行解析即可xstring
)。处理后,我会对另一个文件重新使用这些命令。
我想知道是否有必要打开“全部”文件,因为在某些情况下文件可能非常大(20Mb 或更大)并且我只需要检查其中的一部分。
答案1
下面显示前 5 个字节为 137 80 78 71 13
这与我的测试 png 的十六进制转储相匹配
$ hexdump.exe man2.png | head
0000000 5089 474e 0a0d 0a1a 0000 0d00 4849 5244
0000010 0000 0001 0000 5801 0208 0000 3300 b5cd
0000020 00ab 0000 7301 4752 0042 ceae e91c 0000
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{man2.png}
\directlua{
local inp = assert(io.open("man2.png", "rb"))
local data = inp:read("*all")
local b1,b2,b3,b4,b5 = string.byte(data,1,5)
print(b1 .. ' ' .. b2 .. ' ' ..b3 .. ' ' .. b4 .. ' ' .. b5)
}
\end{document}
只需将 1,5 更改为所需字节序列的开始和长度
使用 seek 的版本(因此不会读取整个文件)并将结果留在 tex 宏中
\documentclass{article}
\usepackage{graphicx}
\begin{document}
\includegraphics{man2.png}
\directlua{
inp = assert(io.open("man2.png", "rb"))
}
\def\zz#1#2{%
\edef\zzhere{\directlua{
local p=inp:seek("cur",#1)
local r=inp:read(#2)
sep=""
for i,_ in string.bytes(r)
do
tex.sprint(sep)
sep=","
tex.sprint(i)
end
}}}
\zz{1}{5}
bytes 1 to 5 are :[\zzhere]
\end{document}
答案2
在考虑了 David 发布的答案(上文)后,我将其扩展为以下 TeX 代码。放在这里以防其他人使用它。
输入文件可以是任何 TeX 可读的内容。输出字符串是纯文本(逗号分隔的数字,范围从 0 到 255),因此可以轻松解析。
在此示例中,输入文件是 PNG 图像。我想知道它的位深度和颜色类型。虽然现有的 Lua 库提供了位深度,但它似乎无法提供颜色类型。因此,我直接获取信息。只需知道在文件中查找的位置以及预期的值。如果所需信息不在特定的字节偏移量处,那么我可以抓取足够大的字符串,解析某种标头,然后从那里偏移。
这也可以查看文件的末尾,某些文件类型在此处存储添加的信息(例如注释)。
% compile only with lualatex
\documentclass{article}
\usepackage{mwe}
\usepackage{xifthen}
\usepackage{xparse}
% Thanks to David Carlisle, via tex.stackexchange.com:
% Output is comma-separated list of byte codes, decimal 0-255.
% Returns -1 if requested start is more than file size.
% Returns all bytes if requested number exceeds file size.
% Does not test if file exists; error if not found.
\DeclareDocumentCommand\getsomebytes { m m m } {%
% filename, start byte (0=beginning, e=end), number of bytes
\ifthenelse{\equal{#2}{e}}{% package xifthen
\long\edef\herearebytes{%
\directlua{
inp = assert(io.open("#1", "rb"))
local e=inp:seek("end")
if #3>e+1 then
inp:seek("set")
local r=inp:read(e)
sep=""
for i,_ in string.bytes(r)
do
tex.sprint(sep)
sep=","
tex.sprint(i)
end
else
local b=e-2-math.min(e,#3)
local w=1+math.min(e,#3)
inp:seek("set",b)
local r=inp:read(w)
sep=""
for i,_ in string.bytes(r)
do
tex.sprint(sep)
sep=","
tex.sprint(i)
end
end
}%
}%
}{%
\long\edef\herearebytes{%
\directlua{
inp = assert(io.open("#1", "rb"))
local e=inp:seek("end")
if #2>e then tex.sprint(-1) else
local w=math.min(#3,e-#2)
inp:seek("set",#2)
local r=inp:read(w)
sep=""
for i,_ in string.bytes(r)
do
tex.sprint(sep)
sep=","
tex.sprint(i)
end
end
}%
}%
}%
} % end getsomebytes
\def\pngbitdepth#1{\getsomebytes{#1}{24}{1}\herearebytes}
\def\pngcolortype#1{\getsomebytes{#1}{25}{1}\herearebytes}
\begin{document}
This `example-image.png' is part of the `mwe' package:\par
PNG bit depth: \pngbitdepth{example-image.png} (expected 8)\par
PNG color type: \pngcolortype{example-image.png} (expected 0)\par
\getsomebytes{example-image.png}{0}{8}
First 8 bytes are: \herearebytes ~(expected 137,80,78,71,13,10,26,10)\par
\getsomebytes{example-image.png}{e}{6}
Last 7 bytes are: \herearebytes ~(expected 73,69,78,68,174,42,60,82)\par
\getsomebytes{example-image.png}{45}{3}
Bytes 45, 46, 47 are: \herearebytes ~(expected 11,252,97)\par
\getsomebytes{example-image.png}{12345}{2}
Bytes 12345 and 12346 are: \herearebytes ~(expected -1 because file is not big enough)\par
\end{document}
编辑:添加案例,如果请求的起始字节大于 EOF,则返回字符串 -1。
编辑 2:我刚刚把 David 的回复用到了极致,现在已包含在“小说”包的 1.52 版中。背景:
这是 LuaLaTeX 特有的,仅指 png 和 jpg 灰度图像。其他一些情况(例如彩色封面图)也可以处理,但代码有所不同。
问题:某些 PDF 文件(例如 PDF/X-1a)限制了可以包含的图像类型。但 TeX 不会检测图像是否符合要求的规格。可以使用 shell-escape 调用外部图形程序,但这会产生两个问题:首先,这种安排不可移植,因为网络或在线用户无法依赖 shell-escape 和外部程序。其次,在 TeX 中处理图像会占用大量时间,每次编译时都会重复此过程。
解决方案:使用 shell/批处理脚本对图像进行预处理。这可以方便地完成,并且不使用 TeX。处理后的图像将包含注释,声明它们是好的。然后,使用 Lua 代码的强大功能,TeX 文档将检查每个图像的注释。这可以快速完成。如果检测到任何未处理的图像,将发出警告。这不是错误,因为未处理的图像可能仍然是好的。由于这部分不需要支持图形或 shell 转义,因此它也是可移植的,可以通过网络或在线完成。此外,TeX 会跟踪图像,因此无需重新检查重复的图像。
有效的 Lua 代码基于 David 的回答。由于所有支持 LuaLaTeX 的代码都太长(而且太具体),因此无法在此处发布。但可以在“novel”软件包版本 1.52 中看到它,位于“novel-Images.sty”文件底部附近。预处理脚本位于文档“extras”文件夹中。如果您愿意,可以查看一下。
为什么这很重要:LuaLaTeX 可以创建 PDF/X-1a 文件,这是一些主要的美国按需印刷服务所要求的。Adobe Acrobat Pro 等程序具有内置图形支持,可以检测和纠正不合规的图像。TeX 没有。也就是说,TeX 直到现在才拥有它!