iText pdf library
Website search

Table and cell events to draw borders

CellTitle.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
101
102
/*
    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:
 * http://stackoverflow.com/questions/35746651
 */
 
package com.itextpdf.samples.sandbox.tables;
 
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
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.Paragraph;
import com.itextpdf.layout.element.Table;
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 CellTitle {
    public static final String DEST = "./target/sandbox/tables/cell_title.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new CellTitle().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);
 
        // By default column width is calculated automatically for the best fit.
        // useAllAvailableWidth() method makes table use the whole page's width while placing the content.
        Table table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
        Cell cell = getCell("The title of this cell is title 1", "title 1");
        table.addCell(cell);
        cell = getCell("The title of this cell is title 2", "title 2");
        table.addCell(cell);
        cell = getCell("The title of this cell is title 3", "title 3");
        table.addCell(cell);
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class CellTitleRenderer extends CellRenderer {
        protected String title;
 
        public CellTitleRenderer(Cell modelElement, String title) {
            super(modelElement);
            this.title = title;
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new CellTitleRenderer((Cell) modelElement, title);
        }
 
        @Override
        public void drawBorder(DrawContext drawContext) {
            PdfPage currentPage = drawContext.getDocument().getPage(getOccupiedArea().getPageNumber());
 
            // Create an above canvas in order to draw above borders.
            // Notice: bear in mind that iText draws cell borders on its TableRenderer level.
            PdfCanvas aboveCanvas = new PdfCanvas(currentPage.newContentStreamAfter(), currentPage.getResources(),
                    drawContext.getDocument());
            new Canvas(aboveCanvas, drawContext.getDocument(), getOccupiedAreaBBox())
                    .add(new Paragraph(title)
                            .setMultipliedLeading(1)
                            .setMargin(0)
                            .setBackgroundColor(ColorConstants.LIGHT_GRAY)
                            .setFixedPosition(getOccupiedAreaBBox().getLeft() + 5,
                                    getOccupiedAreaBBox().getTop() - 8, 30));
        }
    }
 
    private static Cell getCell(String content, String title) {
        Cell cell = new Cell().add(new Paragraph(content));
        cell.setNextRenderer(new CellTitleRenderer(cell, title));
        cell.setPaddingTop(8).setPaddingBottom(8);
        return cell;
    }
}
CustomBorder.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
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
/*
    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/23935566/table-borders-not-expanding-properly-in-pdf-using-itext
 */
package com.itextpdf.samples.sandbox.tables;
 
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.borders.SolidBorder;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.BorderCollapsePropertyValue;
import com.itextpdf.layout.property.Property;
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 com.itextpdf.layout.renderer.TableRenderer;
 
import java.io.File;
 
public class CustomBorder {
    public static final String DEST = "./target/sandbox/tables/custom_border.pdf";
 
    public static final String TEXT = "This is some long paragraph\n" +
            "that will be added over and over\n" +
            "again to prove a point.\n" +
            "It should result in rows\n" +
            "that are split\n" +
            " and rows that aren't.";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new CustomBorder().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);
 
        // By default column width is calculated automatically for the best fit.
        // useAllAvailableWidth() method makes table use the whole page's width while placing the content.
        Table table = new Table(UnitValue.createPercentArray(2)).useAllAvailableWidth();
 
        // Fill a table with cells.
        // Be aware that by default all the cells will not have ay bottom borders
        for (int i = 1; i <= 60; i++) {
            table.addCell(new Cell().add(new Paragraph("Cell " + i)).setBorderBottom(Border.NO_BORDER));
            table.addCell(new Cell().add(new Paragraph(TEXT)).setBorderBottom(Border.NO_BORDER));
        }
 
        // We do not need a smart collapse logic: on the contrary, we want to override
        // processing of some cells, that's why we set SEPARATE value here
        table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
 
        // Use a custom renderer in which borders drawing is overridden
        table.setNextRenderer(new CustomBorderTableRenderer(table));
 
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class CustomBorderTableRenderer extends TableRenderer {
        private boolean bottom = true;
        private boolean top = true;
 
        public CustomBorderTableRenderer(Table modelElement) {
            super(modelElement);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new CustomBorderTableRenderer((Table) modelElement);
        }
 
        @Override
        protected TableRenderer[] split(int row, boolean hasContent, boolean cellWithBigRowspanAdded) {
            TableRenderer[] renderers = super.split(row, hasContent, cellWithBigRowspanAdded);
 
            // The first row of the split renderer represent the first rows of the current renderer
            ((CustomBorderTableRenderer) renderers[0]).top = top;
 
            // If there are some split cells, we should draw top borders of the overflow renderer
            // and bottom borders of the split renderer
            if (hasContent) {
                ((CustomBorderTableRenderer) renderers[0]).bottom = false;
                ((CustomBorderTableRenderer) renderers[1]).top = false;
            }
            return renderers;
        }
 
        @Override
        public void draw(DrawContext drawContext) {
 
            // If not set, iText will omit drawing of top borders
            if (!top) {
                for (CellRenderer cellRenderer : rows.get(0)) {
                    cellRenderer.setProperty(Property.BORDER_TOP, Border.NO_BORDER);
                }
            }
 
            // If set, iText will draw bottom borders
            if (bottom) {
                for (CellRenderer cellRenderer : rows.get(rows.size() - 1)) {
                    cellRenderer.setProperty(Property.BORDER_BOTTOM, new SolidBorder(0.5f));
                }
            }
 
            super.draw(drawContext);
        }
    }
 
}
CustomBorder2.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
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
134
135
/*
    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/23935566/table-borders-not-expanding-properly-in-pdf-using-itext
 */
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.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.renderer.TableRenderer;
 
import java.io.File;
 
public class CustomBorder2 {
    public static final String DEST = "./target/sandbox/tables/custom_border2.pdf";
 
