首页 > 解决方案 > Itext7 希伯来语反向问题

问题描述

我有一段简单的代码可以编写 PDF,有时这个 PDF 将包含 RTL 语言,如希伯来语或阿拉伯语。
我能够操纵文本并使用 Bidi (Ibm lib) 对其进行镜像
但文本仍在反向运行

这是与源的输出比较

在英语中,它会是这样的:

代替:

The quick 
brown fox 
jumps over 
the lazy dog

它显示为:

the lazy dog
jumps over 
brown fox 
The quick 

完整代码:

@Test
public void generatePdf()  {
    
      SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
        String dest = "c:\\temp\\" + formatter.format(Calendar.getInstance().getTime()) + ".pdf";
         String fontPath = "C:\\Windows\\Fonts\\ARIALUNI.TTF";
         FontProgramFactory.registerFont(fontPath, "arialUnicode");
        OutputStream pdfFile = null;
        Document doc = null;
    try {
        ByteArrayOutputStream output = new ByteArrayOutputStream();  
        PdfFont PdfFont  = PdfFontFactory.createRegisteredFont("arialUnicode", PdfEncodings.IDENTITY_H, true);      
        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(output));
        pdfDoc.setDefaultPageSize(PageSize.A4);
        pdfDoc.addFont(PdfFont);
        doc = new Document(pdfDoc);
        doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);

        String txt = "בתשרי נתן הדקל פרי שחום נחמד בחשוון ירד יורה ועל גגי רקד בכסלו נרקיס הופיע בטבת ברד ובשבט חמה הפציעה ליום אחד.  1234 באדר עלה ניחוח מן הפרדסים בניסן הונפו בכוח כל החרמשים";
        Bidi bidi = new Bidi();
        bidi.setPara(txt, Bidi.RTL, null);
        String mirrTxt = bidi.writeReordered(Bidi.DO_MIRRORING);
        Paragraph paragraph1 = new  Paragraph(mirrTxt)
                .setFont(PdfFont)
                .setFontSize(9)
                .setTextAlignment(TextAlignment.CENTER)
                .setHeight(200)
                .setWidth(70);
        paragraph1.setBorder(new SolidBorder(3));
        doc.add(paragraph1);  
                    
        Paragraph paragraph2 = new  Paragraph(txt)
                .setFont(PdfFont)
                .setFontSize(9)
                .setTextAlignment(TextAlignment.CENTER)
                .setHeight(200)
                .setWidth(70);
        paragraph2.setBorder(new SolidBorder(3));
        doc.add(paragraph2);  
        
        doc.close();
        doc.flush();
        pdfFile = new FileOutputStream(dest); 
        pdfFile.write(output.toByteArray()); 
        
        ProcessBuilder b = new ProcessBuilder("cmd.exe","/C","explorer " + dest);
        b.start();
        
        
    } catch (Exception e) {
        e.printStackTrace();
    }finally {          
        try {pdfFile.close();} catch (IOException e) {e.printStackTrace();}
    }
}

标签: javaitext7

解决方案


我在没有任何其他第三方库的情况下使用 iText7 和 IBM ICU4J 找到的唯一解决方案是首先渲染线条,然后逐个镜像它们。这需要一个辅助类LineMirroring,它并不是最优雅的解决方案,但会产生您期望的输出。

线镜像类

