首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >IText 7中的多行文本拟合

IText 7中的多行文本拟合
EN

Stack Overflow用户
提问于 2021-06-14 15:49:56
回答 1查看 1.2K关注 0票数 0

这个问题是this在上一篇文章之后的后续,我创建了以下方法,适合段落中某些空格中的文本。

代码语言:javascript
运行
复制
public static void getPlainFill2(String str, Document doc, PdfDocument document, Paragraph root,
    Paragraph space, boolean isCentred) {
// System.out.println("prevText: "+prev.getText());
float width = doc.getPageEffectiveArea(PageSize.A4).getWidth();
float height = doc.getPageEffectiveArea(PageSize.A4).getHeight();
if (str.isEmpty() || str.isBlank()) {
    str = "________";
}
IRenderer spaceRenderer = space.createRendererSubTree().setParent(doc.getRenderer());

LayoutResult spaceResult = spaceRenderer
    .layout(new LayoutContext(new LayoutArea(1, new Rectangle(width, height))));

Rectangle rectSpaceBox = ((ParagraphRenderer) spaceRenderer).getOccupiedArea().getBBox();

float writingWidth = rectSpaceBox.getWidth();
float writingHeight = rectSpaceBox.getHeight();

Rectangle remaining = doc.getRenderer().getCurrentArea().getBBox();
float yReal = remaining.getTop() + 2f;// orig 4f

float sizet = 0;
for (int i = 0; i < root.getChildren().size(); i++) {
    IElement e = root.getChildren().get(i);

    if (e.equals(space)) {

    break;
    }

    IRenderer ss = e.createRendererSubTree().setParent(doc.getRenderer());
    
    LayoutResult ss2 = ss.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width, height))));

    sizet += ss.getOccupiedArea().getBBox().getWidth();

    System.out.println("width: " + width + " current: " + sizet);

}
float start =  sizet+doc.getLeftMargin();
 if(isCentred) 
     start = (width - getRealWidth(doc, root,width,height))/2+doc.getLeftMargin()+sizet;
 


Rectangle towr = new Rectangle(start, yReal, writingWidth, writingHeight);// sizet+doc.getLeftMargin()

PdfCanvas pdfcanvas = new PdfCanvas(document.getFirstPage());
Canvas canvas = new Canvas(pdfcanvas, towr);
canvas.setTextAlignment(TextAlignment.CENTER);
canvas.setHorizontalAlignment(HorizontalAlignment.CENTER);

Paragraph paragraph = new Paragraph(str).setTextAlignment(TextAlignment.CENTER).setBold();//.setMultipliedLeading(0.9f);
Div lineDiv = new Div();
lineDiv.setVerticalAlignment(VerticalAlignment.MIDDLE);
lineDiv.add(paragraph);

float fontSizeL = 1f;
float fontSizeR = 12;
int adjust = 0;
while (Math.abs(fontSizeL - fontSizeR) > 1e-1) {
    float curFontSize = (fontSizeL + fontSizeR) / 2;
    lineDiv.setFontSize(curFontSize);
    // It is important to set parent for the current element renderer to a root
    // renderer
    IRenderer renderer = lineDiv.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;
    }
    if(adjust>=2) {
    writingHeight -=1.3f;
    yReal += 1.4f;
    adjust= 0;
    }
}

lineDiv.setFontSize(fontSizeL);
canvas.add(lineDiv);
// border
// PdfCanvas(document.getFirstPage()).rectangle(towr).setStrokeColor(ColorConstants.BLACK).stroke();

canvas.close();

}




public static float getRealWidth (Document doc, Paragraph root,float width,float height) {
 float sizet = 0;
    
 for(int  i = 0;i<root.getChildren().size();i++) {
     IElement e =  root.getChildren().get(i);
     
    
        IRenderer ss = e.createRendererSubTree().setParent(doc.getRenderer());
    LayoutResult ss2 = ss.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));

    sizet +=ss.getOccupiedArea().getBBox().getWidth();


        
    }
return sizet;}

现在,这几乎很不错,当文本缩放到较低的大小时,会出现一些小问题,比如:https://i.ibb.co/MkxfwjQ/Screenshot-from-2021-06-14-18-27-09.png (我不能发布图片,因为我没有代表)。但主要的问题是,你必须逐行写段落才能工作。下一个例子是:

