svg格式转ttfObject格式

@param {string} svg svg格式
@param {Object=} options 导入选项
@param {boolean} options.combinePath 是否合并成单个字形，仅限于普通svg导入
@return {Object} ttfObject
779626
function svg2ttfObject(svg, options) {
            options = options || {
                combinePath: false
            };

            var xmlDoc = svg;
            if (typeof svg === 'string') {
                svg = resolveSVG(svg);
                xmlDoc = loadXML(svg);
            }

            var ttf = parseXML(xmlDoc, options);
            return resolve(ttf);
        }
115283
private void doFilledPath(SvgElement obj, Path path)
   {
      // First check for pattern fill. It requires special handling.
      if (state.style.fill instanceof SVG.PaintReference)
      {
         SVG.SvgObject  ref = document.resolveIRI(((SVG.PaintReference) state.style.fill).href);
         if (ref instanceof SVG.Pattern) {
            SVG.Pattern  pattern = (SVG.Pattern)ref;
            fillWithPattern(obj, path, pattern);
            return;
         }
      }

      // Otherwise do a normal fill
      canvas.drawPath(path, state.fillPaint);
   }
3191
def addTurtlePathToSVG(self, svgContainer):
        
        for element in self.getSVGElements():
            svgContainer.addElement(element)
        return svgContainer
915883
function TTFReader(options) {
            options = options || {};
            options.subset = options.subset || [];       // 子集
            options.hinting = options.hinting || false; // 不保留hints信息
            options.compound2simple = options.compound2simple || false; // 复合字形转简单字形

            this.options = options;
        }
254188
function (srcPath, options) {
        _.defaults(options || (options = {}), DEFAULT_OPTIONS);
        var separator = options.separator;

        var reg = new RegExp('^sprite' + separator + '.+@\\d+x\\.png$');
        return reg.test(path.basename(srcPath));
    }