public class LineMirroring {

private final PageSize pageSize;
private final String fontName;
private final int fontSize;

public LineMirroring(PageSize pageSize, String fontName, int fontSize) {
    this.pageSize = pageSize;
    this.fontName = fontName;
    this.fontSize = fontSize;
}

public String mirrorParagraph(String input, int height, int width, Border border) {
    final StringBuilder mirrored = new StringBuilder();
    try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
        PdfFont font = PdfFontFactory.createRegisteredFont(fontName, PdfEncodings.IDENTITY_H, true);
        final PdfWriter writer = new PdfWriter(output);
        final PdfDocument pdfDoc = new PdfDocument(writer);
        pdfDoc.setDefaultPageSize(pageSize);
        pdfDoc.addFont(font);
        final Document doc = new Document(pdfDoc);
        doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);
        final LineTrackingParagraph paragraph = new LineTrackingParagraph(input);
        paragraph.setFont(font)
                .setFontSize(fontSize)
                .setTextAlignment(TextAlignment.RIGHT)
                .setHeight(height)
                .setWidth(width)
                .setBorder(border);
        LineTrackingParagraphRenderer renderer = new LineTrackingParagraphRenderer(paragraph);
        doc.add(paragraph);
        Bidi bidi;
        for (LineRenderer lr : paragraph.getWrittenLines()) {
            bidi = new Bidi(((TextRenderer) lr.getChildRenderers().get(0)).getText().toString(), Bidi.RTL);
            mirrored.append(bidi.writeReordered(Bidi.DO_MIRRORING));
        }
        doc.close();
        pdfDoc.close();
        writer.close();
    } catch (IOException ioe) {
        ioe.printStackTrace();
    }
    return mirrored.toString();
}

private class LineTrackingParagraph extends Paragraph {

    private List<LineRenderer> lines;

    public LineTrackingParagraph(String text) {
        super(text);
    }

    public void addWrittenLines(List<LineRenderer> lines) {
        this.lines = lines;
    }

    public List<LineRenderer> getWrittenLines() {
        return lines;
    }

    @Override
    protected IRenderer makeNewRenderer() {
        return new LineTrackingParagraphRenderer(this);
    }
}

private class LineTrackingParagraphRenderer extends ParagraphRenderer {
    public LineTrackingParagraphRenderer(LineTrackingParagraph modelElement) {
        super(modelElement);
    }

    @Override
    public void drawChildren(DrawContext drawContext) {
        ((LineTrackingParagraph)modelElement).addWrittenLines(lines);
        super.drawChildren(drawContext);
    }

    @Override
    public IRenderer getNextRenderer() {
        return new LineTrackingParagraphRenderer((LineTrackingParagraph) modelElement);
    }
}

}

最小的 JUnit 测试

public class Itext7HebrewTest {

@Test
public void generatePdf() {

    final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
    final String dest = "F:\\Temp\\" + formatter.format(Calendar.getInstance().getTime()) + ".pdf";
    final String fontPath = "C:\\Windows\\Fonts\\ARIALUNI.TTF";
    final String fontName = "arialUnicode";
    FontProgramFactory.registerFont(fontPath, "arialUnicode");

    try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
        PdfFont arial = PdfFontFactory.createRegisteredFont(fontName, PdfEncodings.IDENTITY_H, true);

        PdfDocument pdfDoc = new PdfDocument(new PdfWriter(output));
        pdfDoc.setDefaultPageSize(PageSize.A4);
        pdfDoc.addFont(arial);
        LineMirroring mirroring = new LineMirroring(pdfDoc.getDefaultPageSize(), fontName,9);

        Document doc = new Document(pdfDoc);
        doc.setBaseDirection(BaseDirection.RIGHT_TO_LEFT);

        final String txt = "בתשרי נתן הדקל פרי שחום נחמד בחשוון ירד יורה ועל גגי רקד בכסלו נרקיס הופיע בטבת ברד ובשבט חמה הפציעה ליום אחד.  1234 באדר עלה ניחוח מן הפרדסים בניסן הונפו בכוח כל החרמשים";

        final int height = 200;
        final int width = 70;
        final Border border = new SolidBorder(3);

        Paragraph paragraph1 = new Paragraph(mirroring.mirrorParagraph(txt, height, width, border));
        paragraph1.setFont(arial)
                .setFontSize(9)
                .setTextAlignment(TextAlignment.RIGHT)
                .setHeight(height)
                .setWidth(width)
                .setBorder(border);
        doc.add(paragraph1);

        doc.close();
        doc.flush();
        try (FileOutputStream pdfFile = new FileOutputStream(dest)) {
            pdfFile.write(output.toByteArray());
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

}


推荐阅读