1

I have made a pdf template with a multi-line textbox and have to set some Arabic data in the Acrofields using PDFStamper. The run direction of text is correct for the first line but it changes when text wrapping occurs.

Please guide.

package test;

import java.io.FileOutputStream;
import java.io.IOException;    
import com.itextpdf.text.DocumentException;    
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;

public class TextFields{

    public static final String RESULT1 = "D:/template.pdf";
    public static final String RESULT2 = "D:/pdf/result.pdf";
    protected int tf;

    public TextFields(int tf) {
        this.tf = tf;
    }

    public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
        PdfReader reader = new PdfReader(src);
        FontFactory.registerDirectories();
        BaseFont unicode = null;
        unicode = BaseFont.createFont("D:/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
        AcroFields form = stamper.getAcroFields();
          stamper.getAcroFields().addSubstitutionFont(unicode);
        form.setField("TextBox","اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب");
        stamper.close();
        reader.close();
    }

    public static void main(String[] args) throws DocumentException, IOException {
        TextFields example = new TextFields(0);
        example.manipulatePdf(RESULT1, RESULT2);
    }
}
aanchal
  • 33
  • 1
  • 12

3 Answers3

1

I see that you don't flatten the document. If it's your intention that the document remains interactive, you should instruct iText not to generate any appearances. This can be done like this:

form.setGenerateAppearances(false);

By doing so, you tell the PDF viewer to create the appearances. If the problem persists, the problem resides in the PDF viewer, not at the iText level.

If it's your intention to flatten the form, I fear you've encountered a limitation in the current version of iText. You'll need to use a workaround. Please take a look at the FillFlattenMerge3 example. In this example, we get the position of each field:

AcroFields form = reader.getAcroFields();
positions = new HashMap<String, Rectangle>();
Rectangle rectangle;
Map<String, AcroFields.Item> fields = form.getFields();
for (String name : fields.keySet()) {
    rectangle = form.getFieldPositions(name).get(0).position;
    positions.put(name, rectangle);
}

We use these positions to draw the contents of the fields at the appropriate place using the ColumnText object instead of using the setField() method:

Rectangle rect = positions.get(name);
Phrase p = new Phrase(value, FONT);
ColumnText.showTextAligned(cb, Element.ALIGN_LEFT,
        p, rect.getLeft() + 2, rect.getBottom() + 2, 0);

This doesn't solve your problem yet, because the showTextAligned() method doesn't wrap text. Instead of using the showTextAligned() method, you need to use the setRunDirection(), addElement(), setSimpleColumn() and go() method:

ColumnText column = new ColumnText(writer.getDirectContent());
column.setSimpleColumn(rect);
column.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);
column.addElement(new Paragraph("اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب", unicode));
column.go();

Now your text will be wrapped properly without breaking the ligatures.

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Hi Bruno, I tried the solution given by you but it is not working fine for multi-line text. Wrapping does not occur and the text gets trimmed to the size of the textbox. Also, when I make the form non-interactive, the Arabic data in the textbox disappears while it is working fine for the English data. Please guide. – aanchal Jun 19 '14 at 04:21
0

Following code works for me.

I have used p{font-family:"arial";} in test.css.

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.ElementList;
import com.itextpdf.tool.xml.XMLWorker;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import com.itextpdf.tool.xml.css.CssFile;
import com.itextpdf.tool.xml.html.Tags;
import com.itextpdf.tool.xml.parser.XMLParser;
import com.itextpdf.tool.xml.pipeline.css.CSSResolver;
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline;
import com.itextpdf.tool.xml.pipeline.end.ElementHandlerPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;

public class FillFlattenMerge3 {

    public static final String SRC = "C:/templatestnew.pdf";
    public static final String DEST = "C:/NewFile.pdf";

    public static final Font FONT = new Font(FontFamily.HELVETICA, 10);

    protected Map<String, Rectangle> positions;

    public static void main(String[] args) throws IOException,
            DocumentException {
        File file = new File(DEST);
        file.getParentFile().mkdirs();
        new FillFlattenMerge3().manipulatePdf(SRC, DEST);
    }

    public class Background extends PdfPageEventHelper {

        PdfImportedPage background;

        public Background(PdfImportedPage background) {
            this.background = background;
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            PdfContentByte cb = writer.getDirectContentUnder();
            cb.addTemplate(background, 0, 0);
        }

    }

    public void manipulatePdf(String src, String dest)
            throws DocumentException, IOException {
        PdfReader reader = new PdfReader(src);
        AcroFields form = reader.getAcroFields();
        positions = new HashMap<String, Rectangle>();
        Rectangle rectangle;
        Map<String, AcroFields.Item> fields = form.getFields();
        for (String name : fields.keySet()) {
            rectangle = form.getFieldPositions(name).get(0).position;
            positions.put(name, rectangle);
        }

        Document document = new Document();
        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(dest));
        writer.setPageEvent(new Background(writer.getImportedPage(reader, 1)));
        document.open();

        PdfContentByte cb = writer.getDirectContent();

        process(cb, "TextBox", "<p> اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب اب </p>", writer, document);

        document.close();

        reader.close();
    }

    protected void process(PdfContentByte cb, String name, String value,
            PdfWriter writer, Document document) throws DocumentException,
            IOException {
        Rectangle rect = positions.get(name);

        // mycode starts
        XMLWorkerHelper helper = XMLWorkerHelper.getInstance();
        // CSS
        CSSResolver cssResolver = helper.getDefaultCssResolver(true);
        CssFile cssFile = helper.getCSS(new FileInputStream(
                "D:\\Itext_Test\\Test\\src\\test.css"));
        cssResolver.addCss(cssFile);

        // HTML
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
        htmlContext.autoBookmark(false);

        // Pipelines
        ElementList elements = new ElementList();
        ElementHandlerPipeline end = new ElementHandlerPipeline(elements, null);
        HtmlPipeline html = new HtmlPipeline(htmlContext, end);
        CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

        // XML Worker
        XMLWorker worker = new XMLWorker(css, true);
        XMLParser parser = new XMLParser(worker);

        // mycode ends

        ColumnText column = new ColumnText(writer.getDirectContent());
        column.setSimpleColumn(rect);
         column.setRunDirection(PdfWriter.RUN_DIRECTION_LTR);

        ByteArrayInputStream is = new ByteArrayInputStream(
                value.getBytes("UTF-8"));

        parser.parse(is);
        int status = ColumnText.START_COLUMN;
        for (Element e : elements) {

            if (ColumnText.isAllowedElement(e)) {
                column.addElement(e);
                status = column.go();
            }
        }

    }
}
sheena
  • 77
  • 2
  • 6
  • You have tried my code, but you're not telling me which one of the two workarounds you've tried. Also: you've disguised a question as an answer. I'm pretty sure it will be removed for the reason "Not an answer." – Bruno Lowagie Jun 18 '14 at 12:50
  • Thanks. It is working for me but the content is not adjusting according to the size of the textbox. – aanchal Jun 19 '14 at 06:22
  • Please explain. The size of the text box is `rect` and `ColumnText.go()` only adds text inside this `rect`, so it's wrapping and adjusting text. Maybe you need to use a different font size... – Bruno Lowagie Jun 19 '14 at 13:35
0

i had same problem. you must recreate your template.pdf by adobe acrobat pro and set the font of your textbox to one of known fonts in your os like arial.

good luck.