代码语言:javascript
运行
复制
Cell cell3 = new Cell();
        LineCountingParagraph line3 = new LineCountingParagraph("");
        Text ch07 = new Text("Paragraph Prev ");
        line3.add(ch07);
        Paragraph nrZile =  getEmptySpace(15);
        line3.add(nrZile);
        Text ch08 = new Text("afterStr, textasdsadasdas ");
        line3.add(ch08);
        Paragraph data =  getEmptySpace(18);
        line3.add(data);
        Text ch09 = new Text(".\n");
        line3.add(ch09);
        line3.setTextAlignment(TextAlignment.CENTER);
        cell3.add(line3);
        doc.add(cell3);
        getPlainFill2("thisisalongstring", doc, document, line3, nrZile, true);
        getPlainFill2("1333", doc, document, line3, data, true);
         
           Cell cell4 =  new Cell();
            LineCountingParagraph line4 =  new LineCountingParagraph("");
            Paragraph loc2  = getEmptySpace(30);
            line4.add(loc2);
            Text pr32 = new Text(" aasdbsadasd ");
            line4.add(pr32);
            Paragraph nr2 = getEmptySpace(8);
            line4.add(nr2);
            Text pr33 =  new Text(" asdasdasdasd.\n");
            line4.add(pr33);
            line4.setTextAlignment(TextAlignment.CENTER);
            cell4.add(line4);
            doc.add(cell4);
         
            getPlainFill2("1333", doc, document, line4, nr2, true);

如果你需要更多代码,我会把它上传到某个地方。现在是否有办法在同一段中多行插入文本?因为我似乎找不到一种方法来检测IText 7.1.11中的行中断。

完整代码:

代码语言:javascript
运行
复制
package pdfFill;

import java.io.File;
import java.io.IOException;

import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Div;
import com.itextpdf.layout.element.IElement;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Text;
import com.itextpdf.layout.layout.LayoutArea;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.property.HorizontalAlignment;
import com.itextpdf.layout.property.TextAlignment;
import com.itextpdf.layout.property.VerticalAlignment;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.renderer.ParagraphRenderer;



public class Newway4 {

