imagen - java itext table
Acceder a las variantes de glifos OpenType en iText (1)
Al compilar documentos PDF con fuentes OpenType en iText, deseo acceder a las variantes de glifos desde la fuente, específicamente las figuras tabulares. Como las variantes de glifos OpenType no tienen índices Unicode, no estoy seguro de cómo especificar que deseo usar un conjunto particular de variantes (figuras tabulares) o llamar a un glifo específico por su ID de glifo. Solo estoy buscando el nombre de clase iText relevante, si existe.
Esto no parece posible ni en la última etiqueta 5.5.8 , ni en la rama master de iText.
Como se explica en este artículo y en la especificación de archivo de fuentes OpenType de Microsoft, las variantes de glifos se almacenan en la Glyph Substitution Table (GSUB)
de un archivo de fuente. El acceso a las variantes del glifo requiere leer esta tabla del archivo, que en realidad se implementa en la clase com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader
, aunque esta clase está deshabilitada por el momento.
La llamada a readGsubTable()
en la clase com.itextpdf.text.pdf.TrueTypeFontUnicode
está comentada.
void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException {
super.process(ttfAfm, preload);
//readGsubTable();
}
Resulta que esta línea está deshabilitada por algún motivo, ya que el código en realidad no funciona si intentas activarlo.
Desafortunadamente, no hay forma de usar variantes de glifos, ya que la información de sustitución nunca se carga desde el archivo de fuente.
Actualizar
La respuesta original fue sobre la posibilidad de utilizar iText API
para acceder a las variantes de glifos de manera iText API
, que todavía no está disponible. Sin embargo, el código de bajo nivel está en su lugar y se puede usar después de algunos hackers para acceder a la tabla de mapeo de sustitución de glifos.
Cuando se llama a read()
, GlyphSubstitutionTableReader
lee la tabla GSUB
y aplana las sustituciones de todas las características en un mapa Map<Integer, List<Integer>> rawLigatureSubstitutionMap
. Los nombres simbólicos de las características están actualmente descartados por OpenTypeFontTableReader
. rawLigatureSubstitutionMap
mapea una variante glyphId
a un glyphId
base, o un glyphId
ligadura a una secuencia de glyphIds
como este:
629 -> 66 // a.feature -> a
715 -> 71, 71, 77 // ffl ligature
Este mapeo se puede invertir para obtener todas las variantes para un glyphId
base. Por lo tanto, todos los glifos extendidos con valores Unicode desconocidos pueden determinarse a través de su conexión a un glifo base o una secuencia de glifos.
A continuación, para poder escribir un glifo en PDF, necesitamos saber un valor unicode para ese glyphId
. Una relación unicode -> glyphId
está mapeada por un campo cmap31
en TrueTypeFont
. Invertir el mapa da unicode por glyphId.
Afinando
rawLigatureSubstitutionMap
no se puede acceder en GlyphSubstitutionTableReader
, ya que es un miembro private
y no tiene un acceso GlyphSubstitutionTableReader
getter. El truco más simple sería copiar y pegar la clase original y agregar un getter para el mapa:
public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader {
// copy-pasted code ...
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawLigatureSubstitutionMap;
}
}
El siguiente problema es que GlyphSubstitutionTableReader
necesita un desplazamiento para la tabla GSUB
, información que se almacena en protected HashMap<String, int[]> tables
de la clase TrueTypeFont
. Una clase auxiliar colocada en el mismo paquete reducirá el acceso a los miembros protegidos de TrueTypeFont
.
package com.itextpdf.text.pdf;
import com.itextpdf.text.pdf.fonts.otf.FontReadingException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class GsubHelper {
private Map<Integer, List<Integer>> rawSubstitutionMap;
public GsubHelper(TrueTypeFont font) {
// get tables offsets from the font instance
Map<String, int[]> tables = font.tables;
if (tables.get("GSUB") != null) {
HackedGlyphSubstitutionTableReader gsubReader;
try {
gsubReader = new HackedGlyphSubstitutionTableReader(
font.rf, tables.get("GSUB")[0], glyphToCharacterMap, font.glyphWidthsByIndex);
gsubReader.read();
} catch (IOException | FontReadingException e) {
throw new IllegalStateException(e.getMessage());
}
rawSubstitutionMap = gsubReader.getRawSubstitutionMap();
}
}
/** Returns a glyphId substitution map
*/
public Map<Integer, List<Integer>> getRawSubstitutionMap() {
return rawSubstitutionMap;
}
}
Sería mejor extender TrueTypeFont
, pero eso no funcionaría con los métodos de fábrica createFont()
de BaseFont
, que se basa en nombres de clases codificadas para crear una fuente.