@@ -28,7 +28,11 @@ This file is part of the iText (R) project.
28
28
import com .itextpdf .forms .fields .properties .CheckBoxType ;
29
29
import com .itextpdf .forms .form .FormProperty ;
30
30
import com .itextpdf .forms .form .element .CheckBox ;
31
+ import com .itextpdf .forms .form .element .FormField ;
32
+ import com .itextpdf .forms .form .element .IFormField ;
33
+ import com .itextpdf .forms .form .element .InputField ;
31
34
import com .itextpdf .forms .form .element .Radio ;
35
+ import com .itextpdf .forms .form .element .TextArea ;
32
36
import com .itextpdf .forms .logs .FormsLogMessageConstants ;
33
37
import com .itextpdf .forms .util .DrawingUtil ;
34
38
import com .itextpdf .forms .util .FontSizeUtil ;
@@ -66,6 +70,7 @@ This file is part of the iText (R) project.
66
70
import com .itextpdf .layout .element .Div ;
67
71
import com .itextpdf .layout .element .Paragraph ;
68
72
import com .itextpdf .layout .element .Text ;
73
+ import com .itextpdf .layout .properties .Background ;
69
74
import com .itextpdf .layout .properties .BoxSizingPropertyValue ;
70
75
import com .itextpdf .layout .properties .Leading ;
71
76
import com .itextpdf .layout .properties .OverflowPropertyValue ;
@@ -114,7 +119,6 @@ public class PdfFormAnnotation extends AbstractPdfFormField {
114
119
protected float borderWidth = 1 ;
115
120
protected Color backgroundColor ;
116
121
protected Color borderColor ;
117
- protected int rotation = 0 ;
118
122
119
123
/**
120
124
* Creates a form field annotation as a wrapper of a {@link PdfWidgetAnnotation}.
@@ -205,20 +209,22 @@ public PdfFormAnnotation setRotation(int degRotation) {
205
209
if (degRotation < 0 ) {
206
210
degRotation += 360 ;
207
211
}
208
-
209
- this .rotation = degRotation ;
210
212
}
211
213
PdfDictionary mk = getWidget ().getAppearanceCharacteristics ();
212
214
if (mk == null ) {
213
215
mk = new PdfDictionary ();
214
216
this .put (PdfName .MK , mk );
215
217
}
216
218
mk .put (PdfName .R , new PdfNumber (degRotation ));
217
-
218
- this .rotation = degRotation ;
219
+
219
220
regenerateField ();
220
221
return this ;
221
222
}
223
+
224
+ public int getRotation () {
225
+ PdfDictionary mk = getWidget ().getAppearanceCharacteristics ();
226
+ return mk == null || mk .getAsInt (PdfName .R ) == null ? 0 : (int ) mk .getAsInt (PdfName .R );
227
+ }
222
228
223
229
/**
224
230
* Sets the action on {@link PdfWidgetAnnotation widget} of this annotation form field.
@@ -291,6 +297,21 @@ public float getBorderWidth() {
291
297
return borderWidth ;
292
298
}
293
299
300
+ /**
301
+ * Get border object specified in the widget annotation dictionary.
302
+ *
303
+ * @return {@link Border} specified in the widget annotation dictionary
304
+ */
305
+ public Border getBorder () {
306
+ float borderWidth = getBorderWidth ();
307
+ Border border = FormBorderFactory .getBorder (
308
+ this .getWidget ().getBorderStyle (), borderWidth , borderColor , backgroundColor );
309
+ if (border == null && borderWidth > 0 && borderColor != null ) {
310
+ border = new SolidBorder (borderColor , Math .max (1 , borderWidth ));
311
+ }
312
+ return border ;
313
+ }
314
+
294
315
/**
295
316
* Sets the border width for the field.
296
317
*
@@ -299,13 +320,15 @@ public float getBorderWidth() {
299
320
* @return The edited {@link PdfFormAnnotation}.
300
321
*/
301
322
public PdfFormAnnotation setBorderWidth (float borderWidth ) {
323
+ // Acrobat doesn't support float border width therefore we round it.
324
+ int roundedBorderWidth = (int ) Math .round (borderWidth );
302
325
PdfDictionary bs = getWidget ().getBorderStyle ();
303
326
if (bs == null ) {
304
327
bs = new PdfDictionary ();
305
328
put (PdfName .BS , bs );
306
329
}
307
- bs .put (PdfName .W , new PdfNumber (borderWidth ));
308
- this .borderWidth = borderWidth ;
330
+ bs .put (PdfName .W , new PdfNumber (roundedBorderWidth ));
331
+ this .borderWidth = roundedBorderWidth ;
309
332
310
333
regenerateField ();
311
334
return this ;
@@ -497,7 +520,8 @@ protected void drawTextAppearance(Rectangle rect, PdfFont font, float fontSize,
497
520
saveState ().
498
521
endPath ();
499
522
500
- TextAlignment textAlignment = parent .convertJustificationToTextAlignment ();
523
+ TextAlignment textAlignment =
524
+ parent .getJustification () == null ? TextAlignment .LEFT : parent .getJustification ();
501
525
float x = 0 ;
502
526
if (textAlignment == TextAlignment .RIGHT ) {
503
527
x = rect .getWidth ();
@@ -584,7 +608,7 @@ protected void drawMultiLineTextAppearance(Rectangle rect, PdfFont font, String
584
608
paragraph .setFontSize (getFontSize ());
585
609
}
586
610
paragraph .setProperty (Property .FORCED_PLACEMENT , Boolean .TRUE );
587
- paragraph .setTextAlignment (parent .convertJustificationToTextAlignment ());
611
+ paragraph .setTextAlignment (parent .getJustification ());
588
612
589
613
if (getColor () != null ) {
590
614
paragraph .setFontColor (getColor ());
@@ -891,6 +915,54 @@ protected void drawRadioButtonAndSaveAppearance(String value) {
891
915
getWidget ().setNormalAppearance (normalAppearance );
892
916
}
893
917
918
+ /**
919
+ * Draws the appearance of a text form field with and saves it into an appearance stream.
920
+ */
921
+ protected void drawTextFormFieldAndSaveAppearance () {
922
+ Rectangle rectangle = getRect (this .getPdfObject ());
923
+ if (rectangle == null ) {
924
+ return ;
925
+ }
926
+
927
+ IFormField textFormField ;
928
+ if (parent .isMultiline ()) {
929
+ textFormField = new TextArea (getParentField ().getPartialFieldName ().toUnicodeString ());
930
+ textFormField .setProperty (Property .FONT_SIZE , UnitValue .createPointValue (getFontSize ()));
931
+ } else {
932
+ textFormField = new InputField (getParentField ().getPartialFieldName ().toUnicodeString ());
933
+ textFormField .setProperty (Property .FONT_SIZE ,
934
+ UnitValue .createPointValue (getFontSize (new PdfArray (rectangle ), parent .getValueAsString ())));
935
+ }
936
+ textFormField .setProperty (FormProperty .FORM_FIELD_VALUE , parent .getDisplayValue ());
937
+ textFormField .setProperty (Property .FONT , getFont ());
938
+ textFormField .setProperty (Property .TEXT_ALIGNMENT , parent .getJustification ());
939
+ textFormField .setProperty (FormProperty .FORM_FIELD_PASSWORD_FLAG , getParentField ().isPassword ());
940
+ textFormField .setProperty (Property .ADD_MARKED_CONTENT_TEXT , true );
941
+ if (getColor () != null ) {
942
+ textFormField .setProperty (Property .FONT_COLOR , new TransparentColor (getColor ()));
943
+ }
944
+
945
+ textFormField .setProperty (Property .BORDER , getBorder ());
946
+
947
+ if (backgroundColor != null ) {
948
+ textFormField .setProperty (Property .BACKGROUND , new Background (backgroundColor , 1f , 0 , 0 , 0 , 0 ));
949
+ }
950
+
951
+ textFormField .setProperty (Property .WIDTH , UnitValue .createPointValue (rectangle .getWidth ()));
952
+ textFormField .setProperty (Property .HEIGHT , UnitValue .createPointValue (rectangle .getHeight ()));
953
+ // Always flatten
954
+ textFormField .setProperty (FormProperty .FORM_FIELD_FLATTEN , true );
955
+
956
+ PdfFormXObject xObject = new PdfFormXObject (
957
+ new Rectangle (0 , 0 , rectangle .getWidth (), rectangle .getHeight ()));
958
+ applyRotation (xObject , rectangle .getWidth (), rectangle .getHeight ());
959
+ Canvas canvas = new Canvas (xObject , this .getDocument ());
960
+ canvas .setProperty (Property .APPEARANCE_STREAM_LAYOUT , Boolean .TRUE );
961
+ canvas .add (textFormField );
962
+
963
+ getWidget ().setNormalAppearance (xObject .getPdfObject ());
964
+ }
965
+
894
966
@ Override
895
967
void retrieveStyles () {
896
968
super .retrieveStyles ();
@@ -951,7 +1023,7 @@ void drawChoiceAppearance(Rectangle rect, float fontSize, String value, PdfFormX
951
1023
Paragraph paragraph = new Paragraph (strings .get (index )).setFont (getFont ())
952
1024
.setFontSize (fontSize ).setMargins (0 , 0 , 0 , 0 ).setMultipliedLeading (1 );
953
1025
paragraph .setProperty (Property .FORCED_PLACEMENT , Boolean .TRUE );
954
- paragraph .setTextAlignment (parent .convertJustificationToTextAlignment ());
1026
+ paragraph .setTextAlignment (parent .getJustification ());
955
1027
956
1028
if (getColor () != null ) {
957
1029
paragraph .setFontColor (getColor ());
@@ -1190,7 +1262,10 @@ boolean regenerateWidget() {
1190
1262
}
1191
1263
final PdfName type = parent .getFormType ();
1192
1264
1193
- if (PdfName .Tx .equals (type ) || PdfName .Ch .equals (type )) {
1265
+ if (PdfName .Tx .equals (type ) && ExperimentalFeatures .ENABLE_EXPERIMENTAL_TEXT_FORM_RENDERING ) {
1266
+ drawTextFormFieldAndSaveAppearance ();
1267
+ return true ;
1268
+ } else if (PdfName .Ch .equals (type ) || PdfName .Tx .equals (type )) {
1194
1269
return regenerateTextAndChoiceField ();
1195
1270
} else if (PdfName .Btn .equals (type )) {
1196
1271
if (parent .getFieldFlag (PdfButtonFormField .FF_PUSH_BUTTON )) {
@@ -1391,7 +1466,7 @@ private static String obfuscatePassword(String text) {
1391
1466
}
1392
1467
1393
1468
private void applyRotation (PdfFormXObject xObject , float height , float width ) {
1394
- switch (rotation ) {
1469
+ switch (getRotation () ) {
1395
1470
case 90 :
1396
1471
xObject .put (PdfName .Matrix , new PdfArray (new float [] {0 , 1 , -1 , 0 , height , 0 }));
1397
1472
break ;
0 commit comments