    public static void main(String[] args) {
        PdfWriter writer;

        try {
            writer = new PdfWriter(new File("test4.pdf"));

            PdfDocument document = new PdfDocument(writer);
             document.getDocumentInfo().addCreationDate();
             document.getDocumentInfo().setAuthor("Piri");
             document.getDocumentInfo().setTitle("Test_Stackoverflow");
             document.setDefaultPageSize(PageSize.A4);
             Document doc =  new Document(document);
             doc.setFontSize(12);
          

            
            
        
            final Paragraph titlu = new Paragraph();
            final Text t1 = new Text("\n\n\n\nTest Stackoverflow\n\n\n").setBold().setUnderline();
            titlu.setHorizontalAlignment(HorizontalAlignment.CENTER);
            titlu.setTextAlignment(TextAlignment.CENTER);
            titlu.add(t1).setBold();
            doc.add(titlu);
            

            Cell cell1 = new Cell();
            LineCountingParagraph line1 = new LineCountingParagraph("");
            line1.add( addTab());
            Text ch01 = new Text("This is the 1st example ");
            line1.add(ch01);
            Paragraph name =  getEmptySpace(42);
            line1.add(name);// cnp new line
            Text ch02 = new Text(" that works ");
            line1.add(ch02);
            Paragraph domiciliu =  getEmptySpace(63);
            line1.add(domiciliu);
            /* Text ch03 = new Text("\njudet");
            line1.add(ch03);
            Paragraph judet =  getEmptySpace(12);
            line1.add(judet);*/
           Text ch031 = new Text("\n");
            line1.add(ch031);
            cell1.add(line1);
            doc.add(cell1);
             getPlainFill2("with insertion str", doc, document, line1, name, false);
             getPlainFill2("because is writtin line by line", doc, document, line1, domiciliu, false);
          


             
             
             Cell cell2 =  new Cell();
                LineCountingParagraph line2 =  new LineCountingParagraph("");
                Text p51 = new Text("as you can see in this");
                line2.add(p51);
                Paragraph localitatea = getEmptySpace(30);
                line2.add(localitatea);
                Text p7 = new Text(" and ");
                line2.add(p7);
                Paragraph nrCasa =getEmptySpace(8);
                line2.add(nrCasa);
                Text p09 = new Text(" of text scalling ");
                line2.add(p09);
                Paragraph telefon = getEmptySpace(22);
                line2.add(telefon);
                Text p11 =  new Text(".");
                line2.add(p11);
                line2.setTextAlignment(TextAlignment.CENTER);
                cell2.add(line2);
                doc.add(cell2);
                getPlainFill2("sentence", doc, document, line2, localitatea, true);
                getPlainFill2("example", doc, document, line2, nrCasa, true);
                getPlainFill2("text scalling bla bla", doc, document, line2, telefon, true);
             
             
             doc.add(new Paragraph("\n\n\n"));
             
             
             LineCountingParagraph paragraphTest =  new LineCountingParagraph("");
             paragraphTest.add(addTab());
             Text testch01 =  new Text("This is the 2nd example ");
             paragraphTest.add(testch01);
             Paragraph emptyTest01 =  getEmptySpace(42);
             paragraphTest.add(emptyTest01);
             Text testch02 =  new Text(" that doesn't work ");
             paragraphTest.add(testch02);
             Paragraph  emptyTest02 =  getEmptySpace(53);
             paragraphTest.add(emptyTest02);
             Text testch04 =  new Text(" this next goes to the next line but ");
             paragraphTest.add(testch04);
             Paragraph emptyTest03 =  getEmptySpace(42);
             paragraphTest.add(emptyTest03);
             Text testch05 =  new Text(" won't appear !!");
             paragraphTest.add(testch05);
             doc.add(paragraphTest);
             getPlainFill2("with insertion str", doc, document, paragraphTest, emptyTest01, false);
             getPlainFill2("because next text goes next line", doc, document, paragraphTest, emptyTest02, false);
             getPlainFill2("this text", doc, document, paragraphTest, emptyTest03, false);
             
            
             
             
        
            doc.close();
            writer.flush();


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static String getStrWithDots(final int dots, final String str) {
        final int strSize = str.length();
        final StringBuilder sb = new StringBuilder();
        int dotsRemained;
        if (strSize > dots) {
            dotsRemained = 0;
        } else {
            dotsRemained = dots - strSize;
        }
        for (int i = 0; i < dotsRemained; ++i) {
            if (i == dotsRemained / 2) {
            sb.append(str);
            }
            sb.append(".");
        }
        return sb.toString();
        }
    
      public static void getPlainFill2(String str, Document doc, PdfDocument document, Paragraph root,
                Paragraph space, boolean isCentred) {
            // System.out.println("prevText: "+prev.getText());
            float width = doc.getPageEffectiveArea(PageSize.A4).getWidth();
            float height = doc.getPageEffectiveArea(PageSize.A4).getHeight();
            if (str.isEmpty() || str.isBlank()) {
                str = "________";
            }
            IRenderer spaceRenderer = space.createRendererSubTree().setParent(doc.getRenderer());

            LayoutResult spaceResult = spaceRenderer
                .layout(new LayoutContext(new LayoutArea(1, new Rectangle(width, height))));

            Rectangle rectSpaceBox = ((ParagraphRenderer) spaceRenderer).getOccupiedArea().getBBox();

            float writingWidth = rectSpaceBox.getWidth();
            float writingHeight = rectSpaceBox.getHeight();

            Rectangle remaining = doc.getRenderer().getCurrentArea().getBBox();
            float yReal = remaining.getTop() + 2f;// orig 4f

            float sizet = 0;
            for (int i = 0; i < root.getChildren().size(); i++) {
                IElement e = root.getChildren().get(i);

                if (e.equals(space)) {

                break;
                }

                IRenderer ss = e.createRendererSubTree().setParent(doc.getRenderer());
                
                LayoutResult ss2 = ss.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width, height))));