    public static final String TEXT = "This is some long paragraph that will be added over and over " +
            "again to prove a point. It should result in rows that are split and rows that aren't.";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new CustomBorder2().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);
 
        // By default column width is calculated automatically for the best fit.
        // useAllAvailableWidth() method makes table use the whole page's width while placing the content.
        Table table = new Table(UnitValue.createPercentArray(2)).useAllAvailableWidth();
 
        for (int i = 1; i < 60; i++) {
            table.addCell(new Cell().add(new Paragraph("Cell " + i)));
            table.addCell(new Cell().add(new Paragraph(TEXT)));
        }
 
        // Use a custom renderer in which borders drawing is overridden
        table.setNextRenderer(new CustomBorder2TableRenderer(table));
 
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class CustomBorder2TableRenderer extends TableRenderer {
        private boolean top = true;
        private boolean bottom = true;
 
        public CustomBorder2TableRenderer(Table modelElement) {
            super(modelElement);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new CustomBorder2TableRenderer((Table) modelElement);
        }
 
        @Override
        protected TableRenderer[] split(int row, boolean hasContent, boolean cellWithBigRowspanAdded) {
            // Being inside this method implies that split has occurred
 
            TableRenderer[] results = super.split(row, hasContent, cellWithBigRowspanAdded);
 
            CustomBorder2TableRenderer splitRenderer = (CustomBorder2TableRenderer) results[0];
 
            // iText shouldn't draw the bottom split renderer's border,
            // because there is an overflow renderer
            splitRenderer.bottom = false;
 
            // If top is true, the split renderer is the first renderer of the document.
            // If false, iText has already processed the first renderer
            splitRenderer.top = this.top;
 
            CustomBorder2TableRenderer overflowRenderer = (CustomBorder2TableRenderer) results[1];
 
            // iText shouldn't draw the top overflow renderer's border
            overflowRenderer.top = false;
 
            return results;
        }
 
        @Override
        protected void drawBorders(DrawContext drawContext) {
            Rectangle area = occupiedArea.getBBox();
            PdfCanvas canvas = drawContext.getCanvas();
 
            canvas
                    .saveState()
                    .moveTo(area.getLeft(), area.getBottom())
                    .lineTo(area.getLeft(), area.getTop())
                    .moveTo(area.getRight(), area.getTop())
                    .lineTo(area.getRight(), area.getBottom());
 
            if (top) {
                canvas
                        .moveTo(area.getLeft(), area.getTop())
                        .lineTo(area.getRight(), area.getTop());
            }
 
            if (bottom) {
                canvas
                        .moveTo(area.getLeft(), area.getBottom())
                        .lineTo(area.getRight(), area.getBottom());
            }
 
            canvas
                    .stroke()
                    .restoreState();
        }
    }
}
CustomBorder3.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
    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/34555756/one-cell-with-different-border-types
 */
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.canvas.PdfCanvasConstants;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
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 CustomBorder3 {
    public static final String DEST = "./target/sandbox/tables/custom_border3.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new CustomBorder3().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document document = new Document(pdfDoc);
 
        ILineDash solid = new Solid();
        ILineDash dotted = new Dotted();
        ILineDash dashed = new Dashed();
 
        // By default column width is calculated automatically for the best fit.
        // useAllAvailableWidth() method makes table use the whole page's width while placing the content.
        Table table = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();
        table.setMarginBottom(30);
 
        Cell cell = new Cell().add(new Paragraph("dotted left border"));
        cell.setBorder(Border.NO_BORDER);
 
        // Draws custom borders to current cell
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{null, dotted, null, null}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("solid right border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{null, null, null, solid}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("dashed top border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{dashed, null, null, null}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("bottom border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{null, null, solid, null}));
 
        table.addCell(cell);
        document.add(table);
 
        table = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();
        table.setMarginBottom(30);
 
        cell = new Cell().add(new Paragraph("dotted left and solid top border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{solid, dotted, null, null}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("dashed right and dashed bottom border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{null, null, dashed, dashed}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("no border"));
        cell.setBorder(Border.NO_BORDER);
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("full solid border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new CustomBorder3Renderer(cell,
                new ILineDash[]{solid, solid, solid, solid}));
        table.addCell(cell);
 
        document.add(table);
        document.close();
    }
 
 
    static interface ILineDash {
        void applyLineDash(PdfCanvas canvas);
    }
 
 
    static class Solid implements ILineDash {
        public void applyLineDash(PdfCanvas canvas) {
        }
    }
 
 
    static class Dotted implements ILineDash {
        public void applyLineDash(PdfCanvas canvas) {
            canvas.setLineCapStyle(PdfCanvasConstants.LineCapStyle.ROUND);
            canvas.setLineDash(0, 4, 2);
        }
    }
 
 
    static class Dashed implements ILineDash {
        public void applyLineDash(PdfCanvas canvas) {
            canvas.setLineDash(3, 3);
        }
    }
 
 
    static class CustomBorder3Renderer extends CellRenderer {
        ILineDash[] borders;
 
        public CustomBorder3Renderer(Cell modelElement, ILineDash[] borders) {
            super(modelElement);
            this.borders = new ILineDash[borders.length];
            for (int i = 0; i < this.borders.length; i++) {
                this.borders[i] = borders[i];
            }
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new CustomBorder3Renderer((Cell) modelElement, borders);
        }
 
        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfCanvas canvas = drawContext.getCanvas();
            Rectangle position = getOccupiedAreaBBox();
            canvas.saveState();
 
            if (null != borders[0]) {
                canvas.saveState();
                borders[0].applyLineDash(canvas);
                canvas.moveTo(position.getRight(), position.getTop());
                canvas.lineTo(position.getLeft(), position.getTop());
                canvas.stroke();
                canvas.restoreState();
            }
 
            if (null != borders[2]) {
                canvas.saveState();
                borders[2].applyLineDash(canvas);
                canvas.moveTo(position.getRight(), position.getBottom());
                canvas.lineTo(position.getLeft(), position.getBottom());
                canvas.stroke();
                canvas.restoreState();
            }
 
            if (null != borders[3]) {
                canvas.saveState();
                borders[3].applyLineDash(canvas);
                canvas.moveTo(position.getRight(), position.getTop());
                canvas.lineTo(position.getRight(), position.getBottom());
                canvas.stroke();
                canvas.restoreState();
            }
 
            if (null != borders[1]) {
                canvas.saveState();
                borders[1].applyLineDash(canvas);
                canvas.moveTo(position.getLeft(), position.getTop());
                canvas.lineTo(position.getLeft(), position.getBottom());
                canvas.stroke();
                canvas.restoreState();
            }
 
            canvas.stroke();
            canvas.restoreState();
        }
    }
}
DottedLineCell.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
    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
 */
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.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Tab;
import com.itextpdf.layout.element.Table;
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 com.itextpdf.layout.renderer.TableRenderer;
 
import java.io.File;
 
public class DottedLineCell {
    public static final String DEST = "./target/sandbox/tables/dotted_line_cell.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new DottedLineCell().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document doc = new Document(pdfDoc);
        doc.add(new Paragraph("Table event"));
 
        Table table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth();
 
        // Draws dotted line borders.
        // Bear in mind that now one needs to disable the default border-drawing
        table.setNextRenderer(new DottedLineTableRenderer(table, new Table.RowRange(0, 2)));
        table.addCell(new Cell().add(new Paragraph("A1")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("A2")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("A3")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("B1")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("B2")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("B3")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("C1")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("C2")).setBorder(Border.NO_BORDER));
        table.addCell(new Cell().add(new Paragraph("C3")).setBorder(Border.NO_BORDER));
 
