1

I'm using iTextSharp to populate some PDFs containing forms. These forms consist of textboxes (among other field types) and if I open them in a PDF reader, I can type in arbitrary number of characters without any limitations. But if I print such a PDF form while I entered too many characters in a field, the overflow won't be printed at all.

Now I'm looking for a way to measure the maximum length of a string that fits in some specific textbox without losing any printed data. I know what I need to do in theory, I need to measure the width of the string (in pixels/points) considering the font properties of the textbox and then compare it with the width of the textbox (minus any padding it might have). But I'm all new to PDF concepts and I don't know where to start. Could someone please guide me to the right direction?

One more thing, I've got no control over the template PDFs and I can not change them in any way. All I can do is to prompt the user that your entered text won't fit in the field when he asks for a flattened PDF file!

[UPDATE]

There's another scenario which I was hoping the same solution would apply to, but it seems I need to include this later one as well to guide the answers to the right direction.

I've got three textboxes in my PDF form file and when I'm filling them manually (using a PDF reader), it's my responsibility to split my input among three of them. An example of this is three lines of an address field. If I was designing the form, I would use a multi-line text field so the address wraps automatically but unfortunately I'm just handed the forms and since they are password protected, all I can do is to find the appropriate point to split the input string to enter them in three fields.

Mehran
  • 15,593
  • 27
  • 122
  • 221

1 Answers1

4

By combining answers to different questions that were already answered on StackOverflow, you should be able to solve your problem.

First step: you need to know the size of the rectangle that defines the field. This is explained in my answer to the question Add image to iText dynamically on PDF file

In this answer, I do this:

AcroFields form = stamper.getAcroFields();
AcroFields.FieldPosition fieldPosition = form.getFieldPositions(field).get(0);
Rectangle rect = fieldPosition.position;

Where field holds the name of the field and rect describes a rectangle from which you can get the width and the height.

Second step: you need a BaseFont instance of the font that is defined for the field. This question is answered by Chris Haas: iTextSharp Re-use Font Embedded In Acrofield

I have ported his answer to Java: ReuseFont:

public BaseFont findFontInForm(PdfReader reader, PdfName fontname) {
    PdfDictionary root = reader.getCatalog();
    PdfDictionary acroform = root.getAsDict(PdfName.ACROFORM);
    if (acroform == null) return null;
    PdfDictionary dr = acroform.getAsDict(PdfName.DR);
    if (dr == null) return null;
    PdfDictionary font = dr.getAsDict(PdfName.FONT);
    if (font == null) return null;
    for (PdfName key : font.getKeys()) {
        if (key.equals(fontname)) {
            return BaseFont.createFont((PRIndirectReference)font.getAsIndirectObject(key));
        }
    }
    return null;
}

You'll have to adapt this example because it assume that you already know the name of the font. It should be fairly easy to find that name in the /DR dictionary.

Caveat: this font may not contain sufficient info for the purpose you need it. This is the most delicate step. It may be better if you just use Helvetica or if you change the font. Note that it doesn't matter that the original document is encrypted: if you can read it, you can change the font in the document you are filling (you don't need to change the font in the original template; it will only be changed in the resulting document).

Third step: Now that you have the font and the available width, you can use the answer to this question to calculate the size needed to draw a specific string: How to calculate the string width in iText?

You can use BaseFont.getWidthPoint(String text, float fontSize) to get the width of the string in pt. Or put the string in a Chunk and do chunk.getWidthPoint().

The combination of the three should solve your problem.

Community
  • 1
  • 1
Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Thank you so much for the post. Is this also a correct way to find the field's font? `var ft1 = acroFields.GetFieldItem("FillText1"); var dic = ft1.GetMerged(0); TextField tmp = new TextField(null, null, null); acroFields.DecodeGenericDictionary(dic, tmp); BaseFont font = tmp.Font;` – Mehran Nov 24 '14 at 18:45
  • BTW, `getWidthPoint` requires `fontSize`. How can I retrieve field's font size? I've searched the Internet up and down and all I could find is how to set it. No one ever talked about getting it!! – Mehran Nov 24 '14 at 18:47
  • The font size is usually stored in the `/DA` (default appearance) of the field dictionary. – Bruno Lowagie Nov 26 '14 at 08:18