Browse Source

integrate (very) preliminary cff support

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_CFF@1294537 13f79535-47bb-0310-9956-ffa450edef68
Temp_CFF
Glenn Adams 12 years ago
parent
commit
4104b0bbe7

+ 169
- 0
src/java/org/apache/fop/fonts/truetype/CFFUtil.java View File

@@ -0,0 +1,169 @@
/*
* 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.
*/

/* $Id$ */

package org.apache.fop.fonts.truetype;

import java.io.IOException;
import java.util.Map;

/**
* A utility class for working with Adobe Compact Font Format (CFF) data. See
* Adobe Technical Note #5176 "The Compact Font Format Specification" for more
* information.
*/
final class CFFUtil {

private CFFUtil() {
}

/**
* Extract glyph subset of CFF table ENTRY from input font IN according to
* the specified GLYPHS.
* @param in input font file reader
* @param entry directory entry describing CFF table in input file
* @param glyphs map of original glyph indices to subset indices
* @returns an array of bytes representing a well formed CFF table containing
* the specified glyph subset
* @throws IOException in case of an I/O exception when reading from input font
*/
public static byte[] extractGlyphSubset
( FontFileReader in, TTFDirTabEntry entry, Map<Integer, Integer> glyphs )
throws IOException {

// 1. read CFF data from IN, where ENTRY points at start of CFF table
// 2. while reading CFF data, accumulate necessary information to output subset
// of glyphs, where GLYPHS.keySet() enumerates the desired glyphs, and
// GLYPHS.values() (for the keys) enumerates the new (output) glyph indices
// for the desired glyph subset
// 3. return a BLOB containing a well-formed CFF font according to the Adobe
// spec and constrained as needed by http://www.microsoft.com/typography/otspec/cff.htm

long cffOffset = entry.getOffset();

// HEADER

in.seekSet ( cffOffset );
int major = in.readTTFUByte();
int minor = in.readTTFUByte();
int hdrSize = in.readTTFUByte();
int hdrOffSize = in.readTTFUByte();

// Name INDEX

in.seekSet ( cffOffset + hdrSize );
int nameIndexCount = in.readTTFUShort();
if ( nameIndexCount > 0 ) {
int nameIndexOffsetSize = in.readTTFUByte();
long nameIndexOffsets[] = new long [ nameIndexCount + 1 ];
if ( nameIndexOffsetSize == 1 ) {
for ( int i = 0, n = nameIndexCount + 1; i < n; i++ ) {
nameIndexOffsets [ i ] = in.readTTFUByte();
}
} else if ( nameIndexOffsetSize == 2 ) {
for ( int i = 0, n = nameIndexCount + 1; i < n; i++ ) {
nameIndexOffsets [ i ] = in.readTTFUShort();
}
} else if ( nameIndexOffsetSize == 4 ) {
for ( int i = 0, n = nameIndexCount + 1; i < n; i++ ) {
nameIndexOffsets [ i ] = in.readTTFULong();
}
} else {
throw new RuntimeException ( "invalid offset size, got " + nameIndexOffsetSize + ", expected 1, 2, or 4" );
}
int nameIndexDataOffset = in.getCurrentPos() - 1;
String[] names = new String [ nameIndexCount ];
for ( int i = 0, n = names.length, nOffsets = nameIndexOffsets.length; i < n; i++ ) {
assert ( i + 1 ) < nOffsets;
long offCurrent = nameIndexOffsets [ i ];
long offNext = nameIndexOffsets [ i + 1 ];
long numBytes = offNext - offCurrent;
String name;
if ( numBytes > 0 ) {
if ( numBytes < Integer.MAX_VALUE ) {
long nameOffset = nameIndexDataOffset + offCurrent;
if ( nameOffset < Integer.MAX_VALUE ) {
byte[] nameBytes = in.getBytes ( (int) nameOffset, (int) numBytes );
name = new String ( nameBytes, 0, (int) numBytes, "US-ASCII" );
} else {
throw new UnsupportedOperationException ( "unsupported index offset value, got " + nameOffset + ", expected less than " + Integer.MAX_VALUE );
}
} else {
throw new UnsupportedOperationException ( "unsupported indexed data length, got " + numBytes + ", expected less than " + Integer.MAX_VALUE );
}
} else {
name = "";
}
names [ i ] = name;
}
in.seekSet ( nameIndexDataOffset + nameIndexOffsets [ nameIndexCount ] );
}

// Top Dict INDEX

int topDictIndexCount = in.readTTFUShort();
if ( topDictIndexCount > 0 ) {
int topDictIndexOffsetSize = in.readTTFUByte();
long topDictIndexOffsets[] = new long [ topDictIndexCount + 1 ];
if ( topDictIndexOffsetSize == 1 ) {
for ( int i = 0, n = topDictIndexCount + 1; i < n; i++ ) {
topDictIndexOffsets [ i ] = in.readTTFUByte();
}
} else if ( topDictIndexOffsetSize == 2 ) {
for ( int i = 0, n = topDictIndexCount + 1; i < n; i++ ) {
topDictIndexOffsets [ i ] = in.readTTFUShort();
}
} else if ( topDictIndexOffsetSize == 4 ) {
for ( int i = 0, n = topDictIndexCount + 1; i < n; i++ ) {
topDictIndexOffsets [ i ] = in.readTTFULong();
}
} else {
throw new RuntimeException ( "invalid offset size, got " + topDictIndexOffsetSize + ", expected 1, 2, or 4" );
}
int topDictIndexDataOffset = in.getCurrentPos() - 1;
byte[][] topDicts = new byte [ topDictIndexCount ][];
for ( int i = 0, n = topDicts.length, nOffsets = topDictIndexOffsets.length; i < n; i++ ) {
assert ( i + 1 ) < nOffsets;
long offCurrent = topDictIndexOffsets [ i ];
long offNext = topDictIndexOffsets [ i + 1 ];
long numBytes = offNext - offCurrent;
byte[] topDict;
if ( numBytes > 0 ) {
if ( numBytes < Integer.MAX_VALUE ) {
long topDictOffset = topDictIndexDataOffset + offCurrent;
if ( topDictOffset < Integer.MAX_VALUE ) {
byte[] topDictBytes = in.getBytes ( (int) topDictOffset, (int) numBytes );
topDict = topDictBytes;
} else {
throw new UnsupportedOperationException ( "unsupported index offset value, got " + topDictOffset + ", expected less than " + Integer.MAX_VALUE );
}
} else {
throw new UnsupportedOperationException ( "unsupported indexed data length, got " + numBytes + ", expected less than " + Integer.MAX_VALUE );
}
} else {
topDict = new byte [ 0 ];
}
topDicts [ i ] = topDict;
}
in.seekSet ( topDictIndexDataOffset + topDictIndexOffsets [ topDictIndexCount ] );
}

return new byte[] {};
}

}

