I can insert simple text like this:
我可以像这样插入简单的文字:
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();
but how can I create a paragraph similar to HTML using the width attribute?
但是如何使用width属性创建类似于HTML的段落?
<p style="width:200px;">test text</p>
2 个解决方案
#1
20
According to this answer it's not possible to insert line breaks into some text and have PDF display it correctly (whether using PDFBox or something else), so I believe auto-wrapping some text to fit in some width may also be something it can't do automatically. (besides, there are many ways to wrap a text - whole words only, break them in smaller parts, etc)
根据这个答案,不可能在某些文本中插入换行符并让PDF正确显示它(无论是使用PDFBox还是其他东西),所以我相信自动换行一些文本以适应某种宽度也可能是它不能自动做。 (此外,有很多方法可以包装文本 - 仅限整个单词,将它们分成较小的部分等)
This answer to another question (about centering a string) gives some pointers on how to do this yourself. Assuming you wrote a function possibleWrapPoints(String):int[]
to list all points in the text a word wrap can happen (excluding "zero", including "text length"), one possible solution could be:
这个回答另一个问题(关于字符串居中)给出了一些关于如何自己做这个的指示。假设您编写了一个函数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));
One example of possibleWrapPoints
, that allow wrapping at any point that's not part of a word (reference), could be:
possibleWrapPoints的一个例子,允许在不属于单词(引用)的任何点包装,可以是:
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: some additional info:
更新:一些额外的信息:
-
The PDF file format was designed to look the same in different situations, functionality like the one you requested makes sense in a PDF editor/creator, but not in the PDF file per se. For this reason, most "low level" tools tend to concentrate on dealing with the file format itself and leave away stuff like that.
PDF文件格式的设计在不同情况下看起来相同,您所请求的功能在PDF编辑器/创建者中是有意义的,但在PDF文件本身中则不然。出于这个原因,大多数“低级”工具倾向于专注于处理文件格式本身并留下类似的东西。
-
Higher level tools OTOH usually have means to make this conversion. An example is Platypus (for Python, though), that do have easy ways of creating paragraphs, and relies on the lower level ReportLab functions to do the actual PDF rendering. I'm unaware of similar tools for PDFBox, but this post gives some hints on how to convert HTML content to PDF in a Java environment, using freely available tools. Haven't tried them myself, but I'm posting here since it might be useful (in case my hand-made attempt above is not enough).
更高级别的工具OTOH通常有进行此转换的手段。一个例子是Platypus(虽然是Python),它有简单的方法来创建段落,并依赖于较低级别的ReportLab函数来进行实际的PDF渲染。我不知道PDFBox的类似工具,但这篇文章提供了一些关于如何使用免费提供的工具将Java内容转换为PDF的提示。没有自己试过,但我在这里发帖,因为它可能有用(如果上面的手工制作尝试还不够)。
#2
4
I have been working combining Lukas answer with mgibsonbr and arrived at this. More helpful to people looking for an out-of-the-box solution, I think.
我一直在努力将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;
}
}
#1
20
According to this answer it's not possible to insert line breaks into some text and have PDF display it correctly (whether using PDFBox or something else), so I believe auto-wrapping some text to fit in some width may also be something it can't do automatically. (besides, there are many ways to wrap a text - whole words only, break them in smaller parts, etc)
根据这个答案,不可能在某些文本中插入换行符并让PDF正确显示它(无论是使用PDFBox还是其他东西),所以我相信自动换行一些文本以适应某种宽度也可能是它不能自动做。 (此外,有很多方法可以包装文本 - 仅限整个单词,将它们分成较小的部分等)
This answer to another question (about centering a string) gives some pointers on how to do this yourself. Assuming you wrote a function possibleWrapPoints(String):int[]
to list all points in the text a word wrap can happen (excluding "zero", including "text length"), one possible solution could be:
这个回答另一个问题(关于字符串居中)给出了一些关于如何自己做这个的指示。假设您编写了一个函数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));
One example of possibleWrapPoints
, that allow wrapping at any point that's not part of a word (reference), could be:
possibleWrapPoints的一个例子,允许在不属于单词(引用)的任何点包装,可以是:
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: some additional info:
更新:一些额外的信息:
-
The PDF file format was designed to look the same in different situations, functionality like the one you requested makes sense in a PDF editor/creator, but not in the PDF file per se. For this reason, most "low level" tools tend to concentrate on dealing with the file format itself and leave away stuff like that.
PDF文件格式的设计在不同情况下看起来相同,您所请求的功能在PDF编辑器/创建者中是有意义的,但在PDF文件本身中则不然。出于这个原因,大多数“低级”工具倾向于专注于处理文件格式本身并留下类似的东西。
-
Higher level tools OTOH usually have means to make this conversion. An example is Platypus (for Python, though), that do have easy ways of creating paragraphs, and relies on the lower level ReportLab functions to do the actual PDF rendering. I'm unaware of similar tools for PDFBox, but this post gives some hints on how to convert HTML content to PDF in a Java environment, using freely available tools. Haven't tried them myself, but I'm posting here since it might be useful (in case my hand-made attempt above is not enough).
更高级别的工具OTOH通常有进行此转换的手段。一个例子是Platypus(虽然是Python),它有简单的方法来创建段落,并依赖于较低级别的ReportLab函数来进行实际的PDF渲染。我不知道PDFBox的类似工具,但这篇文章提供了一些关于如何使用免费提供的工具将Java内容转换为PDF的提示。没有自己试过,但我在这里发帖,因为它可能有用(如果上面的手工制作尝试还不够)。
#2
4
I have been working combining Lukas answer with mgibsonbr and arrived at this. More helpful to people looking for an out-of-the-box solution, I think.
我一直在努力将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;
}
}