
com.sta.cts.TTFReader Maven / Gradle / Ivy
package com.sta.cts;
import org.apache.fop.fonts.CMapSegment;
import org.w3c.dom.Document;
import org.apache.fop.fonts.truetype.FontFileReader;
import java.io.FileInputStream;
import java.util.ArrayList;
import org.w3c.dom.Element;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.fop.fonts.truetype.TTFFile;
import java.io.FileOutputStream;
import java.util.List;
import com.sta.mlogger.MLogger;
/**
* Name: TTFReader
* Description: TTF-Reader.
* Copyright: Copyright (c) 2012, 2013, 2016, 2017, 2019, 2021
* Company: >StA-Soft<
* @author StA
* @version 1.0
*/
public class TTFReader
{
/**
* Verwendung unklar.
*/
private boolean invokedStandalone = false;
//===========================================================================
/**
* Constructor.
*/
public TTFReader()
{
}
/**
* Parse commandline arguments. put options in the HashMap and return
* arguments in the String array
* the arguments: -fn Perpetua,Bold -cn PerpetuaBold per.ttf Perpetua.xml
* returns a String[] with the per.ttf and Perpetua.xml. The hash
* will have the (key, value) pairs: (-fn, Perpetua) and (-cn, PerpetuaBold)
* @param options Options
* @param args Arguments
* @return parsed arguments
*/
private static String[] parseArguments(HashMap options, String[] args)
{
ArrayList arguments = new ArrayList();
for (int i = 0; i < args.length; i++)
{
if (args[i].startsWith("-"))
{
if ((i + 1) < args.length && !args[i + 1].startsWith("-"))
{
options.put(args[i], args[i + 1]);
i++;
}
else
{
options.put(args[i], "");
}
}
else
{
arguments.add(args[i]);
}
}
String[] argStrings = new String[arguments.size()];
arguments.toArray(argStrings);
return argStrings;
}
/**
* Hinweise zur Verwendung.
*/
private static void displayUsage()
{
MLogger.err(" java org.apache.fop.fonts.apps.TTFReader [options] fontfile.ttf xmlfile.xml");
MLogger.err(" where options can be:");
MLogger.err("-enc ansi");
MLogger.err(" With this option you create a WinAnsi encoded font.");
MLogger.err(" The default is to create a CID keyed font.");
MLogger.err(" If you're not going to use characters outside the");
MLogger.err(" pdfencoding range (almost the same as iso-8889-1)");
MLogger.err(" you can add this option.");
MLogger.err("-ttcname ");
MLogger.err(" If you're reading data from a TrueType Collection");
MLogger.err(" (.ttc file) you must specify which font from the");
MLogger.err(" collection you will read metrics from. If you read");
MLogger.err(" from a .ttc file without this option, the fontnames");
MLogger.err(" will be listed for you.");
MLogger.err(" -fn ");
MLogger.err(" default is to use the fontname in the .ttf file, but");
MLogger.err(" you can override that name to make sure that the");
MLogger.err(" embedded font is used (if you're embedding fonts)");
MLogger.err(" instead of installed fonts when viewing documents with Acrobat Reader.");
}
/**
* The main method for the TTFReader tool.
*
* @param args Command-line arguments: [options] fontfile.ttf xmlfile.xml
* where options can be:
* -fn <fontname>
* default is to use the fontname in the .ttf file, but you can override
* that name to make sure that the embedded font is used instead of installed
* fonts when viewing documents with Acrobat Reader.
* -cn <classname>
* default is to use the fontname
* -ef <path to the truetype fontfile>
* will add the possibility to embed the font. When running fop, fop will look
* for this file to embed it
* -er <path to truetype fontfile relative to org/apache/fop/render/pdf/fonts>
* you can also include the fontfile in the fop.jar file when building fop.
* You can use both -ef and -er. The file specified in -ef will be searched first,
* then the -er file.
*/
public static void main(String[] args)
{
String embFile = null;
String embResource = null;
String className = null;
String fontName = null;
String ttcName = null;
boolean isCid = true;
HashMap options = new HashMap();
String[] arguments = parseArguments(options, args);
TTFReader app = new TTFReader();
app.invokedStandalone = true;
MLogger.inf("TTF Reader v1.1.1");
MLogger.inf("");
if (options.get("-enc") != null)
{
String enc = (String) options.get("-enc");
if ("ansi".equals(enc))
{
isCid = false;
}
}
if (options.get("-ttcname") != null)
{
ttcName = (String) options.get("-ttcname");
}
if (options.get("-ef") != null)
{
embFile = (String) options.get("-ef");
}
if (options.get("-er") != null)
{
embResource = (String) options.get("-er");
}
if (options.get("-fn") != null)
{
fontName = (String) options.get("-fn");
}
if (options.get("-cn") != null)
{
className = (String) options.get("-cn");
}
if ((arguments.length != 2) || (options.get("-h") != null) || (options.get("-help") != null) || (options.get("--help") != null))
{
displayUsage();
}
else
{
TTFFile ttf = app.loadTTF(arguments[0], ttcName);
if (ttf != null)
{
org.w3c.dom.Document doc = app.constructFontXML(ttf, fontName, className, embResource, embFile, isCid, ttcName);
if (isCid)
{
MLogger.inf("Creating CID encoded metrics");
}
else
{
MLogger.inf("Creating WinAnsi encoded metrics");
}
if (doc != null)
{
app.writeFontXML(doc, arguments[1]);
}
if (ttf.isEmbeddable())
{
MLogger.inf("This font contains no embedding license restrictions");
}
else
{
MLogger.inf("** Note: This font contains license retrictions for embedding. This font shouldn't be embedded.");
}
}
}
}
/**
* Read a TTF file and returns it as an object.
* @param filename The filename of the PFM file.
* @param fontname font name
* @return The TTF as an object.
*/
public TTFFile loadTTF(String filename, String fontname)
{
TTFFile ttfFile = new TTFFile();
try
{
MLogger.inf("Reading " + filename + "...");
MLogger.inf("");
FontFileReader reader = new FontFileReader(new FileInputStream(filename));
ttfFile.readFont(reader, fontname);
}
catch (Exception ex)
{
MLogger.err("", ex);
return null;
}
return ttfFile;
}
/**
* Writes the generated DOM Document to a file.
*
* @param doc The DOM Document to save.
* @param target The target filename for the XML file.
*/
public void writeFontXML(org.w3c.dom.Document doc, String target)
{
MLogger.inf("Writing xml font file " + target + "...");
MLogger.inf("");
try
{
javax.xml.transform.TransformerFactory.newInstance()
.newTransformer().transform(
new javax.xml.transform.dom.DOMSource(doc),
new javax.xml.transform.stream.StreamResult(new FileOutputStream(target)));
// new javax.xml.transform.stream.StreamResult(new File(target)));
/* OutputFormat format = new OutputFormat(doc); // Serialize DOM
FileWriter out = new FileWriter(target); // Writer will be a String
XMLSerializer serial = new XMLSerializer(out, format);
serial.asDOMSerializer(); // As a DOM Serializer
serial.serialize(doc.getDocumentElement());
out.close();
*/
}
catch (Exception ex)
{
MLogger.err("", ex);
}
}
/**
* Generates the font metrics file from the TTF/TTC file.
* @param ttf The PFM file to generate the font metrics from.
* @param fontname font name
* @param classname class name
* @param resource resource
* @param file file
* @param isCid is cid
* @param ttcName TTC-Name
* @return The DOM document representing the font metrics file.
*/
public org.w3c.dom.Document constructFontXML(TTFFile ttf,
String fontname,
String classname,
String resource, String file,
boolean isCid, String ttcName)
{
MLogger.inf("Creating xml font file...");
MLogger.inf("");
// Document doc = new DocumentImpl();
Document doc;
try
{
doc = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
}
catch (javax.xml.parsers.ParserConfigurationException ex)
{
MLogger.err("Can't create DOM implementation.", ex);
return null;
}
Element root = doc.createElement("font-metrics");
doc.appendChild(root);
if (isCid)
{
root.setAttribute("type", "TYPE0");
}
else
{
root.setAttribute("type", "TRUETYPE");
}
Element el = doc.createElement("font-name");
root.appendChild(el);
// Note that the PostScript name usually is something like
// "Perpetua-Bold", but the TrueType spec says that in the ttf file
// it should be "Perpetua,Bold".
String s = stripWhiteSpace(ttf.getPostScriptName());
if (fontname != null)
{
MLogger.inf("FontName = " + fontname);
el.appendChild(doc.createTextNode(stripWhiteSpace(fontname)));
}
else
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++)
{
char ch = s.charAt(i);
if ((ch > 32) && (ch < 128))
{
sb.append(ch);
}
}
int len = sb.length();
if (sb.charAt(len - 1) == ',')
{
sb.delete(len - 1, len);
}
s = sb.toString();
MLogger.inf("PostscriptName = " + s);
el.appendChild(doc.createTextNode(s));
}
el = doc.createElement("embed");
root.appendChild(el);
if (file != null && ttf.isEmbeddable())
{
el.setAttribute("file", file);
}
if (resource != null && ttf.isEmbeddable())
{
el.setAttribute("class", resource);
}
el = doc.createElement("cap-height");
root.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getCapHeight())));
el = doc.createElement("x-height");
root.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getXHeight())));
el = doc.createElement("ascender");
root.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseAscent())));
el = doc.createElement("descender");
root.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getLowerCaseDescent())));
Element bbox = doc.createElement("bbox");
root.appendChild(bbox);
int[] bb = ttf.getFontBBox();
String[] names =
{
"left", "bottom", "right", "top"
};
for (int i = 0; i < 4; i++)
{
el = doc.createElement(names[i]);
bbox.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(bb[i])));
}
el = doc.createElement("flags");
root.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getFlags())));
el = doc.createElement("stemv");
root.appendChild(el);
el.appendChild(doc.createTextNode(ttf.getStemV()));
el = doc.createElement("italicangle");
root.appendChild(el);
el.appendChild(doc.createTextNode(ttf.getItalicAngle()));
if (ttcName != null)
{
el = doc.createElement("ttc-name");
root.appendChild(el);
el.appendChild(doc.createTextNode(ttcName));
}
el = doc.createElement("subtype");
root.appendChild(el);
// Fill in extras for CID keyed fonts
if (isCid)
{
el.appendChild(doc.createTextNode("TYPE0"));
Element mel = doc.createElement("multibyte-extras");
root.appendChild(mel);
el = doc.createElement("cid-type");
mel.appendChild(el);
el.appendChild(doc.createTextNode("CIDFontType2"));
el = doc.createElement("default-width");
mel.appendChild(el);
el.appendChild(doc.createTextNode("0"));
el = doc.createElement("bfranges");
mel.appendChild(el);
// ArrayList cmaps = ttf.getCMaps();
List cmaps = ttf.getCMaps();
for (int i = 0; i < cmaps.size(); i++)
{
CMapSegment ce = cmaps.get(i);
Element el2 = doc.createElement("bf");
el.appendChild(el2);
el2.setAttribute("us", String.valueOf(ce.getUnicodeStart()));
el2.setAttribute("ue", String.valueOf(ce.getUnicodeEnd()));
el2.setAttribute("gi", String.valueOf(ce.getGlyphStartIndex()));
}
el = doc.createElement("cid-widths");
el.setAttribute("start-index", "0");
mel.appendChild(el);
int[] wx = ttf.getWidths();
for (int i = 0; i < wx.length; i++)
{
Element wxel = doc.createElement("wx");
wxel.setAttribute("w", String.valueOf(wx[i]));
el.appendChild(wxel);
}
}
else
{
// Fill in extras for singlebyte fonts
el.appendChild(doc.createTextNode("TRUETYPE"));
Element sel = doc.createElement("singlebyte-extras");
root.appendChild(sel);
el = doc.createElement("encoding");
sel.appendChild(el);
el.appendChild(doc.createTextNode(ttf.getCharSetName()));
el = doc.createElement("first-char");
sel.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getFirstChar())));
el = doc.createElement("last-char");
sel.appendChild(el);
el.appendChild(doc.createTextNode(String.valueOf(ttf.getLastChar())));
Element widths = doc.createElement("widths");
sel.appendChild(widths);
for (short i = ttf.getFirstChar(); i <= ttf.getLastChar(); i++)
{
el = doc.createElement("char");
widths.appendChild(el);
el.setAttribute("idx", String.valueOf(i));
el.setAttribute("wdt", String.valueOf(ttf.getCharWidth(i)));
}
}
// Get kerning
Iterator enumx;
if (isCid)
{
enumx = ttf.getKerning().keySet().iterator();
}
else
{
enumx = ttf.getAnsiKerning().keySet().iterator();
}
while (enumx.hasNext())
{
Integer kpx1 = (Integer) enumx.next();
el = doc.createElement("kerning");
el.setAttribute("kpx1", kpx1.toString());
root.appendChild(el);
Element el2 = null;
HashMap h2;
if (isCid)
{
h2 = (HashMap) ttf.getKerning().get(kpx1);
}
else
{
h2 = (HashMap) ttf.getAnsiKerning().get(kpx1);
}
for (Iterator enum2 = h2.keySet().iterator(); enum2.hasNext();)
{
Integer kpx2 = (Integer) enum2.next();
if (isCid || kpx2.intValue() < 256)
{
el2 = doc.createElement("pair");
el2.setAttribute("kpx2", kpx2.toString());
Integer val = (Integer) h2.get(kpx2);
el2.setAttribute("kern", val.toString());
el.appendChild(el2);
}
}
}
return doc;
}
/**
* White-Spaces entfernen.
* @param s Text
* @return Text ohne White-Spaces
*/
private String stripWhiteSpace(String s)
{
char[] ch = new char[s.length()];
s.getChars(0, s.length(), ch, 0);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ch.length; i++)
{
if (ch[i] != ' ' && ch[i] != '\r' && ch[i] != '\n' && ch[i] != '\t')
{
sb.append(ch[i]);
}
}
return sb.toString();
}
/**
* Text mit Escape-Sequenzen versehen.
* @param str Text
* @return Text mit Escape-Sequenzen
*/
private String escapeString(String str)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++)
{
if (str.charAt(i) == '\\')
{
sb.append("\\\\");
}
else
{
sb.append(str.charAt(i));
}
}
return sb.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy