diff --git a/scour_svg.sh b/scour_svg.sh new file mode 100755 index 000000000..f1de64ba9 --- /dev/null +++ b/scour_svg.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +SRC_DIR="" +DST_DIR="" + +SCOUR_ARGS="--strip-xml-prolog --enable-viewboxing --enable-id-stripping --enable-comment-stripping --shorten-ids --no-line-breaks --strip-xml-space" + +while [ $# != 0 ]; do + case "$1" in + -s) SRC_DIR=${2} + shift + shift + ;; + -d) DST_DIR=${2} + shift + shift + ;; + *) echo "unrecognized arg $1" + exit 1 + ;; + esac +done + +if [ -z "$SRC_DIR" ]; then + echo "missing source directory" + exit 1; +fi + +if [ ! -d "$SRC_DIR" ]; then + echo "source dirctory '$SRC_DIR' does not exist" + exit 1; +fi + +if [ -z "$DST_DIR" ]; then + echo "missing destination directory" + exit 1 +fi + +if [ ! -d "$DST_DIR" ]; then + echo "creating destination directory '$DST_DIR'" + mkdir -p "$DST_DIR" +fi + +for file in "$SRC_DIR"/*.svg; do + dst="${file##*/}" + echo $dst + scour $SCOUR_ARGS -i "$file" -o "$DST_DIR/$dst" +done + diff --git a/svg_cleaner.py b/svg_cleaner.py index f61ccf7bc..e968d2fc8 100755 --- a/svg_cleaner.py +++ b/svg_cleaner.py @@ -72,18 +72,19 @@ class _Text_Node(object): class SvgCleaner(object): """Strip out unwanted parts of an svg file, primarily the xml declaration and doctype lines, comments, and some attributes of the outermost element. - The id will be replaced when it is inserted into the font. viewBox causes + The id will be replaced when it is inserted into the font. (viewBox causes unwanted scaling when used in a font and its effect is difficult to - predict. version is unneeded, xml:space is ignored (we're processing spaces + predict, but for outside a font we need to keep it sometimes so we keep it). + version is unneeded, xml:space is ignored (we're processing spaces so a request to maintain them has no effect). enable-background appears to have no effect. x and y on the outermost svg element have no effect. We keep width and height, and will elsewhere assume these are the dimensions used for the character box.""" - def __init__(self): + def __init__(self, strip=False): self.reader = SvgCleaner._Reader() self.cleaner = SvgCleaner._Cleaner() - self.writer = SvgCleaner._Writer() + self.writer = SvgCleaner._Writer(strip) class _Reader(object): """Loosely based on fonttools's XMLReader. This generates a tree of nodes, @@ -130,7 +131,7 @@ class SvgCleaner(object): class _Cleaner(object): def _clean_elem(self, node): - viewBox, width, height = None, None, None + viewBox, x, y, width, height = None, None, None, None, None nattrs = {} for k, v in node.attrs.items(): if node.name == 'svg' and k in [ @@ -153,14 +154,25 @@ class SvgCleaner(object): nattrs[k] = v if node.name == 'svg': + if viewBox: + x, y, width, height = viewBox.split() if not width or not height: if not viewBox: raise ValueError('no viewBox, width, or height') - width, height = viewBox.split()[2:] nattrs['width'] = width nattrs['height'] = height + # keep for svg use outside of font + if viewBox and (int(x) != 0 or int(y) != 0): + logging.warn('viewbox "%s" x: %s y: %s' % (viewBox, x, y)); + nattrs['viewBox'] = viewBox node.attrs = nattrs + # if display:none, skip this and its children + style = node.attrs.get('style') + if (style and 'display:none' in style) or node.attrs.get('display') == 'none': + node.contents = [] + return + # scan contents. remove any empty text nodes, or empty 'g' element nodes. # if a 'g' element has no attrs and only one subnode, replace it with the # subnode. @@ -212,6 +224,9 @@ class SvgCleaner(object): """For text nodes, replaces sequences of whitespace with a single space. For elements, replaces sequences of whitespace in attributes, and removes unwanted attributes from elements.""" + def __init__(self, strip): + logging.warning('writer strip: %s' % strip); + self._strip = strip def _write_node(self, node, lines, indent): """Node is a node generated by _Reader, either a TextNode or an @@ -222,7 +237,7 @@ class SvgCleaner(object): if node.text: lines.append(node.text) else: - margin = ' ' * indent + margin = '' if self._strip else ' ' * indent line = [margin] line.append('<%s' % node.name) # custom sort attributes of svg, yes this is a hack @@ -258,7 +273,7 @@ class SvgCleaner(object): # the result. lines = [] self._write_node(root, lines, 0) - return '\n'.join(lines) + return ''.join(lines) if self._strip else '\n'.join(lines) def tree_from_text(self, svg_text): return self.reader.from_text(svg_text) @@ -276,7 +291,7 @@ class SvgCleaner(object): return self.tree_to_text(tree) -def clean_svg_files(in_dir, out_dir, match_pat=None, clean=False): +def clean_svg_files(in_dir, out_dir, match_pat=None, clean=False, strip=False): regex = re.compile(match_pat) if match_pat else None count = 0 @@ -286,7 +301,7 @@ def clean_svg_files(in_dir, out_dir, match_pat=None, clean=False): out_dir = tool_utils.ensure_dir_exists(out_dir, clean=clean) - cleaner = SvgCleaner() + cleaner = SvgCleaner(strip) for file_name in os.listdir(in_dir): if regex and not regex.match(file_name): continue @@ -320,6 +335,9 @@ def main(): metavar='regex', default=None) parser.add_argument( '-l', '--loglevel', help='log level name/value', default='warning') + parser.add_argument( + '-w', '--strip_whitespace', help='remove newlines and indentation', + action='store_true') args = parser.parse_args() tool_utils.setup_logging(args.loglevel) @@ -331,7 +349,8 @@ def main(): logging.info('Writing output to %s', args.out_dir) clean_svg_files( - args.in_dir, args.out_dir, match_pat=args.regex, clean=args.clean) + args.in_dir, args.out_dir, match_pat=args.regex, clean=args.clean, + strip=args.strip_whitespace) if __name__ == '__main__':