        doc.add(table);
        doc.add(new Paragraph("Cell event"));
 
        table = new Table(UnitValue.createPercentArray(1)).useAllAvailableWidth();
 
        Cell cell = new Cell().add(new Paragraph("Test"));
        cell.setNextRenderer(new DottedLineCellRenderer(cell));
        cell.setBorder(Border.NO_BORDER);
        table.addCell(cell);
 
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class DottedLineTableRenderer extends TableRenderer {
        public DottedLineTableRenderer(Table modelElement, Table.RowRange rowRange) {
            super(modelElement, rowRange);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new DottedLineTableRenderer((Table) modelElement, rowRange);
        }
 
        @Override
        public void drawChildren(DrawContext drawContext) {
            super.drawChildren(drawContext);
            PdfCanvas canvas = drawContext.getCanvas();
            canvas.setLineDash(3f, 3f);
 
            // first horizontal line
            CellRenderer[] cellRenderers = rows.get(0);
            canvas.moveTo(cellRenderers[0].getOccupiedArea().getBBox().getLeft(),
                    cellRenderers[0].getOccupiedArea().getBBox().getTop());
            canvas.lineTo(cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getRight(),
                    cellRenderers[cellRenderers.length - 1].getOccupiedArea().getBBox().getTop());
 
            for (CellRenderer[] renderers : rows) {
 
                // horizontal lines
                canvas.moveTo(renderers[0].getOccupiedArea().getBBox().getX(),
                        renderers[0].getOccupiedArea().getBBox().getY());
                canvas.lineTo(renderers[renderers.length - 1].getOccupiedArea().getBBox().getRight(),
                        renderers[renderers.length - 1].getOccupiedArea().getBBox().getBottom());
 
                // first vertical line
                Rectangle cellRect = renderers[0].getOccupiedArea().getBBox();
                canvas.moveTo(cellRect.getLeft(), cellRect.getBottom());
                canvas.lineTo(cellRect.getLeft(), cellRect.getTop());
 
                // vertical lines
                for (CellRenderer renderer : renderers) {
                    cellRect = renderer.getOccupiedArea().getBBox();
                    canvas.moveTo(cellRect.getRight(), cellRect.getBottom());
                    canvas.lineTo(cellRect.getRight(), cellRect.getTop());
                }
            }
 
            canvas.stroke();
        }
    }
 
 
    private static class DottedLineCellRenderer extends CellRenderer {
        public DottedLineCellRenderer(Cell modelElement) {
            super(modelElement);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new DottedLineCellRenderer((Cell) modelElement);
        }
 
        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            drawContext.getCanvas().setLineDash(3f, 3f);
            drawContext.getCanvas().rectangle(this.getOccupiedArea().getBBox());
            drawContext.getCanvas().stroke();
        }
    }
}
DottedLineCell2.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
    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/34555756/one-cell-with-different-border-types
 */
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.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
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 DottedLineCell2 {
    public static final String DEST = "./target/sandbox/tables/dotted_line_cell2.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new DottedLineCell2().manipulatePdf(DEST);
    }
 
    protected void manipulatePdf(String dest) throws Exception {
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
        Document document = new Document(pdfDoc);
 
        Table table = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();
        table.setMarginBottom(30);
 
        Cell cell = new Cell().add(new Paragraph("left border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {false, true, false, false}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("right border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {false, false, false, true}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("top border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {true, false, false, false}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("bottom border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {false, false, true, false}));
        table.addCell(cell);
 
        document.add(table);
 
        table = new Table(UnitValue.createPercentArray(4)).useAllAvailableWidth();
        table.setMarginBottom(30);
 
        cell = new Cell().add(new Paragraph("left and top border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {true, true, false, false}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("right and bottom border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {false, false, true, true}));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("no border"));
        cell.setBorder(Border.NO_BORDER);
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("full border"));
        cell.setBorder(Border.NO_BORDER);
        cell.setNextRenderer(new DottedLineCellRenderer(cell, new boolean[] {true, true, true, true}));
        table.addCell(cell);
 
        document.add(table);
 
        document.close();
    }
 
    private static class DottedLineCellRenderer extends CellRenderer {
        boolean[] borders;
 
        public DottedLineCellRenderer(Cell modelElement, boolean[] borders) {
            super(modelElement);
            this.borders = new boolean[borders.length];
 
            for (int i = 0; i < this.borders.length; i++) {
                this.borders[i] = borders[i];
            }
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new DottedLineCellRenderer((Cell) modelElement, borders);
        }
 
        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfCanvas canvas = drawContext.getCanvas();
            Rectangle position = getOccupiedAreaBBox();
            canvas.saveState();
            canvas.setLineDash(0, 4, 2);
 
            if (borders[0]) {
                canvas.moveTo(position.getRight(), position.getTop());
                canvas.lineTo(position.getLeft(), position.getTop());
            }
 
            if (borders[2]) {
                canvas.moveTo(position.getRight(), position.getBottom());
                canvas.lineTo(position.getLeft(), position.getBottom());
            }
 
            if (borders[3]) {
                canvas.moveTo(position.getRight(), position.getTop());
                canvas.lineTo(position.getRight(), position.getBottom());
            }
 
            if (borders[1]) {
                canvas.moveTo(position.getLeft(), position.getTop());
                canvas.lineTo(position.getLeft(), position.getBottom());
            }
 
            canvas.stroke();
            canvas.restoreState();
        }
    }
}
DottedLineHeader.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
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
    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
 */
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.layout.Document;
import com.itextpdf.layout.Style;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Tab;
import com.itextpdf.layout.element.Table;
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 com.itextpdf.layout.renderer.TableRenderer;
 
import java.io.File;
 
public class DottedLineHeader {
    public static final String DEST = "./target/sandbox/tables/dotted_line_header.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new DottedLineHeader().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(3)).useAllAvailableWidth();
 
        // Draws dotted line border in table
        table.setNextRenderer(new DottedHeaderTableRenderer(table, new Table.RowRange(0, 1)));
 
        Style noBorder = new Style().setBorder(Border.NO_BORDER);
 
