Подтвердить что ты не робот

Как создать несколько строк в PDF с помощью Apache pdfbox

Я использую Pdfbox для создания PDF файлов с использованием Java. Проблема в том, что когда я добавляю длинное текстовое содержимое в документ, оно отображается неправильно. Отображается только его часть. Это тоже в одной строке.

Я хочу, чтобы текст был в нескольких строках.

Мой код приведен ниже:

PDPageContentStream pdfContent=new PDPageContentStream(pdfDocument, pdfPage, true, true);

pdfContent.beginText();
pdfContent.setFont(pdfFont, 11);
pdfContent.moveTextPositionByAmount(30,750);            
pdfContent.drawString("I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox");
pdfContent.endText();

Мой вывод:

This is my output file

4b9b3361

Ответ 1

Добавляя к ответу Mark, вы можете узнать, где можно разделить длинную строку. Вы можете использовать метод PDFont getStringWidth для этого.

Собирая все вместе, вы получаете что-то вроде этого (с небольшими отличиями в зависимости от версии PDFBox):

PDFBox 1.8.x

PDDocument doc = null;
try
{
    doc = new PDDocument();
    PDPage page = new PDPage();
    doc.addPage(page);
    PDPageContentStream contentStream = new PDPageContentStream(doc, page);

    PDFont pdfFont = PDType1Font.HELVETICA;
    float fontSize = 25;
    float leading = 1.5f * fontSize;

    PDRectangle mediabox = page.findMediaBox();
    float margin = 72;
    float width = mediabox.getWidth() - 2*margin;
    float startX = mediabox.getLowerLeftX() + margin;
    float startY = mediabox.getUpperRightY() - margin;

    String text = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox"; 
    List<String> lines = new ArrayList<String>();
    int lastSpace = -1;
    while (text.length() > 0)
    {
        int spaceIndex = text.indexOf(' ', lastSpace + 1);
        if (spaceIndex < 0)
            spaceIndex = text.length();
        String subString = text.substring(0, spaceIndex);
        float size = fontSize * pdfFont.getStringWidth(subString) / 1000;
        System.out.printf("'%s' - %f of %f\n", subString, size, width);
        if (size > width)
        {
            if (lastSpace < 0)
                lastSpace = spaceIndex;
            subString = text.substring(0, lastSpace);
            lines.add(subString);
            text = text.substring(lastSpace).trim();
            System.out.printf("'%s' is line\n", subString);
            lastSpace = -1;
        }
        else if (spaceIndex == text.length())
        {
            lines.add(text);
            System.out.printf("'%s' is line\n", text);
            text = "";
        }
        else
        {
            lastSpace = spaceIndex;
        }
    }

    contentStream.beginText();
    contentStream.setFont(pdfFont, fontSize);
    contentStream.moveTextPositionByAmount(startX, startY);            
    for (String line: lines)
    {
        contentStream.drawString(line);
        contentStream.moveTextPositionByAmount(0, -leading);
    }
    contentStream.endText(); 
    contentStream.close();

    doc.save("break-long-string.pdf");
}
finally
{
    if (doc != null)
    {
        doc.close();
    }
}

(BreakLongString.java test testBreakString для PDFBox 1.8.x)

PDFBox 2.0.x

PDDocument doc = null;
try
{
    doc = new PDDocument();
    PDPage page = new PDPage();
    doc.addPage(page);
    PDPageContentStream contentStream = new PDPageContentStream(doc, page);

    PDFont pdfFont = PDType1Font.HELVETICA;
    float fontSize = 25;
    float leading = 1.5f * fontSize;

    PDRectangle mediabox = page.getMediaBox();
    float margin = 72;
    float width = mediabox.getWidth() - 2*margin;
    float startX = mediabox.getLowerLeftX() + margin;
    float startY = mediabox.getUpperRightY() - margin;

    String text = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox"; 
    List<String> lines = new ArrayList<String>();
    int lastSpace = -1;
    while (text.length() > 0)
    {
        int spaceIndex = text.indexOf(' ', lastSpace + 1);
        if (spaceIndex < 0)
            spaceIndex = text.length();
        String subString = text.substring(0, spaceIndex);
        float size = fontSize * pdfFont.getStringWidth(subString) / 1000;
        System.out.printf("'%s' - %f of %f\n", subString, size, width);
        if (size > width)
        {
            if (lastSpace < 0)
                lastSpace = spaceIndex;
            subString = text.substring(0, lastSpace);
            lines.add(subString);
            text = text.substring(lastSpace).trim();
            System.out.printf("'%s' is line\n", subString);
            lastSpace = -1;
        }
        else if (spaceIndex == text.length())
        {
            lines.add(text);
            System.out.printf("'%s' is line\n", text);
            text = "";
        }
        else
        {
            lastSpace = spaceIndex;
        }
    }

    contentStream.beginText();
    contentStream.setFont(pdfFont, fontSize);
    contentStream.newLineAtOffset(startX, startY);
    for (String line: lines)
    {
        contentStream.showText(line);
        contentStream.newLineAtOffset(0, -leading);
    }
    contentStream.endText(); 
    contentStream.close();

    doc.save(new File(RESULT_FOLDER, "break-long-string.pdf"));
}
finally
{
    if (doc != null)
    {
        doc.close();
    }
}

