/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.svggen.font;
import java.io.FileOutputStream;
import java.io.PrintStream;
import org.apache.batik.util.XMLConstants;
import org.apache.batik.util.SVGConstants;
import org.apache.batik.svggen.font.table.Table;
import org.apache.batik.svggen.font.table.PostTable;
import org.apache.batik.svggen.font.table.KernSubtable;
import org.apache.batik.svggen.font.table.KernTable;
import org.apache.batik.svggen.font.table.SingleSubst;
import org.apache.batik.svggen.font.table.Feature;
import org.apache.batik.svggen.font.table.LangSys;
import org.apache.batik.svggen.font.table.Script;
import org.apache.batik.svggen.font.table.GsubTable;
import org.apache.batik.svggen.font.table.CmapFormat;
import org.apache.batik.svggen.font.table.KerningPair;
import org.apache.batik.svggen.font.table.ScriptTags;
import org.apache.batik.svggen.font.table.FeatureTags;
/**
* Converts a TrueType font to an SVG embedded font.
*
* @version $Id: SVGFont.java,v 1.1 2001/04/27 03:41:08 vhardy Exp $
* @author <a href="mailto:david@steadystate.co.uk">David Schweinsberg</a>
*/
public class SVGFont implements XMLConstants, SVGConstants, ScriptTags, FeatureTags {
static final String EOL;
static final String PROPERTY_LINE_SEPARATOR = "line.separator";
static final String PROPERTY_LINE_SEPARATOR_DEFAULT = "\n";
static {
String temp;
try {
temp = System.getProperty (PROPERTY_LINE_SEPARATOR,
PROPERTY_LINE_SEPARATOR_DEFAULT);
} catch (SecurityException e) {
temp = PROPERTY_LINE_SEPARATOR_DEFAULT;
}
EOL = temp;
}
static private String QUOT_EOL = XML_CHAR_QUOT + EOL;
/**
* Defines the application arguments.
*/
static private String CONFIG_USAGE =
"SVGFont.config.usage";
/**
* Defines the start of the generated SVG document
* {0} SVG public ID
* {1} SVG system ID
*/
static private String CONFIG_SVG_BEGIN =
"SVGFont.config.svg.begin";
/**
* Defines the SVG start fragment that exercise the generated
* Font.
*/
static private String CONFIG_SVG_TEST_CARD_START =
"SVGFont.config.svg.test.card.start";
/**
* Defines the end of the SVG fragment that exercise the generated
* Font.
*/
static private String CONFIG_SVG_TEST_CARD_END =
"SVGFont.config.svg.test.card.end";
protected static String encodeEntities(String s) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == XML_CHAR_LT) {
sb.append(XML_ENTITY_LT);
} else if (s.charAt(i) == XML_CHAR_GT) {
sb.append(XML_ENTITY_GT);
} else if (s.charAt(i) == XML_CHAR_AMP) {
sb.append(XML_ENTITY_AMP);
} else if (s.charAt(i) == XML_CHAR_APOS) {
sb.append(XML_ENTITY_APOS);
} else if(s.charAt(i) == XML_CHAR_QUOT) {
sb.append(XML_ENTITY_QUOT);
} else {
sb.append(s.charAt(i));
}
}
return sb.toString();
}
protected static String getContourAsSVGPathData(Glyph glyph, int startIndex, int count) {
// If this is a single point on it's own, we can't do anything with it
if (glyph.getPoint(startIndex).endOfContour) {
return "";
}
StringBuffer sb = new StringBuffer();
int offset = 0;
while (offset < count) {
Point point_minus1 = glyph.getPoint((offset==0) ? startIndex+count-1 : startIndex+(offset-1)%count);
Point point = glyph.getPoint(startIndex + offset%count);
Point point_plus1 = glyph.getPoint(startIndex + (offset+1)%count);
Point point_plus2 = glyph.getPoint(startIndex + (offset+2)%count);
if (offset == 0) {
sb.append(PATH_MOVE)
.append(String.valueOf(point.x))
.append(XML_SPACE)
.append(String.valueOf(point.y));
}
if (point.onCurve && point_plus1.onCurve) {
if (point_plus1.x == point.x) { // This is a vertical line
sb.append(PATH_VERTICAL_LINE_TO)
.append(String.valueOf(point_plus1.y));
} else if (point_plus1.y == point.y) { // This is a horizontal line
sb.append(PATH_HORIZONTAL_LINE_TO)
.append(String.valueOf(point_plus1.x));
} else {
sb.append(PATH_LINE_TO)
.append(String.valueOf(point_plus1.x))
.append(XML_SPACE)
.append(String.valueOf(point_plus1.y));
}
offset++;
} else if (point.onCurve && !point_plus1.onCurve && point_plus2.onCurve) {
// This is a curve with no implied points
sb.append(PATH_QUAD_TO)
.append(String.valueOf(point_plus1.x))
.append(XML_SPACE)
.append(String.valueOf(point_plus1.y))
.append(XML_SPACE)
.append(String.valueOf(point_plus2.x))
.append(XML_SPACE)
.append(String.valueOf(point_plus2.y));
offset+=2;
} else if (point.onCurve && !point_plus1.onCurve && !point_plus2.onCurve) {
// This is a curve with one implied point
sb.append(PATH_QUAD_TO)
.append(String.valueOf(point_plus1.x))
.append(XML_SPACE)
.append(String.valueOf(point_plus1.y))
.append(XML_SPACE)
.append(String.valueOf(midValue(point_plus1.x, point_plus2.x)))
.append(XML_SPACE)
.append(String.valueOf(midValue(point_plus1.y, point_plus2.y)));
offset+=2;
} else if (!point.onCurve && !point_plus1.onCurve) {
// This is a curve with two implied points
sb.append(PATH_SMOOTH_QUAD_TO)
.append(String.valueOf(midValue(point.x, point_plus1.x)))
.append(XML_SPACE)
.append(String.valueOf(midValue(point.y, point_plus1.y)));
offset++;
} else if (!point.onCurve && point_plus1.onCurve) {
sb.append(PATH_SMOOTH_QUAD_TO)
.append(String.valueOf(point_plus1.x))
.append(XML_SPACE)
.append(String.valueOf(point_plus1.y));
offset++;
} else {
System.out.println("drawGlyph case not catered for!!");
break;
}
}
sb.append(PATH_CLOSE);
return sb.toString();
}
protected static String getSVGFontFaceElement(Font font) {
StringBuffer sb = new StringBuffer();
String fontFamily = font.getNameTable().getRecord(Table.nameFontFamilyName);
short unitsPerEm = font.getHeadTable().getUnitsPerEm();
String panose = font.getOS2Table().getPanose().toString();
short ascent = font.getHheaTable().getAscender();
short descent = font.getHheaTable().getDescender();
int baseline = 0; // bit 0 of head.flags will indicate if this is true
// <!ELEMENT font-face (%descTitleMetadata;,font-face-src?,definition-src?) >
// <!ATTLIST font-face
// %stdAttrs;
// font-family CDATA #IMPLIED
// font-style CDATA #IMPLIED
// font-variant CDATA #IMPLIED
// font-weight CDATA #IMPLIED
// font-stretch CDATA #IMPLIED
// font-size CDATA #IMPLIED
// unicode-range CDATA #IMPLIED
// units-per-em %Number; #IMPLIED
// panose-1 CDATA #IMPLIED
// stemv %Number; #IMPLIED
// stemh %Number; #IMPLIED
// slope %Number; #IMPLIED
// cap-height %Number; #IMPLIED
// x-height %Number; #IMPLIED
// accent-height %Number; #IMPLIED
// ascent %Number; #IMPLIED
// descent %Number; #IMPLIED
// widths CDATA #IMPLIED
// bbox CDATA #IMPLIED
// ideographic %Number; #IMPLIED
// baseline %Number; #IMPLIED
// centerline %Number; #IMPLIED
// mathline %Number; #IMPLIED
// hanging %Number; #IMPLIED
// topline %Number; #IMPLIED
// underline-position %Number; #IMPLIED
// underline-thickness %Number; #IMPLIED
// strikethrough-position %Number; #IMPLIED
// strikethrough-thickness %Number; #IMPLIED
// overline-position %Number; #IMPLIED
// overline-thickness %Number; #IMPLIED >
sb.append(XML_OPEN_TAG_START).append(SVG_FONT_FACE_TAG).append(EOL)
.append(XML_TAB).append(SVG_FONT_FAMILY_ATTRIBUTE).append(XML_EQUAL_QUOT).append(fontFamily).append(QUOT_EOL)
// .append(" font-family=\"").append(fontFamily).append("\"\r\n")
.append(XML_TAB).append(SVG_UNITS_PER_EM_ATTRIBUTE).append(XML_EQUAL_QUOT).append(unitsPerEm).append(QUOT_EOL)
//.append(" units-per-em=\"").append(unitsPerEm).append("\"\r\n")
.append(XML_TAB).append(SVG_PANOSE_1_ATTRIBUTE).append(XML_EQUAL_QUOT).append(panose).append(QUOT_EOL)
// .append(" panose-1=\"").append(panose).append("\"\r\n")
.append(XML_TAB).append(SVG_ASCENT_ATTRIBUTE).append(XML_EQUAL_QUOT).append(ascent).append(QUOT_EOL)
// .append(" ascent=\"").append(ascent).append("\"\r\n")
.append(XML_TAB).append(SVG_DESCENT_ATTRIBUTE).append(XML_EQUAL_QUOT).append(descent).append(QUOT_EOL)
// .append(" descent=\"").append(descent).append("\"\r\n")
.append(XML_TAB).append(SVG_BASELINE_ATTRIBUTE).append(XML_EQUAL_QUOT).append(baseline).append(XML_CHAR_QUOT)
.append(XML_OPEN_TAG_END_NO_CHILDREN).append(EOL);
//.append(" baseline=\"").append(baseline).append("\"/>\r\n");
return sb.toString();
}
/**
* Returns a <font>...</font> block, defining the specified font.
*
* @param font The TrueType font to be converted to SVG
* @param id An XML id attribute for the font element
* @param first The first character in the output range
* @param last The last character in the output range
* @param forceAscii Force the use of the ASCII character map
*/
protected static void writeFontAsSVGFragment(PrintStream ps, Font font, String id, int first, int last, boolean forceAscii)
throws Exception {
// StringBuffer sb = new StringBuffer();
// int horiz_advance_x = font.getHmtxTable().getAdvanceWidth(
// font.getHheaTable().getNumberOfHMetrics() - 1);
int horiz_advance_x = font.getOS2Table().getAvgCharWidth();
ps.print(XML_OPEN_TAG_START);
ps.print(SVG_FONT_TAG);
ps.print(XML_SPACE);
// ps.print("<font ");
if (id != null) {
ps.print(SVG_ID_ATTRIBUTE);
ps.print(XML_EQUAL_QUOT);
// ps.print("id=\"");
ps.print(id);
ps.print(XML_CHAR_QUOT);
ps.print(XML_SPACE);
// ps.print("\" ");
}
ps.print(SVG_HORIZ_ADV_X_ATTRIBUTE);
ps.print(XML_EQUAL_QUOT);
// ps.print("horiz-adv-x=\"");
ps.print(horiz_advance_x);
ps.print(XML_CHAR_QUOT);
ps.print(XML_OPEN_TAG_END_CHILDREN);
// ps.println("\">");
ps.print(getSVGFontFaceElement(font));
// Decide upon a cmap table to use for our character to glyph look-up
CmapFormat cmapFmt = null;
if (forceAscii) {
// We've been asked to use the ASCII/Macintosh cmap format
cmapFmt = font.getCmapTable().getCmapFormat(
Table.platformMacintosh,
Table.encodingRoman );
} else {
// The default behaviour is to use the Unicode cmap encoding
cmapFmt = font.getCmapTable().getCmapFormat(
Table.platformMicrosoft,
Table.encodingUGL );
if (cmapFmt == null) {
// This might be a symbol font, so we'll look for an "undefined" encoding
cmapFmt = font.getCmapTable().getCmapFormat(
Table.platformMicrosoft,
Table.encodingUndefined );
}
}
if (cmapFmt == null) {
throw new Exception("Cannot find a suitable cmap table");
}
// If this font includes arabic script, we want to specify substitutions
// for initial, medial, terminal & isolated cases.
GsubTable gsub = (GsubTable) font.getTable(Table.GSUB);
SingleSubst initialSubst = null;
SingleSubst medialSubst = null;
SingleSubst terminalSubst = null;
if (gsub != null) {
Script s = gsub.getScriptList().findScript(SCRIPT_TAG_ARAB);
if (s != null) {
LangSys ls = s.getDefaultLangSys();
if (ls != null) {
Feature init = gsub.getFeatureList().findFeature(ls, FEATURE_TAG_INIT);
Feature medi = gsub.getFeatureList().findFeature(ls, FEATURE_TAG_MEDI);
Feature fina = gsub.getFeatureList().findFeature(ls, FEATURE_TAG_FINA);
initialSubst = (SingleSubst)
gsub.getLookupList().getLookup(init, 0).getSubtable(0);
medialSubst = (SingleSubst)
gsub.getLookupList().getLookup(medi, 0).getSubtable(0);
terminalSubst = (SingleSubst)
gsub.getLookupList().getLookup(fina, 0).getSubtable(0);
}
}
}
// Include the missing glyph
ps.println(getGlyphAsSVG(font, font.getGlyph(0), 0, horiz_advance_x,
initialSubst, medialSubst, terminalSubst, ""));
try {
// Include our requested range
for (int i = first; i <= last; i++) {
int glyphIndex = cmapFmt.mapCharCode(i);
// ps.println(String.valueOf(i) + " -> " + String.valueOf(glyphIndex));
// if (font.getGlyphs()[glyphIndex] != null)
// sb.append(font.getGlyphs()[glyphIndex].toString() + "\n");
if (glyphIndex > 0) {
ps.println(getGlyphAsSVG(
font,
font.getGlyph(glyphIndex),
glyphIndex,
horiz_advance_x,
initialSubst, medialSubst, terminalSubst,
(32 <= i && i <= 127) ?
encodeEntities("" + (char) i) :
XML_CHAR_REF_PREFIX + Integer.toHexString(i) + XML_CHAR_REF_SUFFIX));
}
}
// Output kerning pairs from the requested range
KernTable kern = (KernTable) font.getTable(Table.kern);
if (kern != null) {
KernSubtable kst = kern.getSubtable(0);
PostTable post = (PostTable) font.getTable(Table.post);
for (int i = 0; i < kst.getKerningPairCount(); i++) {
ps.println(getKerningPairAsSVG(kst.getKerningPair(i), post));
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
}
ps.print(XML_CLOSE_TAG_START);
ps.print(SVG_FONT_TAG);
ps.println(XML_CLOSE_TAG_END);
// ps.println("</font>");
}
protected static String getGlyphAsSVG(
Font font,
Glyph glyph,
int glyphIndex,
int defaultHorizAdvanceX,
String attrib,
String code) {
StringBuffer sb = new StringBuffer();
int firstIndex = 0;
int count = 0;
int i;
int horiz_advance_x;
horiz_advance_x = font.getHmtxTable().getAdvanceWidth(glyphIndex);
if (glyphIndex == 0) {
sb.append(XML_OPEN_TAG_START);
sb.append(SVG_MISSING_GLYPH_TAG);
// sb.append("<missing-glyph");
} else {
// Unicode value
sb.append(XML_OPEN_TAG_START)
.append(SVG_GLYPH_TAG).append(XML_SPACE).append(SVG_UNICODE_ATTRIBUTE)
.append(XML_EQUAL_QUOT).append(code).append(XML_CHAR_QUOT);
// sb.append("<glyph unicode=\"").append(code).append("\"");
// Glyph name
sb.append(XML_SPACE).append(SVG_GLYPH_NAME_ATTRIBUTE).append(XML_EQUAL_QUOT)
// sb.append(" glyph-name=\"")
.append(font.getPostTable().getGlyphName(glyphIndex))
// .append("\"");
.append(XML_CHAR_QUOT);
}
if (horiz_advance_x != defaultHorizAdvanceX) {
sb.append(XML_SPACE).append(SVG_HORIZ_ADV_X_ATTRIBUTE).append(XML_EQUAL_QUOT)
.append(horiz_advance_x).append(XML_CHAR_QUOT);
// sb.append(" horiz-adv-x=\"").append(horiz_advance_x).append("\"");
}
if (attrib != null) {
sb.append(attrib);
}
if (glyph != null) {
// sb.append(" d=\"");
sb.append(XML_SPACE).append(SVG_D_ATTRIBUTE).append(XML_EQUAL_QUOT);
for (i = 0; i < glyph.getPointCount(); i++) {
count++;
if (glyph.getPoint(i).endOfContour) {
sb.append(getContourAsSVGPathData(glyph, firstIndex, count));
firstIndex = i + 1;
count = 0;
}
}
// sb.append("\"");
sb.append(XML_CHAR_QUOT);
}
sb.append(XML_OPEN_TAG_END_NO_CHILDREN);
// sb.append("/>");
// Chop-up the string into 255 character lines
chopUpStringBuffer(sb);
return sb.toString();
}
protected static String getGlyphAsSVG(
Font font,
Glyph glyph,
int glyphIndex,
int defaultHorizAdvanceX,
SingleSubst arabInitSubst,
SingleSubst arabMediSubst,
SingleSubst arabTermSubst,
String code) {
StringBuffer sb = new StringBuffer();
boolean substituted = false;
// arabic = "initial | medial | terminal | isolated"
int arabInitGlyphIndex = glyphIndex;
int arabMediGlyphIndex = glyphIndex;
int arabTermGlyphIndex = glyphIndex;
if (arabInitSubst != null) {
arabInitGlyphIndex = arabInitSubst.substitute(glyphIndex);
}
if (arabMediSubst != null) {
arabMediGlyphIndex = arabMediSubst.substitute(glyphIndex);
}
if (arabTermSubst != null) {
arabTermGlyphIndex = arabTermSubst.substitute(glyphIndex);
}
if (arabInitGlyphIndex != glyphIndex) {
sb.append(getGlyphAsSVG(
font,
font.getGlyph(arabInitGlyphIndex),
arabInitGlyphIndex,
defaultHorizAdvanceX,
// " arabic-form=\"initial\"",
SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_INITIAL_VALUE + XML_CHAR_QUOT,
code));
// sb.append("\r\n");
sb.append(EOL);
substituted = true;
}
if (arabMediGlyphIndex != glyphIndex) {
sb.append(getGlyphAsSVG(
font,
font.getGlyph(arabMediGlyphIndex),
arabMediGlyphIndex,
defaultHorizAdvanceX,
SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_MEDIAL_VALUE + XML_CHAR_QUOT,
// " arabic-form=\"medial\"",
code));
// sb.append("\r\n");
sb.append(EOL);
substituted = true;
}
if (arabTermGlyphIndex != glyphIndex) {
sb.append(getGlyphAsSVG(
font,
font.getGlyph(arabTermGlyphIndex),
arabTermGlyphIndex,
defaultHorizAdvanceX,
SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_TERMINAL_VALUE + XML_CHAR_QUOT,
// " arabic-form=\"terminal\"",
code));
// sb.append("\r\n");
sb.append(EOL);
substituted = true;
}
if (substituted) {
sb.append(getGlyphAsSVG(
font,
glyph,
glyphIndex,
defaultHorizAdvanceX,
SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_ISOLATED_VALUE + XML_CHAR_QUOT,
// " arabic-form=\"isolated\"",
code));
} else {
sb.append(getGlyphAsSVG(
font,
glyph,
glyphIndex,
defaultHorizAdvanceX,
null,
code));
}
return sb.toString();
}
protected static String getKerningPairAsSVG(KerningPair kp, PostTable post) {
StringBuffer sb = new StringBuffer();
// sb.append("<hkern g1=\"");
sb.append(XML_OPEN_TAG_START).append(SVG_HKERN_TAG).append(XML_SPACE);
sb.append(SVG_G1_ATTRIBUTE).append(XML_EQUAL_QUOT);
sb.append(post.getGlyphName(kp.getLeft()));
// sb.append("\" g2=\"");
sb.append(XML_CHAR_QUOT).append(XML_SPACE).append(SVG_G2_ATTRIBUTE).append(XML_EQUAL_QUOT);
sb.append(post.getGlyphName(kp.getRight()));
// sb.append("\" k=\"");
sb.append(XML_CHAR_QUOT).append(XML_SPACE).append(SVG_K_ATTRIBUTE).append(XML_EQUAL_QUOT);
sb.append(kp.getValue());
// sb.append("\"/>");
sb.append(XML_CHAR_QUOT).append(XML_OPEN_TAG_END_NO_CHILDREN);
return sb.toString();
}
/*
protected static String getGlyphAsPath(Glyph glyph) {
StringBuffer sb = new StringBuffer();
int firstIndex = 0;
int count = 0;
int i;
for (i = 0; i < glyph.getPointCount(); i++) {
count++;
if (glyph.getPoint(i).endOfContour) {
sb.append(getContourAsSVGPathData(glyph, firstIndex, count));
firstIndex = i + 1;
count = 0;
}
}
return sb.toString();
}
protected static void writeTextAsSVGFragment(PrintStream ps, Font f, int size, String text) {
CmapFormat cmapFmt = f.getCmapTable().getCmapFormat(Table.platformMicrosoft, Table.encodingUGL);
int x = 0;
for (short i = 0; i < text.length(); i++) {
int glyphIndex = cmapFmt.mapCharCode((short)text.charAt(i));
Glyph glyph = f.getGlyph(glyphIndex);
if (glyph != null) {
ps.println(translateSVG(x, 0, getGlyphAsSVGPath(glyph)));
x += glyph.getAdvanceWidth();
}
}
}
*/
protected static void writeSvgBegin(PrintStream ps) {
// ps.println("<?xml version=\"1.0\" standalone=\"no\"?>");
// ps.println("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20001102//EN\"");
// ps.println("\"http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd\" >");
// ps.println("<svg width=\"100%\" height=\"100%\">");
ps.println(Messages.formatMessage(CONFIG_SVG_BEGIN,
new Object[]{SVG_PUBLIC_ID, SVG_SYSTEM_ID}));
}
protected static void writeSvgDefsBegin(PrintStream ps) {
// ps.println("<defs>");
ps.println(XML_OPEN_TAG_START + SVG_DEFS_TAG + XML_OPEN_TAG_END_CHILDREN);
}
protected static void writeSvgDefsEnd(PrintStream ps) {
// ps.println("</defs>");
ps.println(XML_CLOSE_TAG_START + SVG_DEFS_TAG + XML_CLOSE_TAG_END);
}
protected static void writeSvgEnd(PrintStream ps) {
// ps.println("</svg>");
ps.println(XML_CLOSE_TAG_START + SVG_SVG_TAG + XML_CLOSE_TAG_END);
}
protected static void writeSvgTestCard(PrintStream ps, String fontFamily) {
ps.println(Messages.formatMessage(CONFIG_SVG_TEST_CARD_START, null));
ps.println(fontFamily);
ps.println(Messages.formatMessage(CONFIG_SVG_TEST_CARD_END, null));
/*ps.println("<g style=\"font-family: '" + fontFamily + "'; font-size:18;fill:black\">");
ps.println("<text x=\"20\" y=\"60\"> !"#$%&'()*+,-./0123456789:;<>?</text>");
ps.println("<text x=\"20\" y=\"120\">@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_</text>");
ps.println("<text x=\"20\" y=\"180\">`abcdefghijklmnopqrstuvwxyz{|}~</text>");
ps.println("<text x=\"20\" y=\"240\">€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ</text>");
ps.println("<text x=\"20\" y=\"300\"> ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿</text>");
ps.println("<text x=\"20\" y=\"360\">ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß</text>");
ps.println("<text x=\"20\" y=\"420\">àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ</text>");
ps.println("</g>");*/
}
public static final char ARG_KEY_START_CHAR = '-';
public static final String ARG_KEY_CHAR_RANGE_LOW = "-l";
public static final String ARG_KEY_CHAR_RANGE_HIGH = "-h";
public static final String ARG_KEY_ID = "-id";
public static final String ARG_KEY_ASCII = "-ascii";
public static final String ARG_KEY_TESTCARD = "-testcard";
public static final String ARG_KEY_OUTPUT_PATH = "-o";
/**
* Starts the application.
* @param args an array of command-line arguments
*/
public static void main(String[] args) {
try {
String path = parseArgs(args, null);
String low = parseArgs(args, ARG_KEY_CHAR_RANGE_LOW);
String high = parseArgs(args, ARG_KEY_CHAR_RANGE_HIGH);
String id = parseArgs(args, ARG_KEY_ID);
String ascii = parseArgs(args, ARG_KEY_ASCII);
String testCard = parseArgs(args, ARG_KEY_TESTCARD);
String outPath = parseArgs(args, ARG_KEY_OUTPUT_PATH);
PrintStream ps = null;
FileOutputStream fos = null;
// What are we outputting to?
if (outPath != null) {
// If an output path was specified, write to a file
fos = new FileOutputStream(outPath);
ps = new PrintStream(fos);
} else {
// Otherwise we'll just put it to stdout
ps = System.out;
}
// The font path is the only required argument
if (path != null) {
Font font = Font.create(path);
// Write the various parts of the SVG file
writeSvgBegin(ps);
writeSvgDefsBegin(ps);
writeFontAsSVGFragment(
ps,
font,
id,
(low != null ? Integer.parseInt(low) : 32),
(high != null ? Integer.parseInt(high) : 127),
(ascii != null));
writeSvgDefsEnd(ps);
if (testCard != null) {
String fontFamily = font.getNameTable().getRecord(Table.nameFontFamilyName);
writeSvgTestCard(ps, fontFamily);
}
writeSvgEnd(ps);
// Close the output stream (if we have one)
if (fos != null) {
fos.close();
}
} else {
usage();
}
} catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
usage();
}
}
private static void chopUpStringBuffer(StringBuffer sb) {
if (sb.length() < 256) {
return;
} else {
// Being rather simplistic about it, for now we'll insert a newline after
// 240 chars
for (int i = 240; i < sb.length(); i++) {
if (sb.charAt(i) == ' ') {
sb.setCharAt(i, '\n');
i += 240;
}
}
}
}
private static int midValue(int a, int b) {
return a + (b - a)/2;
}
/*private static String translateSVG(int x, int y, String svgText) {
StringBuffer sb = new StringBuffer();
sb.append("<g transform=\"translate(")
.append(String.valueOf(x))
.append(" ")
.append(String.valueOf(y))
.append(")\">")
.append(svgText)
.append("</g>");
return sb.toString();
}*/
private static String parseArgs(String[] args, String name) {
for (int i = 0; i < args.length; i++) {
if (name == null) {
if (args[i].charAt(0) != ARG_KEY_START_CHAR) {
return args[i];
}
} else if (name.equalsIgnoreCase(args[i])) {
if ((i < args.length - 1) && (args[i+1].charAt(0) != ARG_KEY_START_CHAR)) {
return args[i+1];
} else {
return args[i];
}
}
}
return null;
}
private static void usage() {
System.err.println(Messages.formatMessage(CONFIG_USAGE, null));
}
}