我遇到了一个非常棘手的问题。我们有一些本来应该填写的html" target="_blank">表单,但有些人在foxit中使用了注释自由格式文本注释,而不是填写表单字段,所以注释永远不会变平。当我们的渲染软件生成最终文档时,注释并不包括在内。
我尝试的解决方案是,基本上遍历文档,获取注释文本内容,并将其写入pdf,这样它就在最终文档上,然后删除实际的注释,但我遇到了一个问题,我不知道注释使用的字体、行空间等,因此无法找到如何从pdfbox获取它,以便在未展平的表单上精确地重新创建注释。基本上,我想要扁平化在foxit(打字机注释功能)中创建的自由形式的注释,这里是代码。它是工作的,但再次我挣扎于弄清楚如何得到注释写到我的最终pdf文档。再一次,压扁在顶形是不起作用的,因为这些不是顶形场!活动代码过滤掉任何不是freetext类型注释的内容,但下面的代码应该显示我的问题。
public static void main(String [] args)
{
String startDoc = "C:/test2/test.pdf";
String finalFlat = "C:/test2/test_FLAT.pdf";
try {
// for testing
try {
//BasicConfigurator.configure();
File myFile = new File(startDoc);
PDDocument pdDoc = PDDocument.load( myFile );
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
// set the NeedApperances flag
pdAcroForm.setNeedAppearances(false);
// correct the missing page link for the annotations
for (PDPage page : pdDoc.getPages()) {
for (PDAnnotation annot : page.getAnnotations()) {
System.out.println(annot.getContents());
System.out.println(annot.isPrinted());
System.out.println(annot.isLocked());
System.out.println(annot.getAppearance().toString());
PDPageContentStream contentStream = new PDPageContentStream(pdDoc, page, PDPageContentStream.AppendMode.APPEND,true,true);
int fontHeight = 14;
contentStream.setFont(PDType1Font.TIMES_ROMAN, fontHeight);
float height = annot.getRectangle().getLowerLeftY();
String s = annot.getContents().replaceAll("\t", " ");
String ss[] = s.split("\\r");
for(String sss : ss)
{
contentStream.beginText();
contentStream.newLineAtOffset(annot.getRectangle().getLowerLeftX(),height );
contentStream.showText(sss);
height = height + fontHeight * 2 ;
contentStream.endText();
}
contentStream.close();
page.getAnnotations().remove(annot);
}
}
pdAcroForm.flatten();
pdDoc.save(finalFlat);
pdDoc.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
catch (Exception e) {
System.err.println("Exception: " + e.getLocalizedMessage());
}
}
这不是一个有趣的。经过一百万次不同的测试,我仍然不理解所有的细微差别,但这是一个版本,呼吁扁平所有pdf文件和注解,如果他们在pdf上可见。测试了大约六个pdf Creator,如果一个注释在页面上是可见的,这有望使它扁平化。我怀疑有一个更好的方法,通过拉矩阵,并转换它和其他什么,但这是唯一的方法,我让它工作在任何地方。
public static void flattenv3(String startDoc, String endDoc) {
org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.INFO);
String finalFlat = endDoc;
try {
try {
//BasicConfigurator.configure();
File myFile = new File(startDoc);
PDDocument pdDoc = PDDocument.load(myFile);
PDDocumentCatalog pdCatalog = pdDoc.getDocumentCatalog();
PDAcroForm pdAcroForm = pdCatalog.getAcroForm();
if (pdAcroForm != null) {
pdAcroForm.setNeedAppearances(false);
pdAcroForm.flatten();
}
// set the NeedApperances flag
boolean isContentStreamWrapped;
int ii = 0;
for (PDPage page: pdDoc.getPages()) {
PDPageContentStream contentStream;
isContentStreamWrapped = false;
List < PDAnnotation > annotations = new ArrayList < > ();
for (PDAnnotation annotation: page.getAnnotations()) {
if (!annotation.isInvisible() && !annotation.isHidden() && annotation.getNormalAppearanceStream() != null)
{
ii++;
if (ii > 1) {
// contentStream.close();
// continue;
}
if (!isContentStreamWrapped) {
contentStream = new PDPageContentStream(pdDoc, page, AppendMode.APPEND, true, true);
isContentStreamWrapped = true;
} else {
contentStream = new PDPageContentStream(pdDoc, page, AppendMode.APPEND, true);
}
PDAppearanceStream appearanceStream = annotation.getNormalAppearanceStream();
PDFormXObject fieldObject = new PDFormXObject(appearanceStream.getCOSObject());
contentStream.saveGraphicsState();
boolean needsTranslation = resolveNeedsTranslation(appearanceStream);
Matrix transformationMatrix = new Matrix();
boolean transformed = false;
float lowerLeftX = annotation.getNormalAppearanceStream().getBBox().getLowerLeftX();
float lowerLeftY = annotation.getNormalAppearanceStream().getBBox().getLowerLeftY();
PDRectangle bbox = appearanceStream.getBBox();
PDRectangle fieldRect = annotation.getRectangle();
float xScale = fieldRect.getWidth() - bbox.getWidth();
transformed = true;
lowerLeftX = fieldRect.getLowerLeftX();
lowerLeftY = fieldRect.getLowerLeftY();
if (bbox.getLowerLeftX() <= 0 && bbox.getLowerLeftY() < 0 && Math.abs(xScale) < 1) //BASICALLY EQUAL TO 0 WITH ROUNDING
{
lowerLeftY = fieldRect.getLowerLeftY() - bbox.getLowerLeftY();
if (bbox.getLowerLeftX() < 0 && bbox.getLowerLeftY() < 0) //THis is for the o
{
lowerLeftX = lowerLeftX - bbox.getLowerLeftX();
}
} else if (bbox.getLowerLeftX() == 0 && bbox.getLowerLeftY() < 0 && xScale >= 0) {
lowerLeftX = fieldRect.getUpperRightX();
} else if (bbox.getLowerLeftY() <= 0 && xScale >= 0) {
lowerLeftY = fieldRect.getLowerLeftY() - bbox.getLowerLeftY() - xScale;
} else if (bbox.getUpperRightY() <= 0) {
if (annotation.getNormalAppearanceStream().getMatrix().getShearY() < 0) {
lowerLeftY = fieldRect.getUpperRightY();
lowerLeftX = fieldRect.getUpperRightX();
}
} else {
}
transformationMatrix.translate(lowerLeftX,
lowerLeftY);
contentStream.transform(transformationMatrix);
contentStream.drawForm(fieldObject);
contentStream.restoreGraphicsState();
contentStream.close();
}
}
page.setAnnotations(annotations);
}
pdDoc.save(finalFlat);
pdDoc.close();
File file = new File(finalFlat);
// Desktop.getDesktop().browse(file.toURI());
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
System.err.println("Exception: " + e.getLocalizedMessage());
}
}
}
Foxit Reader(福昕阅读器)是一个小巧的 PDF 文档阅读器,完全免费(非开源软件)。有了它,你无须为仅仅阅读PDF文档而下载和安装庞大的Adobe Reader,而且启动快速,无需安装。对中文支持非常好。 全新的Ribbon界面; 支持PDF文档手写签名、插入印章; 更多安全控制包括Foxit DRM内容管理插件; 支持微软AD RMS对PDF文档的安全应用
Foxit PDF Creator是一款虚拟打印机(非开源软件,可免费使用),通过这款虚拟打印机任何支持打印的应用程序可以非常方便、高效地创建生成高品质的PDF文档。和备受大家欢迎的 Foxit Reader一样,Foxit PDF Creator也是基于Foxit同一核心技术研发并设计出来的。 此工具具备有强大的 搜索功能和高效的PDF显示及处理能力,本身体积小巧,运行快速并且 显示精确,可以将
在pdf文件中,在按钮后面的代码中,我有 exit命令在Phantom PDF(旧版本,2.2)中运行良好,但在Foxit Reader(8.3,相当新的版本)中运行不好。那里什么也没有发生。 我还检查了一个旧的Foxit阅读器版本3.3,它在那里按预期工作。 我尝试了“安全性”和“信任管理器”设置,但这些设置并没有改善这种情况。 我想在按下按钮时关闭读卡器。
Blade 中注册路由有 2 种方式,一种是使用 Blade 对象硬编码注册,另一种是通过控制器来管理多个路由。 在前面的 main 函数中我们使用第一种方式注册了一个路由。 上面的写法看起来是很简洁的,也用到java8的语法,但是一般我们编写一个站点的时候会有很多的路由,都放在一个文件中不是很好管理,这时候 Blade 支持你沿用 SpringMvc 的编程习惯,我们可以编写一个控制器,在你的
如果你只需要掌控一个应用的全部的消息和触发的事件,那么使用默认的**/**命名空间即可。如果你想要利用第三方代码,或者分享你的代码给别人,http://socket.io提供了一种命名一个socket的途径。 使用多路由控制一条单一的连接是有好处的。比如下方的示例代码,客户端发起两个WebSocket连接,而服务器端使用多路由技术仅仅只需要建立一个连接。 服务器端(app.js) var io =