Fit text in TextField IText

2019-06-27 12:10发布

问题:

Sorry if there exists similar post like mine but I'm new on this forum and I haven't find it.

I have problem with dynamically resize TextField size depends on text size. I fill existing PDF - fill fields in AcroForm:

form.setField("field", "value"); (etc.)

Everything it's OK, but I also want to set text (in TextField) which size is greater than field size. How can I dynamically resize TextField (after/before setField or maybe set some field property in AcroForm creation process) to fit text (text larger than TextField)? This TextField must have size exactly like text size, without changing font size to smaller size and without scrolls in this TextField.

Thanks in advance for helping.

回答1:

Well it's easy to do the opposite of what you want, change the font size so all the text is visible. You just set the font size to '0', and iText (or Acrobat, or whatever) determines what font size to use on the fly (within some reasonable limits).


To determine the length of a given chunk of text, you can call myBaseFont.getWidthPoint( fieldValToBe, fontSize ). Then you can size the field before you call setField. iText renders field appearances for you by default, and that rendering is done when you can setField. Changing the field size afterwords won't change the field's appearance unless you call setField again.

Okay, so how do you change the field's size? iText doesn't support that directly, so you have to do it with iText's low-level PDF objects. Something like this:

AcroFields.Item fldItem = myAcroFields.getFieldItem("fieldName");

for (int i =0; i < fldItem.size(); ++i) {
  // "widget" is the visible portion of the field
  PdfDictionary widgetDict = fldItem.getwidget(0);  

  // pdf rectangles are stored as [llx, lly, urx, ury]
  PdfArray rectArr = widgetDict.getAsArray(PdfName.RECT); // should never be null
  float origX = rectArr.getAsNumber(0).floatValue();
  // overwrite the old value.  
  rectArr.set( 2, new PdfNumber( origX + newWidth + FUDGE_FACTOR ) );
}

FUDGE_FACTOR needs to account for right & left border thicknesses. I'd guess 3-5 points, depending on beveled vs flat borders, line thickness and so forth. You can probably just pick a value and go with it.

The loop is probably uneccessary, as it's rare for more than one field to share a name. OTOH, if that's what you're up against, you might also need to recalculate newWidth because different instances need not share the same font size.

And finally, you might need to write this new rectArr into the "merged" version of the item as well as the widget version. iText almost universally works with the merged version when manipulating a field because all the possible key/value pairs are right there, where you might have to check parent field values with the widget version.

OTOH, a given "merged" and "widget" should share the same rectangle PdfArray, rendering the point moot. "Rect" is a "leaf" value and will never be inherited from a parent, so the widget's array will have been "shallow-copied" into the merged dictionary... thus sharing it. In any case, you should be able to check it fairly easily.

assert item.getWidget(0).getAsArray(PdfName.RECT) ==
       item.getMerged(0).getAsArray(PdfName.RECT);

Note that this is == not .equals. I don't think PdfArray has an equals(), so this point isn't all that relevant either.

Oh, and just because I've actually got work to do, I'll let you figure out how to get a BaseFont from a field on your own, with a nudge in the right direction. You'll want a DocumentFont via BaseFont.createFont(PRIndirectReference fontRef), and you should check out The PDF Spec, chapter 12.7 (Interactive Forms) and 9.5-9.10 (various font types... which DocumentFont will largely take care of for you) to find out where to find that indirect reference.

And to figure out what the heck an indirect reference is, you'll need to read chapter 7.3, "Objects", particularly 7.3.10, "Indirect Objects".



标签: itext