在PostScript中显示Unicode字符

时间:2019-02-23 10:24:20

标签: unicode postscript lang

如何使我的PostScript程序显示Bravura字体中的G谱号字符?根据此SMuFL文档,Bravura中G(高音)谱号的Unicode代码点为U + E050(请参见第48页谱号(U + E050–U + E07F))。 PostScript字形名称可能是gClef(不确定)。

到目前为止,这是我最好的尝试,以获取页面上的unicode字符。我正在使用GhostScript 9.25生成PDF。这是GhostScript的输出:

GPL Ghostscript 9.25 (2018-09-13)
Copyright (C) 2018 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Scanning C:/Windows/Fonts for fonts... 550 files, 358 scanned, 337 new fonts.
Can't find (or can't open) font file %rom%Resource/Font/Calibri.
Can't find (or can't open) font file Calibri.
Loading Calibri font from C:/Windows/Fonts/calibri.ttf... 8525920 7081126 4118548 2767358 1 done.
Can't find (or can't open) font file %rom%Resource/Font/BravuraText.
Can't find (or can't open) font file BravuraText.
Loading BravuraText font from C:/Windows/Fonts/BravuraText.otf... 9545496 7985907 8185868 6762307 1 done.
GPL Ghostscript 9.25: Can't embed the complete font BravuraText as it is too large, embedding a subset.
Main

这是最小的PostScript程序:

%!PS-Adobe-3.0
%%Title: unicode.ps
%%LanguageLevel: 3
%%EndComments


%%BeginProlog

userdict begin

%%EndProlog


%%BeginSetup

/mm { 25.4 div 72 mul } bind def
/A4Landscape [297 mm 210 mm] def
/PageSize //A4Landscape def
<< /PageSize PageSize >> setpagedevice


% ‘‘ReEncodeSmall’’ generates a new re-encoded font. It
% takes 3 arguments: the name of the font to be
% re-encoded, a new name, and an array of new character
% encoding and character name pairs (see the definition of
% the ‘‘scandvec’’ array below for the format of this
% array). This method has the advantage that it allows the
% user to make changes to an existing encoding vector
% without having to specify an entire new encoding
% vector. It also saves space when the character encoding
% and name pairs array is smaller than an entire encoding
% vector.

% Usage: /Times-Roman /Times-Roman-Scand scandvec new-font-encoding

/new-font-encoding { <<>> begin
    /newcodesandnames exch def
    /newfontname exch def
    /basefontname exch def

    /basefontdict basefontname findfont def     % Get the font dictionary on which to base the re-encoded version.
    /newfont basefontdict maxlength dict def    % Create a dictionary to hold the description for the re-encoded font.

    basefontdict 
        { exch dup /FID ne      % Copy all the entries in the base font dictionary to the new dictionary except for the FID field.
            { dup /Encoding eq
                { exch dup length array copy    % Make a copy of the Encoding field.
                    newfont 3 1 roll put }
                { exch newfont 3 1 roll put }
                ifelse
            }
            { pop pop }         % Ignore the FID pair.
            ifelse
        } forall

    newfont /FontName newfontname put   % Install the new name.
    newcodesandnames aload pop      % Modify the encoding vector. First load the new encoding and name pairs onto the operand stack.
    newcodesandnames length 2 idiv
        { newfont /Encoding get 3 1 roll put}
        repeat  % For each pair on the stack, put the new name into the designated position in the encoding vector. 
    newfontname newfont definefont pop      % Now make the re-encoded font description into a POSTSCRIPT font. Ignore the modified dictionary returned on the operand stack by the definefont operator.
end} def


/Calibri /TextFont [
    16#41   /Scaron     % A (/Scaron Š U+0160)
    16#42   /quarternote                % B U+2669
    16#43   /musicalnote                % C
    16#44   /eighthnotebeamed           % D
    16#45   /musicalnotedbl             % E
    16#46   /beamedsixteenthnotes       % F
    16#47   /musicflatsign              % G
    16#47   /musicsharpsign             % H U+266F
] new-font-encoding

% https://github.com/steinbergmedia/bravura
% The Unicode code point for a G (treble) clef in Bravura Text is U+E050
% http://www.smufl.org/files/smufl-0.9.pdf
% p48 Clefs (U+E050–U+E07F)
% U+E050 (and U+1D11E) gClef G clef 
% http://www.jdawiseman.com/papers/trivia/character-entities.html
/Bravura /MusicFont [
    16#41   /gClef                      % A
    16#42   /quarternote                % B U+2669
    16#43   /musicalnote                % C
    16#44   /eighthnotebeamed           % D
    16#45   /musicalnotedbl             % E
    16#46   /beamedsixteenthnotes       % F
    16#47   /musicflatsign              % G
    16#47   /musicsharpsign             % H U+266F
] new-font-encoding

