最小可能的有效 PDF 是什么?

出于简单的好奇心,看过 最小的 GIF之后,最小的可能有效的 PDF 文件是什么?

49703 次浏览

这是一个有趣的问题。按照书上的说法,你可以这样开始:

%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj
xref
0 4
0000000000 65535 f
0000000010 00000 n
0000000053 00000 n
0000000102 00000 n
trailer<</Size 4/Root 1 0 R>>
startxref
149
%EOF

这是291字节的 PDF 乔伊。Acrobat 打开了它,但它有些抱怨。有一个页面,它是3/72“正方形,规格允许的最低限度。

然而,Acrobat X 甚至不再使用交叉参考表,所以我们可以删除它:

%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj
trailer<</Size 4/Root 1 0 R>>

Acrobat 抱怨,但打开它。现在我们在178字节。 事实证明你不需要那个/拖车的大小。现在我们是172:

%PDF-1.0
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj 2 0 obj<</Type/Pages/Kids[3 0 R]/Count 1>>endobj 3 0 obj<</Type/Page/MediaBox[0 0 3 3]>>endobj
trailer<</Root 1 0 R>>

事实证明,你的字典里不需要那些烦人的/Type 元素:

%PDF-1.0
1 0 obj<</Pages 2 0 R>>endobj 2 0 obj<</Kids[3 0 R]/Count 1>>endobj 3 0 obj<</MediaBox[0 0 3 3]>>endobj
trailer<</Root 1 0 R>>

现在是138字节。

它还表明,当规范说明“ shall be a between reference”和/Count 是必需的,并且头部“ must”是% PDF-1.0时,他们提出了一些不严谨的建议。这是我能做到的最小的一个,在 Acrobat X 中可以打开:

%PDF-1.
trailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>

70字节。

现在,我的编辑器使用 Windows 的换行规则,但 Acrobat 接受 Windows、 Mac 或 Unix 的约定,所以通过使用十六进制编辑器,我将 r n 替换为 r,并删除了最后一个换行,这样我只剩下67个字节

25 50 44 46 2D 31 2E 0D 74 72 61 69 6C 65 72 3C
3C 2F 52 6F 6F 74 3C 3C 2F 50 61 67 65 73 3C 3C
2F 4B 69 64 73 5B 3C 3C 2F 4D 65 64 69 61 42 6F
78 5B 30 20 30 20 33 20 33 5D 3E 3E 5D 3E 3E 3E
3E 3E 3E

我试着去掉最后一个词典(> >) ,但是 Acrobat 没有这个功能。Google Chrome 内置的 PDF 阅读器(FoxIt)无法打开它。

作为 PostScript (HA!看到我做了什么吗?),如果你同意 Acrobat“修复”文件,它突破了3550字节,其中大部分是可选的元数据,但它留下了一些明确的规范违反。

我想我会做一个最小的 pdf,显示“你好世界”。文本在左下角。对于9点字体,我很抱歉,任何更大的字体都需要额外的字节:)

Adobe Reader X 为172字节(如果保存为只有 linefeed 的换行符,没有尾随换行符或空字节) :

%PDF-1.
1 0 obj<</Kids[<</Parent 1 0 R/Resources<<>>/Contents 2 0 R>>]>>endobj 2 0 obj<<>>stream
BT/ 9 Tf(Hello World)' ET
endstream
endobj trailer<</Root<</Pages 1 0 R>>>>

Chrome 内置 PDF 浏览器120字节:

%PDF 1 0 obj<</Pages<</Kids[<</Contents<<>>stream
BT 9 Tf(Hello World)' ET endstream>>]>>>>endobj trailer<</Root 1 0 R>>

要在 Chrome 中轻松看到这一点,请将这个 URI 粘贴到地址栏(因此不允许我链接到它,而且它在其他浏览器中根本无法工作) :

data:application/pdf,%25PDF%201%200%20obj%3C%3C%2FPages%3C%3C%2FKids%5B%3C%3C%2FContents%3C%3C%3E%3Estream%0ABT%209%20Tf(Hello%20World)'%20ET%20endstream%3E%3E%5D%3E%3E%3E%3Eendobj%20trailer%3C%3C%2FRoot%201%200%20R%3E%3E

我无法打开 hello world 示例。

对于带有文本内容的小型文件:

%PDF-1.2
9 0 obj
<<
>>
stream
BT/ 9 Tf(Test)' ET
endstream
endobj
4 0 obj
<<
/Type /Page
/Parent 5 0 R
/Contents 9 0 R
>>
endobj
5 0 obj
<<
/Kids [4 0 R ]
/Count 1
/Type /Pages
/MediaBox [ 0 0 99 9 ]
>>
endobj
3 0 obj
<<
/Pages 5 0 R
/Type /Catalog
>>
endobj
trailer
<<
/Root 3 0 R
>>
%%EOF

在 Java 中,使用以下方法:

 private static String samplepdf = "255044462D312E0D747261696C65723C3C2F526F6F743C3C2F50616765733C3C2F4B6964735B3C3C2F4D65646961426F785B302030203320335D3E3E5D3E3E3E3E3E3E";

然后

byte[] bytes = hexStringToByteArray(samplepdf);

...

public byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}

根据这个 Ange Albertini 演讲,最小可能的有效 PDF 是36字节:

% PDF-(NULL)拖车 < > > > > >

其中(NULL)是不可打印的 ASCII 0字符。

然而,正如 Ange 指出的那样,虽然这个 PDF 在技术上是有效的,但是大多数 PDF 阅读器应用程序仅仅根据它的大小就认为它是无效的,因此无法打开它。

基于这里所有的答案,下面是最小的 PDF 文档:

SMALL_PDF = (
b"%PDF-1.2 \n"
b"9 0 obj\n<<\n>>\nstream\nBT/ 32 Tf(  YOUR TEXT HERE   )' ET\nendstream\nendobj\n"
b"4 0 obj\n<<\n/Type /Page\n/Parent 5 0 R\n/Contents 9 0 R\n>>\nendobj\n"
b"5 0 obj\n<<\n/Kids [4 0 R ]\n/Count 1\n/Type /Pages\n/MediaBox [ 0 0 250 50 ]\n>>\nendobj\n"
b"3 0 obj\n<<\n/Pages 5 0 R\n/Type /Catalog\n>>\nendobj\n"
b"trailer\n<<\n/Root 3 0 R\n>>\n"
b"%%EOF"
)

复制到 base64并在 Chrome 中进行测试:

Something 9nCj4 + CmVuZG9iagp0cmFpbGVyCjw8Ci9Sb290IDMgMCBSCj4 + CiUlRU9G

要使页面变大,请调整 MediaBox 的尺寸:)

/MediaBox [0025050]

我需要一个 PDF 版本是可用的 PDF 转换器(A4格式的问题。.上述所有构造都可以与 Adobe Reader 和 Chrome 一起使用,但不能与需要 DIN A4的 PDF 转换器一起使用)。 我发现这个网站和这个 PDF 与我正在使用的 PDF 转换器工作得很好: < a href = “ https://help. callassoftware.com/m/73261/l/798383-how-to-create-a-simple-PDF-file”rel = “ nofollow norefrer”> https://help.callassoftware.com/m/73261/l/798383-how-to-create-a-simple-PDF-file

我将给出一个我认为是最小有效的“通用”PDF 的例子。直到我注意到,使用 PDF 的整个理念就是确保它在所有设备和它们的 PDF 阅读器上呈现完全相同的内容。然而,在交叉检查我的“完美的小型形式良好的 PDF”,我发现了这一点。DR 这是固定在我的个人最小文本模板(在最后)

enter image description here

因此,基本原则是 “最小可能有效的 PDF”,但我认为这个短缺应算作一个无效的 PDF,因为它不符合“适合用途”的概念,因此最低限度的 PDF 必须作为一个最低限度包含一个最低限度的方法来修复一个工作字体。

为了解释我提出的解决方案,以及为什么它不是完美的这里,它是在一个粗略的形式,因为剪切和粘贴。

%PDF-1.0
%µ¶


1 0 obj
<</Type/Catalog/Pages 2 0 R>>
endobj


2 0 obj
<</Kids[3 0 R]/Count 1/Type/Pages/MediaBox[0 0 595 792]>>
endobj


3 0 obj
<</Type/Page/Parent 2 0 R/Contents 4 0 R/Resources<<>>>>
endobj


4 0 obj
<</Length 58>>
stream
q
BT
/ 96 Tf
1 0 0 1 36 684 Tm
(Hello World!) Tj
ET
Q


endstream
endobj


xref
0 5
0000000000 65536 f
0000000016 00000 n
0000000062 00000 n
0000000136 00000 n
0000000209 00000 n


trailer
<</Size 5/Root 1 0 R>>
startxref
316
%%EOF

虽然没有定义的规则 有个问题我已经包括了一些过去的用户问题的经验。

你可能注意到的第一个不同之处是,第二个 obj 中的媒体框是一个混合 MediaBox[0 0 595 792],它是一个极小极大 A4宽度和极小极大美国字母高度,因为否则,在大多数国家的“通用页面”将迫使第二个页面@100% 比例打印过宽或过高的页面定义的地区默认值。

当前的问题在第三个 obj 中得到了证明,因为没有为资源设置字体,因此在针对 最小化的 PDF 中,我没有定义字体的比赛将是无效的。

因此,到目前为止,没有一个答案,包括我自己的,似乎生产一个 PDF,将 "WORK"作为一个“有效”意味着生产相同的打印输出,无论平台或观众。

转向库,我发现了一个3MB 的压缩包,它有一个异常多功能的 windows.exe (一个单独的文件,可以执行大多数 pdf 功能,如分割合并导入邮票导出附件等) ,它可以采用“ Hello World!在命令行中并产生一个良好的工作文件,这是页面中心放大 enter image description here

它使用一个文本流及其定位,并有其他一致的数据,如生产商,所以我提供这作为一个潜在的良好的最低限度削减,注意,这个文件将出现空白,由于流损坏从二进制到文本。

%PDF-1.7
%µ¶


1 0 obj
<</Pages 2 0 R/Type/Catalog>>
endobj


2 0 obj
<</Count 1/Kids[5 0 R]/MediaBox[0 0 595 792]/Type/Pages>>
endobj


3 0 obj
<</BaseFont/Helvetica/Encoding/WinAnsiEncoding/Subtype/Type1/Type/Font>>
endobj


