Skip to content

Commit 5c4e1ac

Browse files
committed
PdfType3Font: add FontDescriptor
DEVSIX-1468
1 parent 991b0bb commit 5c4e1ac

File tree

8 files changed

+160
-46
lines changed

8 files changed

+160
-46
lines changed

io/src/main/java/com/itextpdf/io/LogMessageConstant.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ public final class LogMessageConstant {
129129
public static final String TABLE_WIDTH_IS_MORE_THAN_EXPECTED_DUE_TO_MIN_WIDTH = "Table width is more than expected due to min width of cell(s).";
130130
public static final String TAG_STRUCTURE_CONTEXT_WILL_BE_REINITIALIZED_ON_SERIALIZATION = "Tag structure context is not null and will be reinitialized in the copy of document. The copy may lose some data";
131131
public static final String TAG_STRUCTURE_INIT_FAILED = "Tag structure initialization failed, tag structure is ignored, it might be corrupted.";
132+
public static final String TYPE3_FONT_ISSUE_TAGGED_PDF = "Type 3 font issue. Font Descriptor is required for tagged PDF. FontName shall be specified.";
132133
public static final String TOUNICODE_CMAP_MORE_THAN_2_BYTES_NOT_SUPPORTED = "ToUnicode CMap more than 2 bytes not supported.";
133134
public static final String UNEXPECTED_BEHAVIOUR_DURING_TABLE_ROW_COLLAPSING = "Unexpected behaviour during table row collapsing. Calculated rowspan was less then 1.";
134135
public static final String UNKNOWN_CMAP = "Unknown CMap {0}";
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.itextpdf.io.font.constants;
2+
3+
/**
4+
* Font descriptor flags
5+
*/
6+
public final class FontDescriptorFlags {
7+
private FontDescriptorFlags() {
8+
}
9+
10+
public static int FixedPitch = 1;
11+
public static int Serif = 1 << 1;
12+
public static int Symbolic = 1 << 2;
13+
public static int Script = 1 << 3;
14+
public static int Nonsymbolic = 1 << 5;
15+
public static int Italic = 1 << 6;
16+
public static int AllCap = 1 << 16;
17+
public static int SmallCap = 1 << 17;
18+
public static int ForceBold = 1 << 18;
19+
}

kernel/src/main/java/com/itextpdf/kernel/font/PdfFontFactory.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,19 @@ public static PdfType3Font createType3Font(PdfDocument document, boolean coloriz
330330
return new PdfType3Font(document, colorized);
331331
}
332332

333+
/**
334+
* Creates a new instance of {@link PdfType3Font}
335+
*
336+
* @param document the target document of the new font.
337+
* @param fontName the PostScript name of the font, shall not be null or empty.
338+
* @param fontFamily a preferred font family name.
339+
* @param colorized indicates whether the font will be colorized
340+
* @return created font.
341+
*/
342+
public static PdfType3Font createType3Font(PdfDocument document, String fontName, String fontFamily, boolean colorized) {
343+
return new PdfType3Font(document, fontName, fontFamily, colorized);
344+
}
345+
333346
/**
334347
* Creates {@link PdfFont} based on registered {@link FontProgram}'s.
335348
*

kernel/src/main/java/com/itextpdf/kernel/font/PdfSimpleFont.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ This file is part of the iText (R) project.
4848
import com.itextpdf.io.font.FontNames;
4949
import com.itextpdf.io.font.FontProgram;
5050
import com.itextpdf.io.font.PdfEncodings;
51+
import com.itextpdf.io.font.constants.FontDescriptorFlags;
5152
import com.itextpdf.io.font.otf.Glyph;
5253
import com.itextpdf.io.font.otf.GlyphLine;
5354
import com.itextpdf.io.util.ArrayUtil;
@@ -430,6 +431,7 @@ protected boolean isBuiltInFont() {
430431
*/
431432
@Override
432433
protected PdfDictionary getFontDescriptor(String fontName) {
434+
assert fontName != null && fontName.length() > 0;
433435
FontMetrics fontMetrics = fontProgram.getFontMetrics();
434436
FontNames fontNames = fontProgram.getFontNames();
435437
PdfDictionary fontDescriptor = new PdfDictionary();
@@ -457,10 +459,10 @@ protected PdfDictionary getFontDescriptor(String fontName) {
457459
//add font stream and flush it immediately
458460
addFontStream(fontDescriptor);
459461
int flags = fontProgram.getPdfFontFlags();
460-
if (fontProgram.isFontSpecific() != fontEncoding.isFontSpecific()) {
461-
flags &= ~(4 | 32); // reset both flags
462-
flags |= fontEncoding.isFontSpecific() ? 4 : 32; // set based on font encoding
463-
}
462+
flags &= ~(FontDescriptorFlags.Symbolic | FontDescriptorFlags.Nonsymbolic); // reset both flags
463+
flags |= fontEncoding.isFontSpecific() ? // set based on font encoding
464+
FontDescriptorFlags.Symbolic : FontDescriptorFlags.Nonsymbolic;
465+
464466
fontDescriptor.put(PdfName.Flags, new PdfNumber(flags));
465467
return fontDescriptor;
466468
}

kernel/src/main/java/com/itextpdf/kernel/font/PdfType3Font.java

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ This file is part of the iText (R) project.
4343
*/
4444
package com.itextpdf.kernel.font;
4545

46+
import com.itextpdf.io.LogMessageConstant;
4647
import com.itextpdf.io.font.AdobeGlyphList;
4748
import com.itextpdf.io.font.FontEncoding;
4849
import com.itextpdf.io.font.FontMetrics;
4950
import com.itextpdf.io.font.FontNames;
5051
import com.itextpdf.io.font.cmap.CMapToUnicode;
52+
import com.itextpdf.io.font.constants.FontDescriptorFlags;
5153
import com.itextpdf.io.font.constants.FontStretches;
5254
import com.itextpdf.io.font.constants.FontWeights;
5355
import com.itextpdf.io.font.otf.Glyph;
@@ -60,6 +62,8 @@ This file is part of the iText (R) project.
6062
import com.itextpdf.kernel.pdf.PdfObject;
6163
import com.itextpdf.kernel.pdf.PdfObjectWrapper;
6264
import com.itextpdf.kernel.pdf.PdfString;
65+
import org.slf4j.Logger;
66+
import org.slf4j.LoggerFactory;
6367

6468
/**
6569
* Low-level API class for Type 3 fonts.
@@ -194,6 +198,17 @@ public void setFontStretch(String fontWidth) {
194198
((Type3Font)fontProgram).setFontStretch(fontWidth);
195199
}
196200

201+
/**
202+
* Sets Font descriptor flags.
203+
* @see FontDescriptorFlags
204+
*
205+
* @param flags font descriptor flags.
206+
*/
207+
public void setPdfFontFlags(int flags) {
208+
((Type3Font)fontProgram).setPdfFontFlags(flags);
209+
}
210+
211+
197212
public Type3Glyph getType3Glyph(int unicode) {
198213
return ((Type3Font) getFontProgram()).getType3Glyph(unicode);
199214
}
@@ -280,29 +295,33 @@ public boolean containsGlyph(int unicode) {
280295

281296
@Override
282297
protected PdfDictionary getFontDescriptor(String fontName) {
283-
assert fontName != null && fontName.length() > 0;
284-
PdfDictionary fontDescriptor = new PdfDictionary();
285-
makeObjectIndirect(fontDescriptor);
286-
287-
FontMetrics fontMetrics = fontProgram.getFontMetrics();
288-
FontNames fontNames = fontProgram.getFontNames();
289-
fontDescriptor.put(PdfName.Type, PdfName.FontDescriptor);
290-
fontDescriptor.put(PdfName.FontName, new PdfName(fontName));
291-
fontDescriptor.put(PdfName.CapHeight, new PdfNumber(fontMetrics.getCapHeight()));
292-
fontDescriptor.put(PdfName.ItalicAngle, new PdfNumber(fontMetrics.getItalicAngle()));
293-
fontDescriptor.put(PdfName.FontWeight, new PdfNumber(fontNames.getFontWeight()));
294-
if (fontNames.getFamilyName() != null && fontNames.getFamilyName().length > 0 && fontNames.getFamilyName()[0].length >= 4) {
295-
fontDescriptor.put(PdfName.FontFamily, new PdfString(fontNames.getFamilyName()[0][3]));
296-
}
297-
//add font stream and flush it immediately
298-
addFontStream(fontDescriptor);
299-
int flags = fontProgram.getPdfFontFlags();
300-
if (fontProgram.isFontSpecific() != fontEncoding.isFontSpecific()) {
301-
flags &= ~(4 | 32); // reset both flags
302-
flags |= fontEncoding.isFontSpecific() ? 4 : 32; // set based on font encoding
298+
if (fontName != null && fontName.length() > 0) {
299+
PdfDictionary fontDescriptor = new PdfDictionary();
300+
makeObjectIndirect(fontDescriptor);
301+
FontMetrics fontMetrics = fontProgram.getFontMetrics();
302+
FontNames fontNames = fontProgram.getFontNames();
303+
fontDescriptor.put(PdfName.Type, PdfName.FontDescriptor);
304+
fontDescriptor.put(PdfName.FontName, new PdfName(fontName));
305+
fontDescriptor.put(PdfName.CapHeight, new PdfNumber(fontMetrics.getCapHeight()));
306+
fontDescriptor.put(PdfName.ItalicAngle, new PdfNumber(fontMetrics.getItalicAngle()));
307+
fontDescriptor.put(PdfName.FontWeight, new PdfNumber(fontNames.getFontWeight()));
308+
if (fontNames.getFamilyName() != null && fontNames.getFamilyName().length > 0 && fontNames.getFamilyName()[0].length >= 4) {
309+
fontDescriptor.put(PdfName.FontFamily, new PdfString(fontNames.getFamilyName()[0][3]));
310+
}
311+
312+
int flags = fontProgram.getPdfFontFlags();
313+
flags &= ~(FontDescriptorFlags.Symbolic | FontDescriptorFlags.Nonsymbolic); // reset both flags
314+
flags |= fontEncoding.isFontSpecific() ? // set based on font encoding
315+
FontDescriptorFlags.Symbolic : FontDescriptorFlags.Nonsymbolic;
316+
317+
fontDescriptor.put(PdfName.Flags, new PdfNumber(flags));
318+
return fontDescriptor;
319+
} else if (getPdfObject().getIndirectReference() != null
320+
&& getPdfObject().getIndirectReference().getDocument().isTagged()) {
321+
Logger logger = LoggerFactory.getLogger(PdfType3Font.class);
322+
logger.warn(LogMessageConstant.TYPE3_FONT_ISSUE_TAGGED_PDF);
303323
}
304-
fontDescriptor.put(PdfName.Flags, new PdfNumber(flags));
305-
return fontDescriptor;
324+
return null;
306325
}
307326

308327
@Override
@@ -319,6 +338,7 @@ public void flush() {
319338
if (((Type3Font) getFontProgram()).getGlyphsCount() < 1) {
320339
throw new PdfException("no.glyphs.defined.fo r.type3.font");
321340
}
341+
322342
PdfDictionary charProcs = new PdfDictionary();
323343
for (int i = 0; i < 256; i++) {
324344
if (fontEncoding.canDecode(i)) {
@@ -334,17 +354,7 @@ public void flush() {
334354
getPdfObject().put(PdfName.FontMatrix, new PdfArray(getFontMatrix()));
335355
getPdfObject().put(PdfName.FontBBox, new PdfArray(fontProgram.getFontMetrics().getBbox()));
336356

337-
if (fontProgram.getFontNames().getFontName() != null) {
338-
assert fontProgram.getFontNames().getFontName().length() > 0;
339-
PdfDictionary fontDescriptor = !isBuiltInFont() ? getFontDescriptor(fontProgram.getFontNames().getFontName()) : null;
340-
if (fontDescriptor != null) {
341-
getPdfObject().put(PdfName.FontDescriptor, fontDescriptor);
342-
if (fontDescriptor.getIndirectReference() != null) {
343-
fontDescriptor.flush();
344-
}
345-
}
346-
}
347-
super.flushFontData(null, PdfName.Type3);
357+
super.flushFontData(fontProgram.getFontNames().getFontName(), PdfName.Type3);
348358
super.flush();
349359
}
350360

kernel/src/main/java/com/itextpdf/kernel/font/Type3Font.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ This file is part of the iText (R) project.
4545

4646
import com.itextpdf.io.font.FontNames;
4747
import com.itextpdf.io.font.FontProgram;
48+
import com.itextpdf.io.font.constants.FontDescriptorFlags;
4849
import com.itextpdf.io.font.constants.FontStretches;
4950
import com.itextpdf.io.font.constants.FontWeights;
5051
import com.itextpdf.io.font.otf.Glyph;
@@ -75,15 +76,6 @@ public int getPdfFontFlags() {
7576
return flags;
7677
}
7778

78-
/**
79-
* Sets Font descriptor flags.
80-
*
81-
* @param flags
82-
*/
83-
public void setPdfFontFlags(int flags) {
84-
this.flags = flags;
85-
}
86-
8779
@Override
8880
public boolean isFontSpecific() {
8981
return false;
@@ -154,6 +146,16 @@ protected void setItalicAngle(int italicAngle) {
154146
super.setItalicAngle(italicAngle);
155147
}
156148

149+
/**
150+
* Sets Font descriptor flags.
151+
* @see FontDescriptorFlags
152+
*
153+
* @param flags
154+
*/
155+
void setPdfFontFlags(int flags) {
156+
this.flags = flags;
157+
}
158+
157159
void addGlyph(int code, int unicode, int width, int[] bbox, Type3Glyph type3Glyph) {
158160
Glyph glyph = new Glyph(code, width, unicode, bbox);
159161
codeToGlyph.put(code, glyph);

kernel/src/test/java/com/itextpdf/kernel/pdf/PdfFontTest.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,73 @@ public void createDocumentWithType3Font() throws IOException, InterruptedExcepti
323323
Assert.assertNull(new CompareTool().compareByContent(filename, cmpFilename, destinationFolder, "diff_"));
324324
}
325325

326+
@Test
327+
public void createTaggedDocumentWithType3Font() throws IOException, InterruptedException {
328+
String filename = destinationFolder + "createTaggedDocumentWithType3Font.pdf";
329+
String cmpFilename = sourceFolder + "cmp_createTaggedDocumentWithType3Font.pdf";
330+
String testString = "A A A A E E E ~ \u00E9"; // A A A A E E E ~ é
331+
332+
//writing type3 font characters
333+
String title = "Type3 font iText 7 Document";
334+
335+
PdfWriter writer = new PdfWriter(filename, new WriterProperties());
336+
writer.setCompressionLevel(CompressionConstants.NO_COMPRESSION);
337+
PdfDocument pdfDoc = new PdfDocument(writer).setTagged();
338+
339+
PdfType3Font type3 = PdfFontFactory.createType3Font(pdfDoc, "T3Font", "T3Font", false);
340+
Type3Glyph a = type3.addGlyph('A', 600, 0, 0, 600, 700);
341+
a.setLineWidth(100);
342+
a.moveTo(5, 5);
343+
a.lineTo(300, 695);
344+
a.lineTo(595, 5);
345+
a.closePathFillStroke();
346+
347+
Type3Glyph space = type3.addGlyph(' ', 600, 0, 0, 600, 700);
348+
space.setLineWidth(10);
349+
space.closePathFillStroke();
350+
351+
Type3Glyph e = type3.addGlyph('E', 600, 0, 0, 600, 700);
352+
e.setLineWidth(100);
353+
e.moveTo(595, 5);
354+
e.lineTo(5, 5);
355+
e.lineTo(300, 350);
356+
e.lineTo(5, 695);
357+
e.lineTo(595, 695);
358+
e.stroke();
359+
360+
Type3Glyph tilde = type3.addGlyph('~', 600, 0, 0, 600, 700);
361+
tilde.setLineWidth(100);
362+
tilde.moveTo(595, 5);
363+
tilde.lineTo(5, 5);
364+
tilde.stroke();
365+
366+
Type3Glyph symbol233 = type3.addGlyph('\u00E9', 600, 0, 0, 600, 700);
367+
symbol233.setLineWidth(100);
368+
symbol233.moveTo(540, 5);
369+
symbol233.lineTo(5, 340);
370+
symbol233.stroke();
371+
372+
pdfDoc.getDocumentInfo().setAuthor(author).
373+
setCreator(creator).
374+
setTitle(title);
375+
376+
for (int i = 0; i < PageCount; i++) {
377+
PdfPage page = pdfDoc.addNewPage();
378+
PdfCanvas canvas = new PdfCanvas(page);
379+
canvas.saveState()
380+
.beginText()
381+
.setFontAndSize(type3, 12)
382+
.moveText(50, 800)
383+
.showText(testString)
384+
.endText();
385+
page.flush();
386+
}
387+
pdfDoc.close();
388+
389+
// reading and comparing text
390+
Assert.assertNull(new CompareTool().compareByContent(filename, cmpFilename, destinationFolder, "diff_"));
391+
}
392+
326393
@Test
327394
public void createDocumentWithHelvetica() throws IOException, InterruptedException {
328395
String filename = destinationFolder + "DocumentWithHelvetica.pdf";

0 commit comments

Comments
 (0)