#java #pdf-generation #pdfbox #java-11
#java #PDF #javafx #шрифты #pdfbox
Вопрос:
Я хочу распечатать это в формате PDF, созданном PDFBOX. Это не позволит мне вставлять табуляции и пробелы, потому что шрифт их не поддерживает. Почему это проблема и, что более важно, как я могу это исправить?
StudentData student = listOfDebtors.get(j);
contentStream.beginText();
contentStream.setFont(font, 8);
contentStream.newLineAtOffset(xPosition, yPosition);
contentStream.showText("Member #:" student.getMembershipNumber() "t"
"Grade:" getStudentGradeInSchool(student.getYearGraduate()) "t"
"Year Joined" student.getYearJoined() "n"
"Name:" student.getFirstName() " " student.getLastName() "n"
"Amount Owed : $" student.getAmountOwed());
Показана ошибка:
Caused by: java.lang.IllegalArgumentException: No glyph for U 0009 in font Courier
at org.apache.pdfbox.pdmodel.font.PDType1Font.encode(PDType1Font.java:353)
at org.apache.pdfbox.pdmodel.font.PDFont.encode(PDFont.java:283)
at org.apache.pdfbox.pdmodel.PDPageContentStream.showText(PDPageContentStream.java:341)
at fbla.rahulshah.database.dataManipulation.PDFCreator.createDebtorPDF(PDFCreator.java:61)
at fbla.rahulshah.database.view.MainScreenController.generateDebtReport(MainScreenController.java:114)
... 62 more
Комментарии:
1. Это, безусловно, какой-то отдельный код. Генерирует ли это какие-либо ошибки? Если да, можете ли вы также показать ошибки?
2. добавлена ошибка, которую он показывает
3. Поскольку мы знаем, что шрифт real Courier содержит U 0009, следующий вопрос, который я предполагаю, «вы работаете с реальным Courier или производным подмножеством?», Потому что я уверен, что это последнее, и в этом случае вы не можете выполнять какие-либо изменения, которые используют глифы за пределами подмножества.
Ответ №1:
Шрифт — это набор символов. Не существует такого понятия, как «символ ТАБУЛЯЦИИ». Просто представьте, что вы набираете текст с помощью металлических символов 100 лет назад, и какой-то парень (у которого есть пишущая машинка) спрашивает вас о «символе табуляции».
В пишущей машинке нажатие TAB означает «перейти к следующей позиции табуляции». Шрифт не знает своего собственного положения, он знает только внешний вид и размер своих символов. В PDF или PDFBox также нет понятия «позиции табуляции». PDF или PDFBox не являются текстовыми редакторами.
И даже в редакторе слепое нажатие на ВКЛАДКУ не всегда доставляет вам удовольствие, в зависимости от длины текста, который вы только что написали. Сначала вам нужно будет проверить свою собственную позицию, а затем подумать о том, чтобы нажать TAB или, возможно, нажать его дважды.
Вместо этого вам следует сделать так, чтобы после записи столбца данных вы разместили себя в соответствующей позиции X следующего столбца. Используя шрифт courier (исправленный с помощью), вы также можете сделать это, вычисляя длину строки и добавляя соответствующее количество пробелов.
Что подводит нас к следующей части, отсутствующему пробелу. Что ж, используйте другой шрифт с пробелами, потому что там есть символ пробела: он выглядит невидимым, но имеет фиксированный размер.
И, наконец, также нет такого понятия, как «символ новой строки». Новая строка — это команда. Вы уже используете «newLineAtOffset», который должен работать нормально, чтобы позиционировать себя. Смотрите ответ mkl о том, как это сделать.
Комментарии:
1. следующая часть, недостающий пробел — Учитывая исключение OP, я сомневаюсь, что существует реальная проблема с символами пробела.
2. @mkl да, возможно, но никто не знает, какие странные шрифты используют люди. И я хотел опубликовать разглагольствование для «всех очень запутанных людей», чтобы объяснить разницу между пробелом и табуляцией.
Ответ №2:
Причина в том, что PDPageContentStream.showText(String)
может отображать только текст, он не может выполнять какие-либо дополнительные компоновки, такие как интерпретация горизонтальных вкладок, разрывов строк или других управляющих символов; Тилман подробно объяснил это в своем ответе.
Вы могли бы достичь своей цели с помощью чего-то вроде этого:
contentStream.newLineAtOffset(xPosition, yPosition);
contentStream.showText("Member #: " student.getMembershipNumber());
contentStream.newLineAtOffset(200, 0);
contentStream.showText("Grade: " getStudentGradeInSchool(student.getYearGraduate()));
contentStream.newLineAtOffset(200, 0);
contentStream.showText("Year Joined: " student.getYearJoined());
contentStream.newLineAtOffset(-400, -12);
contentStream.showText("Name: " student.getFirstName() " " student.getLastName());
contentStream.newLineAtOffset(0, -12);
contentStream.showText("Amount Owed: $" student.getAmountOwed());