/MusicFont findfont 48 scalefont setfont

%%EndSetup


%%BeginScript

%% Main
(Main\n) print
<<>>begin
    /TextFont findfont 48 scalefont setfont
    0 setgray
    72 72 moveto
    (@ABCDEFGHIJKL) show

    0 72 translate

    /MusicFont findfont 48 scalefont setfont
    0 setgray
    72 72 moveto
    (@ABCDEFGHIJKL) show
end
showpage

%%EndScript

%%Trailer
%%EOF

1 个答案:

答案 0 :(得分:2)

第一个问题是如何定义Bravura和Calibri。这些字体不是标准Ghostscript安装的一部分,因此必须以某种方式添加它们,可能通过fontconfig(在Linux上)进行添加,但是我看到您正在使用Windows(从路径名开始)。您如何添加字体?

现在(再次从上个频道消息中)您正在加载TrueType字体,并将它们用作丢失的PostScript字体的替代品。这是一项非标准功能,因此Ghostscript必须进行大量猜测才能尝试从TrueType字体创建Type 42字体(带有TrueType轮廓的PostScript字体)。尽管现在情况还不错,但不能保证它会做对。

顺便说一下,这与Unicode无关:-)

在PostScript中,您要为每个要显示的字符使用一个字符代码。在您的情况下,您已连续使用0x40(@)至0x4C(L)。渲染字形时,解释器获取字符代码,并在该位置查找“编码”。请注意,您的编码数组仅包含从0x41到0x47的条目,因此代码0x48到0x4C将是未定义的。

让我们考虑一下您的“文字字体”,即Calibri。在“编码”中的位置0x41,您具有字形名称“ Scaron”。因此,解释器然后查询字体的CharStrings字典。 CharStrings词典包含键/值对,键(在本例中为名称),值是定义如何呈现字形的可执行程序。

因此,解释器在CharStrings词典中查找名为/ Scaron的键,然后执行与其关联的程序。如果找不到键/ Scaron,则会查找键/.notdef(需要所有字体都必须具有.notdef),然后执行该键。

您实际上并没有说出要做什么。我假设存在问题,因为您已经发布了一个问题(该问题似乎没有包含任何实际问题...。),但您没有说它是什么。如果您得到的是空心矩形而不是期望的字形,那是因为解释程序正在执行/.notdef,对于TrueType字体,它通常是一个矩形(PostScript字体通常具有完全空白的.notdef,但是两种字体类型都可以包含它们想要)

在这种情况下,问题是您使用了CharStrings词典中不存在的字形名称(例如/ muscialnote)。除非TrueType字体具有POST表(大多数情况下没有),否则这并不奇怪,因为/ musicalnote是字形的非常不标准的名称。

如果我将Calibri添加到fontmap.GS,然后执行以下操作:

%!
/Calibri findfont /CharStrings get {== ==} forall

然后我看到很多表单:

0 / _6756 0 / _6689

这些将名称(例如/ _6576)映射到TrueType GID。使用TrueType字体时,Ghostscript需要GID,以便它可以从GLYF表中找到该字体中的字形程序。当定义TrueType字体用作类型42时,这是Ghostscript必须尝试自己创建的(此字典定义了真正的Type 42字体作为字体的一部分)。它是如何实现的是启发式的,即猜测很多。

在这种情况下,GID为0,这是.notdef字形的TrueType保留GID,因此这些名称都将映射到.​​notdef。

我还看到了许多条目,例如:

4 / A

这些(显然)是您可以使用的字形,在这种情况下,名称/ A映射到GID4。检查输出,没有名称'quarternote,'musicalnote'等。有一个Scaron,所以我期望您的'@'字符将呈现为带有重音符号的大写字母S。其余字形将呈现为空正方形,或完全不显示。这里的测试(有趣地)显示了一个带有问号的矩形。

现在,Calibri字体可能包含所需的字形,如果确实如此,那么恐怕访问它们的唯一方法(从PostScript)是识别Ghostscript与该字形关联的名称。 Bravura字体也是如此。

进行一些PostScript编程(似乎您胜任编写该文件)可以使您从字体中检索CharStrings字典,对其进行迭代,并构建一个包含所有非零名称的数组。值。然后,您可以打印一个页面(可能有很多页面),在该页面中您可以从字体中打印命名的字形,并在其下方打印与该字形关联的名称。有您的地图,现在您可以构建一个Encoding,将字形名称映射到要在PostScript程序中使用以绘制该字形的字符代码。

当我尝试使用Bravura(这是OpenType字体,而不是TrueType字体)时,FWIW在加载字体时出现语法错误。对于BravuraText也是如此。