【问题标题】:Box Cloud Annotation Appearance in iTextiText 中的 Box Cloud 注释外观
【发布时间】:2019-05-31 03:03:07
【问题描述】:

这是我绘制框云注释的示例代码。我在 PDFBox 的实现中使用了代码来绘制一个盒子云,但是在 iText 中使用时我遇到了一个小问题。我修改了边框类和一些部分以在 iText 中使用。

你可以找到边框类here

我的问题是,没有绘制顶部和右侧的边界云。似乎它们的位置超出了矩形差异。我认为问题在于在 cloudyPolygonImpl() 中绘制曲线。也许itext有不同的方式来绘制PdfAppearance?我不确定。

这是我到目前为止所拥有的。

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

    PdfDictionary be = new PdfDictionary();
    be.put(PdfName.S, PdfName.C);
    be.put(PdfName.I, new PdfNumber(1));

    Rectangle location = new Rectangle(123.6f, 584.4f, 252.6f, 653.4f);
    PdfAnnotation stamp = PdfAnnotation.createSquareCircle(stamper.getWriter(), location, "", true);
    stamp.setBorderStyle(new PdfBorderDictionary(1, PdfBorderDictionary.STYLE_SOLID));
    stamp.put(new PdfName("BE"), be);
    stamp.setColor(BaseColor.RED);

    PdfContentByte cb = stamper.getOverContent(1);
    PdfAppearance app = cb.createAppearance(location.getWidth(), location.getHeight());
    stamp.setAppearance(PdfName.N, app);

    PdfArray stickyRect = stamp.getAsArray(PdfName.RECT);
    Rectangle annotRect = new Rectangle(stickyRect.getAsNumber(0).floatValue(),
        stickyRect.getAsNumber(1).floatValue(),
        stickyRect.getAsNumber(2).floatValue(),
        stickyRect.getAsNumber(3).floatValue());

    PdfArray arrDiff = annotation.getAsArray(PdfName.RD);
    Rectangle annotRectDiff = null;
    if (arrDiff != null) {
            annotRectDiff = new Rectangle(arrDiff.getAsNumber(0).floatValue(), arrDiff.getAsNumber(1).floatValue(),
        arrDiff.getAsNumber(2).floatValue(), arrDiff.getAsNumber(3).floatValue()
    }

    // Create cloud appearance
    CBorder cborder = new CBorder(app, 1, 1, annotRect);
    cborder.createCloudyRectangle(annotRectDiff);

    stamp.put(PdfName.RECT, new PdfRectangle(cborder.getRectangle()));
    stamp.put(PdfName.RD, new PdfArray(new float[] { 
        cborder.getRectDifference().getLeft(), 
        cborder.getRectDifference().getBottom(), 
        cborder.getRectDifference().getRight(), 
        cborder.getRectDifference().getTop() }));

    app.rectangle(cborder.getBBox());
    app.transform(cborder.getMatrix());


    app.setColorStroke(BaseColor.RED);
    app.setLineWidth(1);
    app.stroke();

    stamper.addAnnotation(stamp, 1);
    stamper.close();
    reader.close();
}    
    }

正确的输出应该是所有边框都用云绘制,但目前只绘制了左侧和底部。

【问题讨论】:

  • 您调用了cborder.createCloudyRectangle(null);,而 PDFBox PDSquareAppearanceHandler.java 调用了cloudyBorder.createCloudyRectangle(annotation.getRectDifference());。 PDFBox 还会在云完成后修改注释矩形。 (Adobe Reader 也做这个 IIRC)
  • 你好,蒂尔曼。是的。正在试验代码,但结果是相同的,因为 getRectDifference() 即使在 pdfbox 中也返回 null,即使我使用该方法而不是 null,结果外观也是一样的。我会改回代码。
  • @TilmanHausherr 矩形值与 PDFBox 中的值相同。我认为问题可能在边界类的 cloudyPolygonImpl() 内。它在 iText 中的绘制方式可能有所不同。
  • 你最近的编辑很奇怪,它引入了一个新变量annotation,它在任何地方都没有定义,新的if (arrDiff != null)块中的代码在语法上被破坏了。因此,我将根据原始代码进行回答。
  • 顺便说一句:您的代码似乎存在页面旋转 90° 或 270° 的问题...

标签: annotations itext cloud pdf-generation


【解决方案1】:

(此答案基于revision 3 of your question 中的代码,因为revision 4 中的更改引入了多个错误。)

您的代码在此处创建了无效的注释外观流:

CBorder cborder = new CBorder(app, 1, 1, annotRect);
cborder.createCloudyRectangle(null);

stamp.put(PdfName.RECT, new PdfRectangle(cborder.getRectangle()));
stamp.put(PdfName.RD, new PdfArray(new float[] { 
    cborder.getRectDifference().getLeft(), 
    cborder.getRectDifference().getBottom(), 
    cborder.getRectDifference().getRight(), 
    cborder.getRectDifference().getTop() }));

app.rectangle(cborder.getBBox());
app.transform(cborder.getMatrix());


app.setColorStroke(BaseColor.RED);
app.setLineWidth(1);
app.stroke();

它的上半部分创建了一条路径:

2 j
121.58 588.63 m
122.06 588.95 122.6 589.18 123.16 589.3 c
120.73 588.78 119.18 586.4 119.7 583.96 c
120.19 581.67 122.35 580.14 124.68 580.44 c
...
122.06 596.42 122.6 596.64 123.16 596.76 c
121.09 596.32 119.6 594.49 119.6 592.36 c
119.6 590.87 120.34 589.47 121.58 588.63 c
h

那么app.rectangle(cborder.getBBox()) 不会创建任何东西(请注意,这个rectangle 重载并不是您期望的那样!)。

然后app.transform(cborder.getMatrix())对当前变换矩阵添加变化,app.setColorStroke(BaseColor.RED)添加描边颜色变化,app.setLineWidth(1)添加线宽变化:

1 0 0 1 -118.68 -579.48 cm
1 0 0 RG
1 w

最后app.stroke()添加了描边路径的命令:

S

但是在路径的定义和对应的路径绘制命令之间,只允许剪切路径指令!参照。图 9 – 图形对象 – 在 PDF 规范 ISO 32000-1 中。

你可以这样修复这段代码,拉起颜色和线宽的变化,直接使用云边界框:

// Create cloud appearance
app.setColorStroke(BaseColor.RED);
app.setLineWidth(1);

CBorder cborder = new CBorder(app, 1, 1, annotRect);
cborder.createCloudyRectangle(null);

stamp.put(PdfName.RECT, new PdfRectangle(cborder.getRectangle()));
stamp.put(PdfName.RD, new PdfArray(new float[] { 
    cborder.getRectDifference().getLeft(), 
    cborder.getRectDifference().getBottom(), 
    cborder.getRectDifference().getRight(), 
    cborder.getRectDifference().getTop() }));

app.stroke();
app.setBoundingBox(cborder.getBBox());

(CloudBoxAnnotation 测试testDrawLikeChitgoksImproved)

这特别改变了结果(如在 Adob​​e Acrobat 中看到的)

【讨论】:

  • 它有效!虽然我认为这样做的方式与 PDFBox 相同。我对不必使用 cs.rectangle() 和 cs.transform() 感到惊讶。绘制云注释的方式与此相同。谢谢!
  • @chitgoks 好吧,您的原始方法尝试移动外观以匹配先前设置的注释外观边界框值。我的方法更改了注释外观边界框值以匹配未移动的外观。两种方法都可以。
猜你喜欢
  • 2017-12-17
  • 1970-01-01
  • 2016-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多