@@ -24,6 +24,7 @@ This file is part of the iText (R) project.
24
24
25
25
import com .itextpdf .commons .utils .MessageFormatUtil ;
26
26
import com .itextpdf .forms .PdfAcroForm ;
27
+ import com .itextpdf .forms .fields .AbstractPdfFormField ;
27
28
import com .itextpdf .forms .fields .PdfFormCreator ;
28
29
import com .itextpdf .forms .fields .PdfSignatureFormField ;
29
30
import com .itextpdf .forms .fields .SignatureFormFieldBuilder ;
@@ -69,6 +70,8 @@ public class SigFieldRenderer extends AbstractTextFieldRenderer {
69
70
70
71
private static final float EPS = 1e-5f ;
71
72
73
+ private boolean isFontSizeApproximated = false ;
74
+
72
75
/**
73
76
* Creates a new {@link SigFieldRenderer} instance.
74
77
*
@@ -111,7 +114,8 @@ protected IRenderer createFlatRenderer() {
111
114
throw new IllegalStateException ("A signature image must be present when rendering mode is " +
112
115
"graphic and description. Use setSignatureGraphic()" );
113
116
}
114
- div .add (new Image (signatureGraphic )).add (new Paragraph (description ).setMultipliedLeading (0.9f ));
117
+ div .add (new Image (signatureGraphic ))
118
+ .add (new Paragraph (description ).setMargin (0 ).setMultipliedLeading (0.9f ));
115
119
break ;
116
120
}
117
121
case GRAPHIC :
@@ -123,12 +127,21 @@ protected IRenderer createFlatRenderer() {
123
127
div .add (new Image (signatureGraphic ));
124
128
break ;
125
129
default :
126
- div .add (new Paragraph (description ).setMultipliedLeading (0.9f ));
130
+ div .add (new Paragraph (description ).setMargin ( 0 ). setMultipliedLeading (0.9f ));
127
131
break ;
128
132
}
129
133
return div .createRendererSubTree ();
130
134
}
131
135
136
+ /**
137
+ * {@inheritDoc}
138
+ */
139
+ @ Override
140
+ public LayoutResult layout (LayoutContext layoutContext ) {
141
+ approximateFontSizeToFitLayoutArea (layoutContext );
142
+ return super .layout (layoutContext );
143
+ }
144
+
132
145
/**
133
146
* {@inheritDoc}
134
147
*
@@ -153,28 +166,33 @@ protected void adjustFieldLayout(LayoutContext layoutContext) {
153
166
case GRAPHIC_AND_DESCRIPTION : {
154
167
// Split the signature field into two and add the name of the signer or an image to the one side,
155
168
// the description to the other side.
169
+ UnitValue [] paddings = getPaddings ();
156
170
if (bBox .getHeight () > bBox .getWidth ()) {
171
+ float topPadding = paddings [0 ].getValue ();
172
+ float bottomPadding = paddings [2 ].getValue ();
157
173
signatureRect = new Rectangle (
158
174
bBox .getX (),
159
- bBox .getY () + bBox .getHeight () / 2 ,
175
+ bBox .getY () + bBox .getHeight () / 2 + bottomPadding / 2 ,
160
176
bBox .getWidth (),
161
- bBox .getHeight () / 2 );
177
+ bBox .getHeight () / 2 - bottomPadding / 2 );
162
178
descriptionRect = new Rectangle (
163
179
bBox .getX (),
164
180
bBox .getY (),
165
181
bBox .getWidth (),
166
- bBox .getHeight () / 2 );
182
+ bBox .getHeight () / 2 - topPadding / 2 );
167
183
} else {
168
184
// origin is the bottom-left
185
+ float rightPadding = paddings [1 ].getValue ();
186
+ float leftPadding = paddings [3 ].getValue ();
169
187
signatureRect = new Rectangle (
170
188
bBox .getX (),
171
189
bBox .getY (),
172
- bBox .getWidth () / 2 ,
190
+ bBox .getWidth () / 2 - rightPadding / 2 ,
173
191
bBox .getHeight ());
174
192
descriptionRect = new Rectangle (
175
- bBox .getX () + bBox .getWidth () / 2 ,
193
+ bBox .getX () + bBox .getWidth () / 2 + leftPadding / 2 ,
176
194
bBox .getY (),
177
- bBox .getWidth () / 2 ,
195
+ bBox .getWidth () / 2 - leftPadding / 2 ,
178
196
bBox .getHeight ());
179
197
}
180
198
break ;
@@ -185,7 +203,15 @@ protected void adjustFieldLayout(LayoutContext layoutContext) {
185
203
break ;
186
204
default :
187
205
// Default one, it just shows whatever description was defined for the signature.
188
- descriptionRect = bBox .setHeight (getOccupiedArea ().getBBox ().getHeight () * (1 - TOP_SECTION ));
206
+ if (retrieveHeight () == null ) {
207
+ // Adjust calculated occupied area height to keep the same font size.
208
+ float calculatedHeight = getOccupiedArea ().getBBox ().getHeight ();
209
+ getOccupiedArea ().getBBox ().moveDown (calculatedHeight * TOP_SECTION )
210
+ .setHeight (calculatedHeight * (1 + TOP_SECTION ));
211
+ bBox .moveDown (calculatedHeight * TOP_SECTION );
212
+ }
213
+ descriptionRect = bBox .setHeight (getOccupiedArea ().getBBox ().getHeight () * (1 - TOP_SECTION )
214
+ - calculateAdditionalHeight ());
189
215
break ;
190
216
}
191
217
@@ -331,10 +357,10 @@ private void relayoutImage(Rectangle signatureRect, int pageNum) {
331
357
}
332
358
333
359
private void relayoutParagraph (IRenderer renderer , Rectangle rect , int pageNum ) {
334
- UnitValue fontSize = this .hasOwnProperty (Property .FONT_SIZE ) ?
360
+ UnitValue fontSizeAsUV = this .hasOwnProperty (Property .FONT_SIZE ) ?
335
361
(UnitValue ) this .<UnitValue >getOwnProperty (Property .FONT_SIZE ) :
336
362
(UnitValue ) modelElement .<UnitValue >getOwnProperty (Property .FONT_SIZE );
337
- if (fontSize == null || fontSize .getValue () < EPS ) {
363
+ if (fontSizeAsUV == null || fontSizeAsUV .getValue () < EPS || isFontSizeApproximated ) {
338
364
// Calculate font size.
339
365
IRenderer helper = ((Paragraph ) renderer .getModelElement ()).createRendererSubTree ()
340
366
.setParent (renderer .getParent ());
@@ -343,19 +369,8 @@ private void relayoutParagraph(IRenderer renderer, Rectangle rect, int pageNum)
343
369
float lFontSize = 0.1f , rFontSize = 100 ;
344
370
int numberOfIterations = 15 ;
345
371
// 15 iterations with lFontSize = 0.1 and rFontSize = 100 should result in ~0.003 precision.
346
- for (int i = 0 ; i < numberOfIterations ; i ++) {
347
- float mFontSize = (lFontSize + rFontSize ) / 2 ;
348
- UnitValue fontSizeAsUV = UnitValue .createPointValue (mFontSize );
349
- helper .setProperty (Property .FONT_SIZE , fontSizeAsUV );
350
- LayoutResult result = helper .layout (layoutContext );
351
- if (result .getStatus () == LayoutResult .FULL ) {
352
- lFontSize = mFontSize ;
353
- } else {
354
- rFontSize = mFontSize ;
355
- }
356
- }
357
- UnitValue fontSizeAsUV = UnitValue .createPointValue (lFontSize );
358
- renderer .getModelElement ().setProperty (Property .FONT_SIZE , fontSizeAsUV );
372
+ float fontSize = calculateFittingFontSize (helper , lFontSize , rFontSize , layoutContext , numberOfIterations );
373
+ renderer .getModelElement ().setProperty (Property .FONT_SIZE , UnitValue .createPointValue (fontSize ));
359
374
}
360
375
// Relayout the element after font size was changed or signature was split into 2 parts.
361
376
LayoutContext layoutContext = new LayoutContext (new LayoutArea (pageNum , rect ));
@@ -390,4 +405,29 @@ private void applyBackgroundImage(SigField modelElement) {
390
405
.build ());
391
406
}
392
407
}
408
+
409
+ private float calculateAdditionalHeight () {
410
+ Rectangle dummy = new Rectangle (0 , 0 );
411
+ this .applyMargins (dummy , true );
412
+ this .applyBorderBox (dummy , true );
413
+ this .applyPaddings (dummy , true );
414
+ return dummy .getHeight ();
415
+ }
416
+
417
+ private void approximateFontSizeToFitLayoutArea (LayoutContext layoutContext ) {
418
+ if (this .hasOwnProperty (Property .FONT_SIZE ) || modelElement .hasOwnProperty (Property .FONT_SIZE )) {
419
+ return ;
420
+ }
421
+ if (SigField .RenderingMode .GRAPHIC == ((SigField ) modelElement ).getRenderingMode () ||
422
+ SigField .RenderingMode .GRAPHIC_AND_DESCRIPTION == ((SigField ) modelElement ).getRenderingMode ()) {
423
+ // We can expect CLIP_ELEMENT log messages since the initial image size may be larger than the field height.
424
+ // But image size will be adjusted during its relayout in #adjustFieldLayout.
425
+ return ;
426
+ }
427
+ float fontSize = approximateFontSize (layoutContext , 0.1f , AbstractPdfFormField .DEFAULT_FONT_SIZE );
428
+ if (fontSize > 0 ) {
429
+ isFontSizeApproximated = true ;
430
+ modelElement .setProperty (Property .FONT_SIZE , UnitValue .createPointValue (fontSize ));
431
+ }
432
+ }
393
433
}
0 commit comments