diff options
author | David Schweinsberg <[email protected]> | 2019-09-15 17:00:43 -0700 |
---|---|---|
committer | David Schweinsberg <[email protected]> | 2019-09-15 17:00:43 -0700 |
commit | 55e11ec99807fb91c1ca07396d28edf3fbbb611c (patch) | |
tree | c2b020c6e13652985202b099ed19bbc4843aeb95 | |
parent | 88367285132439ed13fb24c6631faa63a2746665 (diff) |
Re-enable SVG font export
-rw-r--r-- | src/main/java/net/java/dev/typecast/exchange/SVGExporter.java | 336 | ||||
-rw-r--r-- | src/main/java/net/java/dev/typecast/ot/OTFont.java | 19 | ||||
-rw-r--r-- | src/main/java/net/java/dev/typecast/ot/TTFont.java | 7 |
3 files changed, 160 insertions, 202 deletions
diff --git a/src/main/java/net/java/dev/typecast/exchange/SVGExporter.java b/src/main/java/net/java/dev/typecast/exchange/SVGExporter.java index c5c276b..3a774ec 100644 --- a/src/main/java/net/java/dev/typecast/exchange/SVGExporter.java +++ b/src/main/java/net/java/dev/typecast/exchange/SVGExporter.java @@ -1,60 +1,27 @@ /* - - ============================================================================ - The Apache Software License, Version 1.1 - ============================================================================ - - Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. - - Redistribution and use in source and binary forms, with or without modifica- - tion, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - 3. The end-user documentation included with the redistribution, if any, must - include the following acknowledgment: "This product includes software - developed by the Apache Software Foundation (http://www.apache.org/)." - Alternately, this acknowledgment may appear in the software itself, if - and wherever such third-party acknowledgments normally appear. - - 4. The names "Batik" and "Apache Software Foundation" must not be - used to endorse or promote products derived from this software without - prior written permission. For written permission, please contact - - 5. Products derived from this software may not be called "Apache", nor may - "Apache" appear in their name, without prior written permission of the - Apache Software Foundation. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- - DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - This software consists of voluntary contributions made by many individuals - on behalf of the Apache Software Foundation. For more information on the - Apache Software Foundation, please see <http://www.apache.org/>. - -*/ + * Typecast + * + * Copyright © 2004-2019 David Schweinsberg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package net.java.dev.typecast.exchange; import java.io.OutputStream; import java.io.PrintStream; -import net.java.dev.typecast.ot.Glyph; -import net.java.dev.typecast.ot.OTFont; -import net.java.dev.typecast.ot.Point; + +import net.java.dev.typecast.ot.*; import net.java.dev.typecast.ot.table.CmapFormat; import net.java.dev.typecast.ot.table.Feature; import net.java.dev.typecast.ot.table.FeatureTags; @@ -68,7 +35,6 @@ import net.java.dev.typecast.ot.table.PostTable; import net.java.dev.typecast.ot.table.Script; import net.java.dev.typecast.ot.table.ScriptTags; import net.java.dev.typecast.ot.table.SingleSubst; -import net.java.dev.typecast.ot.table.Table; import net.java.dev.typecast.ot.table.TableException; import org.apache.batik.util.SVGConstants; import org.apache.batik.util.XMLConstants; @@ -299,7 +265,7 @@ public class SVGExporter * @param forceAscii Force the use of the ASCII character map * @throws net.java.dev.typecast.ot.table.TableException */ - protected static void writeFontAsSVGFragment(PrintStream ps, OTFont font, String id, int first, int last, boolean forceAscii) + protected static void writeFontAsSVGFragment(PrintStream ps, TTFont font, String id, int first, int last, boolean forceAscii) throws TableException { int horiz_advance_x = font.getOS2Table().getAvgCharWidth(); @@ -348,66 +314,66 @@ public class SVGExporter throw new TableException("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 && gsub.getScriptList() != 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); -// -// 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()); -// } + // If this font includes arabic script, we want to specify substitutions + // for initial, medial, terminal & isolated cases. + GsubTable gsub = font.getGsubTable(); + SingleSubst initialSubst = null; + SingleSubst medialSubst = null; + SingleSubst terminalSubst = null; + if (gsub != null && gsub.getScriptList() != 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); + + 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 = font.getKernTable(); + if (kern != null) { + KernSubtable kst = kern.getSubtable(0); + PostTable post = font.getPostTable(); + 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); @@ -476,7 +442,7 @@ public class SVGExporter } protected static String getGlyphAsSVG( - OTFont font, + TTFont font, Glyph glyph, int glyphIndex, int defaultHorizAdvanceX, @@ -486,75 +452,75 @@ public class SVGExporter String code) { StringBuilder sb = new StringBuilder(); -// 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, -// SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_INITIAL_VALUE + XML_CHAR_QUOT, -// code)); -// 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, -// code)); -// 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, -// code)); -// 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, -// code)); -// } else { -// sb.append(getGlyphAsSVG( -// font, -// glyph, -// glyphIndex, -// defaultHorizAdvanceX, -// null, -// code)); -// } + 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, + SVG_ARABIC_FORM_ATTRIBUTE + XML_EQUAL_QUOT + SVG_INITIAL_VALUE + XML_CHAR_QUOT, + code)); + 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, + code)); + 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, + code)); + 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, + code)); + } else { + sb.append(getGlyphAsSVG( + font, + glyph, + glyphIndex, + defaultHorizAdvanceX, + null, + code)); + } return sb.toString(); } @@ -601,14 +567,14 @@ public class SVGExporter ps.println(Messages.formatMessage(CONFIG_SVG_TEST_CARD_END, null)); } - private final OTFont _font; + private final TTFont _font; private final int _low = 32; private int _high = 127; private String _id; private final boolean _ascii = false; private final boolean _testCard = true; - public SVGExporter(OTFont font) { + public SVGExporter(TTFont font) { _font = font; } diff --git a/src/main/java/net/java/dev/typecast/ot/OTFont.java b/src/main/java/net/java/dev/typecast/ot/OTFont.java index d753e84..3751828 100644 --- a/src/main/java/net/java/dev/typecast/ot/OTFont.java +++ b/src/main/java/net/java/dev/typecast/ot/OTFont.java @@ -28,7 +28,7 @@ import net.java.dev.typecast.ot.table.*; * The TrueType font. * @author <a href="mailto:[email protected]">David Schweinsberg</a> */ -public class OTFont { +public abstract class OTFont { private Os2Table _os2; private CmapTable _cmap; @@ -150,22 +150,7 @@ public class OTFont { return _maxp.getNumGlyphs(); } -// // TODO What happens with the following when dealing with PostScript? -// public Glyph getGlyph(int i) { -// if (_glyf != null && _glyf.getDescription(i) != null) { -// return new TTGlyph( -// _glyf.getDescription(i), -// _hmtx.getLeftSideBearing(i), -// _hmtx.getAdvanceWidth(i)); -// } else if (_cff != null && _cff.getFont(0).getCharstring(i) != null) { -// return new T2Glyph( -// (CharstringType2) _cff.getFont(0).getCharstring(i), -// _hmtx.getLeftSideBearing(i), -// _hmtx.getAdvanceWidth(i)); -// } else { -// return null; -// } -// } + public abstract Glyph getGlyph(int i); int seekTable( TableDirectory tableDirectory, diff --git a/src/main/java/net/java/dev/typecast/ot/TTFont.java b/src/main/java/net/java/dev/typecast/ot/TTFont.java index 1829c0b..55f333c 100644 --- a/src/main/java/net/java/dev/typecast/ot/TTFont.java +++ b/src/main/java/net/java/dev/typecast/ot/TTFont.java @@ -99,4 +99,11 @@ public class TTFont extends OTFont { return _vdmx; } + public Glyph getGlyph(int i) { + return new TTGlyph( + _glyf.getDescription(i), + getHmtxTable().getLeftSideBearing(i), + getHmtxTable().getAdvanceWidth(i)); + } + } |