Writing Arabic in pdf using itext

2019-04-09 01:13发布

问题:

I am generating PDF file using itext lib. I want to write Arabic words. When i run the below code, The words characters are reverse displayed.

The used code :

PdfContentByte cb = docWriter.getDirectContent();
BaseFont bfBold = BaseFont.createFont("assets/arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);


createHeadings(cb, document.leftMargin(), 70, "السعر الاجمالي: " + tprice + " L.E.");

. . .

private void createHeadings(PdfContentByte cb, float x, float y, String text){
        cb.beginText();
        cb.setFontAndSize(bfBold, 10);
        cb.setTextMatrix(x,y);
        cb.showText(text.trim());
        cb.endText();
    }

This image describes the output of the code above: http://i.stack.imgur.com/OLoLo.jpg

回答1:

Please take a look at the Ligatures2 example.

Aren't you forgetting this line:

cb.setRunDirection(PdfWriter.RUN_DIRECTION_RTL);

The setRunDirection() method is necessary when you want iText to write the text from right to left and create ligatures where necessary. This method also exists in the context of tables in which case you apply it to a PdfPCell object instead of to a ColumnText object.

Also, I don't understand why you use this String: "السعر الاجمالي: ". Please use the Unicode notation instead (e.g. something like "\u0644\u0648\u0631\u0627\u0646\u0633 \u0627\u0644\u0639\u0631\u0628"), because using a String like yours can create all kinds of confusion regarding encoding and ligatures. Some editors won't use the correct encoding (changing your text into gibberish); some editors will make ligatures (which isn't what iText expects).

For instance, in your case, I don't know Arabic, so I don't know if it's "\u0627\u0644\u0633\u0639\u0631 \u0627\u0644\u0627\u062c\u0645\u0627\u0644\u064a" or "\u064a\u0644\u0627\u0645\u062c\u0627\u0644\u0627 \u0631\u0639\u0633\u0644\u0627" because I don't know if I have to start to read at the glyph with value \u0627 or at the glyph with value \u064a. In any case: iText expects the first "character" in the String to be the first thing that is read by humans.

Please take a look at the ArabicExample example:

The first line is incorrect, because RTL nor Arabic ligatures are supported when using document.add(). The second line is correct (as far as I know: I can't read Arabic) because I used ColumnText.

This is the code I used:

public static final String FONT = "resources/fonts/NotoNaskhArabic-Regular.ttf";
public static final String ARABIC = "\u0627\u0644\u0633\u0639\u0631 \u0627\u0644\u0627\u062c\u0645\u0627\u0644\u064a";

public void createPdf(String dest) throws IOException, DocumentException {
    Document document = new Document();
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
    document.open();
    Font f = FontFactory.getFont(FONT, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
    Phrase p = new Phrase("This is incorrect: ");
    p.add(new Chunk(ARABIC, f));
    p.add(new Chunk(": 50.00 USD"));
    document.add(p);

    p = new Phrase("This is correct: ");
    p.add(new Chunk(ARABIC, f));
    p.add(new Phrase(": 50.00"));

    ColumnText canvas = new ColumnText(writer.getDirectContent());
    canvas.setSimpleColumn(36, 750, 559, 780);
    canvas.setRunDirection(PdfWriter.RUN_DIRECTION_LTR);
    canvas.addElement(p);
    canvas.go();

    document.close();
}

I used a Phrase, but you can expect the same result when using a Paragraph (Paragraph extends Phrase). Please clarify if this doesn't answer your question. Take into account that most people on StackOverflow don't understand Arabic, so you have to be very explicit when you ask a question and when you say "it doesn't work". As we don't know Arabic, we don't know how it is supposed to work.