Optimization Itext 7文本拟合的更好解决方案
我有一个项目,使用Itext 5并按预期工作。 程序必须将用户输入放在段落内的某些“块”中。段落每行有不可移动的(块)字,userInput应该在段落内为userInput保留的空间中缩放。 旧项目有以下代码(作为示例)Optimization Itext 7文本拟合的更好解决方案,optimization,itext,itext7,Optimization,Itext,Itext7,我有一个项目,使用Itext 5并按预期工作。 程序必须将用户输入放在段落内的某些“块”中。段落每行有不可移动的(块)字,userInput应该在段落内为userInput保留的空间中缩放。 旧项目有以下代码(作为示例) 公共类旧方式{ 静态最终瞬态字体bold2=FontFactory.getFont(“Times Roman”,10.0f,1); 公共静态void main(字符串[]args){ 文档=新文档(); 文件。设置页面大小(页面大小为A4); 试一试{ PdfWriter wr
公共类旧方式{
静态最终瞬态字体bold2=FontFactory.getFont(“Times Roman”,10.0f,1);
公共静态void main(字符串[]args){
文档=新文档();
文件。设置页面大小(页面大小为A4);
试一试{
PdfWriter writer=PdfWriter.getInstance(文档,新文件输出流(新文件(“itext5.pdf”));
document.open();
段落标题=新段落(“文件标题”);
标题.调整(1);
文件。添加(标题);
第dec段=新的第()段;
Chunk ch01=新块(“上一个文本”);
12月添加(ch01);
Chunk ch02=新块(getEmptySpace(42));
12月添加(ch02);
Chunk ch03=新块(“下一个文本”);
12月增补(ch03);
文件.增补(12月);
float y=writer.getVerticalPosition(false);
float x2=document.left()+ch01.getWidthPoint();
float x3=x2+ch02.getWidthPoint();
getPlainFillTest(“要插入的文本”,文档,y,x3,x2,编写器,false);
document.close();
writer.flush();
}捕获(FileNotFoundException | DocumentException e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
公共静态块getEmptySpace(整数大小){
Chunk ch=新Chunk();
对于(int i=0;i高度){
fontSize-=0.1f;
maxHeight=测量高度(bf、文本、字体大小);
};
返回字体大小;
}
公共静态浮点度量值高(BaseFont BaseFont、字符串文本、浮点fontSize)
{
float ascend=baseFont.getAscentPoint(文本,fontSize);
float down=baseFont.getDescentPoint(文本,fontSize);
返回上升-下降;
}}
现在我正试着在IText 7中做同样的事情,而且…不是那么容易!
我设法创建了一个工作代码,但它很混乱,有些东西没有得到正确的坐标。Itext7代码(作为示例制作):
Newway公共类{
公共静态void main(字符串[]args){
编剧;
试一试{
writer=newpdfwriter(新文件(“test2.pdf”);
PDF文档=新PDF文档(编写器);
document.getDocumentInfo().addCreationDate();
document.getDocumentInfo().setTitle(“标题”);
document.setDefaultPageSize(PageSize.A4);
单据单据=新单据(单据);
文件setFontSize(12);
段落=新段落();
文本ch01=新文本(“上一文本”);
添加(CH01);
段落间距=新段落();
space.setMaxWidth(40);
对于(int i=0;i 1e-1){
float curFontSize=(fontSizeL+fontSizeR)/2;
linePara.setFontSize(curFontSize);
//将当前元素渲染器的父级设置为根渲染器非常重要
IRenderer renderer=linePara.createRenderSubtree().setParent(canvas.getRenderer());
LayoutContext=新的LayoutContext(新的LayoutArea(1,towr));
if(renderer.layout(context.getStatus()==LayoutResult.FULL){
//我们可以用curFontSize匹配所有文本
fontSizeL=curFontSize;
}否则{
fontSizeR=curFontSize;
}
}
canvas.add(linePara);
新的PdfCanvas(document.getFirstPage()).rectangle(towr).setStrokeColor(ColorConstants.BLACK).stroke();
canvas.close();
doc.close();
writer.flush();
}捕获(IOE异常){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}}
问题是
+(rheight*2.05f)这里的代码>而实际上,这里缺少的是,当您通过画布绘制时,您不再定义边距,因此您真正需要的不是rect.getY()+(rheight*2.05f)代码>是rect.getY()+doc.getBottomMargin()
rheight
作为renderer.getInnerAreaBBox()
计算,而此计算不考虑应用于段落的默认边距。边距包括在占用区域中,但不包括内部区域bbox。要解决此问题,请改用renderer.getoccupiedera().getBBox()
。在这种情况下,不再需要将rheight
乘以系数
public class Oldway {
static final transient Font bold2 = FontFactory.getFont("Times-Roman", 10.0f, 1);
public static void main(String[] args) {
Document document = new Document();
document.setPageSize(PageSize.A4);
try {
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(new File("itext5.pdf")));
document.open();
Paragraph title = new Paragraph("Title of doc");
title.setAlignment(1);
document.add(title);
Paragraph dec= new Paragraph();
Chunk ch01 = new Chunk("Prev text ");
dec.add(ch01);
Chunk ch02 = new Chunk(getEmptySpace(42));
dec.add(ch02);
Chunk ch03 = new Chunk(" next Text");
dec.add(ch03);
document.add(dec);
float y = writer.getVerticalPosition(false);
float x2 = document.left() + ch01.getWidthPoint();
float x3 = x2 + ch02.getWidthPoint();
getPlainFillTest("Text to insert", document, y, x3, x2, writer, false);
document.close();
writer.flush();
} catch (FileNotFoundException | DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Chunk getEmptySpace(int size) {
Chunk ch = new Chunk();
for(int i = 0;i<=size;i++) {
ch.append("\u00a0");
}
return new Chunk(ch);
}
public static void getPlainFillTest(String str,Document document,float y, float x1pos,
float x2pos, PdfWriter writer,boolean withTab) {
if(str.isEmpty() || str.isBlank()) {
str = "________";
}
Rectangle rec2 = null;
if(!withTab)
rec2 = new Rectangle(x2pos, y, x1pos-2,y+10);
else {
rec2 = new Rectangle(x2pos+35, y, x1pos+33,y+10);
}
BaseFont bf = bold2.getBaseFont();
PdfContentByte cb = writer.getDirectContent();
float fontSize = getMaxFontSize(bf, str,(int)rec2.getWidth(), (int)rec2.getHeight());
Phrase phrase = new Phrase(str, new Font(bf, fontSize));
ColumnText.showTextAligned(cb, Element.ALIGN_CENTER, phrase,
// center horizontally
(rec2.getLeft() + rec2.getRight()) / 2,
// shift baseline based on descent
rec2.getBottom() - bf.getDescentPoint(str, fontSize),0);
cb.saveState();//patrulaterul albastru
cb.setColorStroke(Color.BLUE);
cb.rectangle(rec2.getLeft(), rec2.getBottom(), rec2.getWidth(), rec2.getHeight());
cb.stroke();
cb.restoreState();
}
//stackoverflow solution
private static float getMaxFontSize(BaseFont bf, String text, int width, int height){
// avoid infinite loop when text is empty
if(text.isEmpty()){
return 0.0f;
}
float fontSize = 0.1f;
while(bf.getWidthPoint(text, fontSize) < width){
fontSize += 0.1f;
}
float maxHeight = measureHeight(bf, text, fontSize);
while(maxHeight > height){
fontSize -= 0.1f;
maxHeight = measureHeight(bf, text, fontSize);
};
return fontSize;
}
public static float measureHeight(BaseFont baseFont, String text, float fontSize)
{
float ascend = baseFont.getAscentPoint(text, fontSize);
float descend = baseFont.getDescentPoint(text, fontSize);
return ascend - descend;
}}
public class Newway {
public static void main(String[] args) {
PdfWriter writer;
try {
writer = new PdfWriter(new File("test2.pdf"));
PdfDocument document = new PdfDocument(writer);
document.getDocumentInfo().addCreationDate();
document.getDocumentInfo().setTitle("Title");
document.setDefaultPageSize(PageSize.A4);
Document doc = new Document(document);
doc.setFontSize(12);
Paragraph par = new Paragraph();
Text ch01 = new Text("Prev Text ");
par.add(ch01);
Paragraph space = new Paragraph();
space.setMaxWidth(40);
for(int i=0;i<40;i++) {
par.add("\u00a0");
space.add("\u00a0");
}
Text ch02 = new Text(" next text");
par.add(ch02);
doc.add(par);
Paragraph linePara = new Paragraph().add("Test from UserInput")
.setTextAlignment(TextAlignment.CENTER).setBorder(new DottedBorder(1));
float width = doc.getPageEffectiveArea(PageSize.A4).getWidth();
float height = doc.getPageEffectiveArea(PageSize.A4).getHeight();
IRenderer primul = ch01.createRendererSubTree().setParent(doc.getRenderer());
IRenderer spaceR = space.createRendererSubTree().setParent(doc.getRenderer());
LayoutResult primulResult = primul.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));
LayoutResult layoutResult = spaceR.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));
Rectangle primulBox = ((TextRenderer) primul).getInnerAreaBBox();
Rectangle rect = ((ParagraphRenderer) spaceR).getInnerAreaBBox();
float rwidth = rect.getWidth();
float rheight = rect.getHeight();
float x = primulBox.getWidth()+ doc.getLeftMargin();
float y = rect.getY()+(rheight*2.05f);//rect.getY() is never accurate, is always below the paragraph. WHY ??
Rectangle towr = new Rectangle(x, y, rwidth, rheight*1.12f);//rheight on default is way too small
PdfCanvas pdfcanvas = new PdfCanvas(document.getFirstPage());
Canvas canvas = new Canvas(pdfcanvas, towr);
//from theinternet
float fontSizeL = 1;
float fontSizeR = 14;
while (Math.abs(fontSizeL - fontSizeR) > 1e-1) {
float curFontSize = (fontSizeL + fontSizeR) / 2;
linePara.setFontSize(curFontSize);
// It is important to set parent for the current element renderer to a root renderer
IRenderer renderer = linePara.createRendererSubTree().setParent(canvas.getRenderer());
LayoutContext context = new LayoutContext(new LayoutArea(1, towr));
if (renderer.layout(context).getStatus() == LayoutResult.FULL) {
// we can fit all the text with curFontSize
fontSizeL = curFontSize;
} else {
fontSizeR = curFontSize;
}
}
canvas.add(linePara);
new PdfCanvas(document.getFirstPage()).rectangle(towr).setStrokeColor(ColorConstants.BLACK).stroke();
canvas.close();
doc.close();
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}
PdfWriter writer;
try {
writer = new PdfWriter(new File("test2.pdf"));
PdfDocument document = new PdfDocument(writer);
document.getDocumentInfo().addCreationDate();
document.getDocumentInfo().setTitle("Title");
document.setDefaultPageSize(PageSize.A4);
Document doc = new Document(document);
doc.setFontSize(12);
Paragraph par = new Paragraph();
Text ch01 = new Text("Prev Text ");
par.add(ch01);
Paragraph space = new Paragraph();
space.setMaxWidth(40);
for(int i=0;i<40;i++) {
par.add("\u00a0");
space.add("\u00a0");
}
Text ch02 = new Text(" next text");
par.add(ch02);
doc.add(par);
Paragraph linePara = new Paragraph().add("Test from UserInput")
.setTextAlignment(TextAlignment.CENTER).setBorder(new DottedBorder(1));
float width = doc.getPageEffectiveArea(PageSize.A4).getWidth();
float height = doc.getPageEffectiveArea(PageSize.A4).getHeight();
IRenderer primul = ch01.createRendererSubTree().setParent(doc.getRenderer());
IRenderer spaceR = space.createRendererSubTree().setParent(doc.getRenderer());
LayoutResult primulResult = primul.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));
LayoutResult layoutResult = spaceR.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));
Rectangle primulBox = ((TextRenderer) primul).getInnerAreaBBox();
Rectangle rect = ((ParagraphRenderer) spaceR).getOccupiedArea().getBBox();
float rwidth = rect.getWidth();
float rheight = rect.getHeight();
float x = primulBox.getWidth()+ doc.getLeftMargin();
float y = rect.getY() + doc.getBottomMargin();
Rectangle towr = new Rectangle(x, y, rwidth, rheight);
PdfCanvas pdfcanvas = new PdfCanvas(document.getFirstPage());
Canvas canvas = new Canvas(pdfcanvas, towr);
//from theinternet
float fontSizeL = 1;
float fontSizeR = 14;
while (Math.abs(fontSizeL - fontSizeR) > 1e-1) {
float curFontSize = (fontSizeL + fontSizeR) / 2;
linePara.setFontSize(curFontSize);
// It is important to set parent for the current element renderer to a root renderer
IRenderer renderer = linePara.createRendererSubTree().setParent(canvas.getRenderer());
LayoutContext context = new LayoutContext(new LayoutArea(1, towr));
if (renderer.layout(context).getStatus() == LayoutResult.FULL) {
// we can fit all the text with curFontSize
fontSizeL = curFontSize;
} else {
fontSizeR = curFontSize;
}
}
canvas.add(linePara);
new PdfCanvas(document.getFirstPage()).rectangle(towr).setStrokeColor(ColorConstants.BLACK).stroke();
canvas.close();
doc.close();
writer.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}