Skip to main content
Skip table of contents

Fit text in cell

These examples were written in answer to questions such as:

clipcentercellcontent

JAVA

Java

JAVA
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.sandbox.tables;

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.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.layout.LayoutArea;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;

import java.io.File;

public class ClipCenterCellContent {
    public static final String DEST = "./target/sandbox/tables/clip_center_cell_content.pdf";

    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new ClipCenterCellContent().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth();

        for (int r = 'A'; r <= 'Z'; r++) {
            for (int c = 1; c <= 5; c++) {
                Cell cell = new Cell();

                if (r == 'D' && c == 2) {

                    // Draw a content that will be clipped in the cell
                    cell.setNextRenderer(new ClipCenterCellContentCellRenderer(cell,
                            new Paragraph("D2 is a cell with more content than we can fit into the cell.")));
                } else {
                    cell.add(new Paragraph(String.valueOf((char) r) + c));
                }
                table.addCell(cell);
            }
        }

        doc.add(table);

        doc.close();
    }


    private static class ClipCenterCellContentCellRenderer extends CellRenderer {
        private Paragraph content;

        public ClipCenterCellContentCellRenderer(Cell modelElement, Paragraph content) {
            super(modelElement);
            this.content = content;
        }

        // If a renderer overflows on the next area, iText uses #getNextRenderer() method to create a new renderer for the overflow part.
        // If #getNextRenderer() isn't overridden, the default method will be used and thus the default rather than the custom
        // renderer will be created
        @Override
        public IRenderer getNextRenderer() {
            return new ClipCenterCellContentCellRenderer((Cell) modelElement, content);
        }

        @Override
        public void draw(DrawContext drawContext) {

            // Fictitiously layout the renderer and find out, how much space does it require
            IRenderer pr = content.createRendererSubTree().setParent(this);

            LayoutResult textArea = pr.layout(new LayoutContext(
                    new LayoutArea(0, new Rectangle(getOccupiedAreaBBox().getWidth(), 1000))));

            float spaceNeeded = textArea.getOccupiedArea().getBBox().getHeight();
            System.out.println(String.format("The content requires %s pt whereas the height is %s pt.",
                    spaceNeeded, getOccupiedAreaBBox().getHeight()));

            float offset = (getOccupiedAreaBBox().getHeight() - textArea.getOccupiedArea().getBBox().getHeight()) / 2;
            System.out.println(String.format("The difference is %s pt; we'll need an offset of %s pt.",
                    -2f * offset, offset));

            PdfFormXObject xObject = new PdfFormXObject(new Rectangle(getOccupiedAreaBBox().getWidth(),
                    getOccupiedAreaBBox().getHeight()));
            Canvas layoutCanvas = new Canvas(new PdfCanvas(xObject, drawContext.getDocument()),
                    new Rectangle(0, offset, getOccupiedAreaBBox().getWidth(), spaceNeeded));
            layoutCanvas.add(content);

            drawContext.getCanvas().addXObjectAt(xObject, occupiedArea.getBBox().getLeft(), occupiedArea.getBBox().getBottom());
        }
    }
}

C#

C#

C#
using System;
using System.IO;
using iText.Kernel.Geom;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Kernel.Pdf.Xobject;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Layout;
using iText.Layout.Properties;
using iText.Layout.Renderer;

namespace iText.Samples.Sandbox.Tables
{
    public class ClipCenterCellContent
    {
        public static readonly string DEST = "results/sandbox/tables/clip_center_cell_content.pdf";

        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();

            new ClipCenterCellContent().ManipulatePdf(DEST);
        }

        private void ManipulatePdf(string dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document doc = new Document(pdfDoc);

            Table table = new Table(UnitValue.CreatePercentArray(5)).UseAllAvailableWidth();
            
            for (int r = 'A'; r <= 'Z'; r++)
            {
                for (int c = 1; c <= 5; c++)
                {
                    Cell cell = new Cell();
                    if (r == 'D' && c == 2)
                    {
                        // Draw a content that will be clipped in the cell 
                        cell.SetNextRenderer(new ClipCenterCellContentCellRenderer(cell,
                            new Paragraph("D2 is a cell with more content than we can fit into the cell.")));
                    }
                    else
                    {
                        cell.Add(new Paragraph(((char) r).ToString() + c));
                    }

                    table.AddCell(cell);
                }
            }

            doc.Add(table);

            doc.Close();
        }

        private class ClipCenterCellContentCellRenderer : CellRenderer
        {
            private Paragraph content;