(BreakLongString.java test testBreakString для PDFBox 2.0.x)

Результат

Screenshot of the result PDF displayed in Acrobat Reader

Это выглядит так, как ожидалось.

Конечно, есть множество улучшений, но это должно показать, как это сделать.

Добавление безусловных разрывов строк

В комментарии aleskv спросил:

Можете ли вы добавить разрывы строк, когда в строке есть \n?

Можно легко расширить решение для безусловного разбиения на символы новой строки, сначала разделив строку на символы \\\\\\ и затем итерации по результату разбиения.

например. если вместо длинной строки сверху

String text = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox"; 

вы хотите обработать эту еще длинную строку со встроенными символами новой строки

String textNL = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox.\nFurthermore, I have added some newline characters to the string at which lines also shall be broken.\nIt should work alright like this...";

вы можете просто заменить

String text = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox"; 
List<String> lines = new ArrayList<String>();
int lastSpace = -1;
while (text.length() > 0)
{
    [...]
}

в вышеприведенных решениях

String textNL = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox.\nFurthermore, I have added some newline characters to the string at which lines also shall be broken.\nIt should work alright like this..."; 
List<String> lines = new ArrayList<String>();
for (String text : textNL.split("\n"))
{
    int lastSpace = -1;
    while (text.length() > 0)
    {
        [...]
    }
}

(из BreakLongString.java test testBreakStringNL)

Результат:

Снимок экрана

Ответ 2

Я знаю это немного позже, но у меня была небольшая проблема с решением mkl. Если последняя строка содержит только одно слово, ваш алгоритм записывает его на предыдущем.

Например: "Lorem ipsum dolor sit amet" - это ваш текст, и он должен добавить разрыв строки после "сидеть".

Lorem ipsum dolor sit
amet

Но он делает это:

Lorem ipsum dolor sit amet

Я придумал свое решение, которое хочу поделиться с вами.

/**
 * @param text The text to write on the page.
 * @param x The position on the x-axis.
 * @param y The position on the y-axis.
 * @param allowedWidth The maximum allowed width of the whole text (e.g. the width of the page - a defined margin).
 * @param page The page for the text.
 * @param contentStream The content stream to set the text properties and write the text.
 * @param font The font used to write the text.
 * @param fontSize The font size used to write the text.
 * @param lineHeight The line height of the font (typically 1.2 * fontSize or 1.5 * fontSize).
 * @throws IOException
 */
private void drawMultiLineText(String text, int x, int y, int allowedWidth, PDPage page, PDPageContentStream contentStream, PDFont font, int fontSize, int lineHeight) throws IOException {

    List<String> lines = new ArrayList<String>();

    String myLine = "";

    // get all words from the text
    // keep in mind that words are separated by spaces -> "Lorem ipsum!!!!:)" -> words are "Lorem" and "ipsum!!!!:)"
    String[] words = text.split(" ");
    for(String word : words) {

        if(!myLine.isEmpty()) {
            myLine += " ";
        }

        // test the width of the current line + the current word
        int size = (int) (fontSize * font.getStringWidth(myLine + word) / 1000);
        if(size > allowedWidth) {
            // if the line would be too long with the current word, add the line without the current word
            lines.add(myLine);

            // and start a new line with the current word
            myLine = word;
        } else {
            // if the current line + the current word would fit, add the current word to the line
            myLine += word;
        }
    }
    // add the rest to lines
    lines.add(myLine);

    for(String line : lines) {
        contentStream.beginText();
        contentStream.setFont(font, fontSize);
        contentStream.moveTextPositionByAmount(x, y);
        contentStream.drawString(line);
        contentStream.endText();

        y -= lineHeight;
    }

}

Ответ 3

Просто нарисуйте строку в позиции ниже, как правило, в цикле:

float textx = margin+cellMargin;
float texty = y-15;
for(int i = 0; i < content.length; i++){
    for(int j = 0 ; j < content[i].length; j++){
        String text = content[i][j];
        contentStream.beginText();
        contentStream.moveTextPositionByAmount(textx,texty);
        contentStream.drawString(text);
        contentStream.endText();
        textx += colWidth;
    }
    texty-=rowHeight;
    textx = margin+cellMargin;
}

