使用 PDFBOX 以正确的字符呈现形式书写阿拉伯语而不被分离

Writing Arabic with PDFBOX with correct characters presentation form without being separated

我正在尝试使用 PDFBox Apache 生成包含阿拉伯文本的 PDF,但文本生成为分隔字符,因为 Apache 将给定的阿拉伯字符串解析为一系列通用 'official' Unicode 字符,等同于阿拉伯字符的孤立形式。

这是一个例子:
以 PDF 格式写入的目标文本 "Should be expected output in PDF File" -> Passion Text
我在 PDF 文件中得到的内容 ->

我尝试了一些方法,但没有用,这里有一些方法:
1. 将字符串转换为比特流并尝试提取正确的值
2. 使用 UTF-8 && UTF-16 处理字符串字节序列并从中提取值

有一些方法似乎很有希望获得每个字符的值 "Unicode" 但它生成一般 "official Unicode" 这就是我的意思

System.out.println( Integer.toHexString( (int)(new String("كلمة").charAt(1))) );  

输出是 644 但 fee0 是预期的输出,因为这个字符在中间,从那时起我应该得到中间的 Unicode fee0

所以我想要的是一些生成正确 Unicode 的方法,而不仅仅是官方的

后面第一个table最左边的一列link表示通用Unicode
Arabic Unicode Tables Wikipedia

通知:

此答案中的示例代码可能已过时,请参阅 以获取工作示例代码


首先,我要感谢 Tilman Hausherr and M.Prokhorov 向我展示了使使用 PDFBox Apache 编写阿拉伯语成为可能的库。

本回答将分为两部分:

  1. 正在下载并安装库
  2. 如何使用图书馆

正在下载并安装库

我们将使用 ICU 库。
ICU 代表 Unicode 国际组件,它是一套成熟的、广泛使用的 C/C++ 和 Java 库,为软件应用程序提供 Unicode 和全球化支持。 ICU 具有广泛的可移植性,并在所有平台上以及 C/C++ 和 Java 软件之间为应用程序提供相同的结果。

要下载库,请转到 here 的下载页面。
选择最新版本的 ICU4J 如下图所示。

您将转到另一个页面,您会发现一个框,其中包含所需组件的直接链接。继续下载三个文件,您会在下一张图片中找到突出显示的文件。

  1. icu4j-docs.jar
  2. icu4j-src.jar
  3. icu4j.jar

下面对在Netbeans中创建和添加库的解释IDE

  1. 导航到工具栏并单击工具
  2. 选择库
  3. 在左下方您会找到新的库按钮创建您的
  4. 导航到您在库列表中创建的库
  5. 点击它并像那样添加 jar 文件夹
  6. 在class路径中添加icu4j.jar
  7. 在源中添加 icu4j-src.jar
  8. 在 Javadoc
  9. 中添加 icu4j-docs.jar
  10. 从最右边查看您打开的项目
  11. 中展开要使用库的项目
  12. 右键单击库文件夹并选择添加库
  13. 最后选择刚刚创建的库。

现在您可以使用该库了,只需导入您想要的内容即可

import com.ibm.icu.What_You_Want_To_Import;


如何使用图书馆

使用 ArabicShaping Class 并反转字符串,我们可以写出正确的附加阿拉伯语 LINE
这是代码 注意下面代码中的注释

import com.ibm.icu.text.ArabicShaping;
import com.ibm.icu.text.ArabicShapingException;
import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.*;

public class Main {
    public static void main(String[] args) throws IOException , ArabicShapingException
{
        File f = new File("Arabic Font File of format.ttf");
        PDDocument doc = new PDDocument();
        PDPage Page = new PDPage();
        doc.addPage(Page);
        PDPageContentStream Writer = new PDPageContentStream(doc, Page);
        Writer.beginText();
        Writer.setFont(PDType0Font.load(doc, f), 20);
        Writer.newLineAtOffset(0, 700);
        //The Trick in the next Line of Code But Here is some few Notes first  
        //We have to reverse the string because PDFBox is Writting from the left but Arabic is RTL Language  
        //The output will be perfect except every line will be justified to the left "It's not hard to resolve this"
        // So we have to write arabic string to pdf line by line..It will be like this
        String s ="جملة بالعربي لتجربة الكلاس اللذي يساعد علي وصل الحروف بشكل صحيح";
        Writer.showText(new StringBuilder(new ArabicShaping(reverseNumbersInString(ArabicShaping.LETTERS_SHAPE).shape(s))).reverse().toString());
        // Note the previous line of code throws ArabicShapingExcpetion 
        Writer.endText();
        Writer.close();
        doc.save(new File("File_Test.pdf"));
        doc.close();
    }
}

这是输出

我希望我已经了解了所有内容。

更新 : 反转后确保再次反转数字以获得相同的正确数字
这里有几个功能可以帮助

public static boolean isInt(String Input)
{
    try{Integer.parseInt(Input);return true;}
    catch(NumberFormatException e){return false;}
}
public static String reverseNumbersInString(String Input)
{
    char[] Separated = Input.toCharArray();int i = 0;
    String Result = "",Hold = "";
    for(;i<Separated.length;i++ )
    {
        if(isInt(Separated[i]+"") == true)
        {
            while(i < Separated.length && (isInt(Separated[i]+"") == true ||  Separated[i] == '.' ||  Separated[i] == '-'))
            {
                Hold += Separated[i];
                i++;
            }
            Result+=reverse(Hold);
            Hold="";
        }
        else{Result+=Separated[i];}
    }
    return Result;
}

这是一个有效的代码。下载示例字体,例如trado.ttf

确保 pdfbox-appicu4j jar 文件在您的类路径中。

import java.io.File;
import java.io.IOException;

import com.ibm.icu.text.ArabicShaping;
import com.ibm.icu.text.ArabicShapingException;
import com.ibm.icu.text.Bidi;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.*;

public class Main {
    public static void main(String[] args) throws IOException , ArabicShapingException
    {
    File f = new File("trado.ttf");
        PDDocument doc = new PDDocument();
        PDPage Page = new PDPage();
        doc.addPage(Page);
        PDPageContentStream Writer = new PDPageContentStream(doc, Page);
        Writer.beginText();
        Writer.setFont(PDType0Font.load(doc, f), 20);
        Writer.newLineAtOffset(0, 700);
        String s ="جملة بالعربي لتجربة الكلاس اللذي يساعد علي وصل الحروف بشكل صحيح";
        Writer.showText(bidiReorder(s));
        Writer.endText();
        Writer.close();
        doc.save(new File("File_Test.pdf"));
        doc.close();
    }

    private static String bidiReorder(String text)
    {
        try {
        Bidi bidi = new Bidi((new ArabicShaping(ArabicShaping.LETTERS_SHAPE)).shape(text), 127);
            bidi.setReorderingMode(0);
            return bidi.writeReordered(2);
        }
        catch (ArabicShapingException ase3) {
        return text;
    }
    }

}