            public ClipCenterCellContentCellRenderer(Cell modelElement, Paragraph content)
                : base(modelElement)
            {
                this.content = content;
            }            
            
            // If renderer overflows on the next area, iText uses getNextRender() method to create a renderer for the overflow part.
            // If getNextRenderer isn't overriden, the default method will be used and thus a default rather than custom
            // renderer will be created
            public override IRenderer GetNextRenderer()
            {
                return new ClipCenterCellContentCellRenderer((Cell) modelElement, content);
            }

            public override void Draw(DrawContext drawContext)
            {

                // Fictitiously layout the renderer and find out, how much space does it require
                IRenderer pr = content.CreateRendererSubTree().SetParent(this);

                LayoutResult textArea = pr.Layout(new LayoutContext(
                    new LayoutArea(0, new Rectangle(GetOccupiedAreaBBox().GetWidth(), 1000))));

                float spaceNeeded = textArea.GetOccupiedArea().GetBBox().GetHeight();
                Console.WriteLine("The content requires {0} pt whereas the height is {1} pt.",
                    spaceNeeded, GetOccupiedAreaBBox().GetHeight());

                float offset = (GetOccupiedAreaBBox().GetHeight() - textArea.GetOccupiedArea()
                                    .GetBBox().GetHeight()) / 2;
                Console.WriteLine("The difference is {0} pt; we'll need an offset of {1} pt.",
                    -2f * offset, offset);

                PdfFormXObject xObject = new PdfFormXObject(new Rectangle(GetOccupiedAreaBBox().GetWidth(),
                    GetOccupiedAreaBBox().GetHeight()));

                Canvas layoutCanvas = new Canvas(new PdfCanvas(xObject, drawContext.GetDocument()),
                    new Rectangle(0, offset, GetOccupiedAreaBBox().GetWidth(), spaceNeeded));
                layoutCanvas.Add(content);

                drawContext.GetCanvas().AddXObjectAt(xObject, occupiedArea.GetBBox().GetLeft(),
                    occupiedArea.GetBBox().GetBottom());
            }
        }
    }
}

truncatetextincell

JAVA

JAVA

JAVA
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.sandbox.tables;

import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.properties.Property;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.IRenderer;

import java.io.File;

public class TruncateTextInCell {
    public static final String DEST = "./target/sandbox/tables/truncate_text_in_cell.pdf";

    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new TruncateTextInCell().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth();

        for (int r = 'A'; r <= 'Z'; r++) {
            for (int c = 1; c <= 5; c++) {
                Cell cell = new Cell();
                if (r == 'D' && c == 2) {
                    cell.setNextRenderer(new FitCellRenderer(cell,
                            "D2 is a cell with more content than we can fit into the cell."));
                } else {
                    cell.add(new Paragraph(String.valueOf((char) r) + c));
                }

                table.addCell(cell);
            }
        }

        doc.add(table);

        doc.close();
    }

    private static class FitCellRenderer extends CellRenderer {
        private String content;

        public FitCellRenderer(Cell modelElement, String content) {
            super(modelElement);
            this.content = content;
        }

        // If a renderer overflows on the next area, iText uses #getNextRenderer() method to create a new renderer for the overflow part.
        // If #getNextRenderer() isn't overridden, the default method will be used and thus the default rather than the custom
        // renderer will be created
        @Override
        public IRenderer getNextRenderer() {
            return new FitCellRenderer((Cell) modelElement, content);
        }

        /**
         * Method adapts content, that can't be fit into the cell,
         * to prevent truncation by replacing truncated part of content with '...'
         */
        @Override
        public LayoutResult layout(LayoutContext layoutContext) {
            PdfFont bf = getPropertyAsFont(Property.FONT);
            int contentLength = content.length();
            int leftChar = 0;
            int rightChar = contentLength - 1;

            Rectangle rect = layoutContext.getArea().getBBox().clone();

            // Cell's margins, borders and paddings should be extracted from the available width as well.
            // Note that this part of the sample was introduced specifically for iText.
            // since in iText5 the approach of processing cells was different
            applyMargins(rect, false);
            applyBorderBox(rect, false);
            applyPaddings(rect, false);
            float availableWidth = rect.getWidth();

            UnitValue fontSizeUV = this.getPropertyAsUnitValue(Property.FONT_SIZE);

            // Unit values can be of POINT or PERCENT type. In this particular sample
            // the font size value is expected to be of POINT type.
            float fontSize = fontSizeUV.getValue();

            availableWidth -= bf.getWidth("...", fontSize);

            while (leftChar < contentLength && rightChar != leftChar) {
                availableWidth -= bf.getWidth(content.charAt(leftChar), fontSize);
                if (availableWidth > 0) {
                    leftChar++;
                } else {
                    break;
                }

                availableWidth -= bf.getWidth(content.charAt(rightChar), fontSize);

                if (availableWidth > 0) {
                    rightChar--;
                } else {
                    break;
                }
            }

            // left char is the first char which should not be added
            // right char is the last char which should not be added
            String newContent = content.substring(0, leftChar) + "..." + content.substring(rightChar + 1);
            Paragraph p = new Paragraph(newContent);

            // We're operating on a Renderer level here, that's why we need to process a renderer,
            // created with the updated paragraph
            IRenderer pr = p.createRendererSubTree().setParent(this);
            childRenderers.add(pr);

            return super.layout(layoutContext);
        }
    }
}