        table.addHeaderCell(new Cell().add(new Paragraph("A1")).addStyle(noBorder));
        table.addHeaderCell(new Cell().add(new Paragraph("A2")).addStyle(noBorder));
        table.addHeaderCell(new Cell().add(new Paragraph("A3")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("B1")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("B2")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("B3")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C1")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C2")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C3")).addStyle(noBorder));
 
        doc.add(table);
        doc.add(new Paragraph("Cell event"));
 
        table = new Table(UnitValue.createPercentArray(3)).useAllAvailableWidth();
        Cell cell = new Cell().add(new Paragraph("A1")).addStyle(noBorder);
 
        // Draws dotted line border in cell
        cell.setNextRenderer(new DottedHeaderCellRenderer(cell));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("A2")).addStyle(noBorder);
        cell.setNextRenderer(new DottedHeaderCellRenderer(cell));
        table.addCell(cell);
 
        cell = new Cell().add(new Paragraph("A3")).addStyle(noBorder);
        cell.setNextRenderer(new DottedHeaderCellRenderer(cell));
        table.addCell(cell);
 
        table.addCell(new Cell().add(new Paragraph("B1")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("B2")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("B3")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C1")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C2")).addStyle(noBorder));
        table.addCell(new Cell().add(new Paragraph("C3")).addStyle(noBorder));
 
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class DottedHeaderTableRenderer extends TableRenderer {
        public DottedHeaderTableRenderer(Table modelElement, Table.RowRange rowRange) {
            super(modelElement, rowRange);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new DottedHeaderTableRenderer((Table) modelElement, rowRange);
        }
 
        @Override
        public void drawChildren(DrawContext drawContext) {
            super.drawChildren(drawContext);
            Rectangle headersArea = headerRenderer.getOccupiedArea().getBBox();
            PdfCanvas canvas = drawContext.getCanvas();
 
            canvas.setLineDash(3f, 3f);
            canvas.moveTo(headersArea.getLeft(), headersArea.getTop());
            canvas.lineTo(headersArea.getRight(), headersArea.getTop());
            canvas.moveTo(headersArea.getLeft(), headersArea.getBottom());
            canvas.lineTo(headersArea.getRight(), headersArea.getBottom());
            canvas.stroke();
        }
    }
 
 
    private static class DottedHeaderCellRenderer extends CellRenderer {
        public DottedHeaderCellRenderer(Cell modelElement) {
            super(modelElement);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new DottedHeaderCellRenderer((Cell) modelElement);
        }
 
        @Override
        public void draw(DrawContext drawContext) {
            super.draw(drawContext);
            PdfCanvas canvas = drawContext.getCanvas();
            Rectangle bbox = getOccupiedArea().getBBox();
            
            canvas.setLineDash(3f, 3f);
            canvas.moveTo(bbox.getLeft(), bbox.getBottom());
            canvas.lineTo(bbox.getRight(), bbox.getBottom());
            canvas.moveTo(bbox.getLeft(), bbox.getTop());
            canvas.lineTo(bbox.getRight(), bbox.getTop());
            canvas.stroke();
        }
    }
}
RoundedCorners.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
/*
    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
 */
/**
 * This example was written by Bruno Lowagie in answer to the following questions:
 * http://stackoverflow.com/questions/30106862/left-and-right-top-round-corner-for-rectangelroundrectangle
 */
package com.itextpdf.samples.sandbox.tables;
 
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.property.BorderCollapsePropertyValue;
import com.itextpdf.layout.property.BorderRadius;
import com.itextpdf.layout.property.UnitValue;
 
import java.io.File;
 
public class RoundedCorners {
    public static final String DEST = "./target/sandbox/tables/rounded_corners.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new RoundedCorners().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(3)).useAllAvailableWidth();
 
        // By default iText collapses borders and draws them on table level.
        // In this sample, however, we want each cell to draw its borders separately,
        // that's why we need to override border collapse.
        table.setBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
 
        // Sets horizontal spacing between all the table's cells. See css's border-spacing for more information.
        table.setHorizontalBorderSpacing(5);
 
        Cell cell = getCell("These cells have rounded borders at the top.");
        table.addCell(cell);
 
        cell = getCell("These cells aren't rounded at the bottom.");
        table.addCell(cell);
 
        cell = getCell("A custom cell event was used to achieve this.");
        table.addCell(cell);
 
        doc.add(table);
 
        doc.close();
    }
 
    private static Cell getCell(String content) {
        Cell cell = new Cell().add(new Paragraph(content));
        cell.setBorderTopRightRadius(new BorderRadius(4));
        cell.setBorderTopLeftRadius(new BorderRadius(4));
        return cell;
    }
}
TableBorder.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
/*
    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/35340003
 */
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.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Tab;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.property.UnitValue;
import com.itextpdf.layout.renderer.DrawContext;
import com.itextpdf.layout.renderer.IRenderer;
import com.itextpdf.layout.renderer.TableRenderer;
 
import java.io.File;
 
public class TableBorder {
    public static final String DEST = "./target/sandbox/tables/tables_border.pdf";
 
    public static void main(String[] args) throws Exception {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
 
        new TableBorder().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(4)).useAllAvailableWidth();
 
        for (int aw = 0; aw < 16; aw++) {
            table.addCell(new Cell().add(new Paragraph("hi")).setBorder(Border.NO_BORDER));
        }
 
        // Notice that one should set renderer after cells are added to the table
        table.setNextRenderer(new TableBorderRenderer(table));
 
        doc.add(table);
 
        doc.close();
    }
 
 
    private static class TableBorderRenderer extends TableRenderer {
        public TableBorderRenderer(Table modelElement) {
            super(modelElement);
        }
 
        // 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
        @Override
        public IRenderer getNextRenderer() {
            return new TableBorderRenderer((Table) modelElement);
        }
 
        @Override
        protected void drawBorders(DrawContext drawContext) {
            Rectangle rect = getOccupiedAreaBBox();
            drawContext.getCanvas()
                    .saveState()
                    .rectangle(rect.getLeft(), rect.getBottom(), rect.getWidth(), rect.getHeight())
                    .stroke()
                    .restoreState();
        }
    }
}
CellTitle.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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 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.Colors;
using iText.Kernel.Pdf;
using iText.Kernel.Pdf.Canvas;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Layout.Renderer;
 
namespace iText.Samples.Sandbox.Tables
{
    public class CellTitle
    {
        public static readonly string DEST = "results/sandbox/tables/cell_title.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new CellTitle().ManipulatePdf(DEST);
        }
 
        private void ManipulatePdf(String dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document doc = new Document(pdfDoc);
 
            // By default column width is calculated automatically for the best fit.
            // useAllAvailableWidth() method set table to use the whole page's width while placing the content.
            Table table = new Table(UnitValue.CreatePercentArray(1)).UseAllAvailableWidth();
            Cell cell = GetCell("The title of this cell is title 1", "title 1");
            table.AddCell(cell);
            cell = GetCell("The title of this cell is title 2", "title 2");
            table.AddCell(cell);
            cell = GetCell("The title of this cell is title 3", "title 3");
            table.AddCell(cell);
            doc.Add(table);
            
            doc.Close();
        }
 
        private class CellTitleRenderer : CellRenderer
        {
            protected string title;
 
            public CellTitleRenderer(Cell modelElement, String title)
                : base(modelElement)
            {
                this.title = title;
            }            
            
            // 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 CellTitleRenderer((Cell) modelElement, title);
            }
 
            public override void DrawBorder(DrawContext drawContext)
            {
                PdfPage currentPage = drawContext.GetDocument().GetPage(GetOccupiedArea().GetPageNumber());
 
                // Create an above canvas in order to draw above borders.
                // Notice: bear in mind that iText draws cell borders on its TableRenderer level.
                PdfCanvas aboveCanvas = new PdfCanvas(currentPage.NewContentStreamAfter(), currentPage.GetResources(), 
                    drawContext.GetDocument());
                new Canvas(aboveCanvas, drawContext.GetDocument(), GetOccupiedAreaBBox())
                    .Add(new Paragraph(title)
                        .SetMultipliedLeading(1)
                        .SetMargin(0)
                        .SetBackgroundColor(ColorConstants.LIGHT_GRAY)
                        .SetFixedPosition(GetOccupiedAreaBBox().GetLeft() + 5, 
                            GetOccupiedAreaBBox().GetTop() - 8, 30));
            }
        }
 
        private static Cell GetCell(string content, string title)
        {
            Cell cell = new Cell().Add(new Paragraph(content));
            cell.SetNextRenderer(new CellTitleRenderer(cell, title));
            cell.SetPaddingTop(8).SetPaddingBottom(8);
            return cell;
        }
    }
}
CustomBorder.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
/*
    This file is part of the iText (R) project.
    Copyright (c) 1998-2020 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.Pdf;
using iText.Layout;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Layout.Renderer;
 
namespace iText.Samples.Sandbox.Tables
{
    public class CustomBorder
    {
        public static readonly string DEST = "results/sandbox/tables/custom_border.pdf";
 
        public static readonly string TEXT = "This is some long paragraph\n" +
                                             "that will be added over and over\n" +
                                             "again to prove a point.\n" +
                                             "It should result in rows\n" +
                                             "that are split\n" +
                                             " and rows that aren't.";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new CustomBorder().ManipulatePdf(DEST);
        }
 
        private void ManipulatePdf(string dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document doc = new Document(pdfDoc);
 
            // By default column width is calculated automatically for the best fit.
            // useAllAvailableWidth() method set table to use the whole page's width while placing the content.
            Table table = new Table(UnitValue.CreatePercentArray(2)).UseAllAvailableWidth();
 
            // Fill a table with cells.
            // Be aware that by default all the cells will not have ay bottom borders
            for (int i = 1; i <= 60; i++) 
            {
                table.AddCell(new Cell().Add(new Paragraph("Cell " + i)).SetBorderBottom(Border.NO_BORDER));
                table.AddCell(new Cell().Add(new Paragraph(TEXT)).SetBorderBottom(Border.NO_BORDER));
            }
 
            // We do not need a smart collapse logic: on the contrary, we want to override
            // processing of some cells, that's why we set SEPARATE value here
            table.SetBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
 
            // Use a custom renderer in which borders drawing is overridden
            table.SetNextRenderer(new CustomBorderTableRenderer(table));
 
            doc.Add(table);
 
            doc.Close();
        }
 
        private class CustomBorderTableRenderer : TableRenderer 
        {
            private bool bottom = true;
            private bool top = true;
 
            public CustomBorderTableRenderer(Table modelElement) : base(modelElement) 
            {   
            }            
            
            // 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 CustomBorderTableRenderer((Table)modelElement);
            }
 
            protected override TableRenderer[] Split(int row, bool hasContent, bool cellWithBigRowspanAdded) 
            {
                TableRenderer[] renderers = base.Split(row, hasContent, cellWithBigRowspanAdded); 
 
                // The first row of the split renderer represent the first rows of the current renderer
                ((CustomBorderTableRenderer)renderers[0]).top = top;
 
                // If there are some split cells, we should draw top borders of the overflow renderer
                // and bottom borders of the split renderer
                if (hasContent) 
                {
                    ((CustomBorderTableRenderer)renderers[0]).bottom = false;
                    ((CustomBorderTableRenderer)renderers[1]).top = false;
                }
                return renderers;
            }
 
            public override void Draw(DrawContext drawContext) 
            {
 
                // If not set, iText will omit drawing of top borders
                if (!top) 
                {
                    foreach (CellRenderer cellRenderer in rows[0]) 
                    {
                        cellRenderer.SetProperty(Property.BORDER_TOP, Border.NO_BORDER);
                    }
                }
 
                // If set, iText will draw bottom borders
                if (bottom) 
                {
                    foreach (CellRenderer cellRenderer in rows[rows.Count - 1])
                    {
                        cellRenderer.SetProperty(Property.BORDER_BOTTOM, new SolidBorder(0.5f));
                    }
                }
 
                base.Draw(drawContext);
            }
        }
    }
}
DottedLineCell.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><title>Log in - iText Bitbucket</title><script>
window.WRM=window.WRM||{};window.WRM._unparsedData=window.WRM._unparsedData||{};window.WRM._unparsedErrors=window.WRM._unparsedErrors||{};
WRM._unparsedData["com.atlassian.plugins.atlassian-plugins-webresource-plugin:context-path.context-path"]="\u0022\u0022";
WRM._unparsedData["com.atlassian.bitbucket.server.feature-wrm-data:nps.survey.inline.dialog.data"]="true";
WRM._unparsedData["com.atlassian.bitbucket.server.feature-wrm-data:nps.experiment.enabled.by.sen.data"]="false";
WRM._unparsedData["com.atlassian.analytics.analytics-client:policy-update-init.policy-update-data-provider"]="false";
WRM._unparsedData["com.atlassian.analytics.analytics-client:programmatic-analytics-init.programmatic-analytics-data-provider"]="false";
WRM._unparsedData["com.atlassian.bitbucket.server.feature-wrm-data:user.time.zone.onboarding.data"]="true";
WRM._unparsedData["com.onresolve.stash.groovy.groovyrunner:web-item-response-renderer.web-item-actions-data-provider"]="[]";
if(window.WRM._dataArrived)window.WRM._dataArrived();</script>
<link type="text/css" rel="stylesheet" href="/s/2b782bdbb6e1498219b97aff034806ef-CDN/1168031776/ad7f50c/749/36a400f80156c719ac1b3c6e6530ab3c/_/download/contextbatch/css/_super/batch.css" data-wrm-key="_super" data-wrm-batch-type="context" media="all">
<link type="text/css" rel="stylesheet" href="/s/e95e43198a3a352e00dbd6ee452c29e7-CDN/1168031776/ad7f50c/749/ea28cfaf2acbe7b82e7be0a0260044b0/_/download/contextbatch/css/bitbucket.page.login,-_super/batch.css" data-wrm-key="bitbucket.page.login,-_super" data-wrm-batch-type="context" media="all">
<link type="text/css" rel="stylesheet" href="/s/3d3c3c9a2117de59eb99a46a0bd5fff7-CDN/1168031776/ad7f50c/749/c99ac14470b4ab1420aad9f83d78f1e6/_/download/contextbatch/css/bitbucket.layout.focused,bitbucket.layout.base,atl.general,-_super/batch.css?analytics-enabled=true&analytics-uploadable=true&nps-acknowledged=true&nps-enabled=true" data-wrm-key="bitbucket.layout.focused,bitbucket.layout.base,atl.general,-_super" data-wrm-batch-type="context" media="all">
<script type="text/javascript" src="/s/c3cf42574942eed78be3bdaa5f75f2db-CDN/1168031776/ad7f50c/749/36a400f80156c719ac1b3c6e6530ab3c/_/download/contextbatch/js/_super/batch.js?locale=en-US" data-wrm-key="_super" data-wrm-batch-type="context" data-initially-rendered></script>
<script type="text/javascript" src="/s/52baba87de754d3790e0cd678eed5356-CDN/1168031776/ad7f50c/749/ea28cfaf2acbe7b82e7be0a0260044b0/_/download/contextbatch/js/bitbucket.page.login,-_super/batch.js?locale=en-US" data-wrm-key="bitbucket.page.login,-_super" data-wrm-batch-type="context" data-initially-rendered></script>
<script type="text/javascript" src="/s/f382616e687cdc801b0b38497f60de59-CDN/1168031776/ad7f50c/749/c99ac14470b4ab1420aad9f83d78f1e6/_/download/contextbatch/js/bitbucket.layout.focused,bitbucket.layout.base,atl.general,-_super/batch.js?analytics-enabled=true&analytics-uploadable=true&locale=en-US&nps-acknowledged=true&nps-enabled=true" data-wrm-key="bitbucket.layout.focused,bitbucket.layout.base,atl.general,-_super" data-wrm-batch-type="context" data-initially-rendered></script>
<meta name="application-name" content="Bitbucket"><link rel="shortcut icon" type="image/x-icon" href="/s/1168031776/ad7f50c/749/1.0/_/download/resources/com.atlassian.bitbucket.server.bitbucket-web:favicon/favicon.ico" /><link rel="search" href="https://git.itextsupport.com/plugins/servlet/opensearch-descriptor" type="application/opensearchdescription+xml" title="Bitbucket code search" /></head><body class="aui-page-focused aui-page-focused-small aui-page-size-small bitbucket-theme user-login"><ul id="assistive-skip-links" class="assistive"><li><a href="#content">Skip to content</a></li></ul><div id="page"><!-- start #header --><header id="header" role="banner"><section class="notifications"></section><nav class="aui-header aui-dropdown2-trigger-group" role="navigation"><div class="aui-header-inner"><div class="aui-header-before"><a class=" aui-dropdown2-trigger app-switcher-trigger" aria-controls="app-switcher" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger href="#app-switcher"><span class="aui-icon aui-icon-small aui-iconfont-appswitcher">Linked Applications</span></a><div id="app-switcher" class="aui-dropdown2 aui-style-default" role="menu" aria-hidden="true" data-is-switcher="true" data-environment="{"isUserAdmin":false,"isAppSuggestionAvailable":false,"isSiteAdminUser":false}"><div role="application"><div class="app-switcher-loading">Loading…</div></div></div></div><div class="aui-header-primary"><h1 id="logo" class="aui-header-logo aui-header-logo-bitbucket"><a href="https://git.itextsupport.com" class="stash"><span class="aui-header-logo-device">Bitbucket</span></a></h1><ul class="aui-nav"><li class=""title="Latest Activities"><a href="/plugins/servlet/rss4stash/all" title="Latest Activities" data-web-item-key="ch.mibex.stash.rss4stash:rss4stash-latest-global-activities">Latest Activities</a></li></ul></div><div class="aui-header-secondary"><ul class="aui-nav"><li class=" help-link"title="Help"><a class=" aui-dropdown2-trigger aui-dropdown2-trigger-arrowless" aria-controls="com.atlassian.bitbucket.server.bitbucket-server-web-fragments-help-menu" aria-haspopup="true" role="button" tabindex="0" data-aui-trigger><span class="aui-icon aui-icon-small aui-iconfont-help">Help</span><span class="icon aui-icon-dropdown"></span></a><div id="com.atlassian.bitbucket.server.bitbucket-server-web-fragments-help-menu" class="aui-dropdown2 aui-style-default" role="menu" aria-hidden="true"><div role="application"><div class="aui-dropdown2-section help-items-section"><ul class="aui-list-truncate" role="presentation"><li role="presentation"><a href="http://docs.atlassian.com/bitbucketserver/docs-059/Bitbucket+Server+documentation?utm_campaign=in-app-help&amp;utm_medium=in-app-help&amp;utm_source=stash" title="Go to the online documentation for Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:general-help">Online help</a></li><li role="presentation"><a href="https://www.atlassian.com/git?utm_campaign=learn-git&utm_medium=in-app-help&utm_source=stash" title="Learn about Git commands & workflows" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:learn-git">Learn Git</a></li><li role="presentation"><a href="/getting-started" class="getting-started-page-link" title="Overview of Bitbucket features" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:getting-started-page-help-link">Welcome to Bitbucket</a></li><li role="presentation"><a href="/#" class="keyboard-shortcut-link" title="Discover keyboard shortcuts in Bitbucket" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:keyboard-shortcuts-help-link">Keyboard shortcuts</a></li></ul></div></div></div></li><li class=" alerts-menu"title="View system alerts"><a href="#alerts" id="alerts-trigger" class="alerts-menu" title="View system alerts" data-web-item-key="com.atlassian.bitbucket.server.bitbucket-server-web-fragments:global-alerts-menu-item">Alerts</a></li></ul></div></div> <!-- End .aui-header-inner --></nav> <!-- End .aui-header --></header><!-- End #header --><!-- Start #content --><section id="content" role="main" tabindex="-1" data-timezone="-60" ><div class="aui-page-panel content-body"><div class="aui-page-panel-inner"><section class="aui-page-panel-content"><h2>Log in</h2><form class="aui top-label prevent-double-submit " action="/j_atl_security_check" method="post" accept-charset="UTF-8"><div class="field-group"><label for="j_username" >Username</label><input class="text long-field" type="text" id="j_username"  name="j_username"  autofocus accesskey="u"/></div><div class="field-group"><label for="j_password" >Password</label><input class="text long-field" type="password" id="j_password"  name="j_password"  accesskey="p"/></div><div class="aui-group"><fieldset class="group checkbox"><div class="checkbox"><input class="checkbox" type="checkbox" id="_atl_remember_me"  name="_atl_remember_me"  checked="checked"  accesskey="r"/><label for="_atl_remember_me" >Keep me logged in</label></div></fieldset></div><div class="aui-group"><input name="next" type="hidden" value="/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/CustomBorder2.cs.https://git.itextsupport.com/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/CustomBorder3.cs.https://git.itextsupport.com/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/DottedLineCell.cs"/><input name="queryString" type="hidden" value="next=/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/CustomBorder2.cs.https://git.itextsupport.com/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/CustomBorder3.cs.https://git.itextsupport.com/projects/I7NS/repos/samples/raw/itext/itext.samples/itext/samples/sandbox/tables/DottedLineCell.cs"/><input class="aui-button aui-button-primary" type="submit" id="submit"  name="submit"  value="Log in" accesskey="s"/><a id="forgot" class="aui-button aui-button-link"  name="forgot" href="/passwordreset" autocomplete="off" tabindex="0">Unable to access your account?</a></div></form></section><!-- .aui-page-panel-content --></div><!-- .aui-page-panel-inner --></div><!-- .aui-page-panel --></section><!-- End #content --><!-- Start #footer --><footer id="footer" role="contentinfo"><section class="notifications"></section><section class="footer-body"><ul><li data-key="footer.license.message">Git repository management for enterprise teams powered by <a href="http://www.atlassian.com/software/bitbucket/">Atlassian Bitbucket</a></li></ul><ul><li>Atlassian Bitbucket <span title="ad7f50c15d296474e39c8e67b7e1657297d56a50" id="product-version" data-commitid="ad7f50c15d296474e39c8e67b7e1657297d56a50" data-system-build-number="ad7f50c"> v5.9.1</span></li><li data-key="footer.links.documentation"><a href="http://docs.atlassian.com/bitbucketserver/docs-059/Bitbucket+Server+documentation?utm_campaign=in-app-help&utm_medium=in-app-help&utm_source=stash" target="_blank">Documentation</a></li><li data-key="footer.links.contact.support"><a href="https://support.atlassian.com/contact" target="_blank">Contact Support</a></li><li data-key="footer.links.jac"><a href="https://jira.atlassian.com/browse/BSERV" target="_blank">Request a feature</a></li><li data-key="footer.links.about"><a href="/about">About</a></li><li data-key="footer.links.contact.atlassian"><a href="http://www.atlassian.com/company/contact/" target="_blank">Contact Atlassian</a></li></ul><div id="footer-logo"><a href="http://www.atlassian.com/" target="_blank">Atlassian</a></div></section></footer><!-- End #footer --></div><script>require('bitbucket/internal/layout/base/base').onReady(null, "iText Bitbucket" ); require('bitbucket/internal/widget/keyboard-shortcuts/keyboard-shortcuts').onReady();</script><script type="text/javascript">require('bitbucket/internal/page/login/login').onReady();</script></body></html>
DottedLineCell2.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2020 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.Layout;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Layout.Renderer;
 
namespace iText.Samples.Sandbox.Tables
{
    public class DottedLineCell2
    {
        public static readonly string DEST = "results/sandbox/tables/dotted_line_cell2.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new DottedLineCell2().ManipulatePdf(DEST);
        }
 
        private void ManipulatePdf(string dest)
        {
            PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
            Document document = new Document(pdfDoc);
 
            Table table = new Table(UnitValue.CreatePercentArray(4)).UseAllAvailableWidth();
            table.SetMarginBottom(30);
            
            Cell cell = new Cell().Add(new Paragraph("left border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {false, true, false, false}));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("right border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {false, false, false, true}));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("top border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {true, false, false, false}));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("bottom border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {false, false, true, false}));
            table.AddCell(cell);
 
            document.Add(table);
            
            table = new Table(UnitValue.CreatePercentArray(4)).UseAllAvailableWidth();
            table.SetMarginBottom(30);
 
            cell = new Cell().Add(new Paragraph("left and top border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {true, true, false, false}));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("right and bottom border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {false, false, true, true}));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("no border"));
            cell.SetBorder(Border.NO_BORDER);
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("full border"));
            cell.SetBorder(Border.NO_BORDER);
            cell.SetNextRenderer(new DottedLineCellRenderer(cell, new[] {true, true, true, true}));
            table.AddCell(cell);
 
            document.Add(table);
 
            document.Close();
        }
 
        private class DottedLineCellRenderer : CellRenderer
        {
            private bool[] borders;
 
            public DottedLineCellRenderer(Cell modelElement, bool[] borders)
                : base(modelElement)
            {
                this.borders = new bool[borders.Length];
 
                for (int i = 0; i < this.borders.Length; i++)
                {
                    this.borders[i] = borders[i];
                }
            }            
            
            // 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 DottedLineCellRenderer((Cell) modelElement, borders);
            }
 
            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfCanvas canvas = drawContext.GetCanvas();
                Rectangle position = GetOccupiedAreaBBox();
                canvas.SaveState();
                canvas.SetLineDash(0, 4, 2);
 
                if (borders[0])
                {
                    canvas.MoveTo(position.GetRight(), position.GetTop());
                    canvas.LineTo(position.GetLeft(), position.GetTop());
                }
 
                if (borders[2])
                {
                    canvas.MoveTo(position.GetRight(), position.GetBottom());
                    canvas.LineTo(position.GetLeft(), position.GetBottom());
                }
 
                if (borders[3])
                {
                    canvas.MoveTo(position.GetRight(), position.GetTop());
                    canvas.LineTo(position.GetRight(), position.GetBottom());
                }
 
                if (borders[1])
                {
                    canvas.MoveTo(position.GetLeft(), position.GetTop());
                    canvas.LineTo(position.GetLeft(), position.GetBottom());
                }
 
                canvas.Stroke();
                canvas.RestoreState();
            }
        }
    }
}
DottedLineHeader.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2020 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.Layout;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Layout.Renderer;
 
namespace iText.Samples.Sandbox.Tables
{
    public class DottedLineHeader
    {
        public static readonly string DEST = "results/sandbox/tables/dotted_line_header.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new DottedLineHeader().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(3)).UseAllAvailableWidth();
 
            // Draws dotted line border in table
            table.SetNextRenderer(new DottedHeaderTableRenderer(table, new Table.RowRange(0, 1)));
 
            Style noBorder = new Style().SetBorder(Border.NO_BORDER);
 
            table.AddHeaderCell(new Cell().Add(new Paragraph("A1")).AddStyle(noBorder));
            table.AddHeaderCell(new Cell().Add(new Paragraph("A2")).AddStyle(noBorder));
            table.AddHeaderCell(new Cell().Add(new Paragraph("A3")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("B1")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("B2")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("B3")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C1")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C2")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C3")).AddStyle(noBorder));
 
            doc.Add(table);
            doc.Add(new Paragraph("Cell event"));
 
            table = new Table(UnitValue.CreatePercentArray(3)).UseAllAvailableWidth();
            Cell cell = new Cell().Add(new Paragraph("A1")).AddStyle(noBorder);
 
            // Draws dotted line border in cell
            cell.SetNextRenderer(new DottedHeaderCellRenderer(cell));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("A2")).AddStyle(noBorder);
            cell.SetNextRenderer(new DottedHeaderCellRenderer(cell));
            table.AddCell(cell);
 
            cell = new Cell().Add(new Paragraph("A3")).AddStyle(noBorder);
            cell.SetNextRenderer(new DottedHeaderCellRenderer(cell));
            table.AddCell(cell);
 
            table.AddCell(new Cell().Add(new Paragraph("B1")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("B2")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("B3")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C1")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C2")).AddStyle(noBorder));
            table.AddCell(new Cell().Add(new Paragraph("C3")).AddStyle(noBorder));
 
            doc.Add(table);
 
            doc.Close();
        }
 
        private class DottedHeaderTableRenderer : TableRenderer
        {
            public DottedHeaderTableRenderer(Table modelElement, Table.RowRange rowRange)
                : base(modelElement, rowRange)
            {
            }            
            
            // 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 DottedHeaderTableRenderer((Table) modelElement, rowRange);
            }
 
            public override void DrawChildren(DrawContext drawContext)
            {
                base.DrawChildren(drawContext);
                PdfCanvas canvas = drawContext.GetCanvas();
                Rectangle headersArea = headerRenderer.GetOccupiedArea().GetBBox();
                
                canvas.SetLineDash(3f, 3f);
                canvas.MoveTo(headersArea.GetLeft(), headersArea.GetTop());
                canvas.LineTo(headersArea.GetRight(), headersArea.GetTop());
                canvas.MoveTo(headersArea.GetLeft(), headersArea.GetBottom());
                canvas.LineTo(headersArea.GetRight(), headersArea.GetBottom());
                canvas.Stroke();
            }
        }
 
        private class DottedHeaderCellRenderer : CellRenderer
        {
            public DottedHeaderCellRenderer(Cell modelElement)
                : base(modelElement)
            {
            }            
            
            // 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 DottedHeaderCellRenderer((Cell) modelElement);
            }
 
            public override void Draw(DrawContext drawContext)
            {
                base.Draw(drawContext);
                PdfCanvas canvas = drawContext.GetCanvas();
                Rectangle bbox = GetOccupiedArea().GetBBox();
 
                canvas.SetLineDash(3f, 3f);
                canvas.MoveTo(bbox.GetLeft(), bbox.GetBottom());
                canvas.LineTo(bbox.GetRight(), bbox.GetBottom());
                canvas.MoveTo(bbox.GetLeft(), bbox.GetTop());
                canvas.LineTo(bbox.GetRight(), bbox.GetTop());
                canvas.Stroke();
            }
        }
    }
}
RoundedCorners.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
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2020 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.Pdf;
using iText.Layout;
using iText.Layout.Element;
using iText.Layout.Properties;
 
namespace iText.Samples.Sandbox.Tables
{
    public class RoundedCorners
    {
        public static readonly string DEST = "results/sandbox/tables/rounded_corners.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new RoundedCorners().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(3)).UseAllAvailableWidth();
 
            // By default iText collapses borders and draws them on table level.
            // In this sample, however, we want each cell to draw its borders separately,
            // that's why we need to override border collapse.
            table.SetBorderCollapse(BorderCollapsePropertyValue.SEPARATE);
 
            // Sets horizontal spacing between all the table's cells. See css's border-spacing for more information.
            table.SetHorizontalBorderSpacing(5);
 
            Cell cell = GetCell("These cells have rounded borders at the top.");
            table.AddCell(cell);
 
            cell = GetCell("These cells aren't rounded at the bottom.");
            table.AddCell(cell);
 
            cell = GetCell("A custom cell event was used to achieve this.");
            table.AddCell(cell);
 
            doc.Add(table);
 
            doc.Close();
        }
 
        private static Cell GetCell(String content)
        {
            Cell cell = new Cell().Add(new Paragraph(content));
            cell.SetBorderTopRightRadius(new BorderRadius(4));
            cell.SetBorderTopLeftRadius(new BorderRadius(4));
            return cell;
        }
    }
}
TableBorder.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
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2020 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.Layout;
using iText.Layout.Borders;
using iText.Layout.Element;
using iText.Layout.Properties;
using iText.Layout.Renderer;
 
namespace iText.Samples.Sandbox.Tables
{
    public class TableBorder
    {
        public static readonly string DEST = "results/sandbox/tables/tables_border.pdf";
 
        public static void Main(String[] args)
        {
            FileInfo file = new FileInfo(DEST);
            file.Directory.Create();
 
            new TableBorder().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(4)).UseAllAvailableWidth();
 
            for (int aw = 0; aw < 16; aw++)
            {
                table.AddCell(new Cell().Add(new Paragraph("hi")).SetBorder(Border.NO_BORDER));
            }
 
            // Notice that one should set renderer after cells are added to the table
            table.SetNextRenderer(new TableBorderRenderer(table));
 
            doc.Add(table);
 
            doc.Close();
        }
 
        private class TableBorderRenderer : TableRenderer
        {
            public TableBorderRenderer(Table modelElement)
                : base(modelElement)
            {
            }            
            
            // 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 TableBorderRenderer((Table) modelElement);
            }
 
            protected override void DrawBorders(DrawContext drawContext)
            {
                Rectangle rect = GetOccupiedAreaBBox();
                drawContext.GetCanvas()
                    .SaveState()
                    .Rectangle(rect.GetLeft(), rect.GetBottom(), rect.GetWidth(), rect.GetHeight())
                    .Stroke()
                    .RestoreState();
            }
        }
    }
}

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