键入3字体转换

时间:2018-02-01 12:29:31

标签: pdf ghostscript acrobat postscript xpdf

我正在从Pdf到postscript解析Type3字形字体。输入文件具有内联图像,其中应用了数据流flate解码过滤器。过滤器具有预测器15。 任何正文都可以帮助我将图像流从pdf格式化为postscript。  这是输入流以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

1 个答案:

答案 0 :(得分:0)

PostScript与PDF大致相同。您不需要解压缩数据,只需在PostScript中使用FlateDecode过滤器并保持压缩数据不变。

请注意,预测器15(或任何其他PNG预测器)需要语言级别3,但这不应该成为问题,级别3已经成为18年的标准。

否则,您需要实现支持PNG预测器的FlateDecode过滤器版本。我相信zlib非常有能力做到这一点。

[编辑]

你的PostScript输出&#39;如果不完整,您使用的是PDF运算符(q和Q),但您没有提供定义。除了其他任何东西,这使得无法通过解释器运行代码。请按要求提供完整简单示例文件。不粘贴代码,我不打算自己创建一个文件,而且二进制文件并没有完全剪切和粘贴。

从桌面检查我的头顶,我无法立即看到问题,但由于我无法运行代码,我很容易丢失一些东西。

[编辑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解码过滤器,它可以添加额外的过滤器。由于数据保证是单色的&#39; (它的掩码)CCITT滤波器通常会给Flate提供更好的压缩。

请注意,如果你真的使用Ghostscript 9.05,那么你应该升级,即6岁。

如果你要解释为什么你想从PDF中获取一个丑陋的,位图的3型字体并从中制作一个丑陋的,位图类型的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处理。不出所料,这会导致错误的语法错误(二进制令牌,类型= 156)&#39;用Ghostscript处理时。

如果你已经过去了,那么你会发现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,以空格字符结束。这是一个数字,所以我们将它存储在操作数堆栈上,同样是其他数字。操作数堆栈现在包含:

/g10135
mark
88
0
4
-70
82
8

然后我们读取setcachedevice,它由一个空格终止。这不是标准令牌,因此解释器开始查看字典堆栈上的字典,寻找定义。由于它是标准运算符,我们在systemdict中找到它并执行它。从操作数堆栈中消耗6个操作数,它没有其他效果(实际上它确实如此,但这有点特殊,因为我们在字体内部执行,但我们现在忽略它)。

接下来我们遇到q,再次查询字典堆栈中的每个字典以查找定义。这在你自己的prolog中被定义为gsave,因此它不需要操作数并且不返回操作数,它只是保存图形状态,将保存深度增加1。

我不会经历剩下的任务,但是,最终我们到达你的/DataSource,这是一个名字,所以我们把它推到操作数堆栈上。接下来我们遇到的是{,它是一个过程定义,因此我们在操作数堆栈上按下一个标记。然后我们遇到417,因此我们推送stringdupcurrentfileexchreadstring,因此我们的堆栈如下所示:

/DataSource
mark
417
string
dup
currentfile
exch
readstring

然后我们得到字符}这是可执行数组的结束标记,所以我们创建数组并将其推送到操作数堆栈:

/DataSource
{....}

然后我们返回程序并继续执行它。接下来我们发现的是一些二进制数据,因此我们尝试将其作为PostScript二进制令牌执行。因为它不是有效的,所以解释器会抛出错误。

仅创建可执行数组并不足以实际执行它。如果你查看我在上面编辑3结尾处发布的大纲代码,你会注意到我readstring等放在可执行数组中,我只是允许解释器立即执行该代码。

通过这样做readstring作用于currentfile(在这种情况下是实际的PostScript程序)并从该文件中的当前点读取数据字节。在消耗终止readstring的空格(即实际二进制数据)之后,当前点将立即生效。 readstring运算符从文件中读取足够的字节以填充字符串,将字符串保留在操作数堆栈上。文件指针已移至二进制数据之后的字节,解释器在该点恢复令牌扫描。然后它创建FilterParams字典将/ FlateDecode名称放在堆栈上,然后执行filter运算符,该运算符使用名称,字典和字符串操作数,返回文件对象。然后,该文件对象将成为与图像字典中的DataSource键关联的值,该值将传递给imagemask运算符。

虽然我还没有测试过该代码,但它基本上是正确的。当然还有其他方法可以实现同样的目标。

基本上我已准备好接受这一点,你需要去看看我写的内容并将其与你自己的程序进行比较。

请注意,调查此问题的最简单方法是获取CharProc的内容(不包括setcachedevice),然后将其作为PostScript程序运行。