经过多次尝试和错误,我终于设法有一些工作-除了字体子集。我这样做的方法是初始化PDFont对象一次使用
try (InputStream fs = PDFService.class.getResourceAsStream("/static/fonts/LiberationSans-Regular.ttf")) {
_font = PDType0Font.load(pddoc, fs, true);
}
然后使用自定义外观流来显示文本。
private void addAnnotation(String name, PDDocument doc, PDPage page, float x, float y, String text) throws IOException {
List<PDAnnotation> annotations = page.getAnnotations();
PDAnnotationRubberStamp t = new PDAnnotationRubberStamp();
t.setAnnotationName(name); // might play important role
t.setPrinted(true); // always visible
t.setReadOnly(true); // does not interact with user
t.setContents(text);
PDRectangle rect = ....;
t.setRectangle(rect);
PDAppearanceDictionary ap = new PDAppearanceDictionary();
ap.setNormalAppearance(createAppearanceStream(doc, t));
ap.getCOSObject().setNeedToBeUpdated(true);
t.setAppearance(ap);
annotations.add(t);
page.setAnnotations(annotations);
t.getCOSObject().setNeedToBeUpdated(true);
page.getResources().getCOSObject().setNeedToBeUpdated(true);
page.getCOSObject().setNeedToBeUpdated(true);
doc.getDocumentCatalog().getPages().getCOSObject().setNeedToBeUpdated(true);
doc.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
}
private PDAppearanceStream createAppearanceStream(final PDDocument document, PDAnnotation ann) throws IOException
{
PDAppearanceStream aps = new PDAppearanceStream(document);
PDRectangle rect = ann.getRectangle();
rect = new PDRectangle(0, 0, rect.getWidth(), rect.getHeight());
aps.setBBox(rect); // set bounding box to the dimensions of the annotation itself
// embed our unicode font (NB: yes, this needs to be done otherwise aps.getResources() == null which will cause NPE later during setFont)
PDResources res = new PDResources();
_fontName = res.add(_font).getName();
aps.setResources(res);
PDAppearanceContentStream apsContent = null;
try {
// draw directly on the XObject's content stream
apsContent = new PDAppearanceContentStream(aps);
apsContent.beginText();
apsContent.setFont(_font, _fontSize);
apsContent.showText(ann.getContents());
apsContent.endText();
}
finally {
if (apsContent != null) {
try { apsContent.close(); } catch (Exception ex) { log.error(ex.getMessage(), ex); }
}
}
aps.getResources().getCOSObject().setNeedToBeUpdated(true);
aps.getCOSObject().setNeedToBeUpdated(true);
return aps;
}
这段代码会运行,但会创建一个带有点而不是实际字符的PDF,我想这意味着字体子集还没有嵌入。而且,我得到以下警告:
在查看了源代码之后,我发现并且我猜我在创建外观流时搞乱了一些东西--不知何故,它与PDDocument没有连接,子集也不能正常继续。注意,当字体完全嵌入时(例如,如果我调用pdtype0font.load,最后一个参数设置为false),上面的代码可以很好地工作
有人能给我一些提示吗?谢谢!
我不知道-我幸运吗?编程中的幸运常常指向一些完全错误或误导的东西。无论如何,如果有人还能给我一个提示,我的耳朵就不止是张着的...
同样,在查看了代码之后,我在pddocument.save()中看到了以下内容:
// subset designated fonts
for (PDFont font : fontsToSubset)
{
font.subset();
}
我正在使用的PDDocument.SaveIncremental()中没有出现这种情况。为了处理代码,在对文档调用saveIncremental()之前,我执行了以下操作:
_font.subset(); // you can see in the beginning of the question how _font is created
_font.getCOSObject().setNeedToBeUpdated(true);
pddoc.saveIncremental(baos);
“...字体的PostScript名称-...-以一个标签开头,后面跟着一个加号(+)。标签正好由六个大写字母组成;字母的选择是任意的,但同一PDF文件中的不同子集必须有不同的标签...”
一旦我开始为我的每个注释调用pdtype0font.load,并在为每个注释创建外观流后调用subset()(当然还有setNeedToBeUpdated),我就看到BaseName属性看起来确实不同了--事实上,2020年版本的Acrobat Reader DC不再抱怨了。
[编辑07/10/2021:即使尝试每页使用一个PDFont对象(这种字体有多个注释),并将其子集一次,在对所有注释的外观调用showText之后,似乎不起作用--似乎子集使用了我传递给第一个showText的字母,而不是其他的,导致第二个、第三个等批注的错误呈现,这些批注可能有第一个批注中不存在的字符--所以我重申,起作用的是对每个单独的批注使用loadFont,然后(在用showText修改外观后,将标记子集期间要使用的字母)对这些字体调用subset()(这将导致字体名称的更改)]
请注意,除了使用iText RUPS检查PDF内容之外,还可以使用Foxit PDF viewer至少确保子集字体名称是不同的。Acrobat Reader DC和PDF-xChange在Properties->Fonts中只显示初始字体名称,如LiberationSans,而不显示6个字母的唯一前缀。
更新19/04/2021我仍在处理这个问题--因为我仍然收到关于臭名昭著的“无法提取嵌入式字体”消息的报告。这条消息的最初原因很可能不是(或者不仅仅是)不同子集具有相同的BaseFont名称这一事实。我观察到的一件事是,在一些计算机上,我使用的邮票注释导致Acrobat Reader DC自动打开所谓的“注释窗格”--有选项可以关闭这种自动的东西(当打开带有注释的PDF时,首选项->注释->显示注释窗格)。当手动或自动打开此窗格时,会出现错误消息(我很想知道为什么相同版本的Acrobat Reader DC对于不同的机器有不同的行为)。我认为Acrobat Reader试图提取字体的完整版本,但失败了,因为它只是一个子集。但是,我想,这与文档的语义内容无关--文档仍然通过“qpdf--check”。我目前正在努力寻找是否有可能限制邮票不允许评论--即某种方法来禁用Acrobat Reader DC中的评论窗格,尽管我没有什么希望。
更新20/04/2021在这里打开了一个新问题
更新:我使用fontforge提取嵌入的字体子组,发现从pdf派生的字体与完整的字体文件完全匹配。所以根本没有使用字体子集。:( 在PDFsharp源代码中,我发现了这个函数 其注释如下:创建一个新的字体图像,该图像是仅包含指定字形的该字体图像的子集。这正是我想在这里用到的。 我不明白的是为什么这个功能似乎没有得到使用时,创建我的PDF。为了使其发挥作用,需要满足哪些标准?
我已将我的Spring应用程序配置如下: 我使用组件扫描来选择@配置。我的问题是Spring会为B注入豆子吗
问题内容: 我需要定义一个切入点,该切入点触发使用自定义注释注释的spring服务的所有方法的执行。我想定义切入点的注释将在另一个注释上。 然后该服务将被注释如下 我尝试使用以下切入点定义,但是仅当@Y在服务本身上时才有效,这意味着它看不到注释在@X上 问题答案: 我在应用程序中有这个确切的需求。我找到了这个答案,但不满意无法完成。 经过更多搜索之后,我发现了用于AspectJ / Spring切
问题内容: 我要呼吁汇率第三方API,但JSON返回不断变化,如果我申请到的转换,它将返回我:,所以如果我的要求来,它将返回我。 我将不得不使用将返回的结果映射到pojo中,是否有任何可行的方法? 我当前的硬编码解决方法: 问题答案: 是具有值的字段的对象。 否是with键/值对。 两者都是正确的,但是由于before的值是动态的(变化的),因此它是您需要的第二种解释。 因此,请勿要求将JSON转
问题内容: 我可以在文件中保留这样的嵌入式注释吗? 我不希望在CSS输出中使用此注释。 问题答案: 在SASS中要考虑两种不同类型的注释。 单行注释将由.scss预处理器删除,并且不会出现在.css文件中。 多行注释是有效的CSS,在从.scss到您的.css文件的转换之间将保留*。 听起来内联注释是您想要的。
(子资源)再次基于构造函数中传入的用户实现为普通的Jersey类。 但是,我的子资源也需要访问字段(如或)。根据Jersey文档,字段不会为子资源注入,因为它们的生命周期未知(文档似乎是真的)。 这对我来说是非常不可原谅的:我真的需要访问这些值。 作为一种解决办法,我目前将这些值作为额外的构造函数参数传递给我的子资源,我认为这一切都不舒服。 我能以某种方式创建这些映射吗? 问题是,我不知道如何在G