2012-05-17 85 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(); 

,但我怎麼可以創建類似使用width屬性爲HTML一個段落?

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

回答

18

根據this answer這是不可能插入換行符一些文字,並有PDF正確顯示我(是否使用PDFBox的或別的東西),所以相信自動包裝一些文字,以適應某些寬度也可是不能自動執行的事情。 (此外,還有很多方法來包裝文本 - 僅整個文字,將它們分成較小的部分等)

This answer給另一個問題(關於居中字符串)給出了一些關於如何自己做這個問題的指示。假設你寫了一個函數possibleWrapPoints(String):int[]列出所有點的自動換行可能發生的文本(不包括「零」,其中「文本長度」),一個可能的解決方案可能是:

例如 possibleWrapPoints
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)); 

一個,那允許在這不是一個字(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; 
} 

更新:一些額外的信息:

  • 的PDF文件格式的目的是要看看在不同的情況一樣,像一個功能,你要求是有道理的PDF編輯/創造者,而不是在PDF文件本身。出於這個原因,大多數「低級別」工具傾向於專注於處理文件格式本身,而忽略這樣的東西。

  • 更高級別的工具OTOH通常具有進行此轉換的方法。一個例子是Platypus(儘管Python),有創建段落的簡單方法,並依靠較低層次ReportLab函數做實際的PDF渲染。我並不知道類似的PDFBox工具,但this post提供了一些關於如何在Java環境中使用免費工具將HTML內容轉換爲PDF的提示。還沒有嘗試過他們自己,但我在這裏發佈,因爲它可能是有用的(如果我上面的手工嘗試是不夠的)。

+1

在PDF它有可能使一個換行符。 (請參閱[我的答案](http://stackoverflow.com/a/15205956/1016477)) – Lukas

4

我一直在努力將Lukas答案與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; 
    } 

}