Skip to content

Instantly share code, notes, and snippets.

@tejash-jl
Created April 12, 2021 10:19
Show Gist options
  • Save tejash-jl/768adf9c2de684b5bdddbcfdbbb79ca7 to your computer and use it in GitHub Desktop.
Save tejash-jl/768adf9c2de684b5bdddbcfdbbb79ca7 to your computer and use it in GitHub Desktop.
PDFBox multi language support
package com.example.evaluatems;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.encoding.GlyphList;
import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class PDFGenerator {
public static void main(String[] args) throws IOException {
try (PDDocument doc = new PDDocument()) {
PDPage myPage = new PDPage();
doc.addPage(myPage);
PDFont defaultFont = PDType1Font.TIMES_ROMAN; // default
List<PDFont> fonts = new ArrayList<>();
fonts.add(defaultFont);
try (Stream<Path> paths = Files.walk(Paths.get("fonts"))) {
paths
.filter(path -> Files.isRegularFile(path) && path.toString().endsWith(".ttf"))
.forEach(x -> {
try {
fonts.add(PDType0Font.load(doc, new File(x.toString())));
} catch (IOException e) {
e.printStackTrace();
}
});
}
try (PDPageContentStream cont = new PDPageContentStream(doc, myPage)) {
cont.beginText();
cont.newLineAtOffset(20, 700);
showTextMultiple(cont, "abc ಬಾ s", fonts, 20);
cont.endText();
}
doc.save("output.pdf");
}
}
private static void showTextMultiple(PDPageContentStream cs, String text, List<PDFont> fonts, float size)
throws IOException {
try {
// first try all at once
fonts.get(0).encode(text);
cs.setFont(fonts.get(0), size);
cs.showText(text);
return;
} catch (IllegalArgumentException ex) {
// do nothing
}
// now try separately
int i = 0;
while (i < text.length()) {
boolean found = false;
for (PDFont font : fonts) {
try {
String s = text.substring(i, i + 1);
font.encode(s);
// it works! Try more with this font
int j = i + 1;
for (; j < text.length(); ++j) {
String s2 = text.substring(j, j + 1);
if (isWinAnsiEncoding(s2.codePointAt(0)) && font != fonts.get(0)) {
// Without this segment, the example would have a flaw:
// This code tries to keep the current font, so
// the second "abc" would appear in a different font
// than the first one, which would be weird.
// This segment assumes that the first font has WinAnsiEncoding.
// (all static PDType1Font Times / Helvetica / Courier fonts)
break;
}
try {
font.encode(s2);
} catch (IllegalArgumentException ex) {
// it's over
break;
}
}
s = text.substring(i, j);
cs.setFont(font, size);
cs.showText(s);
i = j;
found = true;
break;
} catch (IllegalArgumentException ex) {
// didn't work, will try next font
}
}
if (!found) {
throw new IllegalArgumentException("Could not show '" + text.substring(i, i + 1) +
"' with the fonts provided");
}
}
}
private static boolean isWinAnsiEncoding(int unicode) {
String name = GlyphList.getAdobeGlyphList().codePointToName(unicode);
if (".notdef".equals(name)) {
return false;
}
return WinAnsiEncoding.INSTANCE.contains(name);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment