线条绘图在横向模式下使用iText [英] Line Drawing In landscape mode using iText

查看:179
本文介绍了线条绘图在横向模式下使用iText的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我用来画线的代码。

This is the code I use to draw a 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);

Where cs is PdfAppearance, annotation is PdfAnnotation and rect is PdfArray rect = annotation.getAsArray(PdfName.RECT);

这在纵向中可行。但来,景观模式,例如旋转270度,坐标变得错位。我也通过cs.transform()进行了旋转,所以我的0,0会旋转,但它什么也没做。

This works ok in portrait. but come, landscape mode e.g. 270 rotation, the coordinates get misplaced. I also did a rotate via cs.transform() so my 0,0 would be rotated but it does nothing.

知道可能缺少什么吗?

推荐答案

来源



这个答案涵盖OP提供的更新源代码评论中的google驱动器链接:

The source

This answer covers the updated source code provided by the OP via a google drive link in comments:

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将其置于评论中:

No appearance

The first observation when viewing the resulting PDF in Chrome is, as the OP put it in a comment:


没有任何显示

nothing shows up

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

Inspecting the PDF the cause is clear: The annotation has no appearance stream. Thus, limited PDF viewers which only can show annotations by their appearance stream, not by their descriptive values, like the integrated viewer in Chrome don't show it.

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

This is due to the order in which the OP calls iText functionalities in his code:

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

    addAppearance(stamper, stamp, location);

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

So he first adds the annotation to the PDF by means of stamper.addAnnotation and thereafter creates an appearance and attaches it to the stamp object.

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

This order is wrong. In context with iText one has to be aware that the library attempts to write additions as early as possible to the output stream to reduce its memory footprint. (This by the way is one of the important features of iText in the context of server applications in which multiple PDFs may have to be processed in parallel.)

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

So already during stamper.addAnnotation(stamp, 1) the annotation is written to the output stream, and as it has no appearance yet, the annotation in the output stream is without appearance. The later addAppearance call only adds an appearance to the in-memory representation of the annotation which won't be serialized anymore.

将订单更改为

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

    stamper.addAnnotation(stamp, 1);

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

results in a PDF with a line drawn. Unfortunately not at the desired position, but that is another problem.

线路的原因是在错误的位置,并有错误的方向,基于iText的功能,这已成为这个答案的主题此答案

The reason why the line is both in the wrong location and has the wrong direction, is based in a feature of iText which has already been a topic in this answer and in this answer:


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

For rotated pages iText attempts to lift the burden of adding the rotation and translation to page content required to draw upright text and have the coordinate system origin in the lower left of the page of the users' shoulders, so that the users don't have to deal with page rotation at all. Consequently, it also does so for annotations.

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

As you already have the actual coordinates to use, this "help" by iText damages your annotation. As discussed in those other answers, there unfortunately is no explicit switch to turn off that mechanism; there is an easy work-around, though: before your manipulation simply remove the page rotation entry, and afterwards add it back again:

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

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

This appears to create the annotation appearance as required.

这篇关于线条绘图在横向模式下使用iText的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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