pdfmark:生成的PDF书签标题中的某些重音字符无法正确显示

时间:2013-01-30 16:37:54

标签: php pdf pdf-generation ghostscript

我正在为现有PDF插入书签,并且在重音“c”方面存在一些问题。有一个例子(示例中使用的字符集是UTF-8):

$name = "Ruční nářadí";

$name = chr(254).chr(255).iconv('UTF-8', 'UTF-16BE', str_replace(array('(',')','/'),array('\\(','\\)','\\/'),$name));

$fh = fopen('pdfmark.txt', 'w');
fputs($fh, "[/Title ({$name}) /Page 1 /OUT pdfmark\n");
fclose($fh);

$command = "gs -sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH -sOutputFile=out.pdf final.pdf pdfmark.txt; mv out.pdf final.pdf";
exec($command);

问题在于,重音č在最终PDF的书签中显示为Ċ(带有不同重音的大写字母)。我尝试了我的语言(捷克语)中使用的其他重音字符,除此之外一切都还可以。

感谢您解决此问题的任何线索。

编辑(2013-02-01):

使用的GhostScript版本是9.06(2012-08-08)。 我正在使用Adobe Reader 11.0.1查看生成的PDF文件。

我还在考虑它...它是否必须以某种方式在PDF中指定编码?因为源PDF不受我的控制,我对此一无所知。如果是这种情况,有没有办法使用GS或pdfmark这样做? 我认为如果书签的编码是Unicode,那么它确实无关紧要,但也许我错了。

编辑(2013-02-05):

GS的pdfwrite或Acrobat中似乎存在错误,GS's bug tracking中有更多信息。在解决之后,我将在此处编写解决方案信息。

3 个答案:

答案 0 :(得分:2)

我首先将字符串简化为一个违规字符。然后查看pdfmark.txt中的字符串,看看它是否正确UTF-16BE编码。

假设这是正确的,那么尝试从命令行运行Ghostscript,看看是否有效。如果不是,您将能够在http://bugs.ghostscript.com打开错误报告,如果您这样做,请提供源文件和命令行。

您没有说明您使用的是什么版本的Ghostscript,也没有说明您使用什么来查看生成的PDF文件。两者都有用......

答案 1 :(得分:0)

以下代码段说明了您需要执行的操作。

在postscript中,可以使用\ 000表示法访问特殊字符,其中000是字符位置。 3位数位于OCTAL,其中\ 350等于小数位232和十六进制位E8。

你要找的人物是Ccaron和ccaron。为了能够访问这些字符,您需要在字体编码表中定义它们。 CEEncoding表是Adobe的中欧字符集。 Postscript可能已经在某处定义了CEEncoding,但是这个例子定义了它自己的。与此示例一样,您可以定义任何您喜欢的编码。网上提供了postscript语言参考手册,提供了有关可用字符的详细信息。

此示例使用standard / Helvetica输出测试1234,然后基于标准/ Helvetica定义新字体/ Helvetica-CE,但使用CEEncoding编码。 (Ru \350ní)show使用CEEncoding定义为ccaron的字符\ 350。只是为了好玩,我还重新定义了字符\ 001为Ccaron和\ 002为欧元符号,\ 003为商标符号,以说明任何字符都可以定义为任何字符并输出为(测试4567 \ 001 \ 002 \ 003)显示。并非所有字体都定义了所有符号。没有符号的字体将替换空格字符。

就这么简单;)

/Helvetica findfont 46 scalefont setfont
100 75 moveto
(testing 1234) show
/CEEncoding [
/.notdef /Ccaron /Euro /trademark /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /space /exclam /quotedbl
/numbersign /dollar /percent /ampersand /quoteright
/parenleft /parenright /asterisk /plus /comma
/minus /period /slash /zero /one
/two /three /four /five /six
/seven /eight /nine /colon /semicolon
/less /equal /greater /question /at
/A /B /C /D /E
/F /G /H /I /J
/K /L /M /N /O
/P /Q /R /S /T
/U /V /W /X /Y
/Z /bracketleft /backslash /bracketright /asciicircum
/underscore /quoteleft /a /b /c
/d /e /f /g /h
/i /j /k /l /m
/n /o /p /q /r
/s /t /u /v /w
/x /y /z /braceleft /bar
/braceright /tilde /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/Sacute /.notdef /.notdef /Zacute /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /sacute /.notdef /.notdef /zacute
/space /.notdef /breve /Lslash /currency
/Aogonek /.notdef /dieresis /.notdef /Scaron
/Scedilla /Tcaron /Zacute /hyphen /Zcaron
/Zdotaccent /degree /aogonek /ogonek /lslash
/acute /lcaron /.notdef /caron /cedilla
/aogonek /scedilla /tcaron /zacute /hungarumlaut
/zcaron /zdotaccent /Racute /Aacute /Acircumflex
/Abreve /Adieresis /Lacute /Cacute /Ccedilla
/Ccaron /Eacute /Eogonek /Edieresis /Ecaron
/Iacute /Icircumflex /Dcaron /Eth /Nacute
/Ncaron /Oacute /Ocircumflex /Ohungarumlaut /Odieresis
/multiply /Rcaron /Uring /Uacute /Uhungarumlaut
/Udieresis /Yacute /Tcedilla /germandbls /racute
/aacute /acircumflex /abreve /adieresis /lacute
/cacute /ccedilla /ccaron /eacute /eogonek
/edieresis /ecaron /iacute /icircumflex /dcaron
/eth /nacute /ncaron /oacute /ocircumflex
/ohungarumlaut /odieresis /divide /rcaron /uring
/uacute /uhungarumlaut /udieresis /yacute /tcedilla
/dotaccent
] def

/Helvetica findfont
dup length dict begin
{ 1 index /FID ne
{def}
{pop pop}
ifelse
} forall
/Encoding CEEncoding def
currentdict
end
/Helvetica-CE exch definefont pop
/Helvetica-CE findfont 36 scalefont setfont
100 100 moveto
(\310\350) show
100 150 moveto 
(Ru\350ní) show
100 200 moveto
(testing 4567\001\002\003) show
 showpage

答案 2 :(得分:0)

根据bug tracking post,我可以用不同的方式对字符串进行编码(也可以帮助下载更新的版本9.08 PRERELEASE):

$name = "Ruční nářadí";

$name = 'FEFF'.strtoupper(bin2hex(iconv('UTF-8', 'UCS-2BE', str_replace(array('(',')','/'),array('\\(','\\)','\\/'),$name))));

$fh = fopen('pdfmark.txt', 'w');
fputs($fh, "[/Title <{$name}> /Page 1 /OUT pdfmark\n");
fclose($fh);

$command = "gs -sDEVICE=pdfwrite -dNOPAUSE -dQUIET -dBATCH -sOutputFile=out.pdf final.pdf pdfmark.txt; mv out.pdf final.pdf";
exec($command);

请注意编码为十六进制格式以及标题定义中的不同括号。