Optimization Itext 7文本拟合的更好解决方案

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

我有一个项目,使用Itext 5并按预期工作。 程序必须将用户输入放在段落内的某些“块”中。段落每行有不可移动的(块)字,userInput应该在段落内为userInput保留的空间中缩放。 旧项目有以下代码(作为示例)

公共类旧方式{
静态最终瞬态字体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();
}
}}
问题是

  • 有没有更好、更优雅的方法
  • 为什么rect.getY()总是在段落下方?我怎样才能让Y与真正的Y coorinate匹配呢
  • 为什么默认的“rheight”总是太小?但是(rheight*1.1f)有效吗
  • (可选)如何在IText 7中设置tab()空间大小
  • 这种方法非常好,因为它考虑了所有可能的模型元素设置和布局过程的含义。您的iText 5替代方案对于基于拉丁语的文本的基本情况来说已经足够好了,在视觉方面没有任何修改。您拥有的iText 7代码更加灵活,如果您使用更复杂的布局设置、复杂的脚本等,它仍然可以工作。此外,我看到在您的示例中,iText 5代码是105行,而iText 7代码是80行

  • 您正在添加一些神奇的
    +(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();
    }