846736
function getRootSvg() {
  var childNodes = document.body.childNodes;
  var length = childNodes.length;
  for (var k = 0; k < length; k++) {
    var node = childNodes[k];
    if (node.tagName === 'svg' || node.tagName === 'SVG') {
      return node;
    }
  }
  return false;
}
365606
function(el, options) {
    var defaults = require('../utils/default-options')();

    if (typeof options === 'undefined') {
        options = {};
    }

    this.options = _.extend(defaults, options);
    this.color = this.options.color;

    this.xAccessor = this.options.xAccessor;
    this.yAccessor = this.options.yAccessor;

    this.el = el;

    this.selection = d3.select(el);

    this.transform = 0;

    this._data = [];

    this.area = d3.svg.area();

    this.zeroArea = d3.svg.area();

    this.series = this.selection.append('g')
        .attr('class', 'series')
        .attr('clip-path', 'url(#areaClip)');
}
485683
function clean(svgString, options) {
  var aSVGCleaner = new SVGCleaner(options);
  aSVGCleaner.load(svgString);
  return aSVGCleaner.clean().svgString();
}
1280868
async function buildPathsObject(files) {
  return Promise.all(
    files.map(async filepath => {
      const name = path.basename(filepath, '.svg');
      const svg = fs.readFileSync(filepath, 'utf-8');
      const pathStrings = await svgo.optimize(svg, { path: filepath })
        .then(({ data }) => data.match(/ d="[^"]+"/g) || [])
        .then(paths => paths.map(s => s.slice(3)));
      return `"${name}": [${pathStrings.join(',\n')}]`;
    }),
  );
}
1005635
private void textPath(Attributes attributes) throws SVGParseException
   {
      debug("<textPath>");

      if (currentElement == null)
         throw new SVGParseException("Invalid document. Root element must be <svg>");
      SVG.TextPath  obj = new SVG.TextPath();
      obj.document = svgDocument;
      obj.parent = currentElement;
      parseAttributesCore(obj, attributes);
      parseAttributesStyle(obj, attributes);
      parseAttributesConditional(obj, attributes);
      parseAttributesTextPath(obj, attributes);
      currentElement.addChild(obj);
      currentElement = obj;
      if (obj.parent instanceof TextRoot)
         obj.setTextRoot((TextRoot) obj.parent);
      else
         obj.setTextRoot(((TextChild) obj.parent).getTextRoot());
   }
1120774
def cleanPath(element, options):
    
    global _num_bytes_saved_in_path_data
    global _num_path_segments_removed

    # this gets the parser object from svg_regex.py
    oldPathStr = element.getAttribute('d')
    path = svg_parser.parse(oldPathStr)
    style = _getStyle(element)

    # This determines whether the stroke has round or square linecaps.  If it does, we do not want to collapse empty
    # segments, as they are actually rendered (as circles or squares with diameter/dimension matching the path-width).
    has_round_or_square_linecaps = (
        element.getAttribute('stroke-linecap') in ['round', 'square']
        or 'stroke-linecap' in style and style['stroke-linecap'] in ['round', 'square']
    )

    # This determines whether the stroke has intermediate markers.  If it does, we do not want to collapse
    # straight segments running in the same direction, as markers are rendered on the intermediate nodes.
    has_intermediate_markers = (
        element.hasAttribute('marker')
        or element.hasAttribute('marker-mid')
        or 'marker' in style
        or 'marker-mid' in style
    )

    # The first command must be a moveto, and whether it's relative (m)
    # or absolute (M), the first set of coordinates *is* absolute. So
    # the first iteration of the loop below will get x,y and startx,starty.

    # convert absolute coordinates into relative ones.
    # Reuse the data structure 'path', since we're not adding or removing subcommands.
    # Also reuse the coordinate lists since we're not adding or removing any.
    x = y = 0
    for pathIndex in range(len(path)):
        cmd, data = path[pathIndex]  # Changes to cmd don't get through to the data structure
        i = 0
        # adjust abs to rel
        # only the A command has some values that we don't want to adjust (radii, rotation, flags)
        if cmd == 'A':
            for i in range(i, len(data), 7):
                data[i + 5] -= x
                data[i + 6] -= y
                x += data[i + 5]
                y += data[i + 6]
            path[pathIndex] = ('a', data)
        elif cmd == 'a':
            x += sum(data[5::7])
            y += sum(data[6::7])
        elif cmd == 'H':
            for i in range(i, len(data)):
                data[i] -= x
                x += data[i]
            path[pathIndex] = ('h', data)
        elif cmd == 'h':
            x += sum(data)
        elif cmd == 'V':
            for i in range(i, len(data)):
                data[i] -= y
                y += data[i]
            path[pathIndex] = ('v', data)
        elif cmd == 'v':
            y += sum(data)
        elif cmd == 'M':
            startx, starty = data[0], data[1]
            # If this is a path starter, don't convert its first
            # coordinate to relative; that would just make it (0, 0)
            if pathIndex != 0:
                data[0] -= x
                data[1] -= y

            x, y = startx, starty
            i = 2
            for i in range(i, len(data), 2):
                data[i] -= x
                data[i + 1] -= y
                x += data[i]
                y += data[i + 1]
            path[pathIndex] = ('m', data)
        elif cmd in ['L', 'T']:
            for i in range(i, len(data), 2):
                data[i] -= x
                data[i + 1] -= y
                x += data[i]
                y += data[i + 1]
            path[pathIndex] = (cmd.lower(), data)
        elif cmd in ['m']:
            if pathIndex == 0:
                # START OF PATH - this is an absolute moveto
                # followed by relative linetos
                startx, starty = data[0], data[1]
                x, y = startx, starty
                i = 2
            else:
                startx = x + data[0]
                starty = y + data[1]
            for i in range(i, len(data), 2):
                x += data[i]
                y += data[i + 1]
        elif cmd in ['l', 't']:
            x += sum(data[0::2])
            y += sum(data[1::2])
        elif cmd in ['S', 'Q']:
            for i in range(i, len(data), 4):
                data[i] -= x
                data[i + 1] -= y
                data[i + 2] -= x
                data[i + 3] -= y
                x += data[i + 2]
                y += data[i + 3]
            path[pathIndex] = (cmd.lower(), data)
        elif cmd in ['s', 'q']:
            x += sum(data[2::4])
            y += sum(data[3::4])
        elif cmd == 'C':
            for i in range(i, len(data), 6):
                data[i] -= x
                data[i + 1] -= y
                data[i + 2] -= x
                data[i + 3] -= y
                data[i + 4] -= x
                data[i + 5] -= y
                x += data[i + 4]
                y += data[i + 5]
            path[pathIndex] = ('c', data)
        elif cmd == 'c':
            x += sum(data[4::6])
            y += sum(data[5::6])
        elif cmd in ['z', 'Z']:
            x, y = startx, starty
            path[pathIndex] = ('z', data)

    # remove empty segments and redundant commands
    # Reuse the data structure 'path' and the coordinate lists, even if we're
    # deleting items, because these deletions are relatively cheap.
    if not has_round_or_square_linecaps:
        # remove empty path segments
        for pathIndex in range(len(path)):
            cmd, data = path[pathIndex]
            i = 0
            if cmd in ['m', 'l', 't']:
                if cmd == 'm':
                    # It might be tempting to rewrite "m0 0 ..." into
                    # "l..." here.  However, this is an unsound
                    # optimization in general as "m0 0 ... z" is
                    # different from "l...z".
                    #
                    # To do such a rewrite, we need to understand the
                    # full subpath.  This logic happens after this
                    # loop.
                    i = 2
                while i < len(data):
                    if data[i] == data[i + 1] == 0:
                        del data[i:i + 2]
                        _num_path_segments_removed += 1
                    else:
                        i += 2
            elif cmd == 'c':
                while i < len(data):
                    if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == data[i + 4] == data[i + 5] == 0:
                        del data[i:i + 6]
                        _num_path_segments_removed += 1
                    else:
                        i += 6
            elif cmd == 'a':
                while i < len(data):
                    if data[i + 5] == data[i + 6] == 0:
                        del data[i:i + 7]
                        _num_path_segments_removed += 1
                    else:
                        i += 7
            elif cmd == 'q':
                while i < len(data):
                    if data[i] == data[i + 1] == data[i + 2] == data[i + 3] == 0:
                        del data[i:i + 4]
                        _num_path_segments_removed += 1
                    else:
                        i += 4
            elif cmd in ['h', 'v']:
                oldLen = len(data)
                path[pathIndex] = (cmd, [coord for coord in data if coord != 0])
                _num_path_segments_removed += len(path[pathIndex][1]) - oldLen

        # remove no-op commands
        pathIndex = len(path)
        subpath_needs_anchor = False
        # NB: We can never rewrite the first m/M command (expect if it
        # is the only command)
        while pathIndex > 1:
            pathIndex -= 1
            cmd, data = path[pathIndex]
            if cmd == 'z':
                next_cmd, next_data = path[pathIndex - 1]
                if next_cmd == 'm' and len(next_data) == 2:
                    # mX Yz -> mX Y

                    # note the len check on next_data as it is not
                    # safe to rewrite "m0 0 1 1z" in general (it is a
                    # question of where the "pen" ends - you can
                    # continue a draw on the same subpath after a
                    # "z").
                    del path[pathIndex]
                    _num_path_segments_removed += 1
                else:
                    # it is not safe to rewrite "m0 0 ..." to "l..."
                    # because of this "z" command.
                    subpath_needs_anchor = True
            elif cmd == 'm':
                if len(path) - 1 == pathIndex and len(data) == 2:
                    # Ends with an empty move (but no line/draw
                    # following it)
                    del path[pathIndex]
                    _num_path_segments_removed += 1
                    continue
                if subpath_needs_anchor:
                    subpath_needs_anchor = False
                elif data[0] == data[1] == 0:
                    # unanchored, i.e. we can replace "m0 0 ..." with
                    # "l..." as there is no "z" after it.
                    path[pathIndex] = ('l', data[2:])
                    _num_path_segments_removed += 1

    # fixup: Delete subcommands having no coordinates.
    path = [elem for elem in path if len(elem[1]) > 0 or elem[0] == 'z']

    # convert straight curves into lines
    newPath = [path[0]]
    for (cmd, data) in path[1:]:
        i = 0
        newData = data
        if cmd == 'c':
            newData = []
            while i < len(data):
                # since all commands are now relative, we can think of previous point as (0,0)
                # and new point (dx,dy) is (data[i+4],data[i+5])
                # eqn of line will be y = (dy/dx)*x or if dx=0 then eqn of line is x=0
                (p1x, p1y) = (data[i], data[i + 1])
                (p2x, p2y) = (data[i + 2], data[i + 3])
                dx = data[i + 4]
                dy = data[i + 5]

                foundStraightCurve = False

                if dx == 0:
                    if p1x == 0 and p2x == 0:
                        foundStraightCurve = True
                else:
                    m = dy / dx
                    if p1y == m * p1x and p2y == m * p2x:
                        foundStraightCurve = True

                if foundStraightCurve:
                    # flush any existing curve coords first
                    if newData:
                        newPath.append((cmd, newData))
                        newData = []
                    # now create a straight line segment
                    newPath.append(('l', [dx, dy]))
                else:
                    newData.extend(data[i:i + 6])

                i += 6
        if newData or cmd == 'z' or cmd == 'Z':
            newPath.append((cmd, newData))
    path = newPath

    # collapse all consecutive commands of the same type into one command
    prevCmd = ''
    prevData = []
    newPath = []
    for (cmd, data) in path:
        if prevCmd == '':
            # initialize with current path cmd and data
            prevCmd = cmd
            prevData = data
        else:
            # collapse if
            # - cmd is not moveto (explicit moveto commands are not drawn)
            # - the previous and current commands are the same type,
            # - the previous command is moveto and the current is lineto
            #   (subsequent moveto pairs are treated as implicit lineto commands)
            if cmd != 'm' and (cmd == prevCmd or (cmd == 'l' and prevCmd == 'm')):
                prevData.extend(data)
            # else flush the previous command if it is not the same type as the current command
            else:
                newPath.append((prevCmd, prevData))
                prevCmd = cmd
                prevData = data
    # flush last command and data
    newPath.append((prevCmd, prevData))
    path = newPath

    # convert to shorthand path segments where possible
    newPath = []
    for (cmd, data) in path:
        # convert line segments into h,v where possible
        if cmd == 'l':
            i = 0
            lineTuples = []
            while i < len(data):
                if data[i] == 0:
                    # vertical
                    if lineTuples:
                        # flush the existing line command
                        newPath.append(('l', lineTuples))
                        lineTuples = []
                    # append the v and then the remaining line coords
                    newPath.append(('v', [data[i + 1]]))
                    _num_path_segments_removed += 1
                elif data[i + 1] == 0:
                    if lineTuples:
                        # flush the line command, then append the h and then the remaining line coords
                        newPath.append(('l', lineTuples))
                        lineTuples = []
                    newPath.append(('h', [data[i]]))
                    _num_path_segments_removed += 1
                else:
                    lineTuples.extend(data[i:i + 2])
                i += 2
            if lineTuples:
                newPath.append(('l', lineTuples))
        # also handle implied relative linetos
        elif cmd == 'm':
            i = 2
            lineTuples = [data[0], data[1]]
            while i < len(data):
                if data[i] == 0:
                    # vertical
                    if lineTuples:
                        # flush the existing m/l command
                        newPath.append((cmd, lineTuples))
                        lineTuples = []
                        cmd = 'l'  # dealing with linetos now
                    # append the v and then the remaining line coords
                    newPath.append(('v', [data[i + 1]]))
                    _num_path_segments_removed += 1
                elif data[i + 1] == 0:
                    if lineTuples:
                        # flush the m/l command, then append the h and then the remaining line coords
                        newPath.append((cmd, lineTuples))
                        lineTuples = []
                        cmd = 'l'  # dealing with linetos now
                    newPath.append(('h', [data[i]]))
                    _num_path_segments_removed += 1
                else:
                    lineTuples.extend(data[i:i + 2])
                i += 2
            if lineTuples:
                newPath.append((cmd, lineTuples))
        # convert Bézier curve segments into s where possible
        elif cmd == 'c':
            # set up the assumed bezier control point as the current point,
            # i.e. (0,0) since we're using relative coords
            bez_ctl_pt = (0, 0)
            # however if the previous command was 's'
            # the assumed control point is a reflection of the previous control point at the current point
            if len(newPath):
                (prevCmd, prevData) = newPath[-1]
                if prevCmd == 's':
                    bez_ctl_pt = (prevData[-2] - prevData[-4], prevData[-1] - prevData[-3])
            i = 0
            curveTuples = []
            while i < len(data):
                # rotate by 180deg means negate both coordinates
                # if the previous control point is equal then we can substitute a
                # shorthand bezier command
                if bez_ctl_pt[0] == data[i] and bez_ctl_pt[1] == data[i + 1]:
                    if curveTuples:
                        newPath.append(('c', curveTuples))
                        curveTuples = []
                    # append the s command
                    newPath.append(('s', [data[i + 2], data[i + 3], data[i + 4], data[i + 5]]))
                    _num_path_segments_removed += 1
                else:
                    j = 0
                    while j <= 5:
                        curveTuples.append(data[i + j])
                        j += 1

                # set up control point for next curve segment
                bez_ctl_pt = (data[i + 4] - data[i + 2], data[i + 5] - data[i + 3])
                i += 6

            if curveTuples:
                newPath.append(('c', curveTuples))
        # convert quadratic curve segments into t where possible
        elif cmd == 'q':
            quad_ctl_pt = (0, 0)
            i = 0
            curveTuples = []
            while i < len(data):
                if quad_ctl_pt[0] == data[i] and quad_ctl_pt[1] == data[i + 1]:
                    if curveTuples:
                        newPath.append(('q', curveTuples))
                        curveTuples = []
                    # append the t command
                    newPath.append(('t', [data[i + 2], data[i + 3]]))
                    _num_path_segments_removed += 1
                else:
                    j = 0
                    while j <= 3:
                        curveTuples.append(data[i + j])
                        j += 1

                quad_ctl_pt = (data[i + 2] - data[i], data[i + 3] - data[i + 1])
                i += 4

            if curveTuples:
                newPath.append(('q', curveTuples))
        else:
            newPath.append((cmd, data))
    path = newPath

    # For each m, l, h or v, collapse unnecessary coordinates that run in the same direction
    # i.e. "h-100-100" becomes "h-200" but "h300-100" does not change.
    # If the path has intermediate markers we have to preserve intermediate nodes, though.
    # Reuse the data structure 'path', since we're not adding or removing subcommands.
    # Also reuse the coordinate lists, even if we're deleting items, because these
    # deletions are relatively cheap.
    if not has_intermediate_markers:
        for pathIndex in range(len(path)):
            cmd, data = path[pathIndex]

            # h / v expects only one parameter and we start drawing with the first (so we need at least 2)
            if cmd in ['h', 'v'] and len(data) >= 2:
                coordIndex = 0
                while coordIndex+1 < len(data):
                    if is_same_sign(data[coordIndex], data[coordIndex+1]):
                        data[coordIndex] += data[coordIndex+1]
                        del data[coordIndex+1]
                        _num_path_segments_removed += 1
                    else:
                        coordIndex += 1

            # l expects two parameters and we start drawing with the first (so we need at least 4)
            elif cmd == 'l' and len(data) >= 4:
                coordIndex = 0
                while coordIndex+2 < len(data):
                    if is_same_direction(*data[coordIndex:coordIndex+4]):
                        data[coordIndex] += data[coordIndex+2]
                        data[coordIndex+1] += data[coordIndex+3]
                        del data[coordIndex+2]  # delete the next two elements
                        del data[coordIndex+2]
                        _num_path_segments_removed += 1
                    else:
                        coordIndex += 2

            # m expects two parameters but we have to skip the first pair as it's not drawn (so we need at least 6)
            elif cmd == 'm' and len(data) >= 6:
                coordIndex = 2
                while coordIndex+2 < len(data):
                    if is_same_direction(*data[coordIndex:coordIndex+4]):
                        data[coordIndex] += data[coordIndex+2]
                        data[coordIndex+1] += data[coordIndex+3]
                        del data[coordIndex+2]  # delete the next two elements
                        del data[coordIndex+2]
                        _num_path_segments_removed += 1
                    else:
                        coordIndex += 2

    # it is possible that we have consecutive h, v, c, t commands now
    # so again collapse all consecutive commands of the same type into one command
    prevCmd = ''
    prevData = []
    newPath = [path[0]]
    for (cmd, data) in path[1:]:
        # flush the previous command if it is not the same type as the current command
        if prevCmd != '':
            if cmd != prevCmd or cmd == 'm':
                newPath.append((prevCmd, prevData))
                prevCmd = ''
                prevData = []

        # if the previous and current commands are the same type, collapse
        if cmd == prevCmd and cmd != 'm':
            prevData.extend(data)

        # save last command and data
        else:
            prevCmd = cmd
            prevData = data
    # flush last command and data
    if prevCmd != '':
        newPath.append((prevCmd, prevData))
    path = newPath

    newPathStr = serializePath(path, options)

    # if for whatever reason we actually made the path longer don't use it
    # TODO: maybe we could compare path lengths after each optimization step and use the shortest
    if len(newPathStr) <= len(oldPathStr):
        _num_bytes_saved_in_path_data += (len(oldPathStr) - len(newPathStr))
        element.setAttribute('d', newPathStr)
39266
function convertSVGBufferToPNG(buf, dest) {
    // Create a temporary SVG file to convert
    return fs.tmpFile({
        postfix: '.svg'
    })
    .then(function(tmpSvg) {
        return fs.writeFile(tmpSvg, buf)
        .then(function() {
            return convertSVGToPNG(tmpSvg, dest);
        });
    });
}
1057497
function loadSVGSuccess(text) {
        if (!destroyed && !unloaded) {
            if (!svgLoaded && text) {
                embedSVG(text);
                svgLoaded = true;
                if (!removeOnUnload) {
                    // cleanup the promise (abort will remove the svg text from
                    // the in-memory cache as well)
                    $loadSVGPromise.abort();
                    $loadSVGPromise = null;
                }
            }
            // always insert the svg el when load was successful
            if ($svg.parent().length === 0) {
                $svg.appendTo($svgLayer);
            }
        }
    }
581463
function ttfobject2symbol(ttf, options) {

            var xmlObject = {};
            var unitsPerEm = ttf.head.unitsPerEm;
            var descent = ttf.hhea.descent;
            // glyf 信息
            var symbolList = '';
            for (var i = 1, l = ttf.glyf.length; i < l; i++) {
                var glyf = ttf.glyf[i];
                // 筛选简单字形，并且有轮廓，有编码
                if (!glyf.compound && glyf.contours) {
                    var contours = pathsUtil.flip(glyf.contours);
                    var glyfObject = {
                        descent: descent,
                        unitsPerEm: unitsPerEm,
                        id: getSymbolId(glyf, i),
                        d: contours2svg(contours)
                    };
                    symbolList += string.format(SYMBOL_TPL, glyfObject);
                }
            }
            xmlObject.symbolList = symbolList;

            return string.format(XML_TPL, xmlObject);
        }
1012963
function ttfobject2svg(ttf, options) {

    var OS2 = ttf['OS/2'];

    // 用来填充xml的数据
    var xmlObject = {
        id: ttf.name.uniqueSubFamily || SVG_FONT_ID,
        metadata: string.encodeHTML(options.metadata || ''),
        advanceWidth: ttf.hhea.advanceWidthMax,
        fontFamily: ttf.name.fontFamily,
        fontWeight: OS2.usWeightClass,
        unitsPerEm: ttf.head.unitsPerEm,
        panose: [
            OS2.bFamilyType, OS2.bSerifStyle, OS2.bWeight, OS2.bProportion, OS2.bContrast,
            OS2.bStrokeVariation, OS2.bArmStyle, OS2.bLetterform, OS2.bMidline, OS2.bXHeight
        ].join(' '),
        ascent: ttf.hhea.ascent,
        descent: ttf.hhea.descent,
        xHeight: OS2.bXHeight,
        bbox: [ttf.head.xMin, ttf.head.yMin, ttf.head.xMax, ttf.head.yMax].join(' '),
        underlineThickness: ttf.post.underlineThickness,
        underlinePosition: ttf.post.underlinePosition,
        unicodeRange: 'U+' + string.pad(OS2.usFirstCharIndex.toString(16), 4)
            + '-' + string.pad(OS2.usLastCharIndex.toString(16), 4)
    };

    // glyf 第一个为missing glyph
    xmlObject.missing = {};
    xmlObject.missing.advanceWidth = ttf.glyf[0].advanceWidth || 0;
    xmlObject.missing.d = ttf.glyf[0].contours && ttf.glyf[0].contours.length
        ? 'd="' + contours2svg(ttf.glyf[0].contours) + '"'
        : '';

    // glyf 信息
    var glyphList = '';
    for (var i = 1, l = ttf.glyf.length; i < l; i++) {
        var glyf = ttf.glyf[i];

        // 筛选简单字形，并且有轮廓，有编码
        if (!glyf.compound && glyf.contours && glyf.unicode && glyf.unicode.length) {
            var glyfObject = {
                name: glyf.name,
                unicode: unicode2xml(glyf.unicode),
                d: contours2svg(glyf.contours)
            };
            glyphList += string.format(GLYPH_TPL, glyfObject);
        }
    }
    xmlObject.glyphList = glyphList;

    return string.format(XML_TPL, xmlObject);
}
1233372
function svgs(req, res) {
  const bundle = new Bundle(
    req.url.slice(1, -5).split('-').map(function map(name) {
      return assets[name];
    })
  );

  bundle.run(function (err, output) {
    if (err) throw err;

    res.setHeader('Content-Length', Buffer(output).length);
    res.writeHead(200, { 'Content-Type': 'text/plain' });

    res.end(output);
  });
}
883994
function svgShapesToPathRectToPath(attributes) {
  const x = 'undefined' !== typeof attributes.x ? parseFloat(attributes.x) : 0;
  const y = 'undefined' !== typeof attributes.y ? parseFloat(attributes.y) : 0;
  const width =
    'undefined' !== typeof attributes.width ? parseFloat(attributes.width) : 0;
  const height =
    'undefined' !== typeof attributes.height
      ? parseFloat(attributes.height)
      : 0;
  const rx =
    'undefined' !== typeof attributes.rx
      ? parseFloat(attributes.rx)
      : 'undefined' !== typeof attributes.ry ? parseFloat(attributes.ry) : 0;
  const ry =
    'undefined' !== typeof attributes.ry ? parseFloat(attributes.ry) : rx;

  return (
    '' +
    // start at the left corner
    'M' +
    (x + rx) +
    ' ' +
    y +
    // top line
    'h' +
    (width - rx * 2) +
    // upper right corner
    (rx || ry ? 'a ' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + ry : '') +
    // Draw right side
    'v' +
    (height - ry * 2) +
    // Draw bottom right corner
    (rx || ry ? 'a ' + rx + ' ' + ry + ' 0 0 1 ' + rx * -1 + ' ' + ry : '') +
    // Down the down side
    'h' +
    (width - rx * 2) * -1 +
    // Draw bottom right corner
    (rx || ry
      ? 'a ' + rx + ' ' + ry + ' 0 0 1 ' + rx * -1 + ' ' + ry * -1
      : '') +
    // Down the left side
    'v' +
    (height - ry * 2) * -1 +
    // Draw bottom right corner
    (rx || ry ? 'a ' + rx + ' ' + ry + ' 0 0 1 ' + rx + ' ' + ry * -1 : '') +
    // Close path
    'z'
  );
}