@@ -33,6 +33,7 @@ This file is part of the iText (R) project.
33
33
import com .itextpdf .forms .form .element .InputField ;
34
34
import com .itextpdf .forms .form .element .Radio ;
35
35
import com .itextpdf .forms .form .element .TextArea ;
36
+ import com .itextpdf .forms .form .element .Button ;
36
37
import com .itextpdf .forms .logs .FormsLogMessageConstants ;
37
38
import com .itextpdf .forms .util .DrawingUtil ;
38
39
import com .itextpdf .forms .util .FontSizeUtil ;
@@ -68,6 +69,7 @@ This file is part of the iText (R) project.
68
69
import com .itextpdf .layout .borders .Border ;
69
70
import com .itextpdf .layout .borders .SolidBorder ;
70
71
import com .itextpdf .layout .element .Div ;
72
+ import com .itextpdf .layout .element .Image ;
71
73
import com .itextpdf .layout .element .Paragraph ;
72
74
import com .itextpdf .layout .element .Text ;
73
75
import com .itextpdf .layout .properties .Background ;
@@ -120,6 +122,8 @@ public class PdfFormAnnotation extends AbstractPdfFormField {
120
122
protected Color backgroundColor ;
121
123
protected Color borderColor ;
122
124
125
+ private Button formFieldElement ;
126
+
123
127
/**
124
128
* Creates a form field annotation as a wrapper of a {@link PdfWidgetAnnotation}.
125
129
*
@@ -389,6 +393,19 @@ public PdfFormAnnotation setPage(int pageNum) {
389
393
return this ;
390
394
}
391
395
396
+ /**
397
+ * Sets an element associated with the current field.
398
+ *
399
+ * @param element model element to set.
400
+ *
401
+ * @return this {@link PdfFormAnnotation}.
402
+ */
403
+ public PdfFormAnnotation setFormFieldElement (Button element ) {
404
+ this .formFieldElement = element ;
405
+ regenerateWidget ();
406
+ return this ;
407
+ }
408
+
392
409
/**
393
410
* Gets the appearance state names.
394
411
*
@@ -536,9 +553,7 @@ protected void drawTextAppearance(Rectangle rect, PdfFont font, float fontSize,
536
553
537
554
Style paragraphStyle = new Style ().setFont (font ).setFontSize (fontSize );
538
555
paragraphStyle .setProperty (Property .LEADING , new Leading (Leading .MULTIPLIED , 1 ));
539
- if (getColor () != null ) {
540
- paragraphStyle .setProperty (Property .FONT_COLOR , new TransparentColor (getColor ()));
541
- }
556
+ paragraphStyle .setFontColor (getColor ());
542
557
543
558
int maxLen = new PdfTextFormField (parent .getPdfObject ()).getMaxLen ();
544
559
// check if /Comb has been set
@@ -750,73 +765,67 @@ protected void drawPdfA2CheckAppearance(float width, float height, String onStat
750
765
}
751
766
752
767
/**
753
- * Draws the appearance for a push button.
754
- *
755
- * @param width the width of the pushbutton
756
- * @param height the width of the pushbutton
757
- * @param text the text to display on the button
758
- * @param font a {@link PdfFont}
759
- * @param fontSize the size of the font
760
- *
761
- * @return a new {@link PdfFormXObject}
768
+ * Draws the appearance of a push button and saves it into an appearance stream.
762
769
*/
763
- protected PdfFormXObject drawPushButtonAppearance (float width , float height , String text ,
764
- PdfFont font , float fontSize ) {
765
- PdfStream stream = (PdfStream ) new PdfStream ().makeIndirect (getDocument ());
766
- PdfCanvas canvas = new PdfCanvas (stream , new PdfResources (), getDocument ());
770
+ protected void drawPushButtonFieldAndSaveAppearance () {
771
+ Rectangle rectangle = getRect (this .getPdfObject ());
772
+ if (rectangle == null ) {
773
+ return ;
774
+ }
775
+ float width = rectangle .getWidth ();
776
+ float height = rectangle .getHeight ();
777
+
778
+ createInputButton ();
767
779
768
780
PdfFormXObject xObject = new PdfFormXObject (new Rectangle (0 , 0 , width , height ));
769
- drawBorder (canvas , xObject , width , height );
781
+ applyRotation (xObject , height , width );
782
+ Canvas canvas = new Canvas (xObject , this .getDocument ());
783
+ setMetaInfoToCanvas (canvas );
784
+
785
+ String caption = parent .getDisplayValue ();
786
+ if (caption != null && !caption .isEmpty ()) {
787
+ formFieldElement .setSingleLineValue (caption );
788
+ }
770
789
790
+ float imagePadding = borderColor == null ? 0 : borderWidth ;
771
791
if (parent .img != null ) {
772
- PdfImageXObject imgXObj = new PdfImageXObject (parent .img );
773
- canvas .addXObjectWithTransformationMatrix (imgXObj , width - borderWidth , 0 , 0 ,
774
- height - borderWidth , borderWidth / 2 , borderWidth / 2 );
775
- xObject .getResources ().addImage (imgXObj );
792
+ // If we got here, the button will only contain the image that the user has set into the annotation.
793
+ // There is no way to pass other elements with this image.
794
+ formFieldElement .getChildren ().clear ();
795
+ Image image = new Image (new PdfImageXObject (parent .img ), imagePadding , imagePadding );
796
+ image .setHeight (height - 2 * imagePadding );
797
+ image .setWidth (width - 2 * imagePadding );
798
+ formFieldElement .add (image );
776
799
} else if (parent .form != null ) {
777
- canvas .addXObjectWithTransformationMatrix (parent .form ,
778
- (height - borderWidth ) / parent .form .getHeight (), 0 , 0 ,
779
- (height - borderWidth ) / parent .form .getHeight (), borderWidth / 2 , borderWidth / 2 );
780
- xObject .getResources ().addForm (parent .form );
800
+ // If we got here, the button will only contain the image that the user has set as form into the annotation.
801
+ // There is no way to pass other elements with this image as form.
802
+ formFieldElement .getChildren ().clear ();
803
+ Image image = new Image (parent .form , imagePadding , imagePadding );
804
+ image .setHeight (height - 2 * imagePadding );
805
+ formFieldElement .add (image );
781
806
} else {
782
- drawButton (canvas , 0 , 0 , width , height , text , font , fontSize );
783
- xObject .getResources ().addFont (getDocument (), font );
807
+ xObject .getResources ().addFont (getDocument (), getFont ());
784
808
}
785
- xObject .getPdfObject ().getOutputStream ().writeBytes (stream .getBytes ());
786
-
787
- return xObject ;
788
- }
809
+ canvas .add (formFieldElement );
789
810
790
- /**
791
- * Performs the low-level drawing operations to draw a button object.
792
- *
793
- * @param canvas the {@link PdfCanvas} of the page to draw on.
794
- * @param x will be ignored, according to spec it shall be 0
795
- * @param y will be ignored, according to spec it shall be 0
796
- * @param width the width of the button
797
- * @param height the width of the button
798
- * @param text the text to display on the button
799
- * @param font a {@link PdfFont}
800
- * @param fontSize the size of the font
801
- */
802
- protected void drawButton (PdfCanvas canvas , float x , float y , float width , float height , String text , PdfFont font ,
803
- float fontSize ) {
804
- if (getColor () == null ) {
805
- color = ColorConstants .BLACK ;
806
- }
807
- if (text == null ) {
808
- text = "" ;
811
+ PdfDictionary ap = new PdfDictionary ();
812
+ PdfStream normalAppearanceStream = xObject .getPdfObject ();
813
+ if (normalAppearanceStream != null ) {
814
+ PdfName stateName = getPdfObject ().getAsName (PdfName .AS );
815
+ if (stateName == null ) {
816
+ stateName = new PdfName ("push" );
817
+ }
818
+ getPdfObject ().put (PdfName .AS , stateName );
819
+ PdfDictionary normalAppearance = new PdfDictionary ();
820
+ normalAppearance .put (stateName , normalAppearanceStream );
821
+ ap .put (PdfName .N , normalAppearance );
822
+ ap .setModified ();
809
823
}
810
-
811
- Paragraph paragraph = new Paragraph (text ).setFont (font ).setFontSize (fontSize ).setMargin (0 ).
812
- setMultipliedLeading (1 ).setVerticalAlignment (VerticalAlignment .MIDDLE );
813
- Canvas modelCanvas = new Canvas (canvas , new Rectangle (0 , -height , width , 2 * height ));
814
- modelCanvas .setProperty (Property .APPEARANCE_STREAM_LAYOUT , Boolean .TRUE );
815
-
816
- setMetaInfoToCanvas (modelCanvas );
817
-
818
- modelCanvas .showTextAligned (paragraph , width / 2 , height / 2 , TextAlignment .CENTER ,
819
- VerticalAlignment .MIDDLE );
824
+ put (PdfName .AP , ap );
825
+ // We need to draw waitingDrawingElements (drawn inside close method), but the close method
826
+ // flushes TagTreePointer that will be used later, so set null to the corresponding property.
827
+ canvas .setProperty (Property .TAGGING_HELPER , null );
828
+ canvas .close ();
820
829
}
821
830
822
831
/**
@@ -1052,47 +1061,13 @@ void drawChoiceAppearance(Rectangle rect, float fontSize, String value, PdfFormX
1052
1061
appearance .getPdfObject ().setData (stream .getBytes ());
1053
1062
}
1054
1063
1055
- static void createPushButtonAppearanceState (PdfDictionary widget ) {
1056
- PdfDictionary appearances = widget .getAsDictionary (PdfName .AP );
1057
- PdfStream normalAppearanceStream = appearances .getAsStream (PdfName .N );
1058
- if (normalAppearanceStream != null ) {
1059
- PdfName stateName = widget .getAsName (PdfName .AS );
1060
- if (stateName == null ) {
1061
- stateName = new PdfName ("push" );
1062
- }
1063
- widget .put (PdfName .AS , stateName );
1064
- PdfDictionary normalAppearance = new PdfDictionary ();
1065
- normalAppearance .put (stateName , normalAppearanceStream );
1066
- appearances .put (PdfName .N , normalAppearance );
1067
- }
1068
- }
1069
-
1070
1064
static void setMetaInfoToCanvas (Canvas canvas ) {
1071
1065
MetaInfoContainer metaInfo = FormsMetaInfoStaticContainer .getMetaInfoForLayout ();
1072
1066
if (metaInfo != null ) {
1073
1067
canvas .setProperty (Property .META_INFO , metaInfo );
1074
1068
}
1075
1069
}
1076
1070
1077
- void regeneratePushButtonField () {
1078
- PdfDictionary widget = getPdfObject ();
1079
- PdfFormXObject appearance ;
1080
- Rectangle rect = getRect (widget );
1081
- PdfDictionary apDic = widget .getAsDictionary (PdfName .AP );
1082
-
1083
- if (apDic == null ) {
1084
- put (PdfName .AP , apDic = new PdfDictionary ());
1085
- }
1086
- appearance = drawPushButtonAppearance (rect .getWidth (), rect .getHeight (), parent .getDisplayValue (),
1087
- getFont (), getFontSize (widget .getAsArray (PdfName .Rect ), parent .getDisplayValue ()));
1088
-
1089
- apDic .put (PdfName .N , appearance .getPdfObject ());
1090
-
1091
- if (getPdfAConformanceLevel () != null ) {
1092
- createPushButtonAppearanceState (widget );
1093
- }
1094
- }
1095
-
1096
1071
//TODO DEVSIX-7443 remove method
1097
1072
void regenerateCheckboxField (CheckBoxType checkType ) {
1098
1073
parent .setCheckType (checkType );
@@ -1269,7 +1244,7 @@ boolean regenerateWidget() {
1269
1244
return regenerateTextAndChoiceField ();
1270
1245
} else if (PdfName .Btn .equals (type )) {
1271
1246
if (parent .getFieldFlag (PdfButtonFormField .FF_PUSH_BUTTON )) {
1272
- regeneratePushButtonField ();
1247
+ drawPushButtonFieldAndSaveAppearance ();
1273
1248
} else if (parent .getFieldFlag (PdfButtonFormField .FF_RADIO )) {
1274
1249
drawRadioButtonAndSaveAppearance (getRadioButtonValue ());
1275
1250
} else {
@@ -1286,6 +1261,45 @@ boolean regenerateWidget() {
1286
1261
return false ;
1287
1262
}
1288
1263
1264
+ void createInputButton () {
1265
+ final Rectangle rect = getRect (getPdfObject ());
1266
+ if (rect == null ) {
1267
+ formFieldElement = null ;
1268
+ return ;
1269
+ }
1270
+
1271
+ if (formFieldElement == null ) {
1272
+ // Create it one time and re-set properties during each widget regeneration.
1273
+ formFieldElement = new Button (parent .getFieldName ().toUnicodeString ());
1274
+ }
1275
+
1276
+ formFieldElement .setFont (getFont ());
1277
+ formFieldElement .setFontSize (getFontSize (getPdfObject ()
1278
+ .getAsArray (PdfName .Rect ), parent .getDisplayValue ()));
1279
+ if (getColor () == null ) {
1280
+ final TransparentColor transparentColor =
1281
+ formFieldElement .<TransparentColor >getProperty (Property .FONT_COLOR );
1282
+ color = transparentColor == null ? ColorConstants .BLACK : transparentColor .getColor ();
1283
+ }
1284
+ formFieldElement .setFontColor (color );
1285
+
1286
+ formFieldElement .setBackgroundColor (backgroundColor );
1287
+ if (borderWidth > 0 && borderColor != null ) {
1288
+ final float borderWidth = Math .max (1 , getBorderWidth ());
1289
+ // Don't take border into account as it will be drawn inside
1290
+ Border border = FormBorderFactory .getBorder (getWidget ().getBorderStyle (),
1291
+ borderWidth , borderColor , backgroundColor );
1292
+ formFieldElement .setBorder (border != null ? border : new SolidBorder (borderColor , borderWidth ));
1293
+ }
1294
+
1295
+ // Set fixed size
1296
+ formFieldElement .setProperty (Property .WIDTH , UnitValue .createPointValue (rect .getWidth ()));
1297
+ formFieldElement .setProperty (Property .HEIGHT , UnitValue .createPointValue (rect .getHeight ()));
1298
+
1299
+ // Always flatten
1300
+ formFieldElement .setInteractive (false );
1301
+ }
1302
+
1289
1303
Radio createRadio () {
1290
1304
final Rectangle rect = getRect (getPdfObject ());
1291
1305
if (rect == null ) {
@@ -1311,7 +1325,7 @@ Radio createRadio() {
1311
1325
radio .setProperty (Property .HEIGHT , UnitValue .createPointValue (rect .getHeight ()));
1312
1326
1313
1327
// Always flatten
1314
- radio .setProperty ( FormProperty . FORM_FIELD_FLATTEN , true );
1328
+ radio .setInteractive ( false );
1315
1329
1316
1330
return radio ;
1317
1331
}
0 commit comments