该问题是由 PDF Clown 中的错误引起的:它假定标记的内容部分和保存/恢复图形状态块正确包含在彼此中并且不重叠。即它假设这些结构仅混合为
begin-marked-content
save-graphics-state
restore-graphics-state
end-marked-content
或者
save-graphics-state
begin-marked-content
end-marked-content
restore-graphics-state
但从来没有像
save-graphics-state
begin-marked-content
restore-graphics-state
end-marked-content
或者
begin-marked-content
save-graphics-state
end-marked-content
restore-graphics-state.
不幸的是,这个假设是错误的,标记的内容部分和保存/恢复图形状态块可以以他们喜欢的任何方式混合。
例如,在手头的文档中有这样的序列:
q
[...1...]
/P <</MCID 0 >>BDC
Q
[...2...]
EMC
这里[...1...]
包含在 和 包围的保存/恢复图形状态块中q
并且包含在Q
和[...2...]
包围的标记内容块/P <</MCID 0 >>BDC
中EMC
。
但是,由于错误的假设/P <</MCID 0 >>BDC
以及Q
排列方式,PDF Clown 将上述内容解析为[...1...]
空的标记内容块,[...2...]
并包含在保存/恢复图形状态块中。
因此,如果 内部的图形状态发生变化[...2...]
,PDF Clown 会假定它们仅限于上述行,而实际上并非如此。
我发现修复此问题的唯一简单方法是禁用 PDF Clown 中的标记内容解析。
为此,我进行了org.pdfclown.documents.contents.tokens.ContentParser
如下更改:
在parseContentObjects()
我禁用了该contentObject instanceof EndMarkedContent
选项:
public List<ContentObject> parseContentObjects(
)
{
final List<ContentObject> contentObjects = new ArrayList<ContentObject>();
while(moveNext())
{
ContentObject contentObject = parseContentObject();
// Multiple-operation graphics object end?
if(contentObject instanceof EndText // Text.
|| contentObject instanceof RestoreGraphicsState // Local graphics state.
/* || contentObject instanceof EndMarkedContent // End marked-content sequence. */
|| contentObject instanceof EndInlineImage) // Inline image.
return contentObjects;
contentObjects.add(contentObject);
}
return contentObjects;
}
在parseContentObject
我删除了if(operation instanceof BeginMarkedContent)
分支:
public ContentObject parseContentObject(
)
{
final Operation operation = parseOperation();
if(operation instanceof PaintXObject) // External object.
return new XObject((PaintXObject)operation);
else if(operation instanceof PaintShading) // Shading.
return new Shading((PaintShading)operation);
else if(operation instanceof BeginSubpath
|| operation instanceof DrawRectangle) // Path.
return parsePath(operation);
else if(operation instanceof BeginText) // Text.
return new Text(
parseContentObjects()
);
else if(operation instanceof SaveGraphicsState) // Local graphics state.
return new LocalGraphicsState(
parseContentObjects()
);
/* else if(operation instanceof BeginMarkedContent) // Marked-content sequence.
return new MarkedContent(
(BeginMarkedContent)operation,
parseContentObjects()
);
*/ else if(operation instanceof BeginInlineImage) // Inline image.
return parseInlineImage();
else // Single operation.
return operation;
}
随着这些变化的到位,字符大小被正确提取。
顺便说一句,虽然返回的单个字符框似乎暗示该框是完全针对所讨论的字符自定义的,但事实并非如此:仅仅框的宽度是特定于字符的,高度是根据整体字体属性计算的(以及当前字体大小)但不是专门针对字符的,参见。org.pdfclown.documents.contents.fonts.Font
方法getHeight(char)
:_
/**
Gets the unscaled height of the given character.
@param textChar
Character whose height has to be calculated.
*/
public final double getHeight(
char textChar
)
{
/*
TODO: Calculate actual text height through glyph bounding box.
*/
if(textHeight == -1)
{textHeight = getAscent() - getDescent();}
return textHeight;
}
单个字符高度计算仍然是一个TODO。