/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.icepdf.core.pobjects.fonts; import org.icepdf.core.pobjects.*; import org.icepdf.core.util.Library; import java.util.HashMap; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * This class represents a PDF <code>FontDescriptor</code>. A FontDescriptor object * holds extra information about a particular parent Font object. In particular * information on font widths, flags, to unicode and embedded font program streams. * * @see org.icepdf.core.pobjects.fonts.Font */ public class FontDescriptor extends Dictionary { private static final Logger logger = Logger.getLogger(FontDescriptor.class.toString()); private FontFile font; public static final Name TYPE = new Name("FontDescriptor"); public static final Name FONT_NAME = new Name("FontName"); public static final Name FONT_FAMILY = new Name("FontFamily"); public static final Name MISSING_Stretch = new Name("FontStretch"); public static final Name FONT_WEIGHT = new Name("FontWeight"); public static final Name FLAGS = new Name("Flags"); public static final Name FONT_BBOX = new Name("FontBBox"); public static final Name ITALIC_ANGLE = new Name("ItalicAngle"); public static final Name ASCENT = new Name("Ascent"); public static final Name DESCENT = new Name("Descent"); public static final Name LEADING = new Name("Leading"); public static final Name CAP_HEIGHT = new Name("CapHeight"); public static final Name X_HEIGHT = new Name("XHeight"); public static final Name STEM_V = new Name("StemV"); public static final Name STEM_H = new Name("StemH"); public static final Name AVG_WIDTH = new Name("AvgWidth"); public static final Name MAX_WIDTH = new Name("MaxWidth"); public static final Name MISSING_WIDTH = new Name("MissingWidth"); public static final Name FONT_FILE = new Name("FontFile"); public static final Name FONT_FILE_2 = new Name("FontFile2"); public static final Name FONT_FILE_3 = new Name("FontFile3"); public static final Name FONT_FILE_3_TYPE_1C = new Name("Type1C"); public static final Name FONT_FILE_3_CID_FONT_TYPE_0 = new Name("CIDFontType0"); public static final Name FONT_FILE_3_CID_FONT_TYPE_2 = new Name("CIDFontType2"); public static final Name FONT_FILE_3_CID_FONT_TYPE_0C = new Name("CIDFontType0C"); public static final Name FONT_FILE_3_OPEN_TYPE = new Name("OpenType"); /** * Creates a new instance of a FontDescriptor. * * @param l Libaray of all objects in PDF * @param h hash of parsed FontDescriptor attributes */ public FontDescriptor(Library l, HashMap h) { super(l, h); } /** * Utility method for creating a FontDescriptor based on the font metrics * of the <code>AFM</code> * * @param library document library * @param afm adobe font metrics data * @return new instance of a <code>FontDescriptor</code> */ public static FontDescriptor createDescriptor(Library library, AFM afm) { HashMap<Name, Object> properties = new HashMap<Name, Object>(7); properties.put(FONT_NAME, afm.getFontName()); properties.put(FONT_FAMILY, afm.getFamilyName()); properties.put(FONT_BBOX, afm.getFontBBox()); properties.put(ITALIC_ANGLE, afm.getItalicAngle()); properties.put(MAX_WIDTH, afm.getMaxWidth()); properties.put(AVG_WIDTH, afm.getAvgWidth()); properties.put(FLAGS, afm.getFlags()); return new FontDescriptor(library, properties); } /** * Returns the PostScript name of the font. * * @return PostScript name of font. */ public String getFontName() { Object value = library.getObject(entries, FONT_NAME); if (value instanceof Name) { return ((Name) value).getName(); } else if (value instanceof String) { return (String) value; } return null; } /** * Gets a string specifying the preferred font family name. For example, the font * "Time Bold Italic" would have a font family of Times. * * @return preferred font family name. */ public String getFontFamily() { Object value = library.getObject(entries, FONT_FAMILY); if (value instanceof StringObject) { StringObject familyName = (StringObject) value; return familyName.getDecryptedLiteralString(library.getSecurityManager()); } return FONT_NAME.getName(); } /** * Gets the weight (thickness) component of the fully-qualified font name or * font specifier. The default value is zero. * * @return the weight of the font name. */ public float getFontWeight() { Object value = library.getObject(entries, FONT_WEIGHT); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the width to use for character codes whose widths are not specifed in * the font's dictionary. The default value is zero. * * @return width of non-specified characters. */ public float getMissingWidth() { Object value = library.getObject(entries, MISSING_WIDTH); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the average width of glyphs in the font. The default value is zero. * * @return average width of glyphs. */ public float getAverageWidth() { Object value = library.getObject(entries, AVG_WIDTH); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the maximum width of glyphs in the font. The default value is zero. * * @return maximum width of glyphs. */ public float getMaxWidth() { Object value = library.getObject(entries, MAX_WIDTH); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the ascent of glyphs in the font. The default value is zero. * * @return ascent of glyphs. */ public float getAscent() { Object value = library.getObject(entries, ASCENT); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the descent of glyphs in the font. The default value is zero. * * @return descent of glyphs. */ public float getDescent() { Object value = library.getObject(entries, DESCENT); if (value instanceof Number) { return ((Number) value).floatValue(); } return 0.0f; } /** * Gets the embeddedFont if any. * * @return embedded font; null, if there is no valid embedded font. */ public FontFile getEmbeddedFont() { return font; } /** * Gets the fonts bounding box. * * @return bounding box in PDF coordinate space. */ public PRectangle getFontBBox() { Object value = library.getObject(entries, FONT_BBOX); if (value instanceof List) { List rectangle = (List) value; return new PRectangle(rectangle); } return null; } /** * Gets the font flag value, which is a collection of various characteristics * that describe the font. * * @return int value representing the flags; bits must be looked at to get * attribute values. */ public int getFlags() { Object value = library.getObject(entries, FLAGS); if (value instanceof Number) { return ((Number) value).intValue(); } return 0; } /** * Initiate the Font Descriptor object. Reads embedded font programs * or CMap streams. */ public synchronized void init() { if (inited) { return; } /** * FontFile1 = A stream containing a Type 1 font program * FontFile2 = A stream containing a TrueType font program * FontFile3 = A stream containing a font program other than Type 1 or * TrueType. The format of the font program is specified by the Subtype entry * in the stream dictionary */ try { // get an instance of our font factory FontFactory fontFactory = FontFactory.getInstance(); if (entries.containsKey(FONT_FILE)) { Stream fontStream = (Stream) library.getObject(entries, FONT_FILE); if (fontStream != null) { font = fontFactory.createFontFile( fontStream, FontFactory.FONT_TYPE_1, null); } } if (entries.containsKey(FONT_FILE_2)) { Stream fontStream = (Stream) library.getObject(entries, FONT_FILE_2); if (fontStream != null) { font = fontFactory.createFontFile( fontStream, FontFactory.FONT_TRUE_TYPE, null); } } if (entries.containsKey(FONT_FILE_3)) { Stream fontStream = (Stream) library.getObject(entries, FONT_FILE_3); Name subType = (Name) fontStream.getObject(SUBTYPE_KEY); if (subType != null && (subType.equals(FONT_FILE_3_TYPE_1C) || subType.equals(FONT_FILE_3_CID_FONT_TYPE_0) || subType.equals(FONT_FILE_3_CID_FONT_TYPE_0C)) ) { font = fontFactory.createFontFile( fontStream, FontFactory.FONT_TYPE_1, subType.getName()); } if (subType != null && subType.equals(FONT_FILE_3_OPEN_TYPE)) { // font = new NFontOpenType(fontStreamBytes); font = fontFactory.createFontFile( fontStream, FontFactory.FONT_OPEN_TYPE, subType.getName()); } } } // catch everything, we can fall back to font substitution if a failure // occurs. catch (Throwable e) { logger.log(Level.FINE, "Error Reading Embedded Font ", e); } inited = true; } /** * Return a string representation of the all the FontDescriptor object's * parsed attributes. * * @return all of FontDescriptors parsed attributes. */ public String toString() { String name = null; if (font != null) name = font.getName(); return super.getPObjectReference() + " FONTDESCRIPTOR= " + entries.toString() + " - " + name; } }