4 0 obj
<</Filter/FlateDecode/Length 101>>
stream
xœ*Tp
QÐw3P04Ò30PISp
Q01
à˜kdf¢ga¬`bhâ%ç‚ô(„”#©Aîè"EéÚlA
HW‘‚†GjNN¾Bx~QNŠ¢¦BHÈÞ@@   ÿÿFå
endstream
endobj


5 0 obj
<</Contents 4 0 R/CropBox[0 0 595 792]/MediaBox[0 0 595 792]/Parent 2 0 R/Resources<</Font<</F0 3 0 R>>>>/Type/Page>>
endobj


6 0 obj
<</CreationDate(D:20220600600709+01'00')/ModDate(D:20220600600709+01'00')/Producer(me 2)>>
endobj


xref
0 7
0000000000 65536 f
0000000016 00000 n
0000000062 00000 n
0000000136 00000 n
0000000225 00000 n
0000000395 00000 n
0000000529 00000 n


trailer
<</Size 7/Info 6 0 R/Root 1 0 R/ID[<A2A0CE5CCD9D0DABD5845AD574BF0A5C><09BF9D281BE12CB5B5933BB2B62B0D4D>]>>
startxref
636
%%EOF

另外,我故意添加了一个无效的项目,所以故意不是最低工作回答,看看你能否找出明显错误的地方: -)

我个人的贡献 因此,我经常被问到如何编写纯文本模板 PDF,因此需要字体是静态的(Helvetica 或 Courier 应该这样做)和一个结构,易于修改使用 Windows CMD 行,所以这符合我的目的它的565编辑前,并有两个位置持有人显示多行,所以如果需要可以找到和取代 HelveticaCourier (注意故意 后面两格保持字节计数)

%PDF-1.1
%âãÏÓ
1 0 obj<</Type/Catalog/Pages 2 0 R>>endobj
2 0 obj<</Type/Pages/Kids [3 0 R]/Count 1/MediaBox [0 0 594 792]>>endobj
3 0 obj<</Type/Page/Parent 2 0 R/Resources<</Font<</F1<</Type/Font/Subtype/Type1/BaseFont/Helvetica>>>>>>/Contents 4 0 R>>endobj
4 0 obj<</Length 78
>>
stream


BT /F1 18 Tf 036 740 Td (Body) Tj ET
BT /F1 18 Tf 036 720 Td (Text) Tj ET


endstream
endobj xref
0 5
0000000000 65535 f
0000000021 00000 n
0000000065 00000 n
0000000139 00000 n
0000000269 00000 n
trailer<</Root 1 0 R /Size 5>>startxref
401 %%EOF

@ mkl 你准备好制作你最好的镜头了吗?

在一家 PDF 相关的公司工作,我知道下面的内容会非常好。这是一个有效的空 A4页面:

%PDF-1.4
%âãÏÓ
5 0 obj
<<
/Length 1
>>
stream
 

endstream
endobj
4 0 obj
<<
/Type /Page
/MediaBox [0 0 612 792]
/Resources <<
>>
/Contents 5 0 R
/Parent 2 0 R
>>
endobj
2 0 obj
<<
/Type /Pages
/Kids [4 0 R]
/Count 1
>>
endobj
1 0 obj
<<
/Type /Catalog
/Pages 2 0 R
>>
endobj
3 0 obj
<<
/Creator (PDF Creator http://www.pdf-tools.com)
/CreationDate (D:20150701112447+02'00')
/ModDate (D:20220607183602+02'00')
/Producer (3-Heights\222 PDF Optimization Shell 6.0.0.0 \(http://www.pdf-tools.com\))
>>
endobj
xref
0 6
0000000000 65535 f
0000000226 00000 n
0000000169 00000 n
0000000275 00000 n
0000000065 00000 n
0000000015 00000 n
trailer
<<
/Size 6
/Root 1 0 R
/Info 3 0 R
/ID [<1C3500CA9F7232B97E0EF3F789E8B7F2> <254C8D153F655D49945EAD68D801E011>]
>>
startxref
505
%%EOF

现在使用 Javascript,您可以将它嵌入到您的 js bundle 中。首先在 base64中对上面的内容进行编码,然后使用编码后的字符串并用它创建一个 Blob 文件,方法是:

const str = 'JVBERi0xLjQKJcOiw6PDj8OTCjUgMCBvYmoKPDwKL0xlbmd0aCAxCj4+CnN0cmVhbQogCmVuZHN0cmVhbQplbmRvYmoKNCAwIG9iago8PAovVHlwZSAvUGFnZQovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQovUmVzb3VyY2VzIDw8Cj4+Ci9Db250ZW50cyA1IDAgUgovUGFyZW50IDIgMCBSCj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovS2lkcyBbNCAwIFJdCi9Db3VudCAxCj4+CmVuZG9iagoxIDAgb2JqCjw8Ci9UeXBlIC9DYXRhbG9nCi9QYWdlcyAyIDAgUgo+PgplbmRvYmoKMyAwIG9iago8PAovQ3JlYXRvciAoUERGIENyZWF0b3IgaHR0cDovL3d3dy5wZGYtdG9vbHMuY29tKQovQ3JlYXRpb25EYXRlIChEOjIwMTUwNzAxMTEyNDQ3KzAyJzAwJykKL01vZERhdGUgKEQ6MjAyMjA2MDcxODM2MDIrMDInMDAnKQovUHJvZHVjZXIgKDMtSGVpZ2h0c1wyMjIgUERGIE9wdGltaXphdGlvbiBTaGVsbCA2LjAuMC4wIFwoaHR0cDovL3d3dy5wZGYtdG9vbHMuY29tXCkpCj4+CmVuZG9iagp4cmVmCjAgNgowMDAwMDAwMDAwIDY1NTM1IGYKMDAwMDAwMDIyNiAwMDAwMCBuCjAwMDAwMDAxNjkgMDAwMDAgbgowMDAwMDAwMjc1IDAwMDAwIG4KMDAwMDAwMDA2NSAwMDAwMCBuCjAwMDAwMDAwMTUgMDAwMDAgbgp0cmFpbGVyCjw8Ci9TaXplIDYKL1Jvb3QgMSAwIFIKL0luZm8gMyAwIFIKL0lEIFs8MUMzNTAwQ0E5RjcyMzJCOTdFMEVGM0Y3ODlFOEI3RjI+IDwyNTRDOEQxNTNGNjU1RDQ5OTQ1RUFENjhEODAxRTAxMT5dCj4+CnN0YXJ0eHJlZgo1MDUKJSVFT0Y=';
const blob = new Blob([atob(str)], { type: 'application/pdf' });