如何使用链接注释向现有pdf添加叠加文本? [英] How to add overlay text with link annotations to existing pdf?

查看:313
本文介绍了如何使用链接注释向现有pdf添加叠加文本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



这是我的代码:

  int n = reader.getNumberOfPages(); 
//第4步:我们添加内容
PdfImportedPage页面;
PdfCopy.PageStamp戳;
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);
//添加叠加文本
段落p = new段落();
p.setAlignment(Element.ALIGN_CENTER);
FONT_URL_OVERLAY.setColor(0,191,255);
//获取当前用户
EPerson loggedin = context.getCurrentUser();
String eperson = null;
if(loggedin!= null)
{
eperson = loggedin.getFullName();
}
else eperson =匿名;
短语已下载=新短语();
Chunk site = new Chunk(我的网站,FONT_URL_OVERLAY);
site.setAction(new PdfAction(http://www.mywebsite.com));
downloaded.add(new Chunk(由[,+ eperson +]下载来自,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(已下载);
ColumnText.showTextAligned(stamp.getOverContent(),Element.ALIGN_CENTER,p,
crop.getLeft(10),crop.getHeight()/ 2 + crop.getBottom(),90);
stamp.alterContents();
}
writer.addPage(页);
}

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


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


如何将我的网站转换为链接注释?在这里搜索,我发现了这个

  public class AddAnnotation extends PdfPageEventHelper {
保护PdfStamper压模;
保护AffineTransform转换;

public AddAnnotation(PdfStamper压模,AffineTransform变换){
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 ,否则边框是默认的。)



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

  public void manipulatePdf(String src,String dest)抛出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);
字体粗体=新字体(FontFamily.HELVETICA,12,Font.BOLD);
Chunk chunk = new Chunk(StackOverflow上最好的iText问题,粗体);
chunk.setGenericTag(http://pages.itextpdf.com/ebook-stackoverflow-questions.html);
短语p =新短语(下载);
p.add(chunk);
p.add(发现200多个问题和答案。);
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(), - cf.getLeft()



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


I would like to add a link in my overlay text. I've read that using Anchor will only work for documents made from scratch but not for existing pdfs. My code is adding an overlay text to every page. My goal is to make a portion of that text clickable. I don't know how to make a link annotation that is part of a phrase.

Here's my code:

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

So my overlay would looked like this:

Downloaded by [Anonymous] from My Website on February 17, 2015 at 1:20 AM CST

How can I convert My Website to a link annotation? Searching here in SO, I found this post, but I don't know how to apply adding link annotation to a portion of my overlay text.

Thanks in advance.

EDIT: How to add a rotated overlay text with link annotations to existing pdf?
Thanks to Bruno Lowagie for going out of his way in answering my question. Although I originally asked how to add link annotations in an overlay text to existing pdfs, he also catered my questions in the comments section of his answer about setting the coordinates properly if the overlay text were rotated.

解决方案

You are using ColumnText.showAligned() which is sufficient to add a line of text without any special features, but if you want the anchor to work, you need to use ColumnText differently.

This is shown in the AddLinkAnnotation2 example:

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

In this case, we define a rectangle for a ColumnText object, we add the Phrase to the column, and we go().

If you check the result, link_annotation2.pdf, you'll notice that you can click the words in bold.

There are no plans to support this in ColumnText.showTextAligned(). That is a convenience method that can be used as a short-cut for the handful of lines shown above, but there are some known limitations: lines are not wrapped, interactivity is ignored,...

Update 1: in the comment section, you asked an additional question about rotation the content and the link.

Rotating the content isn't difficult. There's even more than one way to do that. Rotating the link isn't trivial, as a link is a type of annotation, and annotations aren't part of the content.

Let's first take a look at 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();
}

In this example, we define a tranformation of 30 degrees (Math.PI / 6):

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

We use this transformation when rendering the column:

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

This rotates the content, but we didn't add any annotation yet. Instead, we define a page event:

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

and we introduced a generic tag:

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

To add the annotation, we use some magic in the page event implementation:

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

We create an annotation, but before we do so, we perform a transformation on the rectangle. This makes sure that the text fits the rectangle with the text that needs to be clickable, but... this may not be what you expect:

You may have wanted the rectangle to be rotated, and that's possible, but it's more math. For instance: you could create a polygon that is a better fit: ITextShape Clickable Polygon or path

Fortunately, you don't need an angle of 30 degrees, you want to rotate the text with an angle of 90 degrees. In that case, you don't have the strange effect shown in the above screen shot.

Take a look at 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);
    }

}

As you can see, I've added a single line to remove the border (the border is there by default unless you redefine the PdfBorderArray).

The rest of the code is also almost identical. We now define an angle of Math.PI / 2 (90 degrees).

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

Note that the lower left corner of the page is the pivot point, hence we need to adapt the coordinates where we add the column, otherwise you'll rotate all the content outside the visible area of the page.

Update 2:

In yet another comment, you are asking about the coordinates you need to use when adding text in a rotated coordinate system.

I made this drawing:

In the top part, you add the word MIDDLE in the middle of a page, but that's not where it will appear: you are rotating everything by 90 degrees, hence the word MIDDLE will rotate outside your page (into the hatched area). The word will be in the PDF, but you'll never see it.

If you look at my code, you see that I use these coordinates:

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

This is outside the visible area (it's below the actual page dimensions), but as I rotate everything with 90 degrees, it rotates into the visible area.

If you look at my drawing, you can see that the page with coordinates (0, 0), (0, -595), (842, -598) and (842, 0) rotates by 90 degrees and thus gets the coincides with a page with coordinates (0, 0), (595, 0), (595, 842) and (0, 842). That's the type of Math we all learned in high school ;-)

You were adding text at position crop.getLeft(10), crop.getHeight() / 2 + crop.getBottom(). If you know that the text will be rotated by 90 degrees, you should use crop.getHeight() / 2 + crop.getBottom(), -crop.getLeft().

The best way to understand why, is to make a drawing.

这篇关于如何使用链接注释向现有pdf添加叠加文本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