希伯来语、阿拉伯语、意第绪语文本在 PDFBox 2.0.5 中以相反的顺序书写
Hebrew, Arabic, Yiddish text is written in reverse order in PDFBox 2.0.5
我想在 PDF 中写一些阿拉伯语、希伯来语和意第绪语字符,但它们的书写顺序是相反的。我正在使用 PDFBox 2.0.5 创建和写入 PDF 文档。
我的示例代码
String relativeWebPath = "/font/arial.ttf";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File file = new File(absoluteDiskPath);
ByteArrayOutputStream output=new ByteArrayOutputStream();
PDDocument document=new PDDocument();
PDFont font = PDType0Font.load(document, new File(absoluteDiskPath));
PDPage test=new PDPage();
document.addPage(test);
PDPageContentStream content=new PDPageContentStream(document, test);
final String EXAMPLE = "النص العربي";
System.out.print(EXAMPLE);
content.beginText();
content.newLineAtOffset(50, 680);
content.setFont(font, 12);
content.showText(EXAMPLE);
System.out.print(EXAMPLE);
content.endText();
content.close();
document.save(output);
document.close();
在研究解决方案时,我发现它是通过在项目中添加 ICU4j 库来处理的,但它对我不起作用,而且 icu4j 依赖项已从 PDFBox 2.0 中删除 (PDFBox-2118)。
我们需要在最后处理它,因为这不是由 PDFBox 本身处理的。好的,我有一些解决方法,创建 RTL 语言字符的反向字符串并将其传递给 PDFBox,然后 PDFBox 将以正确的方向写入它。
现在下一个问题是如何检测RTL语言的文本以及如何反转它然后解决方案就在这里,这可以通过使用java的BiDi class对象来实现。
完整的解决方案,该解决方案还处理混合字符串:
String word = EXAMPLE; // string from question
Bidi bidi = new Bidi(word, -2);
if (!bidi.isMixed() && bidi.getBaseLevel() == 0) {
return word;
}
else {
int runCount = bidi.getRunCount();
byte[] levels = new byte[runCount];
Integer[] runs = new Integer[runCount];
for (int result = 0; result < runCount; ++result) {
levels[result] = (byte) bidi.getRunLevel(result);
runs[result] = Integer.valueOf(result);
}
Bidi.reorderVisually(levels, 0, runs, 0, runCount);
StringBuilder bidiText = new StringBuilder();
for (int i = 0; i < runCount; ++i) {
int index = runs[i].intValue();
int start = bidi.getRunStart(index);
int end = bidi.getRunLimit(index);
byte level = levels[index];
if ((level & 1) != 0) {
while (true) {
--end;
if (end < start) {
break;
}
char character = word.charAt(end);
if (Character.isMirrored(word.codePointAt(end))) {
bidiText.append(character);
}
else {
bidiText.append(character);
}
}
}
else {
bidiText.append(word, start, end);
}
}
return bidiText.toString();
}
这解决了我的问题。希望对其他人有帮助。
我想在 PDF 中写一些阿拉伯语、希伯来语和意第绪语字符,但它们的书写顺序是相反的。我正在使用 PDFBox 2.0.5 创建和写入 PDF 文档。
我的示例代码
String relativeWebPath = "/font/arial.ttf";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File file = new File(absoluteDiskPath);
ByteArrayOutputStream output=new ByteArrayOutputStream();
PDDocument document=new PDDocument();
PDFont font = PDType0Font.load(document, new File(absoluteDiskPath));
PDPage test=new PDPage();
document.addPage(test);
PDPageContentStream content=new PDPageContentStream(document, test);
final String EXAMPLE = "النص العربي";
System.out.print(EXAMPLE);
content.beginText();
content.newLineAtOffset(50, 680);
content.setFont(font, 12);
content.showText(EXAMPLE);
System.out.print(EXAMPLE);
content.endText();
content.close();
document.save(output);
document.close();
在研究解决方案时,我发现它是通过在项目中添加 ICU4j 库来处理的,但它对我不起作用,而且 icu4j 依赖项已从 PDFBox 2.0 中删除 (PDFBox-2118)。
我们需要在最后处理它,因为这不是由 PDFBox 本身处理的。好的,我有一些解决方法,创建 RTL 语言字符的反向字符串并将其传递给 PDFBox,然后 PDFBox 将以正确的方向写入它。
现在下一个问题是如何检测RTL语言的文本以及如何反转它然后解决方案就在这里,这可以通过使用java的BiDi class对象来实现。
完整的解决方案,该解决方案还处理混合字符串:
String word = EXAMPLE; // string from question
Bidi bidi = new Bidi(word, -2);
if (!bidi.isMixed() && bidi.getBaseLevel() == 0) {
return word;
}
else {
int runCount = bidi.getRunCount();
byte[] levels = new byte[runCount];
Integer[] runs = new Integer[runCount];
for (int result = 0; result < runCount; ++result) {
levels[result] = (byte) bidi.getRunLevel(result);
runs[result] = Integer.valueOf(result);
}
Bidi.reorderVisually(levels, 0, runs, 0, runCount);
StringBuilder bidiText = new StringBuilder();
for (int i = 0; i < runCount; ++i) {
int index = runs[i].intValue();
int start = bidi.getRunStart(index);
int end = bidi.getRunLimit(index);
byte level = levels[index];
if ((level & 1) != 0) {
while (true) {
--end;
if (end < start) {
break;
}
char character = word.charAt(end);
if (Character.isMirrored(word.codePointAt(end))) {
bidiText.append(character);
}
else {
bidiText.append(character);
}
}
}
else {
bidiText.append(word, start, end);
}
}
return bidiText.toString();
}
这解决了我的问题。希望对其他人有帮助。