2015-11-17 26 views
26

Quando si creano documenti PDF con i font OpenType in iText, desidero accedere alle varianti di glifo all'interno del carattere, in particolare figure tabulari. Poiché le varianti di glifi di OpenType non hanno indici Unicode, non sono sicuro di come specificare che voglio usare un particolare insieme di varianti (figure tabulari) o di chiamare un glifo specifico tramite il suo ID di glifo. Sto solo cercando il nome della classe iText pertinente se ne esiste uno.Accesso alle varianti di glifi OpenType in iText

+0

Forse ['Class GlyphSubstitutionTableReader'] (http://api.itextpdf.com/itext/com/itextpdf/text/pdf/fonts/otf/GlyphSubstitutionTableReader.html#getGlyphSubstitutionMap()) vale la pena dare un'occhiata. Utilizza ['OpenTypeFontTableReader'] (http://api.itextpdf.com/itext/com/itextpdf/text/pdf/fonts/otf/OpenTypeFontTableReader.html) - ma, a colpo d'occhio, sembra che tu debba sapere in anticipare quale tabella si desidera leggere. (È ancora poco chiaro che cosa si può fare con il "glifo" grezzo.) – usr2564301

+0

Questo sarebbe di aiuto? La classe 'GlyphList' ha un metodo statico:' String unicodeToName (int) '[http://developers.itextpdf.com/reference/com.itextpdf.text.pdf.GlyphList] –

risposta

8

Questo non sembra essere possibile né nell'ultimo tag 5.5.8, né nel ramodi iText.

Come spiegato in this article e nelle varianti OpenType font file specification, glifi della Microsoft sono memorizzati nella Glyph Substitution Table (GSUB) di un file di font. L'accesso alle varianti di glifo richiede la lettura di questa tabella dal file, che è attualmente implementato nella classe com.itextpdf.text.pdf.fonts.otf.GlyphSubstitutionTableReader, sebbene questa classe sia disabilitata per ora.

La chiamata readGsubTable() nella classe com.itextpdf.text.pdf.TrueTypeFontUnicode è commentata.

void process(byte ttfAfm[], boolean preload) throws DocumentException, IOException { 
    super.process(ttfAfm, preload); 
    //readGsubTable(); 
} 

Si scopre che questa linea è disabilitata per una ragione, come il codice in realtà non funziona se si tenta di attivarlo.

Quindi, sfortunatamente, non è possibile utilizzare le varianti di glifo, poiché le informazioni di sostituzione non vengono mai caricate dal file di font.

Aggiornamento

La risposta originale era circa la possibilità di utilizzare per l'accesso iText API glifo varianti fuori dalla scatola, che non c'è ancora. Tuttavia, il codice di basso livello è a posto e può essere utilizzato dopo un po 'di hacking per accedere alla tabella di mappatura di sostituzione degli glifi.

Quando chiamato read(), il GlyphSubstitutionTableReader legge la tabella GSUB e appiattisce sostituzioni di tutte le funzioni in un unico mappa Map<Integer, List<Integer>> rawLigatureSubstitutionMap. I nomi simbolici delle funzioni sono attualmente scartati da OpenTypeFontTableReader. Il rawLigatureSubstitutionMap Mappe una variante glyphId ad una base glyphId, o una legatura glyphId ad una sequenza di glyphIds come questo:

629 -> 66 // a.feature -> a 
715 -> 71, 71, 77 // ffl ligature 

Questa mappatura può essere invertito per ottenere tutte le varianti per una base glyphId. Quindi tutti i glifi estesi con valori unicode sconosciuti possono essere individuati attraverso la loro connessione a un glifo di base, o una sequenza di glifi.

Successivamente, per poter scrivere un glifo in PDF, è necessario conoscere un valore unicode per tale glyphId. Una relazione unicode -> glyphId viene mappata da un campo cmap31 in TrueTypeFont. L'inversione della mappa dà l'unicode di glyphId.

tweaking

rawLigatureSubstitutionMap non può essere letta in GlyphSubstitutionTableReader, come si tratta di un membro private e non ha una funzione di accesso getter.L'hack semplice sarebbe quella di copiare e incollare la classe originale e aggiungere un getter per la mappa:

public class HackedGlyphSubstitutionTableReader extends OpenTypeFontTableReader { 

    // copy-pasted code ... 

    public Map<Integer, List<Integer>> getRawSubstitutionMap() { 
     return rawLigatureSubstitutionMap; 
    } 
} 

problema successivo è che GlyphSubstitutionTableReader ha bisogno di un offset per GSUB tavolo, le informazioni che sono memorizzate in protected HashMap<String, int[]> tables di TrueTypeFont di classe. Una classe helper inserita nello stesso pacchetto consentirà il collegamento tra gli utenti protetti di 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; 
    } 
} 

Sarebbe bello estendere TrueTypeFont, ma che non avrebbe funzionato con i metodi di fabbrica createFont() di BaseFont, che si basa sui nomi di classe hard coded durante la creazione di un tipo di carattere.

+0

Tu parli e citi con autorità; tuttavia, trovo difficile credere che non sia possibile analizzare le tabelle GSUB con Java. Intendi dire che anche se * puoi * analizzare una tabella GSUB, iText non contiene l'infrastruttura per lavorare con gli indici di "raw", e quindi come parte dell'aggiunta di sostituzioni di GSUB, l'attuale paradigma di gestione del testo di iText avrebbe bisogno sostituzione nella sua interezza? – usr2564301

+1

Scusate, la mia risposta è davvero troppo categorica, persino folle. Non riflette tutta la verità. Quello che intendevo era che l'API per l'utilizzo delle sostituzioni di glifi non è stata completata nella versione corrente di iText. Ma l'infrastruttura è principalmente sul posto. Può essere usato con alcuni copia-incolla e messa a punto delle classi iText. Ho intenzione di aggiornare la mia risposta con maggiori dettagli. – nolexa

+1

Penso che il basso livello di GSUB sia ok. Ogni sezione di dati sembra essere analizzata dal file (non ci sono test per questa funzionalità). Ma il livello API è incompleto, i dati grezzi rimangono incapsulati all'interno delle classi dell'infrastruttura, non consegnati all'API attraverso casi d'uso significativi. Allo stesso modo, le classi chiave di iText in questa storia non sono progettate per l'estensione, il che rende difficile personalizzare la soluzione. – nolexa