C#

C#

C#
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 Apryse Group NV
    Authors: Apryse Software.

    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
package com.itextpdf.samples.sandbox.tables;

import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.layout.LayoutContext;
import com.itextpdf.layout.layout.LayoutResult;
import com.itextpdf.layout.properties.Property;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.IRenderer;

import java.io.File;

public class TruncateTextInCell {
    public static final String DEST = "./target/sandbox/tables/truncate_text_in_cell.pdf";

    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();

        new TruncateTextInCell().manipulatePdf(DEST);
    }

    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);

        Table table = new Table(UnitValue.createPercentArray(5)).useAllAvailableWidth();

        for (int r = 'A'; r <= 'Z'; r++) {
            for (int c = 1; c <= 5; c++) {
                Cell cell = new Cell();
                if (r == 'D' && c == 2) {
                    cell.setNextRenderer(new FitCellRenderer(cell,
                            "D2 is a cell with more content than we can fit into the cell."));
                } else {
                    cell.add(new Paragraph(String.valueOf((char) r) + c));
                }

                table.addCell(cell);
            }
        }

        doc.add(table);

        doc.close();
    }

    private static class FitCellRenderer extends CellRenderer {
        private String content;

        public FitCellRenderer(Cell modelElement, String content) {
            super(modelElement);
            this.content = content;
        }

        // If a renderer overflows on the next area, iText uses #getNextRenderer() method to create a new renderer for the overflow part.
        // If #getNextRenderer() isn't overridden, the default method will be used and thus the default rather than the custom
        // renderer will be created
        @Override
        public IRenderer getNextRenderer() {
            return new FitCellRenderer((Cell) modelElement, content);
        }

        /**
         * Method adapts content, that can't be fit into the cell,
         * to prevent truncation by replacing truncated part of content with '...'
         */
        @Override
        public LayoutResult layout(LayoutContext layoutContext) {
            PdfFont bf = getPropertyAsFont(Property.FONT);
            int contentLength = content.length();
            int leftChar = 0;
            int rightChar = contentLength - 1;

            Rectangle rect = layoutContext.getArea().getBBox().clone();

            // Cell's margins, borders and paddings should be extracted from the available width as well.
            // Note that this part of the sample was introduced specifically for iText.
            // since in iText5 the approach of processing cells was different
            applyMargins(rect, false);
            applyBorderBox(rect, false);
            applyPaddings(rect, false);
            float availableWidth = rect.getWidth();

            UnitValue fontSizeUV = this.getPropertyAsUnitValue(Property.FONT_SIZE);

            // Unit values can be of POINT or PERCENT type. In this particular sample
            // the font size value is expected to be of POINT type.
            float fontSize = fontSizeUV.getValue();

            availableWidth -= bf.getWidth("...", fontSize);

            while (leftChar < contentLength && rightChar != leftChar) {
                availableWidth -= bf.getWidth(content.charAt(leftChar), fontSize);
                if (availableWidth > 0) {
                    leftChar++;
                } else {
                    break;
                }

                availableWidth -= bf.getWidth(content.charAt(rightChar), fontSize);

                if (availableWidth > 0) {
                    rightChar--;
                } else {
                    break;
                }
            }

            // left char is the first char which should not be added
            // right char is the last char which should not be added
            String newContent = content.substring(0, leftChar) + "..." + content.substring(rightChar + 1);
            Paragraph p = new Paragraph(newContent);

            // We're operating on a Renderer level here, that's why we need to process a renderer,
            // created with the updated paragraph
            IRenderer pr = p.createRendererSubTree().setParent(this);
            childRenderers.add(pr);

            return super.layout(layoutContext);
        }
    }
}

#xml_worker #itext_7_suite #itext_7_core #itext_7_community

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.