java/pdf文本呈现

Ale*_*xxx 2 java pdf fonts text

我正在研究自己的pdf生成lib的Java,我遇到了一些字体/文本渲染问题.Java中显示的文本(字体,字间距,字符间距等)与PDF中显示的文本不同.

在我的下面的例子中,我使用的字体是"Time New Roman",这是PDF基本字体之一(所以我没有计算并将所有字体指标输出到pdf中).

具体来说,在我生成的PDF中,我有这样的:

BT
/F5 16 Tf
849 921 Td
(Normal Return Distribution) Tj
ET
Run Code Online (Sandbox Code Playgroud)

并且字体F5由对象29 0 R定义,它是(仅基本的,因此没有指定文本度量):

29 0 obj <</Type /Font /Subtype /Type1 /BaseFont /Times-Roman>>
endobj
Run Code Online (Sandbox Code Playgroud)

在Java中,我正在使用:

g2d.setFont(new Font("TimesRoman", Font.PLAIN, 16));
g2d.drawString("Normal Return Distribution", 849, 921);
Run Code Online (Sandbox Code Playgroud)

我已经将文本绘制成与文本边界匹配的矩形,并且在Java中它都可以(我在java中计算字符串边界),但在adobe acrobat reader中,文本比矩形大.

这是一个截图(我通过截取Adobe Acrobat Reader的屏幕截图显示我的PDF,并截取我的程序显示缓冲图像的截图;然后将pdf屏幕截图的部分复制/粘贴到我的矩形下面来构建它程序截图到MSPaint.为了具有相同的矩形大小,我必须以原始大小的65.5%在Adobe中显示pdf:

Java与PDF文本输出

所以我们可以看到java en adobe中用来显示文本的字体是一样的.但是Adobe的文字看起来有点大.事实上,如果我叠加两个单词(一个来自java在adobe的一个上面),似乎单词间距是相同的,字母间距也是,但是一些字母有1个像素宽度差异.

为什么?我能做些什么来解决这个问题?我尝试使用字符间距(Tc运算符),字间距(Tw运算符),水平缩放(Tz运算符)来播放(pdf格式); 我认为它可以"奏效"; 但为什么两个程序中的缩放/间距/ ...不一样?这些(默认)参数不是Font文件的一部分(这是真正的类型)?以及如何正确检索它们(不手动将参数放入我的java代码中)?

谢谢

编辑

因此,正如您已经解释过的那样,我正在调查不使用pdf基本字体以确保Java和Adobe Reader使用相同的字体(ttf文件).但我有一个问题(同样的?).

在PDF输出中,我正在生成这样的字体:

31 0 obj <<
/Type /Font
/FirstChar 0
/LastChar 255
/Widths[1298 ... 646]
/Name /F7
/Encoding /WinAnsiEncoding
/Subtype /TrueType /BaseFont /Tahoma /FontDescriptor 32 0 R
>>
endobj

32 0 obj <<
/Type /FontDescriptor
/Ascent 1299
/CapHeight 1298
/Descent -269
/Flags 32
/FontBBox [0 -269 2012 1299]
/FontName /Tahoma
/ItalicAngle 0
/StemV 126
/XHeight 1298
>>
endobj
Run Code Online (Sandbox Code Playgroud)

如果我正确理解了规范,所有数字(宽度,上升,下降,......)都是相对于字形单位(基于1em?),其中1em = 1000(而1em是M字符的宽度).

所以要从java生成所有这些参数,我首先尝试找到正确的java字体大小,使M字符的宽度等于1000(因为Java不允许访问Font类或其他类中的这些参数;以及即使这些信息进入ttf文件,PDF也需要它.).

float size = 1f;
while (true) {
    font = font.deriveFont(size);
    fm = g2d.getFontMetrics(font);
    int em = fm.charWidth('M');
    if (em >= 1000)
        break ;
    size += 1;
}
Run Code Online (Sandbox Code Playgroud)

然后我可以生成所有必需的参数.例如,对于Widths数组(每个字符的宽度):

String pdfWidths = "";
for (int i = 0; i <= 255; ++i) {
    int width = fm.charWidth(i);
    pdfWidths += width + " ";
}
Run Code Online (Sandbox Code Playgroud)

但是这样做,我的文本仍然与Adobe Viewer中的矩形重叠.所以我必须将我的EM限制(进入我的暴力循环)设置为Tahoma字体的780; 对于Verdana字体为850; ...显示类似的文本(不完全相同,但也许是由于抗锯齿算法?)(见下面的截图).所以它不是一个恒定的"限制"(必须在理论上等于1000),但变量限制......是正确的吗?(我想不)如果是的话,如何找到这个限制?如果没有,有什么不对?

Java与PDF文本输出 -  EM

再次感谢.

编辑

简单地将字体大小设置为1000并且没有强制执行以找到EM/Line高度大小,pdf中的结果实际上是java.

font = font.deriveFont(1000f);
fm = g2d.getFontMetrics(font);
//Retrieve Widths attribute
_pdfWidths = "";
for (int i = _firstChar; i <= _lastChar; ++i) {
    int width = fm.charWidth(i);
    _pdfWidths += width + " ";
}
Run Code Online (Sandbox Code Playgroud)

但是仍然存在一些差异,也许是由于文本绘图算法(字距调整可能与java和adobe reader不同?).如下图所示,我们可以看到Verdana的文本在pdf中比在java中略小(宽度).

Java与PDF文本输出 -  1000

mkl*_*mkl 5

这个答案基本上是我的评论综述.

第一次尝试使用字体"Time New Roman"(实际上是Times-Roman),这是PDF基本字体之一(不是为PDF计算和输出所有字体度量)和Java的"TimesRoman" AWT,导致了

尝试使用标准的14次Times-Roman

基本上:您的应用程序使用Java AWT认为TimesRoman在16pt时以其自己的方式应用字体度量标准的内容; 您的PDF查看器使用它Times-Roman在16个用户空间单位中考虑的内容,应用PDF规范中指定的字体指标.所有你可以期待的是一些相似之处(否则其中一个上下文会做出一个非常糟糕的选择),但根本不是.

大卫实际上在他的答案中更详细地解释了第1项(不同的字体)和第3项(字距调整和替换的不同应用).

此外,

顺便说一句:从PDF 1.5开始,不推荐对标准14字体给予特殊处理.(ISO 32000-1中的第9.6.2.1节).因此,通过不在PDF中明确包含字体度量,您可以执行已弃用多年的事情.

下一次尝试不使用pdf基本字体来确保Java和Adobe Reader使用相同的字体(ttf文件),需要计算嵌入PDF中的字符宽度.在这种情况下,假设所有数字(宽度,上升,下降,......)都相对于字形单位(基于1em?),其中1em = 1000(并且1em是M字符的宽度).因此,尝试找到正确的java字体大小,使M字符的宽度等于1000,然后从该字体生成所有必需参数.

不,不是基于em,而是:字体定义一个标准尺寸的字形.安排该标准使得紧密间隔的文本行的标称高度为1个单位.因此,1000个字形空间单位是该标称线的高度.

这导致了一个问题究竟是什么"名义线".幸运的是,反过来更容易接近:根据定义,大小为1的字体是"标称线"的高度为1的字体.因此,

不应在宽度阵列来填充1000 * fm.charWidth(i)其中fm的字体的大小在1指标?或者,如AWT的作品与诠释的宽度,与fm.charWidth(i)在那里fm的字体的指标在大小1000?

考虑到这一点,只需将字体大小设置为1000并且没有强制执行以找到EM/Line高度大小,pdf中的结果实际上是java.但是仍然存在一些差异,也许是由于文本绘图算法(字距调整可能与java和adobe reader不同?).如下图所示,我们可以看到Verdana的文本在pdf中比在java中略小(宽度).

尝试使用嵌入字体和正确的字符宽度

看一下FontMetrics.charWidth方法注释:注意String的前进不一定是其字符前进的总和.AWT还应用了字距调整等,导致轻微的偏差.但是,在PDF中,使用单个Tj操作,这些进步确实会增加.

如果要在PDF中使用字距调整,则必须明确写出标准宽度的偏差.这里的TJ运算符非常方便,允许使用字符串和偏移的混合数组作为参数.

如果你想用连字替换某些字符,你也必须自己做