Это мой пример кода для рисования аннотации в виде облака. Я использовал код в реализации PDFBox для рисования облака блоков, но у меня возникла небольшая проблема при использовании в iText. Я изменил класс границы и некоторые части, чтобы их можно было использовать в iText.
вы можете найти класс границы здесь.
Моя проблема в том, что верхние и правые граничные облака не рисуются. кажется, что их расположение нарисовано за пределами прямой разницы. Я полагаю, что проблема заключается в рисовании кривых в 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();
}
}
Правильный вывод должен заключаться в том, что все границы рисуются облаком, но в настоящее время рисуются только левая и нижняя.
Привет, тильман. да. экспериментировал с кодом, но результат тот же, поскольку getRectDifference() возвращает null даже в pdfbox, и даже когда я использовал этот метод вместо null, результат был таким же. я верну код обратно.
@TilmanHausherr значения прямоугольника такие же, как значения в PDFBox. Я полагаю, что проблема может быть в cloudyPolygonImpl() граничного класса. в iText он может отличаться в зависимости от того, как он нарисован.
Ваше недавнее редактирование странное, оно вводит новую переменную annotation
, которая нигде не определена, а код в новом блоке if (arrDiff != null)
синтаксически нарушен. Таким образом, я отвечу на основе исходного кода.
Кстати: у вашего кода есть проблемы с поворотом страницы на 90° или 270°...
(Этот ответ основан на коде в 3 версия вашего вопроса, поскольку изменения в ревизия 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());
(тест CloudBoxАннотацияtestDrawLikeChitgoksImproved
)
Это, в частности, изменяет результат (как показано в Adobe Acrobat) с
к
оно работает! Хотя я думал, что сделать это так же, как PDFBox, поможет. Меня удивило отсутствие необходимости использовать cs.rectangle() и cs.transform(). Тот же самый способ, которым вы делали это, чтобы нарисовать аннотацию облака, также работает. Спасибо!
@chitgoks хорошо, ваш первоначальный подход пытался переместить внешний вид в соответствии с ранее установленным значением границы внешнего вида аннотации. Мой подход изменил значение граничной рамки внешнего вида аннотации, чтобы оно соответствовало недвижимому внешнему виду. Любой подход может работать.
Вы вызвали
cborder.createCloudyRectangle(null);
, а PDFBox PDSquareAppearanceHandler.java вызвалcloudyBorder.createCloudyRectangle(annotation.getRectDifference());
. PDFBox также изменяет прямоугольник аннотаций после того, как облака будут готовы. (Adobe Reader также делает это IIRC)