Это важные строки:

contentStream.beginText();
contentStream.moveTextPositionByAmount(textx,texty);
contentStream.drawString(text);
contentStream.endText();

Просто продолжайте рисовать новые строки в новых позициях. Пример использования таблицы см. Здесь: http://fahdshariff.blogspot.ca/2010/10/creating-tables-with-pdfbox.html

Ответ 4

contentStream.moveTextPositionByAmount(textx, texty) является ключевой точкой.

скажем, например, если вы используете размер A4, значит, 580 800 соответствует ширине и высоте (приблизительно). поэтому вы перемещаете свой текст в зависимости от положения вашего документа.

PDFBox поддерживает формат страницы. поэтому высота и ширина будут различаться для разных страниц

Ответ 5

///// FOR PDBOX 2.0.X
//  FOR ADDING DYNAMIC PAGE ACCORDING THE LENGTH OF THE CONTENT

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType1Font;

public class Document_Creation {

   public static void main (String args[]) throws IOException {

       PDDocument doc = null;
       try
       {
           doc = new PDDocument();
           PDPage page = new PDPage();
           doc.addPage(page);
           PDPageContentStream contentStream = new PDPageContentStream(doc, page);

           PDFont pdfFont = PDType1Font.HELVETICA;
           float fontSize = 25;
           float leading = 1.5f * fontSize;

           PDRectangle mediabox = page.getMediaBox();
           float margin = 72;
           float width = mediabox.getWidth() - 2*margin;
           float startX = mediabox.getLowerLeftX() + margin;
           float startY = mediabox.getUpperRightY() - margin;

           String text = "I am trying to create a PDF file with a lot of text contents in the document. I am using PDFBox.An essay is, generally, a piece of writing that gives the author own argument — but the definition is vague, overlapping with those of an article, a pamphlet, and a short story. Essays have traditionally been sub-classified as formal and informal. Formal essays are characterized by serious purpose, dignity, logical organization, length,whereas the informal essay is characterized by the personal element (self-revelation, individual tastes and experiences, confidential manner), humor, graceful style, rambling structure, unconventionality or novelty of theme.Lastly, one of the most attractive features of cats as housepets is their ease of care. Cats do not have to be walked. They get plenty of exercise in the house as they play, and they do their business in the litter box. Cleaning a litter box is a quick, painless procedure. Cats also take care of their own grooming. Bathing a cat is almost never necessary because under ordinary circumstances cats clean themselves. Cats are more particular about personal cleanliness than people are. In addition, cats can be left home alone for a few hours without fear. Unlike some pets, most cats will not destroy the furnishings when left alone. They are content to go about their usual activities until their owners return."; 
           List<String> lines = new ArrayList<String>();
           int lastSpace = -1;
           while (text.length() > 0)
           {
               int spaceIndex = text.indexOf(' ', lastSpace + 1);
               if (spaceIndex < 0)
                   spaceIndex = text.length();
               String subString = text.substring(0, spaceIndex);
               float size = fontSize * pdfFont.getStringWidth(subString) / 1000;
               System.out.printf("'%s' - %f of %f\n", subString, size, width);
               if (size > width)
               {
                   if (lastSpace < 0)
                       lastSpace = spaceIndex;
                   subString = text.substring(0, lastSpace);
                   lines.add(subString);
                   text = text.substring(lastSpace).trim();
                   System.out.printf("'%s' is line\n", subString);
                   lastSpace = -1;
               }
               else if (spaceIndex == text.length())
               {
                   lines.add(text);
                   System.out.printf("'%s' is line\n", text);
                   text = "";
               }
               else
               {
                   lastSpace = spaceIndex;
               }
           }

           contentStream.beginText();
           contentStream.setFont(pdfFont, fontSize);
           contentStream.newLineAtOffset(startX, startY);
           float currentY=startY;
           for (String line: lines)
           {
               currentY -=leading;

               if(currentY<=margin)
               {

                   contentStream.endText(); 
                   contentStream.close();
                   PDPage new_Page = new PDPage();
                   doc.addPage(new_Page);
                   contentStream = new PDPageContentStream(doc, new_Page);
                   contentStream.beginText();
                   contentStream.setFont(pdfFont, fontSize);
                   contentStream.newLineAtOffset(startX, startY);
                   currentY=startY;
               }
               contentStream.showText(line);
               contentStream.newLineAtOffset(0, -leading);
           }
           contentStream.endText(); 
           contentStream.close();

           doc.save("C:/Users/VINAYAK/Desktop/docccc/break-long-string.pdf");
       }
       finally
       {
           if (doc != null)
           {
               doc.close();
           }
       }

   }  
}

Вывод