如何使用链接注释向现有pdf添加叠加文本?

我想在我的叠加文字中添加一个链接。 我已经读过,使用Anchor只适用于从头开始制作的文档,但不适用于现有的pdf文件。 我的代码是为每个页面添加叠加文本。 我的目标是使该文本的一部分可以点击。 我不知道如何制作链接注释,这是一个短语的一部分。

这是我的代码:

  int n = reader.getNumberOfPages(); // step 4: we add content PdfImportedPage page; PdfCopy.PageStamp stamp; 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 az").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); } 

所以我的叠加层看起来像这样:

2015年2月17日上午1:20从我的网站 [匿名]下载

如何将我的网站转换为链接注释? 在这里搜索,我找到了这篇文章 ,但我不知道如何将链接注释添加到我的叠加文本的一部分。

提前致谢。

编辑:如何添加带有链接注释的旋转叠加文本到现有的pdf?
感谢Bruno Lowagie在回答我的问题时不遗余力 。 虽然我最初询问如何在叠加文本中添加链接注释到现有的pdf,但他也在他的答案的评论部分提供了我的问题,如果旋转叠加文本,则正确设置坐标。

您正在使用ColumnText.showAligned() ,这足以添加一行没有任何特殊function的文本,但如果您希望锚点工作,则需要以不同方式使用ColumnText

这在AddLinkAnnotation2示例中显示:

 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(); } 

在这种情况下,我们为ColumnText对象定义一个矩形,我们将Phrase添加到列中,然后我们go()

如果检查结果link_annotation2.pdf ,您会注意到可以单击粗体字。

没有计划在ColumnText.showTextAligned()支持这一点。 这是一种方便的方法,可以用作上面显示的少数几行的快捷方式,但是有一些已知的限制:线条没有被包裹,交互性被忽略,……

更新1:在评论部分,您询问了有关轮播内容和链接的其他问题。

旋转内容并不困难。 这样做的方法不止一种。 旋转链接并非易事,因为链接是一种注释,注释不是内容的一部分。

我们先来看看AddLinkAnnotation3 :

 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度的转换( Math.PI / 6 ):

 AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 6); 

我们在渲染列时使用此转换:

 canvas.saveState(); canvas.concatCTM(transform); // render column canvas.restoreState(); 

这会旋转内容,但我们还没有添加任何注释。 相反,我们定义一个页面事件:

 stamper.getWriter().setPageEvent(new AddAnnotation(stamper, transform)); 

我们引入了一个通用标签:

 chunk.setGenericTag("http://pages.itextpdf.com/ebook-stackoverflow-questions.html"); 

要添加注释,我们在页面事件实现中使用了一些魔术:

 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或path

幸运的是,您不需要30度的角度,您希望以90度的角度旋转文本。 在这种情况下,您没有上面屏幕截图中显示的奇怪效果。

看一下AddLinkAnnotation4

 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); } } 

如您所见,我添加了一行来删除边框(除非您重新定义PdfBorderArray否则默认情况下会出现PdfBorderArray )。

其余代码也几乎相同。 我们现在定义一个Math.PI / 2 (90度)的角度。

 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中,但你永远不会看到它。

如果你查看我的代码,你会看到我使用这些坐标:

 ct.setSimpleColumn(36, -559, 806, -36); 

这是在可见区域之外 (它在实际页面尺寸之下),但是当我将所有内容旋转90度时,它会旋转到可见区域

如果你看一下我的绘图,你可以看到坐标为(0,0),(0,-595),(842,-598)和(842,0)的页面旋转90度,从而得到与之重合的页面。具有坐标(0,0),(595,0),(595,842)和(0,842)的页面。 那是我们在高中时学到的数学类型;-)

您正在crop.getLeft(10), crop.getHeight() / 2 + crop.getBottom()位置添加文本。 如果您知道文本将旋转90度,则应使用crop.getHeight() / 2 + crop.getBottom(), -crop.getLeft()

了解原因的最佳方法是制作图纸。