How to add overlay text with link annotations to existing pdf?
我想在我的叠加文本中添加一个链接。我已经读过,使用
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | int n = reader.getNumberOfPages(); // step 4: we add content PdfImportedPage page; PdfCopy.PageStamp st for (int j = 0; j < n; ) { ++j; page = writer.getImportedPage(reader, j); if (i == 1) { stamp = writer.createPageStamp(page); Rectangle mediabox = reader.getPageSize(j); Rectangle crop = new Rectangle(mediabox); writer.setCropBoxSize(crop); // add overlay text Paragraph p = new Paragraph(); p.setAlignment(Element.ALIGN_CENTER); FONT_URL_OVERLAY.setColor(0, 191, 255); // get current user EPerson loggedin = context.getCurrentUser(); String eperson = null; if (loggedin != null) { eperson = loggedin.getFullName(); } else eperson ="Anonymous"; Phrase downloaded = new Phrase(); Chunk site = new Chunk("My Website",FONT_URL_OVERLAY); site.setAction(new PdfAction("http://www.mywebsite.com")); downloaded.add(new Chunk("Downloaded by [" + eperson +"] from", FONT_OVERLAY)); downloaded.add(site); downloaded.add(new Chunk(" on", FONT_OVERLAY)); downloaded.add(new Chunk(new SimpleDateFormat("MMMM d, yyyy").format(new Date()), FONT_OVERLAY)); downloaded.add(new Chunk(" at", FONT_OVERLAY)); downloaded.add(new Chunk(new SimpleDateFormat("h:mm a z").format(new Date()), FONT_OVERLAY)); p.add(downloaded); ColumnText.showTextAligned(stamp.getOverContent(), Element.ALIGN_CENTER, p, crop.getLeft(10), crop.getHeight() / 2 + crop.getBottom(), 90); stamp.alterContents(); } writer.addPage(page); } |
所以我的叠加层看起来像这样:
Downloaded by [Anonymous] from My Website on February 17, 2015 at 1:20 AM CST
如何将"我的网站"转换为链接注释?在 SO 中搜索,我找到了这篇文章,但我不知道如何将添加链接注释应用到我的覆盖文本的一部分。
提前致谢。
编辑:如何将带有链接注释的旋转覆盖文本添加到现有 pdf?
感谢 Bruno Lowagie 竭尽全力回答我的问题。虽然我最初询问如何将覆盖文本中的链接注释添加到现有 pdf,但他还在他的答案的评论部分中解决了我的问题,即如果覆盖文本被旋转,则正确设置坐标。
您正在使用
这在 AddLinkAnnotation2 示例中显示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); PdfContentByte canvas = stamper.getOverContent(1); Font bold = new Font(FontFamily.HELVETICA, 12, Font.BOLD); Chunk chunk = new Chunk("The Best iText Questions on StackOverflow", bold); chunk.setAnchor("http://pages.itextpdf.com/ebook-stackoverflow-questions.html"); Phrase p = new Phrase("Download"); p.add(chunk); p.add(" and discover more than 200 questions and answers."); ColumnText ct = new ColumnText(canvas); ct.setSimpleColumn(36, 700, 559, 750); ct.addText(p); ct.go(); stamper.close(); reader.close(); } |
在这种情况下,我们为
如果您检查结果,link_annotation2.pdf,您会注意到您可以单击粗体字。
没有计划在
更新 1:在评论部分,您提出了一个关于旋转内容和链接的附加问题。
旋转内容并不困难。有不止一种方法可以做到这一点。旋转链接并非易事,因为链接是一种注释,而注释不是内容的一部分。
我们先来看看AddLinkAnnotation3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 6); stamper.getWriter().setPageEvent(new AddAnnotation(stamper, transform)); PdfContentByte canvas = stamper.getOverContent(1); Font bold = new Font(FontFamily.HELVETICA, 12, Font.BOLD); Chunk chunk = new Chunk("The Best iText Questions on StackOverflow", bold); chunk.setGenericTag("http://pages.itextpdf.com/ebook-stackoverflow-questions.html"); Phrase p = new Phrase("Download"); p.add(chunk); p.add(" and discover more than 200 questions and answers."); canvas.saveState(); canvas.concatCTM(transform); ColumnText ct = new ColumnText(canvas); ct.setSimpleColumn(300, 0, 800, 400); ct.addText(p); ct.go(); canvas.restoreState(); stamper.close(); reader.close(); } |
在这个例子中,我们定义了一个 30 度的变换 (
1 |
我们在渲染列时使用这个转换:
1 2 3 4 | canvas.saveState(); canvas.concatCTM(transform); // render column canvas.restoreState(); |
这会旋转内容,但我们还没有添加任何注释。相反,我们定义了一个页面事件:
1 | stamper.getWriter().setPageEvent(new AddAnnotation(stamper, transform)); |
我们引入了一个通用标签:
1 | chunk.setGenericTag("http://pages.itextpdf.com/ebook-stackoverflow-questions.html"); |
为了添加注解,我们在页面事件实现中使用了一些魔法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class AddAnnotation extends PdfPageEventHelper { protected PdfStamper stamper; protected AffineTransform transform; public AddAnnotation(PdfStamper stamper, AffineTransform transform) { this.stamper = stamper; this.transform = transform; } @Override public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) { float[] pts = {rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}; transform.transform(pts, 0, pts, 0, 2); float[] dstPts = {pts[0], pts[1], pts[2], pts[3]}; rect = new Rectangle(dstPts[0], dstPts[1], dstPts[2], dstPts[3]); PdfAnnotation annot = PdfAnnotation.createLink(writer, rect, PdfAnnotation.HIGHLIGHT_INVERT, new PdfAction(text)); stamper.addAnnotation(annot, 1); } } |
我们创建了一个注解,但在我们这样做之前,我们对矩形进行了转换。这可以确保文本与需要可点击的文本相匹配,但是......这可能不是您所期望的:
您可能希望旋转矩形,这是可能的,但更多的是数学运算。例如:您可以创建一个更适合的多边形:ITextShape Clickable Polygon or path
幸运的是,您不需要 30 度角,您希望将文本旋转 90 度角。在这种情况下,您就没有上面屏幕截图中显示的奇怪效果了。
看看 AddLinkAnnotation4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class AddAnnotation extends PdfPageEventHelper { protected PdfStamper stamper; protected AffineTransform transform; public AddAnnotation(PdfStamper stamper, AffineTransform transform) { this.stamper = stamper; this.transform = transform; } @Override public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) { float[] pts = {rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop()}; transform.transform(pts, 0, pts, 0, 2); float[] dstPts = {pts[0], pts[1], pts[2], pts[3]}; rect = new Rectangle(dstPts[0], dstPts[1], dstPts[2], dstPts[3]); PdfAnnotation annot = PdfAnnotation.createLink(writer, rect, PdfAnnotation.HIGHLIGHT_INVERT, new PdfAction(text)); annot.setBorder(new PdfBorderArray(0, 0, 0)); stamper.addAnnotation(annot, 1); } } |
如您所见,我添加了一行来移除边框(默认情况下,边框在那里,除非您重新定义
其余代码也几乎相同。我们现在定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public void manipulatePdf(String src, String dest) throws IOException, DocumentException { PdfReader reader = new PdfReader(src); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest)); AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 2); stamper.getWriter().setPageEvent(new AddAnnotation(stamper, transform)); PdfContentByte canvas = stamper.getOverContent(1); Font bold = new Font(FontFamily.HELVETICA, 12, Font.BOLD); Chunk chunk = new Chunk("The Best iText Questions on StackOverflow", bold); chunk.setGenericTag("http://pages.itextpdf.com/ebook-stackoverflow-questions.html"); Phrase p = new Phrase("Download"); p.add(chunk); p.add(" and discover more than 200 questions and answers."); canvas.saveState(); canvas.concatCTM(transform); ColumnText ct = new ColumnText(canvas); ct.setSimpleColumn(36, -559, 806, -36); ct.addText(p); ct.go(); canvas.restoreState(); stamper.close(); reader.close(); } |
注意页面的左下角是轴心点,因此我们需要调整我们添加列的坐标,否则你会旋转页面可见区域之外的所有内容。
更新 2:
在另一条评论中,您询问在旋转坐标系中添加文本时需要使用的坐标。
我画了这幅画:
在顶部,您在页面中间添加了 MIDDLE 一词,但这不是它出现的位置:您将所有内容旋转 90 度,因此 MIDDLE 一词将在您的页面之外旋转(进入阴影区域)。该词将在 PDF 中,但您永远不会看到它。
如果您查看我的代码,您会发现我使用了这些坐标:
1 | ct.setSimpleColumn(36, -559, 806, -36); |
这是在可见区域之外(它低于实际页面尺寸),但是当我将所有内容旋转 90 度时,它会旋转到可见区域中。
如果你看我的图,你可以看到坐标为 (0, 0), (0, -595), (842, -598) 和 (842, 0) 的页面旋转了 90 度,因此得到与坐标为 (0, 0)、(595, 0)、(595, 842) 和 (0, 842) 的页面重合。这就是我们在高中时都学过的数学类型;-)
您在
了解原因的最好方法是画一幅画。