                sizet += ss.getOccupiedArea().getBBox().getWidth();


            }
            float start =  sizet+doc.getLeftMargin();
             if(isCentred) 
                 start = (width - getRealWidth(doc, root,width,height))/2+doc.getLeftMargin()+sizet;
             
            
            
            Rectangle towr = new Rectangle(start, yReal, writingWidth, writingHeight);// sizet+doc.getLeftMargin()

            PdfCanvas pdfcanvas = new PdfCanvas(document.getFirstPage());
            Canvas canvas = new Canvas(pdfcanvas, towr);
            canvas.setTextAlignment(TextAlignment.CENTER);
            canvas.setHorizontalAlignment(HorizontalAlignment.CENTER);

            Paragraph paragraph = new Paragraph(str).setTextAlignment(TextAlignment.CENTER).setBold();//.setMultipliedLeading(0.9f);//setbold oprtional
            Div lineDiv = new Div();
            lineDiv.setVerticalAlignment(VerticalAlignment.MIDDLE);
            lineDiv.add(paragraph);

            float fontSizeL = 0.0001f, fontSizeR= 10000;
            int adjust = 0;
         
            while (Math.abs(fontSizeL - fontSizeR) > 1e-1) {
                float curFontSize = (fontSizeL + fontSizeR) / 2;
                lineDiv.setFontSize(curFontSize);
                // It is important to set parent for the current element renderer to a root
                // renderer
                IRenderer renderer = lineDiv.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;
                
                   if (++adjust>1)
                       towr.setHeight(towr.getHeight()-0.90f);
                } else {
                fontSizeR = curFontSize;
                }
              
            }

            lineDiv.setFontSize(fontSizeL);
            canvas.add(lineDiv);
    
             new PdfCanvas(document.getFirstPage()).rectangle(towr).setStrokeColor(ColorConstants.BLACK).stroke();

            canvas.close();

            }
   
    public static Text addTab() {
        StringBuilder sb =  new StringBuilder();
        for(int i = 0;i<8;i++)
            sb.append("\u00a0");
        return new Text(sb.toString());
    }
    
    
    
    public static float getRealWidth (Document doc, Paragraph root,float width,float height) {
         float sizet = 0;
            
         for(int  i = 0;i<root.getChildren().size();i++) {
             IElement e =  root.getChildren().get(i);
             
            
                IRenderer ss = e.createRendererSubTree().setParent(doc.getRenderer());
            LayoutResult ss2 = ss.layout(new LayoutContext(new LayoutArea(1, new Rectangle(width,height))));
      
            sizet +=ss.getOccupiedArea().getBBox().getWidth();

        
                
            }
        return sizet;
    }
     
     
   
    

     
     private static Paragraph getEmptySpace(int size) {
          Paragraph space = new Paragraph();
            space.setMaxWidth(size);
            for(int i=0;i<size;i++) {
            //    par.add("\u00a0");
                space.add("\u00a0");
            }
            return space;
     }
     
     
     
     private static class LineCountingParagraph extends Paragraph {
            private int linesWritten = 0;

            public LineCountingParagraph(String text) {
                super(text);
            }

            public void addWrittenLines(int toAdd) {
                linesWritten += toAdd;
            }

            public int getNumberOfWrittenLines() {
                return linesWritten;
            }

            @Override
            protected IRenderer makeNewRenderer() {
                return new LineCountingParagraphRenderer(this);
            }
        }

        private static class LineCountingParagraphRenderer extends ParagraphRenderer {
            public LineCountingParagraphRenderer(LineCountingParagraph modelElement) {
                super(modelElement);
            }

            @Override
            public void drawChildren(DrawContext drawContext) {
                ((LineCountingParagraph)modelElement).addWrittenLines(lines.size());
                super.drawChildren(drawContext);
            }

            @Override
            public IRenderer getNextRenderer() {
                return new LineCountingParagraphRenderer((LineCountingParagraph) modelElement);
            }
        }

}

问题:在PDF的上半部分,您可以看到创建两个LineCountingParagraph实例的结果,每一行一个。在PDF的下半部分,您可以看到只创建一个LineCountingParagraph实例时的结果。因此,如果段落的内容被包装到下一行,将文本放在方框中并不能很好地工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-01 19:18:21

你有一些不必要复杂的事情,所以我们必须从头开始:)

因此,的目标是能够创建带有固定宽度的带框侵入的段落,在其中我们需要复制适合(放置)一些文本,确保字体大小的选择能够使文本适合到该框中。

结果应该类似于这张图片:

我们的想法是将固定宽度的段落添加到主要段落中(iText允许添加块元素,段落是块元素-段落)。固定的宽度将由我们的段落内容保证-它将只包含不可破坏的空间。我们的段落实际上将由另一个段落支持,我们希望在包装段落中加入实际内容。在包装段落的布局中,我们将知道它的有效边界,我们将使用该区域来确定内容段落的正确字体大小,使用二进制搜索算法。一旦确定了正确的字体大小,我们将确保包含内容的段落被绘制在包装段落的旁边。