+ 0
- 5
src/java/org/apache/fop/fonts/truetype/TTFFontLoader.java View File

@@ -109,11 +109,6 @@ public class TTFFontLoader extends FontLoader {


private void buildFont(TTFFile ttf, String ttcFontName) {
if (ttf.isCFF()) {
throw new UnsupportedOperationException(
"OpenType fonts with CFF data are not supported, yet");
}

boolean isCid = this.embedded;
if (this.encodingMode == EncodingMode.SINGLE_BYTE) {
isCid = false;

+ 85
- 35
src/java/org/apache/fop/fonts/truetype/TTFSubSetFile.java View File

@@ -43,6 +43,7 @@ public class TTFSubSetFile extends TTFFile {
* Offsets in name table to be filled out by table.
* The offsets are to the checkSum field
*/
private int cffDirOffset = 0;
private int cvtDirOffset = 0;
private int fpgmDirOffset = 0;
private int glyfDirOffset = 0;
@@ -86,10 +87,8 @@ public class TTFSubSetFile extends TTFFile {
private int determineTableCount() {
int numTables = 4; //4 req'd tables: head,hhea,hmtx,maxp
if (isCFF()) {
throw new UnsupportedOperationException(
"OpenType fonts with CFF glyphs are not supported");
numTables += 1; //1 req'd table: CFF
} else {
numTables += 2; //1 req'd table: glyf,loca
if (hasCvt()) {
numTables++;
}
@@ -99,6 +98,7 @@ public class TTFSubSetFile extends TTFFile {
if (hasPrep()) {
numTables++;
}
numTables += 2; //1 req'd table: loca,glyf
}
return numTables;
}
@@ -109,10 +109,17 @@ public class TTFSubSetFile extends TTFFile {
private void createDirectory() {
int numTables = determineTableCount();
// Create the TrueType header
writeByte((byte)0);
writeByte((byte)1);
writeByte((byte)0);
writeByte((byte)0);
if (isCFF() ) {
writeByte((byte)'O');
writeByte((byte)'T');
writeByte((byte)'T');
writeByte((byte)'O');
} else {
writeByte((byte)0);
writeByte((byte)1);
writeByte((byte)0);
writeByte((byte)0);
}
realSize += 4;

writeUShort(numTables);
@@ -131,24 +138,6 @@ public class TTFSubSetFile extends TTFFile {
realSize += 2;

// Create space for the table entries
if (hasCvt()) {
writeString("cvt ");
cvtDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

if (hasFpgm()) {
writeString("fpgm");
fpgmDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

writeString("glyf");
glyfDirOffset = currentPos;
currentPos += 12;
realSize += 16;

writeString("head");
headDirOffset = currentPos;
@@ -165,22 +154,49 @@ public class TTFSubSetFile extends TTFFile {
currentPos += 12;
realSize += 16;

writeString("loca");
locaDirOffset = currentPos;
currentPos += 12;
realSize += 16;

writeString("maxp");
maxpDirOffset = currentPos;
currentPos += 12;
realSize += 16;

if (hasCvt()) {
writeString("cvt ");
cvtDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

if (hasFpgm()) {
writeString("fpgm");
fpgmDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

if (hasPrep()) {
writeString("prep");
prepDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

if (isCFF()) {
writeString("CFF ");
cffDirOffset = currentPos;
currentPos += 12;
realSize += 16;
} else {
writeString("loca");
locaDirOffset = currentPos;
currentPos += 12;
realSize += 16;

writeString("glyf");
glyfDirOffset = currentPos;
currentPos += 12;
realSize += 16;
}

}


@@ -441,6 +457,35 @@ public class TTFSubSetFile extends TTFFile {
}
}

/**
* Create the CFF table
*/
private void createCff(FontFileReader in, Map glyphs) throws IOException {
TTFDirTabEntry entry = (TTFDirTabEntry) dirTabs.get("CFF ");
int size = 0;
int start = 0;
if ( entry != null ) {
pad4();
start = currentPos;

byte[] cffData = CFFUtil.extractGlyphSubset ( in, entry, glyphs );
int cffDataLength = cffData.length;
System.arraycopy ( cffData, 0, output, currentPos, cffDataLength );
currentPos += cffDataLength;
realSize += cffDataLength;
size = currentPos - start;

int checksum = getCheckSum(start, size);
writeULong(cffDirOffset, checksum);
writeULong(cffDirOffset + 4, start);
writeULong(cffDirOffset + 8, size);
currentPos += 12;
realSize += 12;

} else {
throw new IOException("Can't find CFF table");
}
}

/**
* Create the hmtx table by copying metrics from original
@@ -509,9 +554,10 @@ public class TTFSubSetFile extends TTFFile {
getNumGlyphs(in);
readHorizontalHeader(in);
readHorizontalMetrics(in);
readIndexToLocation(in);

scanGlyphs(in, subsetGlyphs);
if (!isCFF()) {
readIndexToLocation(in);
scanGlyphs(in, subsetGlyphs);
}

createDirectory(); // Create the TrueType header and directory

@@ -539,8 +585,12 @@ public class TTFSubSetFile extends TTFFile {
log.debug("TrueType: prep table not present. Skipped.");
}

createLoca(subsetGlyphs.size()); // create empty loca table
createGlyf(in, subsetGlyphs); //create glyf table and update loca table
if (isCFF()) {
createCff(in, subsetGlyphs);
} else {
createLoca(subsetGlyphs.size()); // create empty loca table
createGlyf(in, subsetGlyphs); //create glyf table and update loca table
}

pad4();
createCheckSumAdjustment();

Loading…
Cancel
Save