使用iText

时间:2018-01-11 06:12:22

标签: pdf annotations itext line

这是我用来画线的代码。

double[] lineArray = annotation.getAsArray(PdfName.L).asDoubleArray();
double x1 = lineArray[0] - rect.getAsNumber(0).doubleValue();
double y1 = lineArray[1] - rect.getAsNumber(1).doubleValue();
double x2 = lineArray[2] - rect.getAsNumber(0).doubleValue();
double y2 = lineArray[3] - rect.getAsNumber(1).doubleValue();

cs.moveTo(x1, y1);
cs.lineTo(x2, y2);

其中cs是PdfAppearance,注释是PdfAnnotation,而rect是 PdfArray rect = annotation.getAsArray(PdfName.RECT);

这在肖像中工作正常。但来,横向模式,例如旋转270度,坐标变得错位。我也通过cs.transform()做了一个旋转,所以我的0,0会旋转,但它什么也没做。

知道可能缺少什么吗?

1 个答案:

答案 0 :(得分:1)

来源

此答案涵盖了OP通过评论中的google驱动器链接提供的更新源代码:

public static void main(String[] args) throws Exception {
    PdfReader reader = new PdfReader("src");
    PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("dest"));

    Rectangle location = new Rectangle(544.8f, 517.65f, 663f, 373.35f);

    PdfArray lineEndings = new PdfArray();
    lineEndings.add(new PdfName("None"));
    lineEndings.add(new PdfName("None"));

    PdfAnnotation stamp = PdfAnnotation.createLine(stamper.getWriter(), location, 
        "comment",  550.05f, 510.9f, 656.25f, 378.6f);
    stamp.put(new PdfName("LE"), lineEndings);
    stamp.put(new PdfName("IT"), new PdfName("Line"));
    stamp.setBorderStyle(new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID));
    stamp.setColor(PdfGraphics2D.prepareColor(Color.RED));
    stamp.put(PdfName.ROTATE, new PdfNumber(270));
    stamper.addAnnotation(stamp, 1);

    addAppearance(stamper, stamp, location);

    stamper.close();
    reader.close();
}

private static void addAppearance(PdfStamper stamper, PdfAnnotation stamp, Rectangle location) {
    PdfContentByte cb = stamper.getOverContent(1);
    PdfAppearance app = cb.createAppearance(location.getWidth(),  location.getHeight());        

    PdfArray rect = stamp.getAsArray(PdfName.RECT);
    Rectangle bbox = app.getBoundingBox();

    double[] lineArray = stamp.getAsArray(PdfName.L).asDoubleArray();
    double x1 = lineArray[0] - rect.getAsNumber(0).doubleValue();
    double y1 = lineArray[1] - rect.getAsNumber(1).doubleValue();
    double x2 = lineArray[2] - rect.getAsNumber(0).doubleValue();
    double y2 = lineArray[3] - rect.getAsNumber(1).doubleValue();

    app.moveTo(x1, y1);
    app.lineTo(x2, y2);

    app.stroke();
    stamp.setAppearance(PdfName.N, app);
}

没有出现

在Chrome中查看生成的PDF时的第一个观察结果是,正如OP在评论中所说的那样:

  

什么都没有出现

检查PDF原因很明显:注释没有外观流。因此,有限的PDF查看器只能通过其外观流显示注释,而不是通过其描述性值来显示,例如Chrome中的集成查看器不会显示它。

这是由于OP在其代码中调用iText功能的顺序:

    [... create annotation object stamp ...]
    stamper.addAnnotation(stamp, 1);

    addAppearance(stamper, stamp, location);

因此,他首先通过stamper.addAnnotation将注释添加到PDF中,然后创建一个外观并将其附加到stamp对象。

这个顺序错了。在iText的上下文中,必须意识到库会尽可能早地将添加内容写入输出流以减少其内存占用。 (顺便提一下,这是iText在服务器应用程序环境中的一个重要特性,其中可能需要并行处理多个PDF。)

因此,在stamper.addAnnotation(stamp, 1)期间,注释被写入输出流,并且因为它没有外观,所以输出流中的注释没有外观。后来的addAppearance调用只会在注释的内存中表示中添加一个外观,而不会再序列化。

将订单更改为

    [... create annotation object stamp ...]
    addAppearance(stamper, stamp, location);

    stamper.addAnnotation(stamp, 1);

生成带有线条的PDF。不幸的是,不是在理想的位置,但这是另一个问题。

错误的位置

该行位于错误位置且方向错误的原因基于iText的一项功能,该功能已成为this answerthis answer中的主题:

  

对于旋转页面,iText尝试解除将旋转和翻译添加到绘制直立文本所需的页面内容并使坐标系原点位于用户肩膀页面左下方的负担,以便用户不要根本不必处理页面轮换。因此,它也适用于注释。

由于您已经使用了实际坐标,因此iText的“帮助”会损坏您的注释。正如在其他答案中所讨论的那样,遗憾的是没有明确的转变来关闭这种机制;但是有一个简单的解决方法:在操作之前只需删除页面旋转条目,然后再将其添加回来:

PdfReader reader = ...;
PdfStamper stamper = ...;

// hide the page rotation
PdfDictionary pageDict = reader.getPageN(1);
PdfNumber rotation = pageDict.getAsNumber(PdfName.ROTATE);
pageDict.remove(PdfName.ROTATE);

Rectangle location = new Rectangle(544.8f, 517.65f, 663f, 373.35f);

PdfArray lineEndings = new PdfArray();
lineEndings.add(new PdfName("None"));
lineEndings.add(new PdfName("None"));

PdfAnnotation stamp = PdfAnnotation.createLine(stamper.getWriter(), location, 
    "comment",  550.05f, 510.9f, 656.25f, 378.6f);
stamp.put(new PdfName("LE"), lineEndings);
stamp.put(new PdfName("IT"), new PdfName("Line"));
stamp.setBorderStyle(new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID));
stamp.setColor(PdfGraphics2D.prepareColor(Color.RED));
stamp.put(PdfName.ROTATE, new PdfNumber(270));

addAppearance(stamper, stamp, location);

stamper.addAnnotation(stamp, 1);

// add page rotation again if required
if (rotation != null)
    pageDict.put(PdfName.ROTATE, rotation);

stamper.close();
reader.close();

这似乎可以根据需要创建注释外观。