我们包装段落的代码非常简单。它只是期望底层段落以实际内容作为参数。与iText布局一样,我们应该自定义自动标号段落的呈现器:

代码语言:javascript
运行
复制
private static class AutoScalingParagraph extends Paragraph {
    Paragraph innerParagraph;

    public AutoScalingParagraph(Paragraph innerParagraph) {
        this.innerParagraph = innerParagraph;
    }

    @Override
    protected IRenderer makeNewRenderer() {
        return new AutoScalingParagraphRenderer(this);
    }
}

private static class AutoScalingParagraphRenderer extends ParagraphRenderer {
    private IRenderer innerRenderer;

    public AutoScalingParagraphRenderer(AutoScalingParagraph modelElement) {
        super(modelElement);
    }

    @Override
    public LayoutResult layout(LayoutContext layoutContext) {
        LayoutResult baseResult = super.layout(layoutContext);
        this.innerRenderer = ((AutoScalingParagraph)modelElement).innerParagraph.createRendererSubTree().setParent(this);
        if (baseResult.getStatus() == LayoutResult.FULL) {
            float fontSizeL = 0.0001f, fontSizeR= 10000;

            while (Math.abs(fontSizeL - fontSizeR) > 1e-1) {
                float curFontSize = (fontSizeL + fontSizeR) / 2;
                this.innerRenderer.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(curFontSize));

                if (this.innerRenderer.layout(new LayoutContext(getOccupiedArea().clone())).getStatus() == LayoutResult.FULL) {
                    // we can fit all the text with curFontSize
                    fontSizeL = curFontSize;
                } else {
                    fontSizeR = curFontSize;
                }
            }
            this.innerRenderer.setProperty(Property.FONT_SIZE, UnitValue.createPointValue(fontSizeL));

            this.innerRenderer.layout(new LayoutContext(getOccupiedArea().clone()));
        }
        return baseResult;
    }

    @Override
    public void drawChildren(DrawContext drawContext) {
        super.drawChildren(drawContext);
        innerRenderer.draw(drawContext);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new AutoScalingParagraphRenderer((AutoScalingParagraph) modelElement);
    }
}

现在,我们添加了帮助函数,用于创建包装器段落,这些段落在空格中只接受所需的段落宽度,以及我们希望插入到该空间中的基本内容:

代码语言:javascript
运行
复制
private static Paragraph createAdjustableParagraph(int widthInSpaces, Paragraph innerContent) {
    AutoScalingParagraph paragraph = new AutoScalingParagraph(innerContent);
    paragraph.setBorder(new SolidBorder(1));

    StringBuilder sb = new StringBuilder();
    for(int i=0;i<widthInSpaces;i++) {
        sb.append("\u00a0");
    }
    paragraph.add(sb.toString());
    return paragraph;
}

最后,主要代码:

代码语言:javascript
运行
复制
PdfWriter writer = new PdfWriter(new File("test4.pdf"));

PdfDocument document = new PdfDocument(writer);
Document doc = new Document(document);

Paragraph paragraphTest = new Paragraph();
Text testch01 =  new Text("This is the 2nd example ");
paragraphTest.add(testch01);
paragraphTest.add(createAdjustableParagraph(42, new Paragraph("with insertion str")));
Text testch02 =  new Text(" that doesn't work ");
paragraphTest.add(testch02);
paragraphTest.add(createAdjustableParagraph(53, new Paragraph("because next text goes next line")));
Text testch04 =  new Text(" this next goes to the next line but ");
paragraphTest.add(testch04);
paragraphTest.add(createAdjustableParagraph(42, new Paragraph("this text")));
Text testch05 =  new Text(" won't appear !!");
paragraphTest.add(testch05);
doc.add(paragraphTest);

doc.close();

这给了我们以下结果:

因此,我们只有一个主要段落,其中包含一些内容和我们的段落包装,在tern中有我们想要适应的基本内容。

提示:以文本为中心很容易,不需要计算坐标等。只需将正确的属性设置为段落,并将内容提供给包装器段落:

代码语言:javascript
运行
复制
paragraphTest.add(createAdjustableParagraph(42, new Paragraph("this text").setTextAlignment(TextAlignment.CENTER)));

你得到的结果:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67973438

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档