84 lines
2.5 KiB
Java
84 lines
2.5 KiB
Java
// Copyright 2011 Google Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package com.google.typography.font.compression;
|
|
|
|
import com.google.common.collect.Lists;
|
|
import com.google.common.collect.Maps;
|
|
import com.google.typography.font.sfntly.Font;
|
|
import com.google.typography.font.sfntly.Tag;
|
|
import com.google.typography.font.sfntly.table.core.CMap;
|
|
import com.google.typography.font.sfntly.table.core.CMapTable;
|
|
import com.google.typography.font.sfntly.table.core.MaximumProfileTable;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Experimental CMap encoder, based primarily on writing the _inverse_ encoding.
|
|
*
|
|
* @author raph@google.com (Raph Levien)
|
|
*/
|
|
public class CmapEncoder {
|
|
|
|
public static byte[] encode(Font font) {
|
|
int nGlyphs = font.<MaximumProfileTable>getTable(Tag.maxp).numGlyphs();
|
|
CMapTable cmapTable = font.getTable(Tag.cmap);
|
|
CMap cmap = getBestCMap(cmapTable);
|
|
Map<Integer, Integer> invEncoding = Maps.newHashMap();
|
|
List<Integer> exceptions = Lists.newArrayList();
|
|
for (Integer i : cmap) {
|
|
int glyphId = cmap.glyphId(i);
|
|
if (invEncoding.containsKey(glyphId)) {
|
|
exceptions.add(i);
|
|
exceptions.add(glyphId);
|
|
} else {
|
|
invEncoding.put(glyphId, i);
|
|
}
|
|
}
|
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
|
int last = -1;
|
|
for (int i = 0; i < nGlyphs; i++) {
|
|
if (invEncoding.containsKey(i)) {
|
|
int value = invEncoding.get(i);
|
|
int delta = value - last;
|
|
writeVShort(os, delta);
|
|
last = value;
|
|
} else {
|
|
writeVShort(os, 0);
|
|
}
|
|
}
|
|
for (int i : exceptions) {
|
|
writeVShort(os, i);
|
|
}
|
|
return os.toByteArray();
|
|
}
|
|
|
|
private static CMap getBestCMap(CMapTable cmapTable) {
|
|
for (CMap cmap : cmapTable) {
|
|
if (cmap.format() == CMap.CMapFormat.Format12.value()) {
|
|
return cmap;
|
|
}
|
|
}
|
|
for (CMap cmap : cmapTable) {
|
|
if (cmap.format() == CMap.CMapFormat.Format4.value()) {
|
|
return cmap;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// A simple signed varint encoding
|
|
static void writeVShort(ByteArrayOutputStream os, int value) {
|
|
if (value >= 0x2000 || value < -0x2000) {
|
|
os.write((byte)(0x80 | ((value >> 14) & 0x7f)));
|
|
}
|
|
if (value >= 0x40 || value < -0x40) {
|
|
os.write((byte)(0x80 | ((value >> 7) & 0x7f)));
|
|
}
|
|
os.write((byte)(value & 0x7f));
|
|
}
|
|
}
|