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