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

查看:59
本文介绍了使用 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,annotation是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 通过评论中的谷歌驱动器链接提供的更新源代码:

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:

什么都没有显示

检查 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 中,然后创建外观并将其附加到 stamp 对象.

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天全站免登陆