Author: jahewson Date: Mon Sep 28 03:49:57 2015 New Revision: 1705595 URL: http://svn.apache.org/viewvc?rev=1705595&view=rev Log: PDFBOX-2997: Make FontMapper into a singleton interface
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java (with props) pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java (with props) Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapper.java Mon Sep 28 03:49:57 2015 @@ -16,458 +16,31 @@ */ package org.apache.pdfbox.pdmodel.font; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.PriorityQueue; -import java.util.Set; import org.apache.fontbox.FontBoxFont; -import org.apache.fontbox.cff.CFFFont; -import org.apache.fontbox.cff.CFFType1Font; -import org.apache.fontbox.ttf.OpenTypeFont; -import org.apache.fontbox.ttf.TTFParser; import org.apache.fontbox.ttf.TrueTypeFont; -import org.apache.fontbox.type1.Type1Font; /** - * Font mapper, locates non-embedded fonts via a pluggable FontProvider. + * Font mapper, locates non-embedded fonts. If you implement this then you're responsible for + * caching the fonts. SoftReference<FontBoxFont> is recommended. * * @author John Hewson */ -final class FontMapper +public interface FontMapper { - private FontMapper() {} - - private static final FontCache fontCache = new FontCache(); // todo: static cache isn't ideal - private static FontProvider fontProvider; - private static Map<String, FontInfo> fontInfoByName; - private static final TrueTypeFont lastResortFont; - static - { - try - { - String ttfName = "org/apache/pdfbox/resources/ttf/LiberationSans-Regular.ttf"; - URL url = FontMapper.class.getClassLoader().getResource(ttfName); - if (url == null) - { - throw new IOException("Error loading resource: " + ttfName); - } - InputStream ttfStream = url.openStream(); - TTFParser ttfParser = new TTFParser(); - lastResortFont = ttfParser.parse(ttfStream); - } - catch (IOException e) - { - throw new RuntimeException(e); - } - } - - // lazy thread safe singleton - private static class DefaultFontProvider - { - private static final FontProvider INSTANCE = new FileSystemFontProvider(fontCache); - } - - /** - * Sets the font service provider. - */ - public static synchronized void setProvider(FontProvider fontProvider) - { - FontMapper.fontProvider = fontProvider; - fontInfoByName = createFontInfoByName(fontProvider.getFontInfo()); - } - - /** - * Returns the font service provider. Defaults to using FileSystemFontProvider. - */ - public static synchronized FontProvider getProvider() - { - if (fontProvider == null) - { - setProvider(DefaultFontProvider.INSTANCE); - } - return fontProvider; - } - - /** - * Returns the font cache associated with this FontMapper. This method is needed by - * FontProvider subclasses. - */ - public static FontCache getFontCache() - { - return fontCache; - } - - private static Map<String, FontInfo> createFontInfoByName(List<? extends FontInfo> fontInfoList) - { - Map<String, FontInfo> map = new LinkedHashMap<String, FontInfo>(); - for (FontInfo info : fontInfoList) - { - for (String name : getPostScriptNames(info.getPostScriptName())) - { - map.put(name, info); - } - } - return map; - } - - /** - * Gets alternative names, as seen in some PDFs, e.g. PDFBOX-142. - */ - private static Set<String> getPostScriptNames(String postScriptName) - { - Set<String> names = new HashSet<String>(); - - // built-in PostScript name - names.add(postScriptName); - - // remove hyphens (e.g. Arial-Black -> ArialBlack) - names.add(postScriptName.replaceAll("-", "")); - - return names; - } - - /** Map of PostScript name substitutes, in priority order. */ - private static final Map<String, List<String>> substitutes = new HashMap<String, List<String>>(); - static - { - // substitutes for standard 14 fonts - substitutes.put("Courier", - Arrays.asList("CourierNew", "CourierNewPSMT", "LiberationMono", "NimbusMonL-Regu")); - substitutes.put("Courier-Bold", - Arrays.asList("CourierNewPS-BoldMT", "CourierNew-Bold", "LiberationMono-Bold", - "NimbusMonL-Bold")); - substitutes.put("Courier-Oblique", - Arrays.asList("CourierNewPS-ItalicMT","CourierNew-Italic", - "LiberationMono-Italic", "NimbusMonL-ReguObli")); - substitutes.put("Courier-BoldOblique", - Arrays.asList("CourierNewPS-BoldItalicMT","CourierNew-BoldItalic", - "LiberationMono-BoldItalic", "NimbusMonL-BoldObli")); - substitutes.put("Helvetica", - Arrays.asList("ArialMT", "Arial", "LiberationSans", "NimbusSanL-Regu")); - substitutes.put("Helvetica-Bold", - Arrays.asList("Arial-BoldMT", "Arial-Bold", "LiberationSans-Bold", - "NimbusSanL-Bold")); - substitutes.put("Helvetica-Oblique", - Arrays.asList("Arial-ItalicMT", "Arial-Italic", "Helvetica-Italic", - "LiberationSans-Italic", "NimbusSanL-ReguItal")); - substitutes.put("Helvetica-BoldOblique", - Arrays.asList("Arial-BoldItalicMT", "Helvetica-BoldItalic", - "LiberationSans-BoldItalic", "NimbusSanL-BoldItal")); - substitutes.put("Times-Roman", - Arrays.asList("TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", - "LiberationSerif", "NimbusRomNo9L-Regu")); - substitutes.put("Times-Bold", - Arrays.asList("TimesNewRomanPS-BoldMT", "TimesNewRomanPS-Bold", - "TimesNewRoman-Bold", "LiberationSerif-Bold", - "NimbusRomNo9L-Medi")); - substitutes.put("Times-Italic", - Arrays.asList("TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-Italic", - "TimesNewRoman-Italic", "LiberationSerif-Italic", - "NimbusRomNo9L-ReguItal")); - substitutes.put("Times-BoldItalic", - Arrays.asList("TimesNewRomanPS-BoldItalicMT", "TimesNewRomanPS-BoldItalic", - "TimesNewRoman-BoldItalic", "LiberationSerif-BoldItalic", - "NimbusRomNo9L-MediItal")); - substitutes.put("Symbol", Arrays.asList("Symbol", "SymbolMT", "StandardSymL")); - substitutes.put("ZapfDingbats", Arrays.asList("ZapfDingbatsITC", "Dingbats", "MS-Gothic")); - - // Acrobat also uses alternative names for Standard 14 fonts, which we map to those above - // these include names such as "Arial" and "TimesNewRoman" - for (String baseName : Standard14Fonts.getNames()) - { - if (!substitutes.containsKey(baseName)) - { - String mappedName = Standard14Fonts.getMappedFontName(baseName); - substitutes.put(baseName, copySubstitutes(mappedName)); - } - } - } - - /** - * Copies a list of font substitutes, adding the original font at the start of the list. - */ - private static List<String> copySubstitutes(String postScriptName) - { - return new ArrayList<String>(substitutes.get(postScriptName)); - } - - /** - * Adds a top-priority substitute for the given font. - * - * @param match PostScript name of the font to match - * @param replace PostScript name of the font to use as a replacement - */ - public static void addSubstitute(String match, String replace) - { - if (!substitutes.containsKey(match)) - { - substitutes.put(match, new ArrayList<String>()); - } - substitutes.get(match).add(replace); - } - - /** - * Returns the substitutes for a given font. - */ - private static List<String> getSubstitutes(String postScriptName) - { - List<String> subs = substitutes.get(postScriptName.replaceAll(" ", "")); - if (subs != null) - { - return subs; - } - else - { - return Collections.emptyList(); - } - } - - /** - * Attempts to find a good fallback based on the font descriptor. - */ - private static String getFallbackFontName(PDFontDescriptor fontDescriptor) - { - String fontName; - if (fontDescriptor != null) - { - // heuristic detection of bold - boolean isBold = false; - String name = fontDescriptor.getFontName(); - if (name != null) - { - String lower = fontDescriptor.getFontName().toLowerCase(); - isBold = lower.contains("bold") || - lower.contains("black") || - lower.contains("heavy"); - } - - // font descriptor flags should describe the style - if (fontDescriptor.isFixedPitch()) - { - fontName = "Courier"; - if (isBold && fontDescriptor.isItalic()) - { - fontName += "-BoldOblique"; - } - else if (isBold) - { - fontName += "-Bold"; - } - else if (fontDescriptor.isItalic()) - { - fontName += "-Oblique"; - } - } - else if (fontDescriptor.isSerif()) - { - fontName = "Times"; - if (isBold && fontDescriptor.isItalic()) - { - fontName += "-BoldItalic"; - } - else if (isBold) - { - fontName += "-Bold"; - } - else if (fontDescriptor.isItalic()) - { - fontName += "-Italic"; - } - else - { - fontName += "-Roman"; - } - } - else - { - fontName = "Helvetica"; - if (isBold && fontDescriptor.isItalic()) - { - fontName += "-BoldOblique"; - } - else if (isBold) - { - fontName += "-Bold"; - } - else if (fontDescriptor.isItalic()) - { - fontName += "-Oblique"; - } - } - } - else - { - // if there is no FontDescriptor then we just fall back to Times Roman - fontName = "Times-Roman"; - } - return fontName; - } - /** * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null. * * @param fontDescriptor FontDescriptor */ - public static FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, - PDFontDescriptor fontDescriptor) - { - TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, baseFont); - if (ttf != null) - { - return new FontMapping<TrueTypeFont>(ttf, false); - } - else - { - // fallback - todo: i.e. fuzzy match - String fontName = getFallbackFontName(fontDescriptor); - ttf = (TrueTypeFont) findFont(FontFormat.TTF, fontName); - if (ttf == null) - { - // we have to return something here as TTFs aren't strictly required on the system - ttf = lastResortFont; - } - return new FontMapping<TrueTypeFont>(ttf, true); - } - } - + FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, PDFontDescriptor fontDescriptor); + /** * Finds a font with the given PostScript name, or a suitable substitute, or null. This allows * any font to be substituted with a PFB, TTF or OTF. * * @param fontDescriptor the FontDescriptor of the font to find */ - public static FontMapping<FontBoxFont> getFontBoxFont(String baseFont, - PDFontDescriptor fontDescriptor) - { - FontBoxFont font = findFontBoxFont(baseFont); - if (font != null) - { - return new FontMapping<FontBoxFont>(font, false); - } - else - { - // fallback - todo: i.e. fuzzy match - String fallbackName = getFallbackFontName(fontDescriptor); - font = findFontBoxFont(fallbackName); - if (font == null) - { - // we have to return something here as TTFs aren't strictly required on the system - font = lastResortFont; - } - return new FontMapping<FontBoxFont>(font, true); - } - } - - /** - * Finds a font with the given PostScript name, or a suitable substitute, or null. - * - * @param postScriptName PostScript font name - */ - private static FontBoxFont findFontBoxFont(String postScriptName) - { - Type1Font t1 = (Type1Font)findFont(FontFormat.PFB, postScriptName); - if (t1 != null) - { - return t1; - } - - CFFFont cff = (CFFFont)findFont(FontFormat.OTF, postScriptName); - if (cff instanceof CFFType1Font) - { - return cff; - } - - TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, postScriptName); - if (ttf != null) - { - return ttf; - } - - return null; - } - - /** - * Finds a font with the given PostScript name, or a suitable substitute, or null. - * - * @param postScriptName PostScript font name - */ - private static FontBoxFont findFont(FontFormat format, String postScriptName) - { - // handle damaged PDFs, see PDFBOX-2884 - if (postScriptName == null) - { - return null; - } - - // make sure the font provider is initialized - if (fontProvider == null) - { - getProvider(); - } - - // first try to match the PostScript name - FontInfo info = getFont(format, postScriptName); - if (info != null) - { - return info.getFont(); - } - - // remove hyphens (e.g. Arial-Black -> ArialBlack) - info = getFont(format, postScriptName.replaceAll("-", "")); - if (info != null) - { - return info.getFont(); - } - - // then try named substitutes - for (String substituteName : getSubstitutes(postScriptName)) - { - info = getFont(format, substituteName); - if (info != null) - { - return info.getFont(); - } - } - - // then try converting Windows names e.g. (ArialNarrow,Bold) -> (ArialNarrow-Bold) - info = getFont(format, postScriptName.replaceAll(",", "-")); - if (info != null) - { - return info.getFont(); - } - - // no matches - return null; - } - - /** - * Finds the named font with the given format. - */ - private static FontInfo getFont(FontFormat format, String postScriptName) - { - // strip subset tag (happens when we substitute a corrupt embedded font, see PDFBOX-2642) - if (postScriptName.contains("+")) - { - postScriptName = postScriptName.substring(postScriptName.indexOf('+') + 1); - } - - // look up the PostScript name - FontInfo info = fontInfoByName.get(postScriptName); - if (info != null && info.getFormat() == format) - { - return info; - } - return null; - } + FontMapping<FontBoxFont> getFontBoxFont(String baseFont, PDFontDescriptor fontDescriptor); /** * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null. @@ -476,227 +49,6 @@ final class FontMapper * @param fontDescriptor FontDescriptor * @param cidSystemInfo the CID system info, e.g. "Adobe-Japan1", if any. */ - public static CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, - PDCIDSystemInfo cidSystemInfo) - { - // try name match or substitute with OTF - OpenTypeFont otf1 = (OpenTypeFont)findFont(FontFormat.OTF, baseFont); - if (otf1 != null) - { - return new CIDFontMapping(otf1, null, false); - } - - // try name match or substitute with TTF - TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, baseFont); - if (ttf != null) - { - return new CIDFontMapping(null, ttf, false); - } - - if (cidSystemInfo != null) - { - // "In Acrobat 3.0.1 and later, Type 0 fonts that use a CMap whose CIDSystemInfo - // dictionary defines the Adobe-GB1, Adobe-CNS1 Adobe-Japan1, or Adobe-Korea1 character - // collection can also be substituted." - Adobe Supplement to the ISO 32000 - - String collection = cidSystemInfo.getRegistry() + "-" + cidSystemInfo.getOrdering(); - - if (collection.equals("Adobe-GB1") || collection.equals("Adobe-CNS1") || - collection.equals("Adobe-Japan1") || collection.equals("Adobe-Korea1")) - { - // try automatic substitutes via character collection - PriorityQueue<FontMatch> queue = getFontMatches(fontDescriptor, cidSystemInfo); - FontMatch bestMatch = queue.poll(); - if (bestMatch != null) - { - FontBoxFont font = bestMatch.info.getFont(); - if (font instanceof OpenTypeFont) - { - return new CIDFontMapping((OpenTypeFont)font, null, true); - } - else - { - return new CIDFontMapping(null, font, true); - } - } - } - } - - // last-resort fallback - return new CIDFontMapping(null, lastResortFont, true); - } - - /** - * Returns a list of matching fonts, scored by suitability. Positive scores indicate matches - * for certain attributes, while negative scores indicate mismatches. Zero scores are neutral. - * - * @param fontDescriptor FontDescriptor, always present. - * @param cidSystemInfo Font's CIDSystemInfo, may be null. - */ - private static PriorityQueue<FontMatch> getFontMatches(PDFontDescriptor fontDescriptor, - PDCIDSystemInfo cidSystemInfo) - { - PriorityQueue<FontMatch> queue = new PriorityQueue<FontMatch>(20); - - for (FontInfo info : fontInfoByName.values()) - { - // filter by CIDSystemInfo, if given - if (cidSystemInfo != null && !isCharSetMatch(cidSystemInfo, info)) - { - continue; - } - - FontMatch match = new FontMatch(info); - - // Panose is the most reliable - if (fontDescriptor.getPanose() != null && info.getPanose() != null) - { - PDPanoseClassification panose = fontDescriptor.getPanose().getPanose(); - if (panose.getFamilyKind() == info.getPanose().getFamilyKind()) - { - // serifs - if (panose.getSerifStyle() == info.getPanose().getSerifStyle()) - { - // exact match - match.score += 2; - } - else if (panose.getSerifStyle() >= 2 && panose.getSerifStyle() <= 5 && - info.getPanose().getSerifStyle() >= 2 && - info.getPanose().getSerifStyle() <= 5) - { - // cove (serif) - match.score += 1; - } - else if (panose.getSerifStyle() >= 11 && panose.getSerifStyle() <= 13 && - info.getPanose().getSerifStyle() >= 11 && - info.getPanose().getSerifStyle() <= 13) - { - // sans-serif - match.score += 1; - } - else if (panose.getSerifStyle() != 0 && info.getPanose().getSerifStyle() != 0) - { - // mismatch - match.score -= 1; - } - - // weight - int weight = info.getPanose().getWeight(); - int weightClass = info.getWeightClassAsPanose(); - if (Math.abs(weight - weightClass) > 2) - { - // inconsistent data in system font, usWeightClass wins - weight = weightClass; - } - - if (panose.getWeight() == weight) - { - // exact match - match.score += 2; - } - else if (panose.getWeight() > 1 && weight > 1) - { - float dist = Math.abs(panose.getWeight() - weight); - match.score += 1 - dist * 0.5; - } - - // todo: italic - // ... - } - } - else if (fontDescriptor.getFontWeight() > 0 && info.getWeightClass() > 0) - { - // usWeightClass is pretty reliable - float dist = Math.abs(fontDescriptor.getFontWeight() - info.getWeightClass()); - match.score += 1 - (dist / 100) * 0.5; - } - // todo: italic - // ... - - queue.add(match); - } - return queue; - } - - /** - * Returns true if the character set described by CIDSystemInfo is present in the given font. - * Only applies to Adobe-GB1, Adobe-CNS1, Adobe-Japan1, Adobe-Korea1, as per the PDF spec. - */ - private static boolean isCharSetMatch(PDCIDSystemInfo cidSystemInfo, FontInfo info) - { - if (info.getCIDSystemInfo() != null) - { - return info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) && - info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering()); - } - else - { - long codePageRange = info.getCodePageRange(); - - long JIS_JAPAN = 1 << 17; - long CHINESE_SIMPLIFIED = 1 << 18; - long KOREAN_WANSUNG = 1 << 19; - long CHINESE_TRADITIONAL = 1 << 20; - long KOREAN_JOHAB = 1 << 21; - - if (cidSystemInfo.getOrdering().equals("GB1") && - (codePageRange & CHINESE_SIMPLIFIED) == CHINESE_SIMPLIFIED) - { - return true; - } - else if (cidSystemInfo.getOrdering().equals("CNS1") && - (codePageRange & CHINESE_TRADITIONAL) == CHINESE_TRADITIONAL) - { - return true; - } - else if (cidSystemInfo.getOrdering().equals("Japan1") && - (codePageRange & JIS_JAPAN) == JIS_JAPAN) - { - return true; - } - else return cidSystemInfo.getOrdering().equals("Korea1") && - (codePageRange & KOREAN_WANSUNG) == KOREAN_WANSUNG || - (codePageRange & KOREAN_JOHAB) == KOREAN_JOHAB; - } - } - - /** - * A potential match for a font substitution. - */ - private static class FontMatch implements Comparable<FontMatch> - { - double score; - final FontInfo info; - - FontMatch(FontInfo info) - { - this.info = info; - } - - @Override - public int compareTo(FontMatch match) - { - return Double.compare(match.score, this.score); - } - } - - /** - * For debugging. Prints all matches and returns the best match. - */ - private static FontMatch printMatches(PriorityQueue<FontMatch> queue) - { - FontMatch bestMatch = queue.peek(); - System.out.println("-------"); - while (!queue.isEmpty()) - { - FontMatch match = queue.poll(); - FontInfo info = match.info; - System.out.println(match.score + " | " + info.getMacStyle() + " " + - info.getFamilyClass() + " " + info.getPanose() + " " + - info.getCIDSystemInfo() + " " + info.getPostScriptName() + " " + - info.getFormat()); - } - System.out.println("-------"); - return bestMatch; - } + CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, + PDCIDSystemInfo cidSystemInfo); } Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java?rev=1705595&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java Mon Sep 28 03:49:57 2015 @@ -0,0 +1,701 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.pdfbox.pdmodel.font; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import org.apache.fontbox.FontBoxFont; +import org.apache.fontbox.cff.CFFFont; +import org.apache.fontbox.cff.CFFType1Font; +import org.apache.fontbox.ttf.OpenTypeFont; +import org.apache.fontbox.ttf.TTFParser; +import org.apache.fontbox.ttf.TrueTypeFont; +import org.apache.fontbox.type1.Type1Font; + +/** + * Font mapper, locates non-embedded fonts via a pluggable FontProvider. + * + * @author John Hewson + */ +final class FontMapperImpl implements FontMapper +{ + private static final FontCache fontCache = new FontCache(); // todo: static cache isn't ideal + private FontProvider fontProvider; + private Map<String, FontInfo> fontInfoByName; + private final TrueTypeFont lastResortFont; + + /** Map of PostScript name substitutes, in priority order. */ + private final Map<String, List<String>> substitutes = new HashMap<String, List<String>>(); + + FontMapperImpl() + { + // substitutes for standard 14 fonts + substitutes.put("Courier", + Arrays.asList("CourierNew", "CourierNewPSMT", "LiberationMono", "NimbusMonL-Regu")); + substitutes.put("Courier-Bold", + Arrays.asList("CourierNewPS-BoldMT", "CourierNew-Bold", "LiberationMono-Bold", + "NimbusMonL-Bold")); + substitutes.put("Courier-Oblique", + Arrays.asList("CourierNewPS-ItalicMT","CourierNew-Italic", + "LiberationMono-Italic", "NimbusMonL-ReguObli")); + substitutes.put("Courier-BoldOblique", + Arrays.asList("CourierNewPS-BoldItalicMT","CourierNew-BoldItalic", + "LiberationMono-BoldItalic", "NimbusMonL-BoldObli")); + substitutes.put("Helvetica", + Arrays.asList("ArialMT", "Arial", "LiberationSans", "NimbusSanL-Regu")); + substitutes.put("Helvetica-Bold", + Arrays.asList("Arial-BoldMT", "Arial-Bold", "LiberationSans-Bold", + "NimbusSanL-Bold")); + substitutes.put("Helvetica-Oblique", + Arrays.asList("Arial-ItalicMT", "Arial-Italic", "Helvetica-Italic", + "LiberationSans-Italic", "NimbusSanL-ReguItal")); + substitutes.put("Helvetica-BoldOblique", + Arrays.asList("Arial-BoldItalicMT", "Helvetica-BoldItalic", + "LiberationSans-BoldItalic", "NimbusSanL-BoldItal")); + substitutes.put("Times-Roman", + Arrays.asList("TimesNewRomanPSMT", "TimesNewRoman", "TimesNewRomanPS", + "LiberationSerif", "NimbusRomNo9L-Regu")); + substitutes.put("Times-Bold", + Arrays.asList("TimesNewRomanPS-BoldMT", "TimesNewRomanPS-Bold", + "TimesNewRoman-Bold", "LiberationSerif-Bold", + "NimbusRomNo9L-Medi")); + substitutes.put("Times-Italic", + Arrays.asList("TimesNewRomanPS-ItalicMT", "TimesNewRomanPS-Italic", + "TimesNewRoman-Italic", "LiberationSerif-Italic", + "NimbusRomNo9L-ReguItal")); + substitutes.put("Times-BoldItalic", + Arrays.asList("TimesNewRomanPS-BoldItalicMT", "TimesNewRomanPS-BoldItalic", + "TimesNewRoman-BoldItalic", "LiberationSerif-BoldItalic", + "NimbusRomNo9L-MediItal")); + substitutes.put("Symbol", Arrays.asList("Symbol", "SymbolMT", "StandardSymL")); + substitutes.put("ZapfDingbats", Arrays.asList("ZapfDingbatsITC", "Dingbats", "MS-Gothic")); + + // Acrobat also uses alternative names for Standard 14 fonts, which we map to those above + // these include names such as "Arial" and "TimesNewRoman" + for (String baseName : Standard14Fonts.getNames()) + { + if (!substitutes.containsKey(baseName)) + { + String mappedName = Standard14Fonts.getMappedFontName(baseName); + substitutes.put(baseName, copySubstitutes(mappedName)); + } + } + + // ------------------------- + + try + { + String ttfName = "org/apache/pdfbox/resources/ttf/LiberationSans-Regular.ttf"; + URL url = FontMapper.class.getClassLoader().getResource(ttfName); + if (url == null) + { + throw new IOException("Error loading resource: " + ttfName); + } + InputStream ttfStream = url.openStream(); + TTFParser ttfParser = new TTFParser(); + lastResortFont = ttfParser.parse(ttfStream); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + } + + // lazy thread safe singleton + private static class DefaultFontProvider + { + private static final FontProvider INSTANCE = new FileSystemFontProvider(fontCache); + } + + /** + * Sets the font service provider. + */ + public synchronized void setProvider(FontProvider fontProvider) + { + this.fontProvider = fontProvider; + fontInfoByName = createFontInfoByName(fontProvider.getFontInfo()); + } + + /** + * Returns the font service provider. Defaults to using FileSystemFontProvider. + */ + public synchronized FontProvider getProvider() + { + if (fontProvider == null) + { + setProvider(DefaultFontProvider.INSTANCE); + } + return fontProvider; + } + + /** + * Returns the font cache associated with this FontMapper. This method is needed by + * FontProvider subclasses. + */ + public FontCache getFontCache() + { + return fontCache; + } + + private Map<String, FontInfo> createFontInfoByName(List<? extends FontInfo> fontInfoList) + { + Map<String, FontInfo> map = new LinkedHashMap<String, FontInfo>(); + for (FontInfo info : fontInfoList) + { + for (String name : getPostScriptNames(info.getPostScriptName())) + { + map.put(name, info); + } + } + return map; + } + + /** + * Gets alternative names, as seen in some PDFs, e.g. PDFBOX-142. + */ + private Set<String> getPostScriptNames(String postScriptName) + { + Set<String> names = new HashSet<String>(); + + // built-in PostScript name + names.add(postScriptName); + + // remove hyphens (e.g. Arial-Black -> ArialBlack) + names.add(postScriptName.replaceAll("-", "")); + + return names; + } + + /** + * Copies a list of font substitutes, adding the original font at the start of the list. + */ + private List<String> copySubstitutes(String postScriptName) + { + return new ArrayList<String>(substitutes.get(postScriptName)); + } + + /** + * Adds a top-priority substitute for the given font. + * + * @param match PostScript name of the font to match + * @param replace PostScript name of the font to use as a replacement + */ + public void addSubstitute(String match, String replace) + { + if (!substitutes.containsKey(match)) + { + substitutes.put(match, new ArrayList<String>()); + } + substitutes.get(match).add(replace); + } + + /** + * Returns the substitutes for a given font. + */ + private List<String> getSubstitutes(String postScriptName) + { + List<String> subs = substitutes.get(postScriptName.replaceAll(" ", "")); + if (subs != null) + { + return subs; + } + else + { + return Collections.emptyList(); + } + } + + /** + * Attempts to find a good fallback based on the font descriptor. + */ + private String getFallbackFontName(PDFontDescriptor fontDescriptor) + { + String fontName; + if (fontDescriptor != null) + { + // heuristic detection of bold + boolean isBold = false; + String name = fontDescriptor.getFontName(); + if (name != null) + { + String lower = fontDescriptor.getFontName().toLowerCase(); + isBold = lower.contains("bold") || + lower.contains("black") || + lower.contains("heavy"); + } + + // font descriptor flags should describe the style + if (fontDescriptor.isFixedPitch()) + { + fontName = "Courier"; + if (isBold && fontDescriptor.isItalic()) + { + fontName += "-BoldOblique"; + } + else if (isBold) + { + fontName += "-Bold"; + } + else if (fontDescriptor.isItalic()) + { + fontName += "-Oblique"; + } + } + else if (fontDescriptor.isSerif()) + { + fontName = "Times"; + if (isBold && fontDescriptor.isItalic()) + { + fontName += "-BoldItalic"; + } + else if (isBold) + { + fontName += "-Bold"; + } + else if (fontDescriptor.isItalic()) + { + fontName += "-Italic"; + } + else + { + fontName += "-Roman"; + } + } + else + { + fontName = "Helvetica"; + if (isBold && fontDescriptor.isItalic()) + { + fontName += "-BoldOblique"; + } + else if (isBold) + { + fontName += "-Bold"; + } + else if (fontDescriptor.isItalic()) + { + fontName += "-Oblique"; + } + } + } + else + { + // if there is no FontDescriptor then we just fall back to Times Roman + fontName = "Times-Roman"; + } + return fontName; + } + + /** + * Finds a TrueType font with the given PostScript name, or a suitable substitute, or null. + * + * @param fontDescriptor FontDescriptor + */ + public FontMapping<TrueTypeFont> getTrueTypeFont(String baseFont, + PDFontDescriptor fontDescriptor) + { + TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, baseFont); + if (ttf != null) + { + return new FontMapping<TrueTypeFont>(ttf, false); + } + else + { + // fallback - todo: i.e. fuzzy match + String fontName = getFallbackFontName(fontDescriptor); + ttf = (TrueTypeFont) findFont(FontFormat.TTF, fontName); + if (ttf == null) + { + // we have to return something here as TTFs aren't strictly required on the system + ttf = lastResortFont; + } + return new FontMapping<TrueTypeFont>(ttf, true); + } + } + + /** + * Finds a font with the given PostScript name, or a suitable substitute, or null. This allows + * any font to be substituted with a PFB, TTF or OTF. + * + * @param fontDescriptor the FontDescriptor of the font to find + */ + public FontMapping<FontBoxFont> getFontBoxFont(String baseFont, + PDFontDescriptor fontDescriptor) + { + FontBoxFont font = findFontBoxFont(baseFont); + if (font != null) + { + return new FontMapping<FontBoxFont>(font, false); + } + else + { + // fallback - todo: i.e. fuzzy match + String fallbackName = getFallbackFontName(fontDescriptor); + font = findFontBoxFont(fallbackName); + if (font == null) + { + // we have to return something here as TTFs aren't strictly required on the system + font = lastResortFont; + } + return new FontMapping<FontBoxFont>(font, true); + } + } + + /** + * Finds a font with the given PostScript name, or a suitable substitute, or null. + * + * @param postScriptName PostScript font name + */ + private FontBoxFont findFontBoxFont(String postScriptName) + { + Type1Font t1 = (Type1Font)findFont(FontFormat.PFB, postScriptName); + if (t1 != null) + { + return t1; + } + + CFFFont cff = (CFFFont)findFont(FontFormat.OTF, postScriptName); + if (cff instanceof CFFType1Font) + { + return cff; + } + + TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, postScriptName); + if (ttf != null) + { + return ttf; + } + + return null; + } + + /** + * Finds a font with the given PostScript name, or a suitable substitute, or null. + * + * @param postScriptName PostScript font name + */ + private FontBoxFont findFont(FontFormat format, String postScriptName) + { + // handle damaged PDFs, see PDFBOX-2884 + if (postScriptName == null) + { + return null; + } + + // make sure the font provider is initialized + if (fontProvider == null) + { + getProvider(); + } + + // first try to match the PostScript name + FontInfo info = getFont(format, postScriptName); + if (info != null) + { + return info.getFont(); + } + + // remove hyphens (e.g. Arial-Black -> ArialBlack) + info = getFont(format, postScriptName.replaceAll("-", "")); + if (info != null) + { + return info.getFont(); + } + + // then try named substitutes + for (String substituteName : getSubstitutes(postScriptName)) + { + info = getFont(format, substituteName); + if (info != null) + { + return info.getFont(); + } + } + + // then try converting Windows names e.g. (ArialNarrow,Bold) -> (ArialNarrow-Bold) + info = getFont(format, postScriptName.replaceAll(",", "-")); + if (info != null) + { + return info.getFont(); + } + + // no matches + return null; + } + + /** + * Finds the named font with the given format. + */ + private FontInfo getFont(FontFormat format, String postScriptName) + { + // strip subset tag (happens when we substitute a corrupt embedded font, see PDFBOX-2642) + if (postScriptName.contains("+")) + { + postScriptName = postScriptName.substring(postScriptName.indexOf('+') + 1); + } + + // look up the PostScript name + FontInfo info = fontInfoByName.get(postScriptName); + if (info != null && info.getFormat() == format) + { + return info; + } + return null; + } + + /** + * Finds a CFF CID-Keyed font with the given PostScript name, or a suitable substitute, or null. + * This method can also map CJK fonts via their CIDSystemInfo (ROS). + * + * @param fontDescriptor FontDescriptor + * @param cidSystemInfo the CID system info, e.g. "Adobe-Japan1", if any. + */ + public CIDFontMapping getCIDFont(String baseFont, PDFontDescriptor fontDescriptor, + PDCIDSystemInfo cidSystemInfo) + { + // try name match or substitute with OTF + OpenTypeFont otf1 = (OpenTypeFont)findFont(FontFormat.OTF, baseFont); + if (otf1 != null) + { + return new CIDFontMapping(otf1, null, false); + } + + // try name match or substitute with TTF + TrueTypeFont ttf = (TrueTypeFont)findFont(FontFormat.TTF, baseFont); + if (ttf != null) + { + return new CIDFontMapping(null, ttf, false); + } + + if (cidSystemInfo != null) + { + // "In Acrobat 3.0.1 and later, Type 0 fonts that use a CMap whose CIDSystemInfo + // dictionary defines the Adobe-GB1, Adobe-CNS1 Adobe-Japan1, or Adobe-Korea1 character + // collection can also be substituted." - Adobe Supplement to the ISO 32000 + + String collection = cidSystemInfo.getRegistry() + "-" + cidSystemInfo.getOrdering(); + + if (collection.equals("Adobe-GB1") || collection.equals("Adobe-CNS1") || + collection.equals("Adobe-Japan1") || collection.equals("Adobe-Korea1")) + { + // try automatic substitutes via character collection + PriorityQueue<FontMatch> queue = getFontMatches(fontDescriptor, cidSystemInfo); + FontMatch bestMatch = queue.poll(); + if (bestMatch != null) + { + FontBoxFont font = bestMatch.info.getFont(); + if (font instanceof OpenTypeFont) + { + return new CIDFontMapping((OpenTypeFont)font, null, true); + } + else + { + return new CIDFontMapping(null, font, true); + } + } + } + } + + // last-resort fallback + return new CIDFontMapping(null, lastResortFont, true); + } + + /** + * Returns a list of matching fonts, scored by suitability. Positive scores indicate matches + * for certain attributes, while negative scores indicate mismatches. Zero scores are neutral. + * + * @param fontDescriptor FontDescriptor, always present. + * @param cidSystemInfo Font's CIDSystemInfo, may be null. + */ + private PriorityQueue<FontMatch> getFontMatches(PDFontDescriptor fontDescriptor, + PDCIDSystemInfo cidSystemInfo) + { + PriorityQueue<FontMatch> queue = new PriorityQueue<FontMatch>(20); + + for (FontInfo info : fontInfoByName.values()) + { + // filter by CIDSystemInfo, if given + if (cidSystemInfo != null && !isCharSetMatch(cidSystemInfo, info)) + { + continue; + } + + FontMatch match = new FontMatch(info); + + // Panose is the most reliable + if (fontDescriptor.getPanose() != null && info.getPanose() != null) + { + PDPanoseClassification panose = fontDescriptor.getPanose().getPanose(); + if (panose.getFamilyKind() == info.getPanose().getFamilyKind()) + { + // serifs + if (panose.getSerifStyle() == info.getPanose().getSerifStyle()) + { + // exact match + match.score += 2; + } + else if (panose.getSerifStyle() >= 2 && panose.getSerifStyle() <= 5 && + info.getPanose().getSerifStyle() >= 2 && + info.getPanose().getSerifStyle() <= 5) + { + // cove (serif) + match.score += 1; + } + else if (panose.getSerifStyle() >= 11 && panose.getSerifStyle() <= 13 && + info.getPanose().getSerifStyle() >= 11 && + info.getPanose().getSerifStyle() <= 13) + { + // sans-serif + match.score += 1; + } + else if (panose.getSerifStyle() != 0 && info.getPanose().getSerifStyle() != 0) + { + // mismatch + match.score -= 1; + } + + // weight + int weight = info.getPanose().getWeight(); + int weightClass = info.getWeightClassAsPanose(); + if (Math.abs(weight - weightClass) > 2) + { + // inconsistent data in system font, usWeightClass wins + weight = weightClass; + } + + if (panose.getWeight() == weight) + { + // exact match + match.score += 2; + } + else if (panose.getWeight() > 1 && weight > 1) + { + float dist = Math.abs(panose.getWeight() - weight); + match.score += 1 - dist * 0.5; + } + + // todo: italic + // ... + } + } + else if (fontDescriptor.getFontWeight() > 0 && info.getWeightClass() > 0) + { + // usWeightClass is pretty reliable + float dist = Math.abs(fontDescriptor.getFontWeight() - info.getWeightClass()); + match.score += 1 - (dist / 100) * 0.5; + } + // todo: italic + // ... + + queue.add(match); + } + return queue; + } + + /** + * Returns true if the character set described by CIDSystemInfo is present in the given font. + * Only applies to Adobe-GB1, Adobe-CNS1, Adobe-Japan1, Adobe-Korea1, as per the PDF spec. + */ + private boolean isCharSetMatch(PDCIDSystemInfo cidSystemInfo, FontInfo info) + { + if (info.getCIDSystemInfo() != null) + { + return info.getCIDSystemInfo().getRegistry().equals(cidSystemInfo.getRegistry()) && + info.getCIDSystemInfo().getOrdering().equals(cidSystemInfo.getOrdering()); + } + else + { + long codePageRange = info.getCodePageRange(); + + long JIS_JAPAN = 1 << 17; + long CHINESE_SIMPLIFIED = 1 << 18; + long KOREAN_WANSUNG = 1 << 19; + long CHINESE_TRADITIONAL = 1 << 20; + long KOREAN_JOHAB = 1 << 21; + + if (cidSystemInfo.getOrdering().equals("GB1") && + (codePageRange & CHINESE_SIMPLIFIED) == CHINESE_SIMPLIFIED) + { + return true; + } + else if (cidSystemInfo.getOrdering().equals("CNS1") && + (codePageRange & CHINESE_TRADITIONAL) == CHINESE_TRADITIONAL) + { + return true; + } + else if (cidSystemInfo.getOrdering().equals("Japan1") && + (codePageRange & JIS_JAPAN) == JIS_JAPAN) + { + return true; + } + else return cidSystemInfo.getOrdering().equals("Korea1") && + (codePageRange & KOREAN_WANSUNG) == KOREAN_WANSUNG || + (codePageRange & KOREAN_JOHAB) == KOREAN_JOHAB; + } + } + + /** + * A potential match for a font substitution. + */ + private class FontMatch implements Comparable<FontMatch> + { + double score; + final FontInfo info; + + FontMatch(FontInfo info) + { + this.info = info; + } + + @Override + public int compareTo(FontMatch match) + { + return Double.compare(match.score, this.score); + } + } + + /** + * For debugging. Prints all matches and returns the best match. + */ + private FontMatch printMatches(PriorityQueue<FontMatch> queue) + { + FontMatch bestMatch = queue.peek(); + System.out.println("-------"); + while (!queue.isEmpty()) + { + FontMatch match = queue.poll(); + FontInfo info = match.info; + System.out.println(match.score + " | " + info.getMacStyle() + " " + + info.getFamilyClass() + " " + info.getPanose() + " " + + info.getCIDSystemInfo() + " " + info.getPostScriptName() + " " + + info.getFormat()); + } + System.out.println("-------"); + return bestMatch; + } +} Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMapperImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java?rev=1705595&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java Mon Sep 28 03:49:57 2015 @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.pdfbox.pdmodel.font; + +/** + * FontMapper factory class. + * + * @author John Hewson + */ +public class FontMappers +{ + private static FontMapper instance; + + // lazy thread safe singleton + private static class DefaultFontMapper + { + private static final FontMapper INSTANCE = new FontMapperImpl(); + } + + /** + * Returns the singleton FontMapper instance. + */ + public static FontMapper instance() + { + if (instance == null) + { + instance = DefaultFontMapper.INSTANCE; + } + return instance; + } + + /** + * Sets the singleton FontMapper instance. + */ + public static synchronized void set(FontMapper fontMapper) + { + instance = fontMapper; + } +} Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontMappers.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType0.java Mon Sep 28 03:49:57 2015 @@ -35,9 +35,11 @@ import org.apache.fontbox.util.BoundingB import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.io.IOUtils; import org.apache.pdfbox.pdmodel.common.PDStream; -import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; import org.apache.pdfbox.util.Matrix; + +import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; + /** * Type 0 CIDFont (CFF). * @@ -121,8 +123,9 @@ public class PDCIDFontType0 extends PDCI else { // find font or substitute - CIDFontMapping mapping = FontMapper.getCIDFont(getBaseFont(), getFontDescriptor(), - getCIDSystemInfo()); + CIDFontMapping mapping = FontMappers.instance() + .getCIDFont(getBaseFont(), getFontDescriptor(), + getCIDSystemInfo()); FontBoxFont font; if (mapping.isCIDFont()) { Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDCIDFontType2.java Mon Sep 28 03:49:57 2015 @@ -139,8 +139,9 @@ public class PDCIDFontType2 extends PDCI if (ttfFont == null) { // find font or substitute - CIDFontMapping mapping = FontMapper.getCIDFont(getBaseFont(), getFontDescriptor(), - getCIDSystemInfo()); + CIDFontMapping mapping = FontMappers.instance() + .getCIDFont(getBaseFont(), getFontDescriptor(), + getCIDSystemInfo()); if (mapping.isCIDFont()) { Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDTrueTypeFont.java Mon Sep 28 03:49:57 2015 @@ -37,7 +37,6 @@ import org.apache.pdfbox.cos.COSDictiona import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDStream; -import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; import org.apache.pdfbox.pdmodel.font.encoding.BuiltInEncoding; import org.apache.pdfbox.pdmodel.font.encoding.Encoding; import org.apache.pdfbox.pdmodel.font.encoding.GlyphList; @@ -46,6 +45,9 @@ import org.apache.pdfbox.pdmodel.font.en import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding; import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; + +import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; + /** * TrueType font. * @@ -191,8 +193,9 @@ public class PDTrueTypeFont extends PDSi // substitute if (ttfFont == null) { - FontMapping<TrueTypeFont> mapping = FontMapper.getTrueTypeFont(getBaseFont(), - getFontDescriptor()); + FontMapping<TrueTypeFont> mapping = FontMappers.instance() + .getTrueTypeFont(getBaseFont(), + getFontDescriptor()); ttfFont = mapping.getFont(); if (mapping.isFallback()) Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1CFont.java Mon Sep 28 03:49:57 2015 @@ -114,7 +114,8 @@ public class PDType1CFont extends PDSimp } else { - FontMapping<FontBoxFont> mapping = FontMapper.getFontBoxFont(getBaseFont(), fd); + FontMapping<FontBoxFont> mapping = FontMappers.instance() + .getFontBoxFont(getBaseFont(), fd); genericFont = mapping.getFont(); if (mapping.isFallback()) Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java?rev=1705595&r1=1705594&r2=1705595&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDType1Font.java Mon Sep 28 03:49:57 2015 @@ -27,8 +27,8 @@ import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.fontbox.FontBoxFont; import org.apache.fontbox.EncodedFont; +import org.apache.fontbox.FontBoxFont; import org.apache.fontbox.type1.DamagedFontException; import org.apache.fontbox.type1.Type1Font; import org.apache.fontbox.util.BoundingBox; @@ -37,13 +37,15 @@ import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.common.PDStream; -import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; import org.apache.pdfbox.pdmodel.font.encoding.Encoding; import org.apache.pdfbox.pdmodel.font.encoding.StandardEncoding; import org.apache.pdfbox.pdmodel.font.encoding.Type1Encoding; import org.apache.pdfbox.pdmodel.font.encoding.WinAnsiEncoding; import org.apache.pdfbox.util.Matrix; + +import static org.apache.pdfbox.pdmodel.font.UniUtil.getUniNameOfCodePoint; + /** * A PostScript Type 1 Font. * @@ -108,8 +110,9 @@ public class PDType1Font extends PDSimpl // todo: could load the PFB font here if we wanted to support Standard 14 embedding type1font = null; - FontMapping<FontBoxFont> mapping = FontMapper.getFontBoxFont(getBaseFont(), - getFontDescriptor()); + FontMapping<FontBoxFont> mapping = FontMappers.instance() + .getFontBoxFont(getBaseFont(), + getFontDescriptor()); genericFont = mapping.getFont(); if (mapping.isFallback()) @@ -244,7 +247,8 @@ public class PDType1Font extends PDSimpl } else { - FontMapping<FontBoxFont> mapping = FontMapper.getFontBoxFont(getBaseFont(), fd); + FontMapping<FontBoxFont> mapping = FontMappers.instance() + .getFontBoxFont(getBaseFont(), fd); genericFont = mapping.getFont(); if (mapping.isFallback())