org.mabb.fontverter.cff.CffFontAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of FontVerter Show documentation
Show all versions of FontVerter Show documentation
Library for converting various font formats.
/*
* Copyright (C) Maddie Abboud 2016
*
* FontVerter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FontVerter is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FontVerter. If not, see .
*/
package org.mabb.fontverter.cff;
import org.apache.fontbox.EncodedFont;
import org.apache.fontbox.cff.*;
import org.apache.fontbox.encoding.Encoding;
import org.mabb.fontverter.converter.CFFToOpenTypeConverter;
import org.mabb.fontverter.converter.CombinedFontConverter;
import org.mabb.fontverter.converter.FontConverter;
import org.mabb.fontverter.converter.OtfToWoffConverter;
import org.mabb.fontverter.*;
import org.mabb.fontverter.opentype.GlyphMapReader;
import org.mabb.fontverter.validator.RuleValidator;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;
public class CffFontAdapter implements FVFont {
private byte[] data = new byte[]{};
private CFFFont font;
public static CffFontAdapter parse(byte[] cffData) throws IOException {
CFFFont cfffont = fontboxParse(cffData);
CffFontAdapter font = new CffFontAdapter(cfffont);
font.setData(cffData);
return font;
}
private static CFFFont fontboxParse(byte[] cffData) throws IOException {
CFFParser parser = new CFFParser();
List fonts = parser.parse(cffData);
if (fonts.size() > 1)
throw new FontNotSupportedException("Multiple CFF fonts in one file are not supported.");
return fonts.get(0);
}
public CffFontAdapter(CFFFont font) {
this.font = font;
}
public CffFontAdapter() {
}
public boolean detectFormat(byte[] fontFile) {
try {
// cff has no magic header so check if parseable to detect if cff
fontboxParse(fontFile);
return true;
} catch (Exception e) {
return false;
}
}
public void read(byte[] fontFile) throws IOException {
font = fontboxParse(fontFile);
data = fontFile;
}
public FontConverter createConverterForType(FontVerter.FontFormat fontFormat) throws FontNotSupportedException {
if (fontFormat == FontVerter.FontFormat.OTF)
return new CFFToOpenTypeConverter(this);
if (fontFormat == FontVerter.FontFormat.WOFF1)
return new CombinedFontConverter(new CFFToOpenTypeConverter(this), new OtfToWoffConverter());
if (fontFormat == FontVerter.FontFormat.WOFF2)
return new CombinedFontConverter(new CFFToOpenTypeConverter(this), new OtfToWoffConverter.OtfToWoff2Converter());
throw new FontNotSupportedException("Font conversion not supported");
}
public String getName() {
String name = font.getName();
if (name.isEmpty())
name = nonNullDictEntry("FullName", String.class);
return name;
}
public CFFFont getFont() {
return font;
}
public String getFullName() {
return nonNullDictEntry("FullName", String.class);
}
public String getFamilyName() {
String name = nonNullDictEntry("FamilyName", String.class);
if (name.isEmpty())
name = nonNullDictEntry("FullName", String.class);
return name;
}
public String getSubFamilyName() {
return nonNullDictEntry("Weight", String.class);
}
public String getVersion() {
return nonNullDictEntry("version", String.class);
}
public String getTrademarkNotice() {
return nonNullDictEntry("Notice", String.class);
}
public Integer getUnderLinePosition() {
return nonNullDictEntry("UnderlinePosition", Integer.class);
}
public int getMinX() {
return getBoundingBox().get(0);
}
public int getMinY() {
return getBoundingBox().get(1);
}
public int getMaxX() {
return getBoundingBox().get(2);
}
public int getMaxY() {
return getBoundingBox().get(3);
}
private ArrayList getBoundingBox() {
Object obj = font.getTopDict().get("FontBBox");
ArrayList boundingBox = null;
if (obj != null && obj instanceof ArrayList)
boundingBox = (ArrayList) obj;
if (boundingBox == null || boundingBox.size() < 4)
boundingBox = createDefaultBoundingBox();
return boundingBox;
}
private ArrayList createDefaultBoundingBox() {
// default is actually 0 0 0 0, but using reasonable filler vals here if we don't have a bbox
// for maybe a better result
ArrayList boundingBox;
boundingBox = new ArrayList();
boundingBox.add(30);
boundingBox.add(-2);
boundingBox.add(1300);
boundingBox.add(800);
return boundingBox;
}
@SuppressWarnings("unchecked")
public Map getGlyphIdsToNames() throws IOException {
try {
// reflection to get private map field for lazyness, !fragile!, obviously
Field mapField = FontVerterUtils.findPrivateField("gidToName", CFFCharset.class);
return (Map) mapField.get(font.getCharset());
} catch (Exception ex) {
throw new IOException(ex);
}
}
@SuppressWarnings("unchecked")
public Map getCharCodeToGlyphIds() throws IOException {
try {
Field mapField = FontVerterUtils.findPrivateField("sidOrCidToGid", CFFCharset.class);
return (Map) mapField.get(font.getCharset());
} catch (Exception ex) {
throw new IOException(ex);
}
}
public List getGlyphMaps() throws IOException {
Map glyphIdsToNames = getGlyphIdsToNames();
if (glyphIdsToNames.size() != 0)
return GlyphMapReader.readGlyphsToNames(glyphIdsToNames, getEncoding());
return GlyphMapReader.readCharCodesToGlyphs(getCharCodeToGlyphIds(), getEncoding());
}
public Encoding getEncoding() {
if (font instanceof EncodedFont) {
try {
return ((EncodedFont) font).getEncoding();
} catch (IOException e) {
return CFFStandardEncoding.getInstance();
}
}
return CFFStandardEncoding.getInstance();
}
private X nonNullDictEntry(String key, Class type) {
Object value = font.getTopDict().get(key);
if (value != null)
return (X) value;
if (type == String.class)
return (X) "";
if (type == Integer.class)
return (X) new Integer(1);
return (X) "";
}
public void setData(byte[] data) {
this.data = data;
}
public byte[] getData() {
return data;
}
public void normalize() {
}
public boolean isValid() {
return true;
}
public List getValidationErrors() {
return new ArrayList();
}
public FontProperties getProperties() {
FontProperties properties = new FontProperties();
properties.setMimeType("");
properties.setFileEnding("cff");
properties.setCssFontFaceFormat("");
return properties;
}
public List getGlyphs() throws IOException {
List glyphs = new ArrayList();
for (GlyphMapReader.GlyphMapping mapOn : getGlyphMaps()) {
CffGlyph glyph = createGlyph();
Type2CharString charStr = font.getType2CharString(mapOn.glyphId);
glyph.readType2Sequence(charStr.getType2Sequence());
glyph.map = mapOn;
glyph.charStr = charStr;
glyphs.add(glyph);
}
return glyphs;
}
public Integer getDefaultWidth() {
String key = "defaultWidthX";
if (!getPrivateDict().containsKey(key))
return 1000;
return (Integer) getPrivateDict().get(key);
}
public Integer getNominalWidth() {
String key = "nominalWidthX";
if (!getPrivateDict().containsKey(key))
return 1000;
return (Integer) getPrivateDict().get(key);
}
Map getPrivateDict() {
if (font instanceof CFFType1Font)
return ((CFFType1Font) font).getPrivateDict();
else {
Map dict = new HashMap();
for (Map dictOn : ((CFFCIDFont) font).getPrivDicts())
dict.putAll(dictOn);
return dict;
}
}
public CffGlyph createGlyph() {
CffGlyph glyph = new CffGlyph();
glyph.nominalWidth = getNominalWidth();
glyph.defaultWidth = getDefaultWidth();
glyph.advancedWidth = getDefaultWidth();
return glyph;
}
public static class CffGlyph {
private int leftSideBearing = 0;
private Integer advancedWidth;
Integer nominalWidth;
Integer defaultWidth;
public GlyphMapReader.GlyphMapping map;
public Type2CharString charStr;
public int getLeftSideBearing() {
return leftSideBearing;
}
public void setLeftSideBearing(int leftSideBearing) {
this.leftSideBearing = leftSideBearing;
}
public int getAdvanceWidth() {
return advancedWidth;
}
public void setAdvancedWidth(int advancedWidth) {
this.advancedWidth = advancedWidth;
}
public void readType2Sequence(List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy