Как нарисовать строку в определенной позиции на странице PDF в Java с помощью pdfbox?

У меня есть координата PDF (x, y) в качестве входных данных. Мне нужно нарисовать строку с заданной входной координатой [например: - (x, y) = (200 250)]. Я использую pdfbox. Когда я использую описанный ниже метод moveTextPositionByAmount, я не получаю точную позицию. Даже я пытался использовать moveTo(). Пожалуйста, помогите мне, как нарисовать строку в точном положении?

PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true);
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.moveTextPositionByAmount(xindex, yindex);
contentStream.setNonStrokingColor(color);
contentStream.drawString(comment);                      
contentStream.stroke();
contentStream.endText();

Спасибо.


person byreddy    schedule 28.07.2014    source источник
comment
Что вы ожидаете от данной должности? PDF интерпретирует эту позицию как базовую линию текста.   -  person mkl    schedule 28.07.2014
comment
Я хочу нарисовать строку в этой позиции, когда я попытался выполнить приведенный выше код, он рисует текст с большими вариациями по сравнению с исходным.   -  person byreddy    schedule 28.07.2014
comment
Я заметил одну возможную проблему, ср. мой ответ ниже. Если при использовании предлагаемого исправления у вас все еще есть проблемы, предоставьте образец документа, измененный вашим кодом, иллюстрирующий проблему, и объясните, откуда вы все равно получили эти целевые координаты, потому что внутри PDF-файлов работает несколько систем координат, а некоторые процессоры PDF приносят свои собственный.   -  person mkl    schedule 28.07.2014
comment
Пример данных X:-121,Y:-305,W:-262,h:-104. Пожалуйста, проверьте ссылку ниже для скриншота. [ссылка]tinypic.com/r/11b6lap/8. Я также работаю над рисованием прямоугольника. Мне удалось получить точный результат, когда используются одни и те же координаты. Я использовал contentStream.fillRect(xValue,yValue,wValue,hValue) для рисования прямоугольника, но проблема возникает при использовании шнурка.   -  person byreddy    schedule 28.07.2014
comment
Снимок экрана помогает только в том случае, если PDF также поставляется. Кроме того, вы не объяснили, откуда вы берете эти координаты. Возможно, их придется преобразовать, потому что здесь может быть задействовано несколько систем координат.   -  person mkl    schedule 28.07.2014
comment
Я получу координаты из внешнего приложения. После преобразования координат они работают нормально, пока я использую метод fillRect()/addRect(). Но это не работает для drawString()   -  person byreddy    schedule 28.07.2014
comment
Предоставьте образец PDF, иллюстрирующий проблему. Вероятно, и с прямоугольником (что нормально, как вы говорите), и со строкой. И объясните, где вы ожидали найти строку.   -  person mkl    schedule 28.07.2014
comment
Извините , я не могу поделиться документом . Моя сеть не позволяет мне загрузить документ.   -  person byreddy    schedule 28.07.2014
comment
Тогда трудно сказать. Вот несколько идей для проверки: Есть ли какие-либо изменения в текущей матрице преобразования? Правильно ли вы считаете, что начало глифа находится на базовой линии, а не на линии подъема или спуска? Считаете ли вы медиа-бокс?   -  person mkl    schedule 28.07.2014
comment
Я не рассматривал какую-либо матрицу преобразования, просто код такой, как показано выше. Просто я получу координаты, такие как X:-121,Y:-305,W:-262,h:-104 и размер страницы ширина = 612 и высота = 792 и должны нарисовать строку.   -  person byreddy    schedule 28.07.2014
comment
Что является источником ваших координат, положительные координаты y выше или ниже, X,Y нижний левый угол прямоугольника, что означает отрицательная ширина или высота (вы упоминаете W:-262,h:-104), где внутри этого поля вы хотите нарисовать строку?   -  person mkl    schedule 28.07.2014


Ответы (2)


Избавление от изменений графического состояния из существующего содержимого страницы

Вы используете конструктор PDPageContentStream с двумя аргументами boolean:

new PDPageContentStream(document, page,true,true);

Этот конструктор реализован как:

this(document, sourcePage, appendContent, compress, false);

то есть он вызывает конструктор с тремя аргументами boolean, используя false в качестве последнего. Этот последний аргумент boolean задокументирован как:

* @param resetContext Tell if the graphic context should be reseted.

Таким образом, вы добавляете к содержимому страницы без сброса графического контекста. Это означает, что любые изменения в текущей матрице преобразования, сделанные в существующем содержимом страницы, по-прежнему преобразуют ваши координаты. Чтобы этого не произошло, вы должны использовать конструктор PDPageContentStream с тремя аргументами boolean:

new PDPageContentStream(document, page, true, true, true);

С помощью этого можно легко разместить текст.

Рисование прямоугольников и тест

ОП упомянул, что он успешно рисовал прямоугольники, но не рисовал текст.

Следующий код

PDPage firstPage = allPages.get(0);
PDRectangle pageSize = firstPage.findMediaBox();

float x = 121;
float y = 305;
float w = 262;
float h = 104;

PDPageContentStream contentStream = new PDPageContentStream(document, firstPage, true, true, true);

contentStream.setNonStrokingColor(Color.yellow);
contentStream.fillRect(pageSize.getLowerLeftX() + x, pageSize.getLowerLeftY() + y, w, h);

contentStream.beginText();
contentStream.moveTextPositionByAmount(pageSize.getLowerLeftX() + x, pageSize.getLowerLeftY() + y);
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.setNonStrokingColor(Color.red);
contentStream.drawString("My Text Here");
contentStream.endText();
contentStream.close();

приводит к

Скриншот результата

как и следовало ожидать.

Необходимо пояснить значение введенных координат.

ОП также упомянул X:-121,Y:-305,W:-262,h:-104 как координаты из внешнего приложения в своих комментариях.

Поскольку PDF-файлы чаще всего имеют положительные координаты внутри медиабокса, эти координаты X и Y не имеют смысла для PDF-файлов в целом.

Кроме того, оператору не удалось поделиться документом.

Следовательно, невозможно выяснить, имеют ли смысл эти отрицательные координаты для его специальной PDF.

Кроме того, отрицательные значения ширины и высоты принимаются операциями рисования прямоугольников, но если они используются для текста, они могут подразумевать, что координата Y не обозначает базовую линию или что ожидается, что текст не будет начинаться с X, а заканчиваться там. или что текст будет зеркально отражен, или, или, или...

Таким образом, сначала необходимо объяснить значение этих отрицательных координат и размеров. Что является началом этих координат, являются положительными координатами y выше или ниже, являются ли X, Y нижним левым углом прямоугольника, что означает отрицательная ширина или высота, где по отношению к X, Y должен строка будет нарисована?

person mkl    schedule 28.07.2014
comment
Я не смог найти указанный выше конструктор в API. ">pdfbox.apache.org/apidocs/org/apache/pdfbox/pdmodel/edit/ - person byreddy; 28.07.2014
comment
Что ж, это плохой знак относительно состояния документации API, потому что конструктор был представлен в декабре 2010 года. Он присутствует в выпусках, по крайней мере, начиная с PDFBox 1.4.0. - person mkl; 28.07.2014
comment
Я имею в виду координаты X=121,Y=305,W=262,h=104. Это сработало для меня. Спасибо. Но я получил результат с другим решением. - person byreddy; 30.07.2014
comment
В каких единицах указаны x, y, ширина и высота? Когда я пробую приведенный вами пример, который рисует желтый прямоугольник, я открываю средство просмотра PDF с уровнем масштабирования 100% и измеряю ширину прямоугольника в пикселях. Ширина 350 пикселей, а не 262, как в коде. - person jmrah; 25.08.2017
comment
Единицей пользовательского пространства по умолчанию в PDF-файлах является точка DTP, 1/72. дюйм. - person mkl; 25.08.2017

Я обнаружил, что это работает для меня.

PDPageContentStream contentStream = new PDPageContentStream(document, page,true,true);
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12);
contentStream.moveTextPositionByAmount(xindex, yindex);
contentStream.setNonStrokingColor(color);
contentStream.drawString(comment);                      
contentStream.endText();
person byreddy    schedule 30.07.2014
comment
Вы, кажется, используете старую версию PDFBox; в начале 2013 года были добавлены проверки, из-за которых ваш contentStream.moveTo(0,0) выдавал исключение. Причина: moveTo и stroke добавляют операции создания или рисования пути. Такие операции запрещены внутри текстового объекта (beginText...endText) и, следовательно, создают битый PDF. Однако большинство программ для просмотра PDF игнорируют эту ошибку. - person mkl; 30.07.2014
comment
Да . Я использую более старую версию PDFBox, поскольку проект, над которым я работаю, был разработан ранее, и мне приходится использовать только эти файлы jar. Извините, stroke() не используется в моем коде. - person byreddy; 30.07.2014
comment
stroke() не используется в моем коде - строго говоря, moveTo также не допускается внутри текстовых объектов... - person mkl; 30.07.2014
comment
Точно не знаю, но сработало. contentStream.moveTo (0,0); contentStream.beginText(); contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12); contentStream.moveTextPositionByAmount(xValue,yValue); contentStream.setNonStrokingColor (цвет); contentStream.drawString(комментарий); contentStream.endText(); contentStream.close(); - person byreddy; 30.07.2014
comment
Ваш contentStream.moveTo(0,0) начинает создавать путь. Создание пути должно заканчиваться операцией рисования пути. Вместо такой операции вы начинаете текстовый объект. Таким образом, строго говоря, ваше решение создает недопустимые PDF-файлы. - person mkl; 27.05.2015