Skip to content

Commit f6a3636

Browse files
author
Artyom Yanchevsky
committed
Add form field borders support
DEVSIX-836
1 parent 68de7af commit f6a3636

25 files changed

+941
-120
lines changed

forms/src/main/java/com/itextpdf/forms/fields/PdfFormField.java

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ This file is part of the iText (R) project.
4444
package com.itextpdf.forms.fields;
4545

4646
import com.itextpdf.forms.PdfAcroForm;
47+
import com.itextpdf.forms.fields.borders.FormBorderFactory;
4748
import com.itextpdf.forms.util.DrawingUtil;
4849
import com.itextpdf.io.LogMessageConstant;
4950
import com.itextpdf.io.codec.Base64;
@@ -89,6 +90,7 @@ This file is part of the iText (R) project.
8990
import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
9091
import com.itextpdf.layout.Canvas;
9192
import com.itextpdf.layout.Style;
93+
import com.itextpdf.layout.borders.Border;
9294
import com.itextpdf.layout.element.Div;
9395
import com.itextpdf.layout.element.Paragraph;
9496
import com.itextpdf.layout.element.Text;
@@ -2058,13 +2060,7 @@ public PdfFormField setBorderWidth(float borderWidth) {
20582060
}
20592061

20602062
public PdfFormField setBorderStyle(PdfDictionary style) {
2061-
//PdfDictionary bs = getWidgets().get(0).getBorderStyle();
20622063
getWidgets().get(0).setBorderStyle(style);
2063-
// if (bs == null) {
2064-
// bs = new PdfDictionary();
2065-
// put(PdfName.BS, bs);
2066-
// }
2067-
// bs.put(PdfName.S, style);
20682064
regenerateField();
20692065
return this;
20702066
}
@@ -2670,29 +2666,27 @@ protected void drawBorder(PdfCanvas canvas, PdfFormXObject xObject, float width,
26702666
}
26712667

26722668
if (backgroundColor != null) {
2673-
canvas.
2674-
setFillColor(backgroundColor).
2675-
rectangle(0, 0, width, height).
2676-
fill();
2669+
canvas
2670+
.setFillColor(backgroundColor)
2671+
.rectangle(0, 0, width, height)
2672+
.fill();
26772673
}
26782674

