Type 3 字体转换
Type 3 fonts conversion
我正在将 Type3 字形字体从 Pdf 解析为 postscript。输入文件具有带数据流的内联图像平面解码过滤器 applied.the 过滤器具有预测器 15。
任何机构都可以帮助我如何将图像流从 pdf 格式转换为后记。
这就是输入流以 pdf 格式给出的方式
32 0 obj
<<
/Length 342
>>
stream
37 0 4 -52 33 -1 d1
0.01 0 0 0.01 0 0 concat
gsave 2900 0 0 -5100 400 -100 concat
BI
/IM true
/W 29
/H 51
/BPC 1
/D[1
0]
/F/Fl
/DP<</Predictor 15
/Columns 29>>
ID xœ=Ì¡
Â`ÅñÿeÂLθ n`0>Ù`ñ
f[¦DŒF_ÁhC1ì%Ä)¶o.¢Ÿ"†ßá†s®àì]^ÏŠÅS³tFËÂÚ3sç'Æi èÐÇ:j‹¹¨åìOTÿ ª•ÉÙÕÅŸ¨‡¹Ó$°ÆΚWèÁ!¯Cê
÷0&f µtðV ©Ë÷iôíتÄ~Ø•Œöí&´« +ro#Ê‚ûÏÅùlßG'
EI gRestore
endstream
endobj
这就是我想在 Postscript 的输出中写的内容
/g21 {
37 0 4 -52 33 -1 setcachedevice
q
[0.01 0 0 0.01 0 0] concat
q
[2900 0 0 -5100 400 -100] concat
[ xœ…ѱNÃ0à3©p'l` ¢abä*‰'@‚W`KP¡00öQ`d@ ¨CWž€u`‰štj4Ü]@ /ù¤œíÿ| ÂìÊüå7úŠ‰V'‚ª¦zò¡9à*´º
m1Õ`ñ—íü‹‡½Gù@ãÝAVxc¥Ž®"6oFܬJHÃB3(æod¾…xFP†o$!v±Ã»·0—gØY÷J$û„`´#zÊ
Oí¼œÑ¸é`Ê}ü…ñ.Z¯›cF4\¡*O¤ÑPÒYòî¦/éG‘qÑç¼2>öq<Üœ<
B˜5‚²¢ºÎ/èqUTUàoÓ9͔Π܉ä²z ‡S×ÛÙC(PA²š7èT¾ŽCGÈRaLéåksnˆÃ0z<zø:ž=
]
0
<<
/ImageType 1
/Width 29
/Height 51
/ImageMatrix [29 0 0 -51 0 51]
/BitsPerComponent 1
/Decode [1 0]
/DataSource { 2 copy get exch 1 add exch }
<</Predictor 15
/Columns 29
>>
/FlateDecode filter
>>
imagemask
pop pop
gRestore
gRestore
} def
PostScript 具有与 PDF 基本相同的过滤器。您不需要解压缩数据,只需使用 PostScript 中的 FlateDecode 过滤器并保持压缩数据不变。
请注意,Predictor 15(或任何其他 PNG 预测器)需要语言级别 3,但这应该不是问题,18 年来级别 3 一直是标准。
否则,您将需要实施支持 PNG 预测器的 FlateDecode 过滤器版本。我相信 zlib 完全有能力做到这一点。
[编辑]
您的 'PostScript output' 不完整,您正在使用未提供定义的 PDF 运算符(q 和 Q)。除了其他任何事情,这使得无法通过解释器 运行 代码。请按要求提供 complete 简单示例文件。不是粘贴代码,我不太愿意自己去创建一个文件,而且二进制文件也不能很好地剪切和粘贴。
从桌面检查中脱颖而出,我不能立即发现问题,但由于我不能 运行 代码,所以我很容易遗漏一些东西。
[编辑 2]
不出所料,那个文件工作正常。
您尚未提供正在创建的 PostScript 文件。通过查看您开始使用的 PDF 文件,我很难判断您创建的 PostScript 有什么问题。
当然,您可以使用 Ghostscript(我看到您已经使用它来创建 PDF 文件)来创建 PostScript 文件,然后查看其中包含的内容。如果你设置 -dCompressFonts=false 那么输出字体甚至不会被压缩。
例如:
37 0 4 -52 33 -1 d1
0.01 0 0 0.01 0 0 cm
q 2900 0 0 -5100 400 -99.9998 cm
BI
/IM true
/W 29
/H 51
/BPC 1
/D[1
0]
/F[/A85
/CCF]
/DP[null
<</K -1
/Columns 29>>]
ID
-D=,M5m+t^0_>op8\HM"Du]KKrr2rthqG/5qU_ik]$f$TlUslD91qoN93j0%dckk:ld^*DV25!+
!WX>~>
EI Q
当然,您需要查看序言以了解其中使用的所有过程是如何定义的,但是您可以自己完成,当然不需要我来完成。请注意,imagemask 使用 CCITTFax 和 ASCII85 解码过滤器,添加额外的过滤器很简单。由于数据保证为 'monochrome'(它是一个掩码),因此 CCITT 过滤器通常提供优于 Flate 的压缩。
请注意,如果您真的使用 Ghostscript 9.05,那么您应该升级,即 6 岁。
如果您要解释为什么您想要从 PDF 中获取丑陋的位图 type 3 字体并从中制作丑陋的位图 type 3 PostScript 字体,这可能会有所帮助它。
[编辑 3]
看看你的 PostScript 文件,字形的定义与你在问题中提出的不匹配。实际内容是这样的:
/g10135{
88 0 4 -70 82 8 setcachedevice
q
[
0.01 0 0 0.01 0 0 ] M
q
[7800 0 0 -7800 400 800 ]M
<<
/ImageType 1
/Width 78
/Height 78
/ImageMatrix [ 78 0 0 -78 0 78]
/BitsPerComponent 1
/Decode [1
0]
/DataSource ....binary data.....
<< /Predictor 15
/Columns 78
/BitsPerComponent 1>>
/FlateDecode filter def
>> imagemask
Q
Q
}bind def
您没有提供文件、过程或字符串源作为字典中 DataSource 键的值。本质上,PostScript 解释器读取并标记 /DataSource
键,然后继续将二进制文件作为 PostScript 进行处理。毫不奇怪,这会在使用 Ghostscript 处理时导致错误 'syntaxerror in (binary token, type=156)'。
如果您已经过去了,那么您会发现 filter
运算符也需要一个数据源,而您也没有为此提供数据源。
所以您需要为您的二进制数据创建一个数据源。取决于你如何做到这一点,但 currentfile
是一种方式。或者 readstring
假设您知道字符串长度。
所以像这样:
<<
/ImageType 1
/Width 29
/Height 51
/ImageMatrix [29 0 0 -51 0 51]
/BitsPerComponent 1
/Decode [1 0]
/DataSource
<length> string dup
currentfile exch readstring
.....binary data.....
<<
/Predictor 15
/Columns 29
>> /FlateDecode filter
>> imagemask
显然,您必须知道字符串长度才能自行填写。 FlateDecode 的字典参数在我看来似乎不需要它。
[编辑 4]
我注意到这似乎是用于商业用途。这没什么不对,但我不会为你做所有的功课,如果你的工作是你的工作,那就是你要学好语言来完成这项工作。
我略过下面的实际实施细节,试图概述您出错的地方。实际上事情有点复杂,我没有讨论存储在 CharStrings 字典中的过程是如何创建的,或者与早期名称绑定的区别(这是 PostScript 中的一个重要概念)。
您现有的代码是:
/g10135{
88 0 4 -70 82 8 setcachedevice
q
[
0.01 0 0 0.01 0 0 ] M
q
[7800 0 0 -7800 400 800 ]M
<<
/ImageType 1
/Width 78
/Height 78
/ImageMatrix [ 78 0 0 -78 0 78]
/BitsPerComponent 1
/Decode [1
0]
/DataSource {417 string dup
currentfile exch readstring}
...binary data....
<< /Predictor 15
/Columns 78
>>/FlateDecode filter def
>> imagemask
Q
Q
}bind def
因此,PostScript 解释器一次一个地读取这些字节,并将它们转换为标记。这会导致执行一个可执行令牌,或者在其中一个堆栈上执行操作。
所以 /g10135
由 {
字符终止,因为这是一个保留字符。 /
引入了一个名称对象,所以我们最终得到名称对象 g10135
并将其压入操作数堆栈。 {
字符引入了一个可执行数组,因此我们将 mark
放在操作数堆栈上。
接下来我们读取 88,以白色 space 字符结束。这是一个数字,所以我们将其存储在操作数堆栈中,其他数字也是如此。操作数堆栈现在包含:
/g10135
mark
88
0
4
-70
82
8
然后我们读取 setcachedevice,它以白色终止 space。这不是标准标记,因此解释器开始查看字典堆栈中的字典,寻找定义。由于是标准操作符,我们在systemdict中找到并执行。它从操作数堆栈中消耗了 6 个操作数,它没有其他影响(实际上它有,但这有点特殊,因为我们在字体内执行,但我们现在将忽略它)。
接下来我们遇到一个 q
,再次在字典堆栈中的每个字典中查找它以查找定义。这在您自己的序言中定义为 gsave
,因此它不需要操作数并且 return 没有操作数,它只是保存图形状态,将保存深度递增 1。
我不打算完成其余部分,这会很乏味,但是,最终我们会到达您的 /DataSource
,这是一个名称,因此我们将其压入操作数堆栈。接下来我们遇到的是一个 {
,它是一个过程定义,所以我们将一个标记压入操作数堆栈。然后我们遇到 417
,所以我们将其压入 string
、dup
、currentfile
、exch
和 readstring
,因此我们的堆栈如下所示:
/DataSource
mark
417
string
dup
currentfile
exch
readstring
然后我们得到字符 }
这是可执行数组的结束标记,因此我们创建数组并将其压入操作数堆栈:
/DataSource
{....}
然后我们return到这个过程并继续执行它。我们接下来发现的是一些二进制数据,因此我们尝试将其作为 PostScript 二进制标记执行。因为它无效,解释器会抛出错误。
仅创建一个可执行数组不足以实际执行它。如果您查看我在上面编辑 3 末尾发布的大纲代码,您会注意到我没有 而不是 将 readstring
等放在可执行数组中,我只是允许解释器立即执行该代码。
通过这样做,readstring
作用于 currentfile
(在本例中为实际的 PostScript 程序)并从该文件的当前点读取数据字节。当前点将在消耗终止readstring
的白色space 之后立即显示,即实际二进制数据。 readstring
运算符从文件中读取足够的字节来填充字符串,将字符串留在操作数堆栈中。文件指针已经移动到二进制数据之后的字节,解释器在那个点恢复令牌扫描。所以它然后创建 FilterParams 字典,将 /FlateDecode 名称放在堆栈上,然后执行 filter
运算符,该运算符使用名称、字典和字符串操作数,returning 一个文件对象。该文件对象然后成为与传递给 imagemask
运算符的图像字典中的 DataSource 键关联的值。
虽然我没有测试该代码,但它基本上是正确的。当然还有其他方法可以达到同样的目的。
基本上我准备的就这些了,你需要去看看我写的并与你自己的程序进行比较。
请注意,调查此问题的最简单方法是将 CharProc 的内容(不包括 setcachedevice)作为 PostScript 程序 运行。
我正在将 Type3 字形字体从 Pdf 解析为 postscript。输入文件具有带数据流的内联图像平面解码过滤器 applied.the 过滤器具有预测器 15。 任何机构都可以帮助我如何将图像流从 pdf 格式转换为后记。 这就是输入流以 pdf 格式给出的方式
32 0 obj
<<
/Length 342
>>
stream
37 0 4 -52 33 -1 d1
0.01 0 0 0.01 0 0 concat
gsave 2900 0 0 -5100 400 -100 concat
BI
/IM true
/W 29
/H 51
/BPC 1
/D[1
0]
/F/Fl
/DP<</Predictor 15
/Columns 29>>
ID xœ=Ì¡
Â`ÅñÿeÂLθ n`0>Ù`ñ
f[¦DŒF_ÁhC1ì%Ä)¶o.¢Ÿ"†ßá†s®àì]^ÏŠÅS³tFËÂÚ3sç'Æi èÐÇ:j‹¹¨åìOTÿ ª•ÉÙÕÅŸ¨‡¹Ó$°ÆΚWèÁ!¯Cê
÷0&f µtðV ©Ë÷iôíتÄ~Ø•Œöí&´« +ro#Ê‚ûÏÅùlßG'
EI gRestore
endstream
endobj
这就是我想在 Postscript 的输出中写的内容
/g21 {
37 0 4 -52 33 -1 setcachedevice
q
[0.01 0 0 0.01 0 0] concat
q
[2900 0 0 -5100 400 -100] concat
[ xœ…ѱNÃ0à3©p'l` ¢abä*‰'@‚W`KP¡00öQ`d@ ¨CWž€u`‰štj4Ü]@ /ù¤œíÿ| ÂìÊüå7úŠ‰V'‚ª¦zò¡9à*´º
m1Õ`ñ—íü‹‡½Gù@ãÝAVxc¥Ž®"6oFܬJHÃB3(æod¾…xFP†o$!v±Ã»·0—gØY÷J$û„`´#zÊ
Oí¼œÑ¸é`Ê}ü…ñ.Z¯›cF4\¡*O¤ÑPÒYòî¦/éG‘qÑç¼2>öq<Üœ<
B˜5‚²¢ºÎ/èqUTUàoÓ9͔Π܉ä²z ‡S×ÛÙC(PA²š7èT¾ŽCGÈRaLéåksnˆÃ0z<zø:ž=
]
0
<<
/ImageType 1
/Width 29
/Height 51
/ImageMatrix [29 0 0 -51 0 51]
/BitsPerComponent 1
/Decode [1 0]
/DataSource { 2 copy get exch 1 add exch }
<</Predictor 15
/Columns 29
>>
/FlateDecode filter
>>
imagemask
pop pop
gRestore
gRestore
} def
PostScript 具有与 PDF 基本相同的过滤器。您不需要解压缩数据,只需使用 PostScript 中的 FlateDecode 过滤器并保持压缩数据不变。
请注意,Predictor 15(或任何其他 PNG 预测器)需要语言级别 3,但这应该不是问题,18 年来级别 3 一直是标准。
否则,您将需要实施支持 PNG 预测器的 FlateDecode 过滤器版本。我相信 zlib 完全有能力做到这一点。
[编辑]
您的 'PostScript output' 不完整,您正在使用未提供定义的 PDF 运算符(q 和 Q)。除了其他任何事情,这使得无法通过解释器 运行 代码。请按要求提供 complete 简单示例文件。不是粘贴代码,我不太愿意自己去创建一个文件,而且二进制文件也不能很好地剪切和粘贴。
从桌面检查中脱颖而出,我不能立即发现问题,但由于我不能 运行 代码,所以我很容易遗漏一些东西。
[编辑 2]
不出所料,那个文件工作正常。
您尚未提供正在创建的 PostScript 文件。通过查看您开始使用的 PDF 文件,我很难判断您创建的 PostScript 有什么问题。
当然,您可以使用 Ghostscript(我看到您已经使用它来创建 PDF 文件)来创建 PostScript 文件,然后查看其中包含的内容。如果你设置 -dCompressFonts=false 那么输出字体甚至不会被压缩。
例如:
37 0 4 -52 33 -1 d1
0.01 0 0 0.01 0 0 cm
q 2900 0 0 -5100 400 -99.9998 cm
BI
/IM true
/W 29
/H 51
/BPC 1
/D[1
0]
/F[/A85
/CCF]
/DP[null
<</K -1
/Columns 29>>]
ID
-D=,M5m+t^0_>op8\HM"Du]KKrr2rthqG/5qU_ik]$f$TlUslD91qoN93j0%dckk:ld^*DV25!+
!WX>~>
EI Q
当然,您需要查看序言以了解其中使用的所有过程是如何定义的,但是您可以自己完成,当然不需要我来完成。请注意,imagemask 使用 CCITTFax 和 ASCII85 解码过滤器,添加额外的过滤器很简单。由于数据保证为 'monochrome'(它是一个掩码),因此 CCITT 过滤器通常提供优于 Flate 的压缩。
请注意,如果您真的使用 Ghostscript 9.05,那么您应该升级,即 6 岁。
如果您要解释为什么您想要从 PDF 中获取丑陋的位图 type 3 字体并从中制作丑陋的位图 type 3 PostScript 字体,这可能会有所帮助它。
[编辑 3]
看看你的 PostScript 文件,字形的定义与你在问题中提出的不匹配。实际内容是这样的:
/g10135{
88 0 4 -70 82 8 setcachedevice
q
[
0.01 0 0 0.01 0 0 ] M
q
[7800 0 0 -7800 400 800 ]M
<<
/ImageType 1
/Width 78
/Height 78
/ImageMatrix [ 78 0 0 -78 0 78]
/BitsPerComponent 1
/Decode [1
0]
/DataSource ....binary data.....
<< /Predictor 15
/Columns 78
/BitsPerComponent 1>>
/FlateDecode filter def
>> imagemask
Q
Q
}bind def
您没有提供文件、过程或字符串源作为字典中 DataSource 键的值。本质上,PostScript 解释器读取并标记 /DataSource
键,然后继续将二进制文件作为 PostScript 进行处理。毫不奇怪,这会在使用 Ghostscript 处理时导致错误 'syntaxerror in (binary token, type=156)'。
如果您已经过去了,那么您会发现 filter
运算符也需要一个数据源,而您也没有为此提供数据源。
所以您需要为您的二进制数据创建一个数据源。取决于你如何做到这一点,但 currentfile
是一种方式。或者 readstring
假设您知道字符串长度。
所以像这样:
<<
/ImageType 1
/Width 29
/Height 51
/ImageMatrix [29 0 0 -51 0 51]
/BitsPerComponent 1
/Decode [1 0]
/DataSource
<length> string dup
currentfile exch readstring
.....binary data.....
<<
/Predictor 15
/Columns 29
>> /FlateDecode filter
>> imagemask
显然,您必须知道字符串长度才能自行填写。 FlateDecode 的字典参数在我看来似乎不需要它。
[编辑 4] 我注意到这似乎是用于商业用途。这没什么不对,但我不会为你做所有的功课,如果你的工作是你的工作,那就是你要学好语言来完成这项工作。
我略过下面的实际实施细节,试图概述您出错的地方。实际上事情有点复杂,我没有讨论存储在 CharStrings 字典中的过程是如何创建的,或者与早期名称绑定的区别(这是 PostScript 中的一个重要概念)。
您现有的代码是:
/g10135{
88 0 4 -70 82 8 setcachedevice
q
[
0.01 0 0 0.01 0 0 ] M
q
[7800 0 0 -7800 400 800 ]M
<<
/ImageType 1
/Width 78
/Height 78
/ImageMatrix [ 78 0 0 -78 0 78]
/BitsPerComponent 1
/Decode [1
0]
/DataSource {417 string dup
currentfile exch readstring}
...binary data....
<< /Predictor 15
/Columns 78
>>/FlateDecode filter def
>> imagemask
Q
Q
}bind def
因此,PostScript 解释器一次一个地读取这些字节,并将它们转换为标记。这会导致执行一个可执行令牌,或者在其中一个堆栈上执行操作。
所以 /g10135
由 {
字符终止,因为这是一个保留字符。 /
引入了一个名称对象,所以我们最终得到名称对象 g10135
并将其压入操作数堆栈。 {
字符引入了一个可执行数组,因此我们将 mark
放在操作数堆栈上。
接下来我们读取 88,以白色 space 字符结束。这是一个数字,所以我们将其存储在操作数堆栈中,其他数字也是如此。操作数堆栈现在包含:
/g10135
mark
88
0
4
-70
82
8
然后我们读取 setcachedevice,它以白色终止 space。这不是标准标记,因此解释器开始查看字典堆栈中的字典,寻找定义。由于是标准操作符,我们在systemdict中找到并执行。它从操作数堆栈中消耗了 6 个操作数,它没有其他影响(实际上它有,但这有点特殊,因为我们在字体内执行,但我们现在将忽略它)。
接下来我们遇到一个 q
,再次在字典堆栈中的每个字典中查找它以查找定义。这在您自己的序言中定义为 gsave
,因此它不需要操作数并且 return 没有操作数,它只是保存图形状态,将保存深度递增 1。
我不打算完成其余部分,这会很乏味,但是,最终我们会到达您的 /DataSource
,这是一个名称,因此我们将其压入操作数堆栈。接下来我们遇到的是一个 {
,它是一个过程定义,所以我们将一个标记压入操作数堆栈。然后我们遇到 417
,所以我们将其压入 string
、dup
、currentfile
、exch
和 readstring
,因此我们的堆栈如下所示:
/DataSource
mark
417
string
dup
currentfile
exch
readstring
然后我们得到字符 }
这是可执行数组的结束标记,因此我们创建数组并将其压入操作数堆栈:
/DataSource
{....}
然后我们return到这个过程并继续执行它。我们接下来发现的是一些二进制数据,因此我们尝试将其作为 PostScript 二进制标记执行。因为它无效,解释器会抛出错误。
仅创建一个可执行数组不足以实际执行它。如果您查看我在上面编辑 3 末尾发布的大纲代码,您会注意到我没有 而不是 将 readstring
等放在可执行数组中,我只是允许解释器立即执行该代码。
通过这样做,readstring
作用于 currentfile
(在本例中为实际的 PostScript 程序)并从该文件的当前点读取数据字节。当前点将在消耗终止readstring
的白色space 之后立即显示,即实际二进制数据。 readstring
运算符从文件中读取足够的字节来填充字符串,将字符串留在操作数堆栈中。文件指针已经移动到二进制数据之后的字节,解释器在那个点恢复令牌扫描。所以它然后创建 FilterParams 字典,将 /FlateDecode 名称放在堆栈上,然后执行 filter
运算符,该运算符使用名称、字典和字符串操作数,returning 一个文件对象。该文件对象然后成为与传递给 imagemask
运算符的图像字典中的 DataSource 键关联的值。
虽然我没有测试该代码,但它基本上是正确的。当然还有其他方法可以达到同样的目的。
基本上我准备的就这些了,你需要去看看我写的并与你自己的程序进行比较。
请注意,调查此问题的最简单方法是将 CharProc 的内容(不包括 setcachedevice)作为 PostScript 程序 运行。