Author: jahewson Date: Mon Jul 13 01:11:31 2015 New Revision: 1690560 URL: http://svn.apache.org/r1690560 Log: PDFBOX-2842: Local cache of FontInfo using Preferences API
Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java (with props) Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.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/PDPanoseClassification.java Added: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java?rev=1690560&view=auto ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java (added) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java Mon Jul 13 01:11:31 2015 @@ -0,0 +1,60 @@ +/* + * 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.Serializable; + +/** + * Represents a CIDSystemInfo for the FontMapper API. + * + * @author John Hewson + */ +public final class CIDSystemInfo implements Serializable +{ + private final String registry; + private final String ordering; + private final int supplement; + + CIDSystemInfo(String registry, String ordering, int supplement) + { + this.registry = registry; + this.ordering = ordering; + this.supplement = supplement; + } + + public String getRegistry() + { + return registry; + } + + public String getOrdering() + { + return ordering; + } + + public int getSupplement() + { + return supplement; + } + + @Override + public String toString() + { + return getRegistry() + "-" + getOrdering() + "-" + getSupplement(); + } +} Propchange: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/CIDSystemInfo.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java?rev=1690560&r1=1690559&r2=1690560&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java Mon Jul 13 01:11:31 2015 @@ -16,13 +16,19 @@ */ package org.apache.pdfbox.pdmodel.font; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.prefs.Preferences; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.fontbox.FontBoxFont; @@ -51,11 +57,11 @@ final class FileSystemFontProvider exten private final List<FSFontInfo> fontInfoList = new ArrayList<FSFontInfo>(); private final FontCache cache; - private class FSFontInfo extends FontInfo + private static class FSFontInfo extends FontInfo implements Serializable { private final String postScriptName; private final FontFormat format; - private final PDCIDSystemInfo cidSystemInfo; + private final CIDSystemInfo cidSystemInfo; private final int usWeightClass; private final int sFamilyClass; private final int ulCodePageRange1; @@ -63,10 +69,12 @@ final class FileSystemFontProvider exten private final int macStyle; private final PDPanoseClassification panose; private final File file; + private transient FileSystemFontProvider parent; private FSFontInfo(File file, FontFormat format, String postScriptName, - PDCIDSystemInfo cidSystemInfo, int usWeightClass, int sFamilyClass, - int ulCodePageRange1, int ulCodePageRange2, int macStyle, byte[] panose) + CIDSystemInfo cidSystemInfo, int usWeightClass, int sFamilyClass, + int ulCodePageRange1, int ulCodePageRange2, int macStyle, byte[] panose, + FileSystemFontProvider parent) { this.file = file; this.format = format; @@ -78,6 +86,7 @@ final class FileSystemFontProvider exten this.ulCodePageRange2 = ulCodePageRange2; this.macStyle = macStyle; this.panose = panose != null ? new PDPanoseClassification(panose) : null; + this.parent = parent; } @Override @@ -93,7 +102,7 @@ final class FileSystemFontProvider exten } @Override - public PDCIDSystemInfo getCIDSystemInfo() + public CIDSystemInfo getCIDSystemInfo() { return cidSystemInfo; } @@ -101,7 +110,7 @@ final class FileSystemFontProvider exten @Override public FontBoxFont getFont() { - FontBoxFont cached = cache.getFont(this); + FontBoxFont cached = parent.cache.getFont(this); if (cached != null) { return cached; @@ -111,12 +120,12 @@ final class FileSystemFontProvider exten FontBoxFont font; switch (format) { - case PFB: font = getType1Font(postScriptName, file); break; - case TTF: font = getTrueTypeFont(postScriptName, file); break; - case OTF: font = getOTFFont(postScriptName, file); break; + case PFB: font = parent.getType1Font(postScriptName, file); break; + case TTF: font = parent.getTrueTypeFont(postScriptName, file); break; + case OTF: font = parent.getOTFFont(postScriptName, file); break; default: throw new RuntimeException("can't happen"); } - cache.addFont(this, font); + parent.cache.addFont(this, font); return font; } } @@ -165,6 +174,17 @@ final class FileSystemFontProvider exten } /** + * Represents ignored fonts (i.e. bitmap fonts). + */ + private static class FSIgnored extends FSFontInfo implements Serializable + { + private FSIgnored(File file, FontFormat format, String postScriptName) + { + super(file, format, postScriptName, null, 0, 0, 0, 0, 0, null, null); + } + } + + /** * Constructor. */ FileSystemFontProvider(FontCache cache) @@ -176,6 +196,7 @@ final class FileSystemFontProvider exten LOG.trace("Will search the local system for fonts"); } + // scan the local system for font files List<File> files = new ArrayList<File>(); FontFileFinder fontFileFinder = new FontFileFinder(); List<URI> fonts = fontFileFinder.find(); @@ -189,18 +210,33 @@ final class FileSystemFontProvider exten LOG.trace("Found " + files.size() + " fonts on the local system"); } - // todo: loading all of these fonts is slow, can we cache this? + // load cached FontInfo objects + List<FSFontInfo> cachedInfos = loadCache(files); + if (cachedInfos.size() > 0) + { + fontInfoList.addAll(cachedInfos); + } + else + { + LOG.warn("Building font cache, this may take a while"); + scanFonts(files); + saveCache(); + } + } + + private void scanFonts(List<File> files) + { for (File file : files) { try { if (file.getPath().toLowerCase().endsWith(".ttf") || - file.getPath().toLowerCase().endsWith(".otf")) + file.getPath().toLowerCase().endsWith(".otf")) { addTrueTypeFont(file); } else if (file.getPath().toLowerCase().endsWith(".ttc") || - file.getPath().toLowerCase().endsWith(".otc")) + file.getPath().toLowerCase().endsWith(".otc")) { addTrueTypeCollection(file); } @@ -215,6 +251,73 @@ final class FileSystemFontProvider exten } } } + + private void saveCache() + { + // Get the preferences database for this package. + Preferences prefs = Preferences.userNodeForPackage(FileSystemFontProvider.class); + + // To save, write the object to a byte array. + try + { + for (FSFontInfo fontInfo : fontInfoList) + { + ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); + ObjectOutputStream objectOut = new ObjectOutputStream(byteOut); + objectOut.writeObject(fontInfo); // write it to the stream + prefs.putByteArray(fontInfo.file.getAbsolutePath(), byteOut.toByteArray()); + } + } + catch (IOException e) + { + LOG.error("Could not write to font cache", e); + } + LOG.warn("Finished building font cache, found " + fontInfoList.size() + " fonts"); + } + + private List<FSFontInfo> loadCache(List<File> files) + { + // Get the preferences database for this package. + Preferences prefs = Preferences.userNodeForPackage(FileSystemFontProvider.class); + List<FSFontInfo> results = new ArrayList<FSFontInfo>(); + for (File file : files) + { + // The second argument is the default if the key isn't found. + byte[] stored = prefs.getByteArray(file.getAbsolutePath(), null); + if (stored != null) + { + try + { + ByteArrayInputStream byteIn = new ByteArrayInputStream(stored); + ObjectInputStream objectIn = new ObjectInputStream(byteIn); + Object object = objectIn.readObject(); + if (object instanceof FSFontInfo) + { + FSFontInfo info = (FSFontInfo)object; + info.parent = this; + results.add(info); + } + } + catch (ClassNotFoundException e) + { + LOG.error("Error loading font cache, will be re-built", e); + break; + } + catch (IOException e) + { + LOG.error("Error loading font cache, will be re-built", e); + break; + } + } + else + { + // re-build the entire cache if we encounter un-cached fonts (could be optimised) + LOG.warn("New fonts found, font cache will be re-built"); + return new ArrayList<FSFontInfo>(); + } + } + return results; + } /** * Adds a TTC or OTC to the file cache. To reduce memory, the parsed font is not cached. @@ -306,6 +409,7 @@ final class FileSystemFontProvider exten // ignore bitmap fonts if (ttf.getHeader() == null) { + fontInfoList.add(new FSIgnored(file, FontFormat.TTF, ttf.getName())); return; } int macStyle = ttf.getHeader().getMacStyle(); @@ -315,22 +419,22 @@ final class FileSystemFontProvider exten { format = "OTF"; CFFFont cff = ((OpenTypeFont)ttf).getCFF().getFont(); - PDCIDSystemInfo ros = null; + CIDSystemInfo ros = null; if (cff instanceof CFFCIDFont) { CFFCIDFont cidFont = (CFFCIDFont)cff; String registry = cidFont.getRegistry(); String ordering = cidFont.getOrdering(); int supplement = cidFont.getSupplement(); - ros = new PDCIDSystemInfo(registry, ordering, supplement); + ros = new CIDSystemInfo(registry, ordering, supplement); } fontInfoList.add(new FSFontInfo(file, FontFormat.OTF, ttf.getName(), ros, usWeightClass, sFamilyClass, ulCodePageRange1, ulCodePageRange2, - macStyle, panose)); + macStyle, panose, this)); } else { - PDCIDSystemInfo ros = null; + CIDSystemInfo ros = null; if (ttf.getTableMap().containsKey("gcid")) { // Apple's AAT fonts have a "gcid" table with CID info @@ -338,13 +442,13 @@ final class FileSystemFontProvider exten String registryName = new String(bytes, 10, 64, Charsets.US_ASCII).trim(); String orderName = new String(bytes, 76, 64, Charsets.US_ASCII).trim(); int supplementVersion = bytes[140] << 8 & bytes[141]; - ros = new PDCIDSystemInfo(registryName, orderName, supplementVersion); + ros = new CIDSystemInfo(registryName, orderName, supplementVersion); } format = "TTF"; fontInfoList.add(new FSFontInfo(file, FontFormat.TTF, ttf.getName(), ros, usWeightClass, sFamilyClass, ulCodePageRange1, ulCodePageRange2, - macStyle, panose)); + macStyle, panose, this)); } if (LOG.isTraceEnabled()) @@ -386,7 +490,7 @@ final class FileSystemFontProvider exten { Type1Font type1 = Type1Font.createWithPFB(input); fontInfoList.add(new FSFontInfo(pfbFile, FontFormat.PFB, type1.getName(), - null, -1, -1, 0, 0, -1, null)); + null, -1, -1, 0, 0, -1, null, this)); if (LOG.isTraceEnabled()) { Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java?rev=1690560&r1=1690559&r2=1690560&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FontInfo.java Mon Jul 13 01:11:31 2015 @@ -39,7 +39,7 @@ public abstract class FontInfo /** * Returns the CIDSystemInfo associated with the font, if any. */ - public abstract PDCIDSystemInfo getCIDSystemInfo(); + public abstract CIDSystemInfo getCIDSystemInfo(); /** * Returns a new FontBox font instance for the font. Implementors of this method must not 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=1690560&r1=1690559&r2=1690560&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 Jul 13 01:11:31 2015 @@ -276,7 +276,7 @@ public class PDCIDFontType2 extends PDCI LOG.warn("Trying to map multi-byte character using 'cmap', result will be poor"); } - // a non-embedded font always has a cmap (otherwise ExternalFonts won't load it) + // a non-embedded font always has a cmap (otherwise FontMapper won't load it) return cmap.getGlyphId(unicode.codePointAt(0)); } } Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java?rev=1690560&r1=1690559&r2=1690560&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/PDPanoseClassification.java Mon Jul 13 01:11:31 2015 @@ -17,13 +17,15 @@ package org.apache.pdfbox.pdmodel.font; +import java.io.Serializable; + /** * Represents a 10-byte PANOSE classification. * * @link http://www.monotype.com/services/pan2 * @author John Hewson */ -public class PDPanoseClassification +public class PDPanoseClassification implements Serializable { private final byte[] bytes;