PdfAdvancedPageNumberEvents() throws DocumentException, IOException { super(); bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
/** {@inheritDoc} */
@Override
public void onEndPage(PdfWriter writer, Document document) {
final int pageN = writer.getPageNumber();
final String text = pageN + " / ";
final float len = bf.getWidthPoint(text, 8);
cb.beginText();
cb.setFontAndSize(bf, 8);
final float width = document.getPageSize().getWidth();
cb.setTextMatrix(width / 2, 30);
cb.showText(text);
cb.endText();
cb.addTemplate(template, width / 2 + len, 30);
try {
if (path.toLowerCase().endsWith(".ttf") || path.toLowerCase().endsWith(".otf") || path.toLowerCase().indexOf(".ttc,") > 0) {
Object[] allNames = BaseFont.getAllFontNames(path, BaseFont.WINANSI, null);
trueTypeFonts.setProperty(((String)allNames[0]).toLowerCase(), path);
if (alias != null) {
if (alias != null)
System.err.println("class FontFactory: You can't define an alias for a true type collection.");
String[] names = BaseFont.enumerateTTCNames(path);
for (int i = 0; i < names.length; i++) {
register(path + "," + i);
BaseFont bf = BaseFont.createFont(path, BaseFont.CP1252, false);
String fullName = bf.getFullFontName()[0][3].toLowerCase();
String familyName = bf.getFamilyFontName()[0][3].toLowerCase();
String psName = bf.getPostscriptFontName().toLowerCase();
registerFamily(familyName, fullName, null);
trueTypeFonts.setProperty(psName, path);
/** Gets all the names from the font. Only the required tables are read.
* @param name the name of the font
* @param encoding the encoding of the font
* @param ttfAfm the true type font or the afm in a byte array
* @throws DocumentException on error
* @throws IOException on error
* @return an array of Object[] built with {getPostscriptFontName(), getFamilyFontName(), getFullFontName()}
public static Object[] getAllFontNames(String name, String encoding, byte ttfAfm[]) throws DocumentException, IOException {
String nameBase = getBaseName(name);
BaseFont fontBuilt = null;
if (nameBase.toLowerCase().endsWith(".ttf") || nameBase.toLowerCase().endsWith(".otf") || nameBase.toLowerCase().indexOf(".ttc,") > 0)
fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true, false);
fontBuilt = createFont(name, encoding, false, false, ttfAfm, null);
return new Object[]{fontBuilt.getPostscriptFontName(), fontBuilt.getFamilyFontName(), fontBuilt.getFullFontName()};
String lower = path.toLowerCase();
if (lower.endsWith(".otf") || lower.endsWith(".ttf") || lower.indexOf(".ttc,") != -1) {
BaseFont font = BaseFont.createFont(path, encoding, embedded);
String[] names = BaseFont.enumerateTTCNames(path);
for (int i = 0; i < names.length; i++) {
addFont(path + "," + i, encoding, embedded);
BaseFont font = BaseFont.createFont(
path, encoding, embedded, false, null, readFile(pathToPFB));
String fontFamilyName = font.getFamilyFontName()[0][3];
FontFamily fontFamily = getFontFamily(fontFamilyName);
/** Gets the full name of the font. If it is a True Type font
* each array element will have {Platform ID, Platform Encoding ID,
* Language ID, font name}. The interpretation of this values can be
* found in the Open Type specification, chapter 2, in the 'name' table.<br>
* For the other fonts the array has a single element with {"", "", "",
* font name}.
* @param name the name of the font
* @param encoding the encoding of the font
* @param ttfAfm the true type font or the afm in a byte array
* @throws DocumentException on error
* @throws IOException on error
* @return the full name of the font
public static String[][] getFullFontName(String name, String encoding, byte ttfAfm[]) throws DocumentException, IOException {
String nameBase = getBaseName(name);
BaseFont fontBuilt = null;
if (nameBase.toLowerCase().endsWith(".ttf") || nameBase.toLowerCase().endsWith(".otf") || nameBase.toLowerCase().indexOf(".ttc,") > 0)
fontBuilt = new TrueTypeFont(name, CP1252, false, ttfAfm, true, false);
fontBuilt = createFont(name, encoding, false, false, ttfAfm, null);
return fontBuilt.getFullFontName();
private void setMetricDefaults() {
_underlinePosition = -50;
_underlineThickness = 50;
int[] box = _font.getCharBBox('x');
if (box != null) {
_yStrikeoutPosition = box[3] / 2 + 50;
_yStrikeoutSize = 100;
} else {
// Do what the JDK does, size will be calculated by ITextTextRenderer
_yStrikeoutPosition = _font.getFontDescriptor(BaseFont.BBOXURY, 1000f) / 3.0f;
private float calculateFontSize(float w, float h) throws IOException, DocumentException {
BaseFont ufont = getRealFont();
float fsize = fontSize;
if (fsize == 0) {
float bw = ufont.getWidthPoint(text, 1);
if (bw == 0)
fsize = 12;
fsize = w / bw;
float nfsize = h / (1 - ufont.getFontDescriptor(BaseFont.DESCENT, 1));
fsize = Math.min(fsize, nfsize);
if (fsize < 4)
fsize = 4;
return fsize;
String lower = uri.toLowerCase();
if (lower.endsWith(".otf") || lower.endsWith(".ttf") || lower.indexOf(".ttc,") != -1) {
BaseFont font = BaseFont.createFont(uri, encoding, embedded, false, afmttf, pfb);
BaseFont font = BaseFont.createFont(
name, encoding, embedded, false, afmttf, pfb);
String fontFamilyName = font.getFamilyFontName()[0][3];
FontFamily fontFamily = getFontFamily(fontFamilyName);
public BaseFontFontMetrics( final FontNativeContext record, final BaseFont baseFont, final float size ) {
if ( baseFont == null ) {
throw new NullPointerException( "BaseFont is invalid." );
this.record = record;
this.baseFont = baseFont;
this.size = size;
this.cpBuffer = new char[ 4 ];
this.cachedWidths = new long[ 256 - 32 ];
Arrays.fill( cachedWidths, -1 );
sizeScaled = FontStrictGeomUtility.toInternalValue( size );
this.ascent = (long) baseFont.getFontDescriptor( BaseFont.AWT_ASCENT, sizeScaled );
this.descent = (long) -baseFont.getFontDescriptor( BaseFont.AWT_DESCENT, sizeScaled );
this.leading = (long) baseFont.getFontDescriptor( BaseFont.AWT_LEADING, sizeScaled );
italicsAngle = FontStrictGeomUtility.toInternalValue( baseFont.getFontDescriptor( BaseFont.ITALICANGLE, size ) );
maxAscent = (long) baseFont.getFontDescriptor( BaseFont.BBOXURY, sizeScaled );
maxDescent = (long) -baseFont.getFontDescriptor( BaseFont.BBOXLLY, sizeScaled );
maxCharAdvance = (long) baseFont.getFontDescriptor( BaseFont.AWT_MAXADVANCE, sizeScaled );
final int[] charBBox = this.baseFont.getCharBBox( 'x' );
if ( charBBox != null ) {
this.xHeight = (long) ( charBBox[ 3 ] * size );
if ( this.xHeight == 0 ) {
this.xHeight = getAscent() / 2;
this.trueTypeFont = baseFont.getFontType() == BaseFont.FONT_TYPE_TT ||
baseFont.getFontType() == BaseFont.FONT_TYPE_TTUNI;
/** * Gets the maximum size of the ascender for all the fonts used * in this line. * @return maximum size of all the ascenders used in this line public float getAscender() { float ascender = 0; for (int k = 0; k < line.size(); ++k) { PdfChunk ck = (PdfChunk)line.get(k); if (ck.isImage()) ascender = Math.max(ascender, ck.getImage().getScaledHeight() + ck.getImageOffsetY()); else { PdfFont font = ck.font(); ascender = Math.max(ascender, font.getFont().getFontDescriptor(BaseFont.ASCENT, font.size())); return ascender;
private static IdentValue guessStyle(BaseFont font) {
String[][] names = font.getFullFontName();
for (String[] name : names) {
String lower = name[3].toLowerCase();
if (lower.contains("italic")) {
return IdentValue.ITALIC;
} else if (lower.contains("oblique")) {
return IdentValue.OBLIQUE;
return IdentValue.NORMAL;
public static String[] getFamilyNames(BaseFont font) {
String[][] names = font.getFamilyFontName();
if (names.length == 1) {
return new String[]{names[0][3]};
List<String> result = new ArrayList<String>();
for (String[] name : names) {
if ((name[0].equals("1") && name[1].equals("0")) || name[2].equals("1033")) {
result.add(name[3]);
return result.toArray(new String[result.size()]);
public boolean charExists(int c) {
if (cjkMirror != null) {
return cjkMirror.charExists(c);
} else if (isType0) {
return metrics.containsKey(c);
} else {
return super.charExists(c);
/** * Gets the descent of a <CODE>String</CODE> in normalized 1000 units. The descent will always be * less than or equal to zero even if all the characters have an higher descent. * @param text the <CODE>String</CODE> to get the descent of * @return the descent in normalized 1000 units public int getDescent(String text) { int min = 0; char chars[] = text.toCharArray(); for (int k = 0; k < chars.length; ++k) { int bbox[] = getCharBBox(chars[k]); if (bbox != null && bbox[1] < min) min = bbox[1]; return min;
try {
if (name.endsWith(".ttf") || name.endsWith(".otf") || name.endsWith(".afm")) {
Object allNames[] = BaseFont.getAllFontNames(file.getPath(), BaseFont.CP1252, null);
insertNames(allNames, file.getPath());
++count;
String ttcs[] = BaseFont.enumerateTTCNames(file.getPath());
for (int j = 0; j < ttcs.length; ++j) {
String nt = file.getPath() + "," + j;
Object allNames[] = BaseFont.getAllFontNames(nt, BaseFont.CP1252, null);
insertNames(allNames, nt);
try {
if (path.toLowerCase().endsWith(".ttf") || path.toLowerCase().endsWith(".otf") || path.toLowerCase().indexOf(".ttc,") > 0) {
Object allNames[] = BaseFont.getAllFontNames(path, BaseFont.WINANSI, null);
trueTypeFonts.setProperty(((String)allNames[0]).toLowerCase(), path);
if (alias != null) {
if (alias != null)
System.err.println("class FontFactory: You can't define an alias for a true type collection.");
String[] names = BaseFont.enumerateTTCNames(path);
for (int i = 0; i < names.length; i++) {
register(path + "," + i);
BaseFont bf = BaseFont.createFont(path, BaseFont.CP1252, false);
String fullName = bf.getFullFontName()[0][3].toLowerCase();
String familyName = bf.getFamilyFontName()[0][3].toLowerCase();
String psName = bf.getPostscriptFontName().toLowerCase();
registerFamily(familyName, fullName, null);
trueTypeFonts.setProperty(psName, path);
/** Gets all the names from the font. Only the required tables are read.
* @param name the name of the font
* @param encoding the encoding of the font
* @param ttfAfm the true type font or the afm in a byte array