26792675
if (borderWidth > 0 && borderColor != null) {
26802676
borderWidth = Math.max(1, borderWidth);
2681-
canvas.
2682-
setStrokeColor(borderColor).
2683-
setLineWidth(borderWidth);
2684-
if (bs != null) {
2685-
PdfName borderType = bs.getAsName(PdfName.S);
2686-
if (borderType != null && borderType.equals(PdfName.D)) {
2687-
PdfArray dashArray = bs.getAsArray(PdfName.D);
2688-
int unitsOn = dashArray != null ? (dashArray.size() > 0 ? (dashArray.getAsNumber(0) != null ? dashArray.getAsNumber(0).intValue() : 3) : 3) : 3;
2689-
int unitsOff = dashArray != null ? (dashArray.size() > 1 ? (dashArray.getAsNumber(1) != null ? dashArray.getAsNumber(1).intValue() : unitsOn) : unitsOn) : unitsOn;
2690-
canvas.setLineDash(unitsOn, unitsOff, 0);
2691-
}
2677+
canvas
2678+
.setStrokeColor(borderColor)
2679+
.setLineWidth(borderWidth);
2680+
Border border = FormBorderFactory.getBorder(bs, borderWidth, borderColor, backgroundColor);
2681+
if (border != null) {
2682+
float borderWidthX2 = borderWidth + borderWidth;
2683+
border.draw(canvas, new Rectangle(borderWidth, borderWidth,
2684+
width - borderWidthX2, height - borderWidthX2));
2685+
} else {
2686+
canvas
2687+
.rectangle(0, 0, width, height)
2688+
.stroke();
26922689
}
2693-
canvas.
2694-
rectangle(0, 0, width, height).
2695-
stroke();
26962690
}
26972691

26982692
applyRotation(xObject, height, width);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
3+
This file is part of the iText (R) project.
4+
Copyright (c) 1998-2020 iText Group NV
5+
Authors: Bruno Lowagie, Paulo Soares, et al.
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU Affero General Public License version 3
9+
as published by the Free Software Foundation with the addition of the
10+
following permission added to Section 15 as permitted in Section 7(a):
11+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
12+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
13+
OF THIRD PARTY RIGHTS
14+
15+
This program is distributed in the hope that it will be useful, but
16+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17+
or FITNESS FOR A PARTICULAR PURPOSE.
18+
See the GNU Affero General Public License for more details.
19+
You should have received a copy of the GNU Affero General Public License
20+
along with this program; if not, see http://www.gnu.org/licenses or write to
21+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
23+
http://itextpdf.com/terms-of-use/
24+
25+
The interactive user interfaces in modified source and object code versions
26+
of this program must display Appropriate Legal Notices, as required under
27+
Section 5 of the GNU Affero General Public License.
28+
29+
In accordance with Section 7(b) of the GNU Affero General Public License,
30+
a covered work must retain the producer line in every PDF that is created
31+
or manipulated using iText.
32+
33+
You can be released from the requirements of the license by purchasing
34+
a commercial license. Buying such a license is mandatory as soon as you
35+
develop commercial activities involving the iText software without
36+
disclosing the source code of your own applications.
37+
These activities include: offering paid services to customers as an ASP,
38+
serving PDFs on the fly in a web application, shipping iText with a closed
39+
source product.
40+
41+
For more information, please contact iText Software Corp. at this
42+
43+
*/
44+
package com.itextpdf.forms.fields.borders;
45+
46+
import com.itextpdf.kernel.colors.Color;
47+
import com.itextpdf.layout.borders.Border;
48+
49+
abstract class AbstractFormBorder extends Border {
50+
51+
/**
52+
* The form underline border.
53+
*
54+
* @see com.itextpdf.forms.fields.borders.UnderlineBorder
55+
*/
56+
static final int FORM_UNDERLINE = 1001;
57+
/**
58+
* The form beveled border.
59+
*
60+
* @see com.itextpdf.forms.fields.borders.BeveledBorder
61+
*/
62+
static final int FORM_BEVELED = 1002;
63+
/**
64+
* The form inset border.
65+
*
66+
* @see com.itextpdf.forms.fields.borders.InsetBorder
67+
*/
68+
static final int FORM_INSET = 1003;
69+
70+
protected AbstractFormBorder(Color color, float width) {
71+
super(color, width);
72+
}
73+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
3+
This file is part of the iText (R) project.
4+
Copyright (c) 1998-2020 iText Group NV
5+
Authors: Bruno Lowagie, Paulo Soares, et al.
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU Affero General Public License version 3
9+
as published by the Free Software Foundation with the addition of the
10+
following permission added to Section 15 as permitted in Section 7(a):
11+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
12+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
13+
OF THIRD PARTY RIGHTS
14+
15+
This program is distributed in the hope that it will be useful, but
16+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17+
or FITNESS FOR A PARTICULAR PURPOSE.
18+
See the GNU Affero General Public License for more details.
19+
You should have received a copy of the GNU Affero General Public License
20+
along with this program; if not, see http://www.gnu.org/licenses or write to
21+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
23+
http://itextpdf.com/terms-of-use/
24+
25+
The interactive user interfaces in modified source and object code versions
26+
of this program must display Appropriate Legal Notices, as required under
27+
Section 5 of the GNU Affero General Public License.
28+
29+
In accordance with Section 7(b) of the GNU Affero General Public License,
30+
a covered work must retain the producer line in every PDF that is created
31+
or manipulated using iText.
32+
33+
You can be released from the requirements of the license by purchasing
34+
a commercial license. Buying such a license is mandatory as soon as you
35+
develop commercial activities involving the iText software without
36+
disclosing the source code of your own applications.
37+
These activities include: offering paid services to customers as an ASP,
38+
serving PDFs on the fly in a web application, shipping iText with a closed
39+
source product.
40+
41+
For more information, please contact iText Software Corp. at this
42+
43+
*/
44+
package com.itextpdf.forms.fields.borders;
45+
46+
import com.itextpdf.kernel.colors.Color;
47+
import com.itextpdf.kernel.colors.ColorConstants;
48+
import com.itextpdf.kernel.colors.DeviceCmyk;
49+
import com.itextpdf.kernel.colors.DeviceGray;
50+
import com.itextpdf.kernel.colors.DeviceRgb;
51+
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
52+
import com.itextpdf.layout.borders.SolidBorder;
53+
54+
class BeveledBorder extends AbstractFormBorder {
55+
56+
private final Color backgroundColor;
57+
58+
public BeveledBorder(Color color, float width, Color backgroundColor) {
59+
super(color, width);
60+
this.backgroundColor = backgroundColor;
61+
}
62+
63+
/**
64+
* {@inheritDoc}
65+
*/
66+
@Override
67+
public void draw(PdfCanvas canvas, float x1, float y1, float x2, float y2, Side defaultSide,
68+
float borderWidthBefore, float borderWidthAfter) {
69+
SolidBorder solidBorder = new SolidBorder(getColor(), width);
70+
solidBorder.draw(canvas, x1, y1, x2, y2, defaultSide, borderWidthBefore, borderWidthAfter);
71+
float borderWidth = getWidth();
72+
float borderWidthX2 = borderWidth + borderWidth;
73+
Color darkerBackground = backgroundColor != null ? getDarkerColor(backgroundColor) : ColorConstants.LIGHT_GRAY;
74+
if (Side.TOP.equals(defaultSide)) {
75+
solidBorder = new SolidBorder(ColorConstants.WHITE, borderWidth);
76+
solidBorder.draw(canvas, borderWidthX2, y1 - borderWidth, x2 - borderWidth,
77+
y2 - borderWidth, Side.TOP, borderWidth, borderWidth);
78+
} else if (Side.BOTTOM.equals(defaultSide)) {
79+
solidBorder = new SolidBorder(darkerBackground, borderWidth);
80+
solidBorder.draw(canvas, x1 - borderWidth, borderWidthX2, borderWidthX2, borderWidthX2,
81+
Side.BOTTOM, borderWidth, borderWidth);
82+
} else if (Side.LEFT.equals(defaultSide)) {
83+
solidBorder = new SolidBorder(ColorConstants.WHITE, borderWidth);
84+
solidBorder.draw(canvas, borderWidthX2, borderWidthX2, borderWidthX2, y2 - borderWidth,
85+
Side.LEFT, borderWidth, borderWidth);
86+
} else if (Side.RIGHT.equals(defaultSide)) {
87+
solidBorder = new SolidBorder(darkerBackground, borderWidth);
88+
solidBorder.draw(canvas, x1 - borderWidth, y1 - borderWidth,
89+
x2 - borderWidth, borderWidthX2, Side.RIGHT, borderWidth, borderWidth);
90+
}
91+
}
92+
93+
/**
94+
* {@inheritDoc}
95+
*/
96+
@Override
97+
public void drawCellBorder(PdfCanvas canvas, float x1, float y1, float x2, float y2, Side defaultSide) {
98+
throw new UnsupportedOperationException();
99+
}
100+
101+
/**
102+
* {@inheritDoc}
103+
*/
104+
@Override
105+
public int getType() {
106+
return AbstractFormBorder.FORM_BEVELED;
107+
}
108+
109+
private Color getDarkerColor(Color color) {
110+
if (color instanceof DeviceRgb) {
111+
return DeviceRgb.makeDarker((DeviceRgb) color);
112+
} else if (color instanceof DeviceCmyk) {
113+
return DeviceCmyk.makeDarker((DeviceCmyk) color);
114+
} else if (color instanceof DeviceGray) {
115+
return DeviceGray.makeDarker((DeviceGray) color);
116+
} else {
117+
return color;
118+
}
119+
}
120+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
3+
This file is part of the iText (R) project.
4+
Copyright (c) 1998-2020 iText Group NV
5+
Authors: Bruno Lowagie, Paulo Soares, et al.
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU Affero General Public License version 3
9+
as published by the Free Software Foundation with the addition of the
10+
following permission added to Section 15 as permitted in Section 7(a):
11+
FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
12+
ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
13+
OF THIRD PARTY RIGHTS
14+
15+
This program is distributed in the hope that it will be useful, but
16+
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17+
or FITNESS FOR A PARTICULAR PURPOSE.
18+
See the GNU Affero General Public License for more details.
19+
You should have received a copy of the GNU Affero General Public License
20+
along with this program; if not, see http://www.gnu.org/licenses or write to
21+
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22+
Boston, MA, 02110-1301 USA, or download the license from the following URL:
23+
http://itextpdf.com/terms-of-use/
24+
25+
The interactive user interfaces in modified source and object code versions
26+
of this program must display Appropriate Legal Notices, as required under
27+
Section 5 of the GNU Affero General Public License.
28+
29+
In accordance with Section 7(b) of the GNU Affero General Public License,
30+
a covered work must retain the producer line in every PDF that is created
31+
or manipulated using iText.
32+
33+
You can be released from the requirements of the license by purchasing
34+
a commercial license. Buying such a license is mandatory as soon as you
35+
develop commercial activities involving the iText software without
36+
disclosing the source code of your own applications.
37+
These activities include: offering paid services to customers as an ASP,
38+
serving PDFs on the fly in a web application, shipping iText with a closed
39+
source product.
40+
41+
For more information, please contact iText Software Corp. at this
42+
43+
*/
44+
package com.itextpdf.forms.fields.borders;
45+
46+
import com.itextpdf.kernel.colors.Color;
47+
import com.itextpdf.kernel.pdf.PdfArray;
48+
import com.itextpdf.kernel.pdf.PdfDictionary;
49+
import com.itextpdf.kernel.pdf.PdfName;
50+
import com.itextpdf.layout.borders.Border;
51+
import com.itextpdf.layout.borders.FixedDashedBorder;
52+
import com.itextpdf.layout.borders.SolidBorder;
53+
54+
/**
55+
* A factory for creating {@link AbstractFormBorder} implementations.
56+
*/
57+
public final class FormBorderFactory {
58+
59+
private FormBorderFactory() {
60+
throw new UnsupportedOperationException();
61+
}
62+
63+
/**
64+
* Returns {@link Border} for specific borderStyle.
65+
*
66+
* @param borderStyle border style dictionary. ISO 32000-1 12.5.4
67+
* @param borderWidth width of the border
68+
* @param borderColor color of the border
69+
* @param backgroundColor element background color. This param used for drawing beveled border type
70+
* @return {@link Border} implementation or {@code null}
71+
*/
72+
public static Border getBorder(PdfDictionary borderStyle, float borderWidth, Color borderColor,
73+
Color backgroundColor) {
74+
if (borderStyle == null || borderStyle.getAsName(PdfName.S) == null
75+
|| borderColor == null || borderWidth <= 0) {
76+
return null;
77+
}
78+
Border resultBorder;
79+
PdfName borderType = borderStyle.getAsName(PdfName.S);
80+
if (PdfName.U.equals(borderType)) {
81+
resultBorder = new UnderlineBorder(borderColor, borderWidth);
82+
} else if (PdfName.S.equals(borderType)) {
83+
resultBorder = new SolidBorder(borderColor, borderWidth);
84+
} else if (PdfName.D.equals(borderType)) {
85+
PdfArray dashArray = borderStyle.getAsArray(PdfName.D);
86+
float unitsOn = FixedDashedBorder.DEFAULT_UNITS_VALUE;
87+
if (dashArray != null && dashArray.size() > 0 && dashArray.getAsNumber(0) != null) {
88+
unitsOn = dashArray.getAsNumber(0).intValue();
89+
}
90+
float unitsOff = unitsOn;
91+
if (dashArray != null && dashArray.size() > 1 && dashArray.getAsNumber(1) != null) {
92+
unitsOff = dashArray.getAsNumber(1).intValue();
93+
}
94+
resultBorder = new FixedDashedBorder(borderColor, borderWidth, unitsOn, unitsOff, 0);
95+
} else if (PdfName.I.equals(borderType)) {
96+
resultBorder = new InsetBorder(borderColor, borderWidth);
97+
} else if (PdfName.B.equals(borderType)) {
98+
resultBorder = new BeveledBorder(borderColor, borderWidth, backgroundColor);
99+
} else {
100+
resultBorder = null;
101+
}
102+
return resultBorder;
103+
}
104+
}

0 commit comments

Comments
 (0)