From cd29111611f5741e1130cfb0242b586e3a7ffd20 Mon Sep 17 00:00:00 2001 From: Nilam Gaikwad Date: Thu, 25 Jul 2024 14:00:59 +0530 Subject: [PATCH 1/3] BATIK-1378: MGG-1585 ttf2svg: Add -u option to read list of unicode chacters to export to svg. Present ttf2svg application has a limitation that it export all characters or it export range of characters. Consider a case of Chinese/Japanese language which was resulting in large svg file. To avoid this we have added an option '-u' to specify a text file with unicode symbols, which are required in svg file. Signed-off-by: Nilam Gaikwad --- .../org/apache/batik/svggen/font/SVGFont.java | 132 +++++++++++++++++- .../svggen/font/resources/Messages.properties | 2 +- 2 files changed, 129 insertions(+), 5 deletions(-) diff --git a/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java b/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java index 70201218e8..b8a9142bb2 100644 --- a/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java +++ b/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java @@ -19,10 +19,16 @@ Licensed to the Apache Software Foundation (ASF) under one or more package org.apache.batik.svggen.font; +import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; import java.util.Set; +import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Scanner; import org.apache.batik.svggen.font.table.CmapFormat; import org.apache.batik.svggen.font.table.Feature; @@ -261,6 +267,109 @@ protected static String getSVGFontFaceElement(Font font) { return sb.toString(); } + /** + * Implements an Iterator interface to select required glyphs based on user + * + * @version $Id$ + * @author Nilam Gaikwad + */ + public static class GlyphSelector implements Iterator { + + static final int GLYPH_SELECTOR_LINEAR_RANGE = 1; + static final int GLYPH_SELECTOR_NON_LINEAR_RANGE = 2; + + int type; + int startIndex, endIndex; + int currentIndex = 0; + List requiredGlyphIndexes = null; + + /** + * GlyphSelector Default constructore + */ + public GlyphSelector() { + init(-1,-1); + } + + /** + * GlyphSelector constructor which prepare list of unicode glyph number + * to extract from TTF file. + * + * @param fileName A file containing unicode glyph number list. + */ + public GlyphSelector(String fileName) { + init(fileName); + } + + /** + * Initializes glyphSelector list from given disk file. + * + * @param fileName File which contains list of unicode number of glyphs + * to extract from TTF file. + */ + protected void init(String fileName) { + /* This is non-linear glyph selector */ + type = GLYPH_SELECTOR_NON_LINEAR_RANGE; + + /* Populate array */ + requiredGlyphIndexes = new ArrayList(); + requiredGlyphIndexes.clear(); + currentIndex = 0; + + try { + Scanner intList = new Scanner(new File(fileName)); + while (intList.hasNextInt()) { + requiredGlyphIndexes.add(intList.nextInt()); + } + intList.close(); + } catch (FileNotFoundException e) { + System.err.println(e); + } + } + + /** + * Initializes Unicode number extractor for given start-end range. + * + * @param start The starting unicode number from required glyphs. + * @param end The last unicode number from required glyphs. + */ + protected void init(int start, int end) { + type = GLYPH_SELECTOR_LINEAR_RANGE; + startIndex = start; + endIndex = end; + currentIndex = startIndex; + } + + /** + * Returns true if there are additional unicode number to extract from TTF font + * Return false otherwise + */ + public boolean hasNext() { + boolean result = false; + if (type == GLYPH_SELECTOR_LINEAR_RANGE) { + if (currentIndex >= startIndex && currentIndex < endIndex) + result = true; + } else if (type == GLYPH_SELECTOR_NON_LINEAR_RANGE) { + if (currentIndex < requiredGlyphIndexes.size()) + result = true; + } + return result; + } + + /** + * Returns a unicode character number which user has required for glyph extraction + */ + public Integer next() { + Integer iVal = 0; + if (type == GLYPH_SELECTOR_LINEAR_RANGE) { + iVal = currentIndex; + } else if (type == GLYPH_SELECTOR_NON_LINEAR_RANGE) { + iVal = requiredGlyphIndexes.get(currentIndex); + } + currentIndex++; + return iVal; + } + } + /** * Returns a <font>...</font> block, * defining the specified font. @@ -270,8 +379,9 @@ protected static String getSVGFontFaceElement(Font font) { * @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 + * @param glyphSelector Iterator object which contains list of glyph indexs for extraction */ - protected static void writeFontAsSVGFragment(PrintStream ps, Font font, String id, int first, int last, boolean autoRange, boolean forceAscii) + protected static void writeFontAsSVGFragment(PrintStream ps, Font font, String id, int first, int last, boolean autoRange, boolean forceAscii, GlyphSelector glyphSelector) throws Exception { // StringBuffer sb = new StringBuffer(); // int horiz_advance_x = font.getHmtxTable().getAdvanceWidth( @@ -362,6 +472,7 @@ protected static void writeFontAsSVGFragment(PrintStream ps, Font font, String i initialSubst, medialSubst, terminalSubst, "")); try { + boolean glyphSelectorReInitRequired = (autoRange == true || ( first != -1 && last != -1)); if (first == -1) { if (!autoRange) first = DEFAULT_FIRST; else first = cmapFmt.getFirst(); @@ -371,9 +482,14 @@ protected static void writeFontAsSVGFragment(PrintStream ps, Font font, String i else last = cmapFmt.getLast(); } - // Include our requested range + // Include our requested characters Set glyphSet = new HashSet(); - for (int i = first; i <= last; i++) { + if (glyphSelectorReInitRequired) { + glyphSelector.init(first, last); + } + + while (glyphSelector.hasNext()) { + int i = glyphSelector.next().intValue(); int glyphIndex = cmapFmt.mapCharCode(i); // ps.println(String.valueOf(i) + " -> " + String.valueOf(glyphIndex)); // if (font.getGlyphs()[glyphIndex] != null) @@ -712,6 +828,7 @@ protected static void writeSvgTestCard(PrintStream ps, String fontFamily) { public static final char ARG_KEY_START_CHAR = '-'; public static final String ARG_KEY_CHAR_RANGE_LOW = "-l"; + public static final String ARG_REQUIRED_UNICODE_LIST = "-u"; 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"; @@ -728,6 +845,7 @@ public static void main(String[] args) { String path = parseArgs(args, null); String low = parseArgs(args, ARG_KEY_CHAR_RANGE_LOW); String high = parseArgs(args, ARG_KEY_CHAR_RANGE_HIGH); + String unicodeCharListFile = parseArgs(args, ARG_REQUIRED_UNICODE_LIST); String id = parseArgs(args, ARG_KEY_ID); String ascii = parseArgs(args, ARG_KEY_ASCII); String testCard = parseArgs(args, ARG_KEY_TESTCARD); @@ -735,6 +853,7 @@ public static void main(String[] args) { String autoRange = parseArgs(args, ARG_KEY_AUTO_RANGE); PrintStream ps = null; FileOutputStream fos = null; + GlyphSelector gs = new GlyphSelector(); // What are we outputting to? if (outPath != null) { @@ -750,6 +869,10 @@ public static void main(String[] args) { if (path != null) { Font font = Font.create(path); + if (unicodeCharListFile != null) { + gs.init(unicodeCharListFile); + } + // Write the various parts of the SVG file writeSvgBegin(ps); writeSvgDefsBegin(ps); @@ -760,7 +883,8 @@ public static void main(String[] args) { (low != null ? Integer.parseInt(low) : -1), (high != null ? Integer.parseInt(high) : -1), (autoRange != null), - (ascii != null)); + (ascii != null), + gs); writeSvgDefsEnd(ps); if (testCard != null) { String fontFamily = font.getNameTable().getRecord(Table.nameFontFamilyName); diff --git a/batik-svggen/src/main/resources/org/apache/batik/svggen/font/resources/Messages.properties b/batik-svggen/src/main/resources/org/apache/batik/svggen/font/resources/Messages.properties index 988b8de5fa..87729fe816 100644 --- a/batik-svggen/src/main/resources/org/apache/batik/svggen/font/resources/Messages.properties +++ b/batik-svggen/src/main/resources/org/apache/batik/svggen/font/resources/Messages.properties @@ -19,7 +19,7 @@ # ----------------------------------------------------------------------------- SVGFont.config.usage = \ -usage: java org.apache.batik.svggen.font.SVGFont [-l ] [-h ] [-autorange] [-ascii] [-id ] [-o ] [-testcard] +usage: java org.apache.batik.svggen.font.SVGFont [-l ] [-h ] [-autorange] [-ascii] [-id ] [-o ] [-testcard] [-u ] SVGFont.config.svg.begin = \ \ From e52e94bf24806760cd59441d40938e7251227796 Mon Sep 17 00:00:00 2001 From: Nilam Gaikwad Date: Thu, 25 Jul 2024 15:35:37 +0530 Subject: [PATCH 2/3] BATIK-1378: MGG-1585 ttf2svg: Add support for hex integer in list file - Add support for hex to integer conversion, Since unicode are better written in hex format. - Add warning for duplicate unicode glyphs. And skip duplicate entry from svg generartion. - Add warning for string which failed to parse. Signed-off-by: Nilam Gaikwad --- .../org/apache/batik/svggen/font/SVGFont.java | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java b/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java index b8a9142bb2..1e769f8c27 100644 --- a/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java +++ b/batik-svggen/src/main/java/org/apache/batik/svggen/font/SVGFont.java @@ -317,8 +317,44 @@ protected void init(String fileName) { try { Scanner intList = new Scanner(new File(fileName)); - while (intList.hasNextInt()) { - requiredGlyphIndexes.add(intList.nextInt()); + while (intList.hasNext()) { + String s = intList.next(); + + if (s.length() > 0) { + int radix, p0, v; + boolean intParsingDone = false; + char[] cl = s.toCharArray(); + + if (cl[0] == '0' && (cl[1] == 'x' || cl[1] == 'X')) { + radix = 16; + p0 = 2; + } else { + radix = 10; + p0 = 0; + } + v = 0; + for (int i = p0; i < cl.length; i++) { + char c = cl[i]; + if (c >= 'A' && c <= 'F') + v = v * radix + c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + v = v * radix + c - 'a' + 10; + else if (c >= '0' && c <= '9') + v = v * radix + c - '0'; + else + break; + intParsingDone = true; + } + cl = null; + + if (intParsingDone == false) { + System.err.printf("WARNING: Not-parsed string [%s]\n", s); + } else if (requiredGlyphIndexes.contains(v) == false) { + requiredGlyphIndexes.add(v); + } else { + System.err.printf("WARNING: Duplicate string [%s]\n", s); + } + } } intList.close(); } catch (FileNotFoundException e) { From dfe691200b08c2979fa5d77fc784c967ddf1097a Mon Sep 17 00:00:00 2001 From: Nilam Gaikwad Date: Wed, 22 Jan 2025 16:43:02 +0530 Subject: [PATCH 3/3] BATIK-1378: build.xml: Add arguments to ttf2svg application Signed-off-by: Nilam Gaikwad --- build.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.xml b/build.xml index a856bef99a..2139615609 100644 --- a/build.xml +++ b/build.xml @@ -1350,7 +1350,11 @@ JAVA=/usr/bin/java - + + + + +