2012-05-17 3 views
14

я могу вставить простой текст, как это:Как создать абзацы с фиксированной шириной с помощью PDFbox?

document = new PDDocument(); 
page = new PDPage(PDPage.PAGE_SIZE_A4); 
document.addPage(page); 
PDPageContentStream content = new PDPageContentStream(document, page); 
content.beginText(); 
content.moveTextPositionByAmount (10 , 10); 
content.drawString ("test text"); 
content.endText(); 
content.close(); 

, но как я могу создать пункт, похожий на HTML, используя атрибут ширины?

<p style="width:200px;">test text</p> 

ответ

18

По this answer это не представляется возможным, чтобы вставить разрыв строки в какой-нибудь текст и есть PDF отобразить его правильно (будь то с помощью PDFBox или что-то еще), поэтому считаю, что я автоматически обертывание текст, чтобы поместиться в некоторой ширины также может быть то, что он не может сделать автоматически. (кроме того, есть много способов обернуть текст - только целые слова, разбить их на более мелкие части и т. д.)

This answer в другой вопрос (о центрировании строки) дает некоторые указания относительно того, как это сделать самому. Предполагая, что вы написали функцию possibleWrapPoints(String):int[], чтобы перечислить все точки в тексте слово обертывание может произойти (за исключением «нуля», в том числе «длины текста»), один из возможных решений может быть:

PDFont font = PDType1Font.HELVETICA_BOLD; // Or whatever font you want. 
int fontSize = 16; // Or whatever font size you want. 
int paragraphWidth = 200; 
String text = "test text"; 

int start = 0; 
int end = 0; 
int height = 10; 
for (int i : possibleWrapPoints(text)) { 
    float width = font.getStringWidth(text.substring(start,i))/1000 * fontSize; 
    if (start < end && width > paragraphWidth) { 
     // Draw partial text and increase height 
     content.moveTextPositionByAmount(10 , height); 
     content.drawString(text.substring(start,end)); 
     height += font.getFontDescriptor().getFontBoundingBox().getHeight()/1000 * fontSize; 
     start = end; 
    } 
    end = i; 
} 
// Last piece of text 
content.moveTextPositionByAmount(10 , height); 
content.drawString(text.substring(start)); 

Одним из примеров possibleWrapPoints, что позволяют оборачивать в любой точке, которая не является частью слова (reference), может быть:

int[] possibleWrapPoints(String text) { 
    String[] split = text.split("(?<=\\W)"); 
    int[] ret = new int[split.length]; 
    ret[0] = split[0].length(); 
    for (int i = 1 ; i < split.length ; i++) 
     ret[i] = ret[i-1] + split[i].length(); 
    return ret; 
} 

Update: некоторые дополнительная информация:

  • Формат PDF-файла был разработан так, чтобы выглядеть одинаково в разных ситуациях, функциональность, подобная той, которую вы запросили, имеет смысл в редакторе/создателе PDF, но не в файле PDF per se. По этой причине большинство инструментов «низкого уровня» имеют тенденцию концентрироваться на том, чтобы иметь дело с самим файловым форматом и оставлять подобные вещи.

  • Инструменты высшего уровня OTOH обычно имеют средства для этого преобразования. Примером является Platypus (для Python, хотя), что 10 do имеют простые способы создания абзацев и полагаются на нижний уровень ReportLab функции для реального рендеринга PDF. Я не знаю подобных инструментов для PDFBox, но this post дает некоторые подсказки о том, как конвертировать HTML-контент в PDF в среду Java, используя свободно доступные инструменты. Я не пробовал их самостоятельно, но я размещаю здесь, так как это может быть полезно (в случае, если моей ручной попытки выше недостаточно).

+1

В PDF можно сделать разрыв строки. (см. [мой ответ] (http://stackoverflow.com/a/15205956/1016477)) – Lukas

4

Я работаю, совмещая ответ Лукаса с mgibsonbr и достиг этого. Думаю, более полезно людям, которые ищут готовое решение.

private void write(Paragraph paragraph) throws IOException { 
    out.beginText(); 
    out.appendRawCommands(paragraph.getFontHeight() + " TL\n"); 
    out.setFont(paragraph.getFont(), paragraph.getFontSize()); 
    out.moveTextPositionByAmount(paragraph.getX(), paragraph.getY()); 
    out.setStrokingColor(paragraph.getColor()); 

    List<String> lines = paragraph.getLines(); 
    for (Iterator<String> i = lines.iterator(); i.hasNext();) { 
     out.drawString(i.next().trim()); 
     if (i.hasNext()) { 
      out.appendRawCommands("T*\n"); 
     } 
    } 
    out.endText(); 

} 

public class Paragraph { 

    /** position X */ 
    private float x; 

    /** position Y */ 
    private float y; 

    /** width of this paragraph */ 
    private int width = 500; 

    /** text to write */ 
    private String text; 

    /** font to use */ 
    private PDType1Font font = PDType1Font.HELVETICA; 

    /** font size to use */ 
    private int fontSize = 10; 

    private int color = 0; 

    public Paragraph(float x, float y, String text) { 
     this.x = x; 
     this.y = y; 
     this.text = text; 
    } 

    /** 
    * Break the text in lines 
    * @return 
    */ 
    public List<String> getLines() throws IOException { 
     List<String> result = Lists.newArrayList(); 

     String[] split = text.split("(?<=\\W)"); 
     int[] possibleWrapPoints = new int[split.length]; 
     possibleWrapPoints[0] = split[0].length(); 
     for (int i = 1 ; i < split.length ; i++) { 
      possibleWrapPoints[i] = possibleWrapPoints[i-1] + split[i].length(); 
     } 

     int start = 0; 
     int end = 0; 
     for (int i : possibleWrapPoints) { 
      float width = font.getStringWidth(text.substring(start,i))/1000 * fontSize; 
      if (start < end && width > this.width) { 
       result.add(text.substring(start,end)); 
       start = end; 
      } 
      end = i; 
     } 
     // Last piece of text 
     result.add(text.substring(start)); 
     return result; 
    } 

    public float getFontHeight() { 
     return font.getFontDescriptor().getFontBoundingBox().getHeight()/1000 * fontSize; 
    } 

    public Paragraph withWidth(int width) { 
     this.width = width; 
     return this; 
    } 

    public Paragraph withFont(PDType1Font font, int fontSize) { 
     this.font = font; 
     this.fontSize = fontSize; 
     return this; 
    } 

    public Paragraph withColor(int color) { 
     this.color = color; 
     return this; 
    } 

    public int getColor() { 
     return color; 
    } 

    public float getX() { 
     return x; 
    } 

    public float getY() { 
     return y; 
    } 

    public int getWidth() { 
     return width; 
    } 

    public String getText() { 
     return text; 
    } 

    public PDType1Font getFont() { 
     return font; 
    } 

    public int getFontSize() { 
     return fontSize; 
    } 

}