I am trying to use pdfbox to add text watermark to pdf, but I encountered a problem when adding ttc format fonts.
Font2D font2D = FontUtilities.getFont2D(font);
String fontEnName = font2D.getFamilyName(Locale.ENGLISH);
PDFont pdfFont = PDType0Font.load(doc, new TrueTypeCollection(fontFile).getFontByName(fontEnName), true);
PDPageContentStream contents = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true, true);
contents.beginText();
contents.setFont(pdfFont, fontHeight);
First of all, Font2D and FontUtilities are internal classes, which may be deleted in the future, which is not a good solution. Second, the obtained fontEnName is not necessarily the parameter required by getFontByName, maybe fontEnName is
simsum, but the parameter of getFontByName needs SimSun, and the two names are not matching,there are other ttc Font related example, is there any other good solution?
This shows the names:
TrueTypeCollection ttc = new TrueTypeCollection(new File("c:/windows/fonts/batang.ttc"));
ttc.processAllFonts(new TrueTypeCollection.TrueTypeFontProcessor()
{
#Override
public void process(TrueTypeFont ttf) throws IOException
{
System.out.println(ttf.getName());
}
});
ttc Font:
Font font = Font.createFont(Font.TRUETYPE_FONT, fb);
font = font.deriveFont(Font.PLAIN, fontHeight);
String fontEnName = font.getPSName();
PDFont pdfFont = PDType0Font.load(doc, new TrueTypeCollection(fontFile).getFontByName(fontEnName), true);
Related
i am trying to create pdf using pdfbox. i am storing EditText data as html in Sqlite DB.
now i am retrieving data from sqliteDB and creating pdf of that. this data is having marathi language as well as english language.
i am using NotoSerifDevanagari-Bold font and have added it to assets folder. from there i am accessing this font into code. but i am getting error. please find my code and error below.
AssetManager assetManager;
PDFBoxResourceLoader.init(getApplicationContext());
File FilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
assetManager = getAssets();
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDFont font = PDType0Font.load(document, assetManager.open("notoserifdevanagaribold.ttf"));
PDPageContentStream contentStream;
// Define a content stream for adding to the PDF
contentStream = new PDPageContentStream(document, page);
Cursor data = mDatabaseHelper.getDataByDeckname(deckname);
StringBuilder builder=new StringBuilder();
while (data.moveToNext()) {
String front_page_desc = data.getString(3);
String back_page_desc = data.getString(4);
contentStream.beginText();
contentStream.setNonStrokingColor(15, 38, 192);
contentStream.setFont(font, 12);
contentStream.newLineAtOffset(100, 700);
contentStream.showText(Html.fromHtml(front_page_desc).toString());
contentStream.endText();
contentStream.beginText();
contentStream.setNonStrokingColor(15, 38, 192);
contentStream.setFont(font, 12);
contentStream.newLineAtOffset(100, 700);
contentStream.showText(Html.fromHtml(back_page_desc).toString());
contentStream.endText();
}
contentStream.close();
String path = FilePath.getAbsolutePath() + "/temp.pdf";
document.save(path);
document.close();
ERROR
W/System.err: java.lang.IllegalArgumentException: No glyph for U+000A in font NotoSerifDevanagari-Bold
I tried so many examples for above error but i am not able to fix the issue. this error i am getting on contentStream.showText(Html.fromHtml(front_page_desc).toString()); line. can someone please help me on above.
As per this link U+000A is the Unicode for new line. Any font will fail if you try to render it.
In order to avoid such error you can try something like this:
String[] lines = text.split("\\n");
for (String line : lines) {
if (!line.isBlank()) {
contentStream.showText(line);
// add new line here if you want to
}
}
I'm trying to display an arabic string in a pdf file generated using PDFBox, Actually i can display an arabic string from RTL using ICU4J and a specific font but the problem is this :
even if the string appear correctly from RTL the characters still separated and even if i try some fonts the problem is not solved yet.
Here is a snippet of code used for test:
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
String dir = "resources/fonts/";
//I've used several fonts
PDType0Font farialUni = PDType0Font.load(document, new File(dir + "ARIALUNI.ttf"));
PDFont fArabType = PDType0Font.load(document, new File(dir + "arabtype.ttf"));
PDFont fMuka = PDType0Font.load(document, new File(dir + "Mukadimah.ttf"));
PDFont fFreeSans = PDType0Font.load(document, new File(dir + "FreeSans.ttf"));
PDFont fNoto = PDType0Font.load(document, new File(dir + "NotoNaskhArabic-Regular.ttf"));
PDPageContentStream stream = new PDPageContentStream(document, page);
stream.beginText();
stream.setFont(fNoto, 12);
stream.setLeading(12 * 1.2);
stream.newLineAtOffset(100, 800);
//Switch text order from to RTL
BiDiClass bidiClass = new BiDiClass();
String arabicText = "\u0627\u0644\u0633\u0644\u0627\u0645 \u0639\u0644\u064A\u0643\u0645 ";
//Use icu to inverse the order
String out = bidiClass.makeLineLogicalOrder(arabicText, true);
System.out.println(out);
stream.showText(out);
stream.newLine();
// ligature
stream.showText(out);
stream.endText();
stream.close();
document.save("example.pdf");
document.close();
The resulting string that this code give me is like this :
ال س ل ام ع ل ي ك م
Note: i add the space character in the resulting string only for clarity.
I am trying to create signed PDFs from PDF/A-1A input files, the output must preserve the conformance level.
The signatures have to be added with a customized appearance.
If I do it along the code lines below, everything works on the signature side, and the signature is diplayed correctly and verifies OK.
But the PDF/A conformance is broken by the embedded fonts that do not contain the required toUnicode CMAPs.
PdfADocument pdf = ... the doc to be signed
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
PdfReader reader = pdf.getReader();
PrivateKey privateKey = ...
Provider signatureProvider = new BouncyCastleProvider();
Certificate[] signChain = ...
PdfSigner pdfSigner = new PdfSigner(reader, buffer, true);
PdfSignatureAppearance signatureAppearance = pdfSigner.getSignatureAppearance();
signatureAppearance.setReuseAppearance(false);
signatureAppearance.setPageNumber(pdf.getNumberOfPages());
pdfSigner.setFieldName("Custom Signature");
float margin = 35;
Rectangle pageSize = pdf.getLastPage().getMediaBox();
Rectangle signaturePosition = new Rectangle(pageSize.getLeft()+margin,
pageSize.getBottom()+margin,
pageSize.getWidth()-2*margin,
(pageSize.getHeight()-2*margin)/3);
// need to do this before creating any *Canvas object, else the pageRect will be null and the signature invisible
signatureAppearance.setPageRect(signaturePosition);
PdfFont regularFont = PdfFontFactory.createFont("/path/to/truetypefile-regular.ttf", "ISO-8859-1", true);
PdfFont boldFont = PdfFontFactory.createFont("/path/to/truetypefile-bold.ttf", "ISO-8859-1", true);
int fontSize = 10;
PdfFormXObject n0 = signatureAppearance.getLayer0();
PdfCanvas n0Canvas = new PdfCanvas(n0, pdfSigner.getDocument());
PdfFormXObject n2 = signatureAppearance.getLayer2();
Canvas n2Canvas = new Canvas(n2, pdfSigner.getDocument());
if(regularFont != null) {
n2Canvas.setFont(regularFont);
n0Canvas.setFontAndSize(regularFont, fontSize);
}
ImageData imageData = ImageDataFactory.create("/path/to/image.png");
Image image = new Image(imageData);
n2Canvas.add(image);
String layer2Text = ... some lines of text containing newlines and some simple markdown
String[] paragraphs = layer2text.split("\n\n");
for (String text : paragraphs) {
boolean bold = false;
if(text.startsWith("[bold]")) {
bold = true;
text = text.replaceFirst("^\\s*\\[bold\\]\\s*", "");
}
Paragraph p = new Paragraph(text);
p.setFontSize(fontSize);
if(bold) {
p.setFont(boldFont);
}
n2Canvas.add(p);
}
... pdfSigner.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);
PrivateKeySignature externalSignature = new PrivateKeySignature(privateKey, DigestAlgorithms.SHA512, signatureProvider.getName());
BouncyCastleDigest externalDigest = new BouncyCastleDigest();
pdfSigner.signDetached(externalDigest, externalSignature, signChain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
So I assume there is something missing there. The fonts that get embedded to not conform to PDF/A because they miss the ToUnicode CMAP key.
Another error from pdf-tools validator says:
"The value of the key Encoding is Difference but must be WinAnsiEncoding or MacRomanEncoding." Which seems to be the same problem.
The signature itself is OK and visibly, styling and image in place as should be. It's just the fonts that seem to not be OK.
The trigger for the violation of the PDF/A compliance is the way the fonts are created here
PdfFont regularFont = PdfFontFactory.createFont("/path/to/truetypefile-regular.ttf", "ISO-8859-1", true);
PdfFont boldFont = PdfFontFactory.createFont("/path/to/truetypefile-bold.ttf", "ISO-8859-1", true);
or even more specifically the encoding parameter "ISO-8859-1" used therein.
The PDF/A-1 specification requires:
6.3.7 Character encodings
All non-symbolic TrueType fonts shall specify MacRomanEncoding or WinAnsiEncoding as the value of the
Encoding entry in the font dictionary. All symbolic TrueType fonts shall not specify an Encoding entry in the
font dictionary, and their font programs' “cmap” tables shall contain exactly one encoding.
The use of the encoding parameter "ISO-8859-1" caused a neither MacRomanEncoding nor WinAnsiEncoding to be specified as the value of the
Encoding entry in the font dictionary. Instead the value is a dictionary containing only a Differences entry containing an explicit mapping.
Depending on the PDF/A validator this may result in different error messages.
For (as I assume) historic reasons there are a few different encoding parameter values during font creation which cause iText to use WinAnsiEncoding:
""
PdfEncodings.WINANSI (== "Cp1252")
"winansi" (case-insensitive)
"winansiencoding" (case-insensitive)
The OP used PdfName.WinAnsiEncoding.getValue() which returns a string matching the latest option.
While this indicates that iText can be used to properly sign PDF/A documents, a specific PDFASigner class enforcing conformance probably should be introduced.
when I want to use a font is iText I do the following:
protected final static Font FONT_SIZE_11_BOLD = new Font(Font.HELVETICA, 11f, Font.BOLD);
and then I can use it whereever I want, as follows:
monthSize11 = new Chunk(month, FONT_SIZE_11_BOLD);
I want to use Arial instead of HELVETICA, but Arial is not directly available.
I mean, I cannot do
new Font(Font.ARIAL, 11f, Font.BOLD);
because Arial is not defined at the Font class, but the Arial.ttf file is at my System under C:\WINDOWS\Fonts.
The question is how I can bind the Arial.ttf file to iText and how can I use it.
Many thnaks in advance.
EDIT: I would like to use own fonts. I mean, I have a file called "myCompany.ttf" where own fonts have been defined and at some places I must use. The problem is not only with Arial.
BaseFont base = BaseFont.createFont("c:/windows/fonts/arial.ttf", BaseFont.WINANSI);
Font font = new Font(base, 11f, Font.BOLD);
....
Read more here.
Load it from inside the JAR using a leading slash; otherwise, use the absolute path of your font (C:\...\fonts\Sansation_Regular.ttf). For example:
Font font = FontFactory.getFont("/fonts/Sansation_Regular.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0.8f, Font.NORMAL, BaseColor.BLACK);
BaseFont baseFont = font.getBaseFont();
The relative path of the font is: 'src/main/resources/fonts'
Using Itext 5.4.5
Example code
Use BaseFont.createFont to create a new Font object.
You can pass any Type1 or TTF font. You will just have to ensure your font file is distributed alongwith.
Refer
BaseFont API
Creating custom fonts using itext is simple
I had written code for the same below
Will definitely help someone
public class CustomFontStyle {
public static void main(String[] args) {
// creation of the document with a certain size and certain margins
// may want to use PageSize.LETTER instead
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
try {
// creation of the different writers
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("CustomFontsStyle.pdf"));
final String NEWLINE = "\n";
document.open();
Phrase phrase = new Phrase();
BaseFont baseFont3 = BaseFont.createFont("Xenotron.ttf", BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
Font font2 = new Font(baseFont3, 12);
document.add(new Paragraph("Custom Xenotron Font: ", font2));
phrase.add(NEWLINE);
document.add(phrase);
document.close();
}
catch (Exception ex) {
System.err.println(ex.getMessage());
}
}
}
when I want to use a font is iText I do the following:
protected final static Font FONT_SIZE_11_BOLD = new Font(Font.HELVETICA, 11f, Font.BOLD);
and then I can use it whereever I want, as follows:
monthSize11 = new Chunk(month, FONT_SIZE_11_BOLD);
I want to use Arial instead of HELVETICA, but Arial is not directly available.
I mean, I cannot do
new Font(Font.ARIAL, 11f, Font.BOLD);
because Arial is not defined at the Font class, but the Arial.ttf file is at my System under C:\WINDOWS\Fonts.
The question is how I can bind the Arial.ttf file to iText and how can I use it.
Many thnaks in advance.
EDIT: I would like to use own fonts. I mean, I have a file called "myCompany.ttf" where own fonts have been defined and at some places I must use. The problem is not only with Arial.
BaseFont base = BaseFont.createFont("c:/windows/fonts/arial.ttf", BaseFont.WINANSI);
Font font = new Font(base, 11f, Font.BOLD);
....
Read more here.
Load it from inside the JAR using a leading slash; otherwise, use the absolute path of your font (C:\...\fonts\Sansation_Regular.ttf). For example:
Font font = FontFactory.getFont("/fonts/Sansation_Regular.ttf",
BaseFont.IDENTITY_H, BaseFont.EMBEDDED, 0.8f, Font.NORMAL, BaseColor.BLACK);
BaseFont baseFont = font.getBaseFont();
The relative path of the font is: 'src/main/resources/fonts'
Using Itext 5.4.5
Example code
Use BaseFont.createFont to create a new Font object.
You can pass any Type1 or TTF font. You will just have to ensure your font file is distributed alongwith.
Refer
BaseFont API
Creating custom fonts using itext is simple
I had written code for the same below
Will definitely help someone
public class CustomFontStyle {
public static void main(String[] args) {
// creation of the document with a certain size and certain margins
// may want to use PageSize.LETTER instead
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
try {
// creation of the different writers
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("CustomFontsStyle.pdf"));
final String NEWLINE = "\n";
document.open();
Phrase phrase = new Phrase();
BaseFont baseFont3 = BaseFont.createFont("Xenotron.ttf", BaseFont.WINANSI, BaseFont.NOT_EMBEDDED);
Font font2 = new Font(baseFont3, 12);
document.add(new Paragraph("Custom Xenotron Font: ", font2));
phrase.add(NEWLINE);
document.add(phrase);
document.close();
}
catch (Exception ex) {
System.err.println(ex.getMessage());
}
}
}