You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ja...@apache.org on 2015/04/09 07:58:21 UTC
svn commit: r1672243 - in /pdfbox/trunk:
fontbox/src/main/java/org/apache/fontbox/ttf/
pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/
Author: jahewson
Date: Thu Apr 9 05:58:20 2015
New Revision: 1672243
URL: http://svn.apache.org/r1672243
Log:
PDFBOX-2752: Support for TrueType collections (.ttc)
Added:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java (with props)
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java (with props)
Modified:
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFDataStream.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/font/FileSystemFontProvider.java
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/MemoryTTFDataStream.java Thu Apr 9 05:58:20 2015
@@ -28,7 +28,7 @@ import java.io.InputStream;
* @author Ben Litchfield
*
*/
-public class MemoryTTFDataStream extends TTFDataStream
+class MemoryTTFDataStream extends TTFDataStream
{
private byte[] data = null;
private int currentPosition = 0;
@@ -38,7 +38,7 @@ public class MemoryTTFDataStream extends
* @param is The stream of read from.
* @throws IOException If an error occurs while reading from the stream.
*/
- public MemoryTTFDataStream( InputStream is ) throws IOException
+ MemoryTTFDataStream( InputStream is ) throws IOException
{
try
{
@@ -60,8 +60,6 @@ public class MemoryTTFDataStream extends
}
}
-
-
/**
* Read an unsigned byte.
* @return An unsigned byte.
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/OTFParser.java Thu Apr 9 05:58:20 2015
@@ -24,7 +24,7 @@ import java.io.InputStream;
/**
* OpenType font file parser.
*/
-public class OTFParser extends TTFParser
+public final class OTFParser extends TTFParser
{
/**
* Constructor.
@@ -74,13 +74,13 @@ public class OTFParser extends TTFParser
}
@Override
- public OpenTypeFont parse(TTFDataStream raf) throws IOException
+ protected OpenTypeFont parse(TTFDataStream raf) throws IOException
{
return (OpenTypeFont)super.parse(raf);
}
-
+
@Override
- protected OpenTypeFont newFont(TTFDataStream raf)
+ OpenTypeFont newFont(TTFDataStream raf)
{
return new OpenTypeFont(raf);
}
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/RAFDataStream.java Thu Apr 9 05:58:20 2015
@@ -28,7 +28,7 @@ import java.io.RandomAccessFile;
*
* @author Ben Litchfield
*/
-public class RAFDataStream extends TTFDataStream
+class RAFDataStream extends TTFDataStream
{
private RandomAccessFile raf = null;
private File ttfFile = null;
@@ -43,7 +43,7 @@ public class RAFDataStream extends TTFDa
*
* @see RandomAccessFile#RandomAccessFile( String, String )
*/
- public RAFDataStream(String name, String mode) throws FileNotFoundException
+ RAFDataStream(String name, String mode) throws FileNotFoundException
{
this( new File( name ), mode );
}
@@ -58,7 +58,7 @@ public class RAFDataStream extends TTFDa
*
* @see RandomAccessFile#RandomAccessFile( File, String )
*/
- public RAFDataStream(File file, String mode) throws FileNotFoundException
+ RAFDataStream(File file, String mode) throws FileNotFoundException
{
raf = new RandomAccessFile( file, mode );
ttfFile = file;
Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java?rev=1672243&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java Thu Apr 9 05:58:20 2015
@@ -0,0 +1,91 @@
+/*
+ * 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.fontbox.ttf;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * A wrapper for a TTF stream inside a TTC file, does not close the underlying shared stream.
+ *
+ * @author John Hewson
+ */
+class TTCDataStream extends TTFDataStream
+{
+ private final TTFDataStream stream;
+
+ TTCDataStream(TTFDataStream stream)
+ {
+ this.stream = stream;
+ }
+
+ @Override
+ public int read() throws IOException
+ {
+ return stream.read();
+ }
+
+ @Override
+ public long readLong() throws IOException
+ {
+ return stream.readLong();
+ }
+
+ @Override
+ public int readUnsignedShort() throws IOException
+ {
+ return stream.readUnsignedShort();
+ }
+
+ @Override
+ public short readSignedShort() throws IOException
+ {
+ return stream.readSignedShort();
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ // don't close the underlying stream, as it is shared by all fonts from the same TTC
+ // TrueTypeCollection.close() must be called instead
+ }
+
+ @Override
+ public void seek(long pos) throws IOException
+ {
+ stream.seek(pos);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ return stream.read(b, off, len);
+ }
+
+ @Override
+ public long getCurrentPosition() throws IOException
+ {
+ return stream.getCurrentPosition();
+ }
+
+ @Override
+ public InputStream getOriginalData() throws IOException
+ {
+ return stream.getOriginalData();
+ }
+}
Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTCDataStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFDataStream.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFDataStream.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFDataStream.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFDataStream.java Thu Apr 9 05:58:20 2015
@@ -28,11 +28,13 @@ import java.util.TimeZone;
* An interface into a data stream.
*
* @author Ben Litchfield
- *
*/
-public abstract class TTFDataStream implements Closeable
+abstract class TTFDataStream implements Closeable
{
-
+ TTFDataStream()
+ {
+ }
+
/**
* Read a 16.16 fixed value, where the first 16 bits are the decimal and the last 16 bits are the fraction.
*
@@ -205,6 +207,15 @@ public abstract class TTFDataStream impl
}
/**
+ * Reads a tag, an arrau of four uint8s used to identify a script, language system, feature,
+ * or baseline.
+ */
+ public String readTag() throws IOException
+ {
+ return new String(read(4), "US-ASCII");
+ }
+
+ /**
* Close the underlying resources.
*
* @throws IOException If there is an error closing the resources.
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TTFParser.java Thu Apr 9 05:58:20 2015
@@ -116,7 +116,7 @@ public class TTFParser
* @return A true type font.
* @throws IOException If there is an error parsing the true type font.
*/
- public TrueTypeFont parse(TTFDataStream raf) throws IOException
+ TrueTypeFont parse(TTFDataStream raf) throws IOException
{
TrueTypeFont font = newFont(raf);
font.setVersion(raf.read32Fixed());
@@ -138,7 +138,7 @@ public class TTFParser
return font;
}
- protected TrueTypeFont newFont(TTFDataStream raf)
+ TrueTypeFont newFont(TTFDataStream raf)
{
return new TrueTypeFont(raf);
}
Added: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java?rev=1672243&view=auto
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java (added)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java Thu Apr 9 05:58:20 2015
@@ -0,0 +1,127 @@
+/*
+ * 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.fontbox.ttf;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A TrueType Collection, now more properly known as a "Font Collection" as it may contain either
+ * TrueType or OpenType fonts.
+ *
+ * @author John Hewson
+ */
+public class TrueTypeCollection implements Closeable
+{
+ private final TTFDataStream stream;
+ private final List<TrueTypeFont> fonts;
+
+ /**
+ * Creates a new TrueTypeCollection from a .ttc file.
+ *
+ * @param file The TTC file.
+ * @throws IOException If the font could not be parsed.
+ */
+ public TrueTypeCollection(File file) throws IOException
+ {
+ this(new RAFDataStream(file, "r"));
+ }
+
+ /**
+ * Creates a new TrueTypeCollection from a .ttc input stream.
+ *
+ * @param stream A TTC input stream.
+ * @throws IOException If the font could not be parsed.
+ */
+ public TrueTypeCollection(InputStream stream) throws IOException
+ {
+ this(new MemoryTTFDataStream(stream));
+ }
+
+ /**
+ * Creates a new TrueTypeCollection from a TTC stream.
+ *
+ * @param stream The TTF file.
+ * @throws IOException If the font could not be parsed.
+ */
+ TrueTypeCollection(TTFDataStream stream) throws IOException
+ {
+ this.stream = stream;
+
+ // TTC header
+ String tag = stream.readTag();
+ if (!tag.equals("ttcf"))
+ {
+ throw new IOException("Missing TTC header");
+ }
+ float version = stream.read32Fixed();
+ int numFonts = (int)stream.readUnsignedInt();
+ long[] fontOffsets = new long[numFonts];
+ for (int i = 0; i < numFonts; i++)
+ {
+ fontOffsets[i] = stream.readUnsignedInt();
+ }
+ if (version >= 2)
+ {
+ int ulDsigTag = stream.readUnsignedShort();
+ int ulDsigLength = stream.readUnsignedShort();
+ int ulDsigOffset = stream.readUnsignedShort();
+ }
+
+ // lazy-load the fonts
+ List<TrueTypeFont> fonts = new ArrayList<TrueTypeFont>();
+ for (int i = 0; i < numFonts; i++)
+ {
+ stream.seek(fontOffsets[i]);
+ if (stream.readTag().equals("OTTO"))
+ {
+ stream.seek(fontOffsets[i]);
+ OTFParser parser = new OTFParser(false, true);
+ OpenTypeFont otf = parser.parse(new TTCDataStream(stream));
+ fonts.add(otf);
+ }
+ else
+ {
+ stream.seek(fontOffsets[i]);
+ TTFParser parser = new TTFParser(false, true);
+ TrueTypeFont ttf = parser.parse(new TTCDataStream(stream));
+ fonts.add(ttf);
+ }
+ }
+ this.fonts = Collections.unmodifiableList(fonts);
+ }
+
+ /**
+ * Returns the fonts in the collection, these may be {@link OpenTypeFont} instances.
+ */
+ public List<TrueTypeFont> getFonts()
+ {
+ return fonts;
+ }
+
+ @Override
+ public void close() throws IOException
+ {
+ stream.close();
+ }
+}
Propchange: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeCollection.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java?rev=1672243&r1=1672242&r2=1672243&view=diff
==============================================================================
--- pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java (original)
+++ pdfbox/trunk/fontbox/src/main/java/org/apache/fontbox/ttf/TrueTypeFont.java Thu Apr 9 05:58:20 2015
@@ -18,6 +18,7 @@ package org.apache.fontbox.ttf;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
+import java.io.Closeable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -32,7 +33,7 @@ import org.apache.fontbox.util.BoundingB
*
* @author Ben Litchfield
*/
-public class TrueTypeFont implements Type1Equivalent
+public class TrueTypeFont implements Type1Equivalent, Closeable
{
private float version;
private int numberOfGlyphs = -1;
@@ -51,11 +52,7 @@ public class TrueTypeFont implements Typ
data = fontData;
}
- /**
- * Close the underlying resources.
- *
- * @throws IOException If there is an error closing the resources.
- */
+ @Override
public void close() throws IOException
{
data.close();
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=1672243&r1=1672242&r2=1672243&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 Thu Apr 9 05:58:20 2015
@@ -23,6 +23,7 @@ import org.apache.fontbox.cff.CFFFont;
import org.apache.fontbox.cff.CFFParser;
import org.apache.fontbox.ttf.NamingTable;
import org.apache.fontbox.ttf.TTFParser;
+import org.apache.fontbox.ttf.TrueTypeCollection;
import org.apache.fontbox.ttf.TrueTypeFont;
import org.apache.fontbox.type1.Type1Font;
import org.apache.fontbox.util.autodetect.FontFileFinder;
@@ -78,7 +79,12 @@ final class FileSystemFontProvider exten
if (fontFile.getPath().toLowerCase().endsWith(".ttf") ||
fontFile.getPath().toLowerCase().endsWith(".otf"))
{
- addOpenTypeFont(fontFile);
+ addTrueTypeFont(fontFile);
+ }
+ else if (fontFile.getPath().toLowerCase().endsWith(".ttc") ||
+ fontFile.getPath().toLowerCase().endsWith(".otc"))
+ {
+ addTrueTypeCollection(fontFile);
}
else if (fontFile.getPath().toLowerCase().endsWith(".pfb"))
{
@@ -98,25 +104,62 @@ final class FileSystemFontProvider exten
}
/**
+ * Adds a TTC or OTC to the file cache. To reduce memory, the parsed font is not cached.
+ */
+ private void addTrueTypeCollection(File ttcFile) throws IOException
+ {
+ TrueTypeCollection ttc = null;
+ try
+ {
+ ttc = new TrueTypeCollection(ttcFile);
+ for (TrueTypeFont ttf : ttc.getFonts())
+ {
+ addTrueTypeFontImpl(ttf, ttcFile);
+ }
+ }
+ catch (NullPointerException e) // TTF parser is buggy
+ {
+ LOG.error("Could not load font file: " + ttcFile, e);
+ }
+ catch (IOException e)
+ {
+ LOG.error("Could not load font file: " + ttcFile, e);
+ }
+ finally
+ {
+ if (ttc != null)
+ {
+ ttc.close();
+ }
+ }
+ }
+
+ /**
* Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font is not cached.
*/
- private void addOpenTypeFont(File otfFile) throws IOException
+ private void addTrueTypeFont(File ttfFile) throws IOException
{
TTFParser ttfParser = new TTFParser(false, true);
- TrueTypeFont ttf = null;
try
{
- ttf = ttfParser.parse(otfFile);
+ TrueTypeFont ttf = ttfParser.parse(ttfFile);
+ addTrueTypeFontImpl(ttf, ttfFile);
}
catch (NullPointerException e) // TTF parser is buggy
{
- LOG.error("Could not load font file: " + otfFile, e);
+ LOG.error("Could not load font file: " + ttfFile, e);
}
catch (IOException e)
{
- LOG.error("Could not load font file: " + otfFile, e);
+ LOG.error("Could not load font file: " + ttfFile, e);
}
-
+ }
+
+ /**
+ * Adds an OTF or TTF font to the file cache. To reduce memory, the parsed font is not cached.
+ */
+ private void addTrueTypeFontImpl(TrueTypeFont ttf, File file) throws IOException
+ {
try
{
// check for 'name' table
@@ -130,7 +173,7 @@ final class FileSystemFontProvider exten
if (nameTable == null)
{
- LOG.warn("Missing 'name' table in font " + otfFile);
+ LOG.warn("Missing 'name' table in font " + file);
}
else
{
@@ -143,12 +186,12 @@ final class FileSystemFontProvider exten
if (ttf.getTableMap().get("CFF ") != null)
{
format = "OTF";
- cffFontFiles.putAll(toMap(getNames(ttf), otfFile));
+ cffFontFiles.putAll(toMap(getNames(ttf), file));
}
else
{
format = "TTF";
- ttfFontFiles.putAll(toMap(getNames(ttf), otfFile));
+ ttfFontFiles.putAll(toMap(getNames(ttf), file));
}
if (LOG.isTraceEnabled())
@@ -159,7 +202,7 @@ final class FileSystemFontProvider exten
}
else
{
- LOG.warn("Missing 'name' entry for PostScript name in font " + otfFile);
+ LOG.warn("Missing 'name' entry for PostScript name in font " + file);
}
}
}
@@ -196,7 +239,7 @@ final class FileSystemFontProvider exten
input.close();
}
}
-
+
@Override
public synchronized TrueTypeFont getTrueTypeFont(String postScriptName)
{
@@ -209,10 +252,9 @@ final class FileSystemFontProvider exten
File file = ttfFontFiles.get(postScriptName);
if (file != null)
{
- TTFParser ttfParser = new TTFParser(false, true);
try
{
- ttf = ttfParser.parse(file);
+ ttf = readTrueTypeFont(postScriptName, file);
for (String name : getNames(ttf))
{
@@ -236,6 +278,27 @@ final class FileSystemFontProvider exten
return null;
}
+ private TrueTypeFont readTrueTypeFont(String postScriptName, File file) throws IOException
+ {
+ if (file.getName().toLowerCase().endsWith(".ttc"))
+ {
+ TrueTypeCollection ttc = new TrueTypeCollection(file);
+ for (TrueTypeFont ttf : ttc.getFonts())
+ {
+ if (ttf.getName().equals(postScriptName))
+ {
+ return ttf;
+ }
+ }
+ throw new IOException("Font " + postScriptName + " not found in " + file);
+ }
+ else
+ {
+ TTFParser ttfParser = new TTFParser(false, true);
+ return ttfParser.parse(file);
+ }
+ }
+
@Override
public synchronized CFFFont getCFFFont(String postScriptName)
{
@@ -251,6 +314,7 @@ final class FileSystemFontProvider exten
InputStream input = null;
try
{
+ // todo JH: we don't yet support loading CFF fonts from OTC collectionsâ¨
input = new FileInputStream(file);
byte[] bytes = IOUtils.toByteArray(input);
CFFParser cffParser = new CFFParser();