Fit text in cell

31st May 2016
admin-marketing
ClipCenterCellContent.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/**
 * Example written by Bruno Lowagie in answer to the following question:
 * http://stackoverflow.com/questions/22095320/can-i-tell-itext-how-to-clip-text-to-fit-in-a-cell
 */
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.property.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();
        Cell cell;
        for (int r = 'A'; r <= 'Z'; r++) {
            for (int c = 1; c <= 5; c++) {
                cell = new Cell();
                if (r == 'D' && c == 2) {
                    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) + String.valueOf(c)));
                }
                table.addCell(cell);
            }
        }
        doc.add(table);
 
        doc.close();
    }
 
 
    private class ClipCenterCellContentCellRenderer extends CellRenderer {
        private Paragraph content;
 
        public ClipCenterCellContentCellRenderer(Cell modelElement, Paragraph content) {
            super(modelElement);
            this.content = content;
        }
 
        @Override
        public void draw(DrawContext drawContext) {
            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()), drawContext.getDocument(),
                    new Rectangle(0, offset, getOccupiedAreaBBox().getWidth(), spaceneeded));
            layoutCanvas.add(content);
 
            drawContext.getCanvas().addXObject(xObject, occupiedArea.getBBox().getLeft(), occupiedArea.getBBox().getBottom());
        }
    }
}
TruncateTextInCell.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
/**
 * Example written by Bruno Lowagie in answer to the following question:
 * http://stackoverflow.com/questions/22093488/itext-how-do-i-get-the-rendered-dimensions-of-text
 */
package com.itextpdf.samples.sandbox.tables;
 
import com.itextpdf.kernel.font.PdfFont;
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.property.Property;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.renderer.CellRenderer;
import com.itextpdf.layout.renderer.IRenderer;
 
import java.io.File;
import java.io.IOException;
 
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();
        Cell cell;
        for (int r = 'A'; r <= 'Z'; r++) {
            for (int c = 1; c <= 5; c++) {
                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) + String.valueOf(c)));
                }
                table.addCell(cell);
            }
        }
        doc.add(table);
 
        doc.close();
    }
 
    private static class FitCellRenderer extends CellRenderer {
        private String content;
 
        public FitCellRenderer(Cell modelElement, String content) throws IOException {
            super(modelElement);
            this.content = content;
        }
 
        @Override
        public LayoutResult layout(LayoutContext layoutContext) {
            PdfFont bf = getPropertyAsFont(Property.FONT);
            float availableWidth = layoutContext.getArea().getBBox().getWidth();
            int contentLength = content.length();
            int leftChar = 0;
            int rightChar = contentLength - 1;
            availableWidth -= bf.getWidth("...", 12);
            while (leftChar < contentLength && rightChar != leftChar) {
                availableWidth -= bf.getWidth(content.charAt(leftChar), 12);
                if (availableWidth > 0)
                    leftChar++;
                else
                    break;
                availableWidth -= bf.getWidth(content.charAt(rightChar), 12);
                if (availableWidth > 0)
                    rightChar--;
                else
                    break;
            }
            String newContent = content.substring(0, leftChar) + "..." + content.substring(rightChar);
            Paragraph p = new Paragraph(newContent);
 
            IRenderer pr = p.createRendererSubTree().setParent(this);
            this.childRenderers.add(pr);
            return super.layout(layoutContext);
        }
    }
}
ClipCenterCellContent.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2019 iText Group NV
    Authors: iText Software.
 
    For more information, please contact iText Software at this address:
    sales@itextpdf.com
 */
 
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)
            {
                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()),
                    drawContext.GetDocument(),
                    new Rectangle(0, offset, GetOccupiedAreaBBox().GetWidth(), spaceneeded));
                layoutCanvas.Add(content);
 
                drawContext.GetCanvas().AddXObject(xObject, occupiedArea.GetBBox().GetLeft(),
                    occupiedArea.GetBBox().GetBottom());
            }
        }
    }
}
TruncateTextInCell.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2019 iText Group NV
Authors: iText Software.
 
For more information, please contact iText Software at this address:
sales@itextpdf.com
*/
 
using System;
using System.IO;
using iText.Kernel.Font;
using iText.Kernel.Pdf;
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 TruncateTextInCell
    {
        public static readonly string DEST = "../../results/sandbox/tables/truncate_text_in_cell.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new TruncateTextInCell().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)
                    {
                        cell.SetNextRenderer(new FitCellRenderer(cell,
                            "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 FitCellRenderer : CellRenderer
        {
            private String content;
 
            public FitCellRenderer(Cell modelElement, String 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 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 '...'
             */
            public override LayoutResult Layout(LayoutContext layoutContext)
            {
                PdfFont bf = GetPropertyAsFont(Property.FONT);
                int contentLength = content.Length;
                int leftCharIndex = 0;
                int rightCharIndex = contentLength - 1;
                float availableWidth = layoutContext.GetArea().GetBBox().GetWidth();
 
                availableWidth -= bf.GetWidth("...", 12);
 
                while (leftCharIndex < contentLength && rightCharIndex != leftCharIndex)
                {
                    availableWidth -= bf.GetWidth(content[leftCharIndex], 12);
                    if (availableWidth > 0)
                    {
                        leftCharIndex++;
                    }
                    else
                    {
                        break;
                    }
 
                    availableWidth -= bf.GetWidth(content[rightCharIndex], 12);
 
                    if (availableWidth > 0)
                    {
                        rightCharIndex--;
                    }
                    else
                    {
                        break;
                    }
                }
 
                String newContent = content.Substring(0, leftCharIndex) + "..." + content.Substring(rightCharIndex);
                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 base.Layout(layoutContext);
            }
        }
    }
}

Click the following link to see the legacy example for iText 5. Except for security fixes, iText 5 is no longer being developed.



Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now