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,所以我们将其压入 stringdupcurrentfileexchreadstring,因此我们的堆栈如下所示:

/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 程序 运行。