Mercurial > MadButterfly
view tools/svg2code.py @ 842:76fe4afce640
The inkscape:bbox is defined as the global coordinate system. However, the center.x and center.y must be the coordiante system of the parent group of the SVG entity. Therefore, we need to do coordinate transformation from the global coordination system to the local coordination system.
author | wycc |
---|---|
date | Sat, 18 Sep 2010 21:23:51 +0800 |
parents | 586e50f82c1f |
children |
line wrap: on
line source
#! /usr/bin/env python # -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*- # vim: sw=4:ts=8:sts=4 from xml.dom.minidom import parse import sys import re svgns='http://www.w3.org/2000/svg' xlinkns='http://www.w3.org/1999/xlink' re_rgb = re.compile('rgb\\( *([0-9]+(\\.[0-9]+)?) *, *([0-9]+(\\.[0-9]+)?) *, *([0-9]+(\\.[0-9]+)?) *\\)') def translate_stops(parent, codefo, parent_id): stops = [] for node in parent.childNodes: if node.localName == 'stop' and node.namespaceURI == svgns: style = node.getAttribute('style') style_props = [prop.strip() for prop in style.split(';') if prop.strip()] style_kvpairs = [prop.split(':') for prop in style_props] style_kvpairs = [(prop[0].strip(), prop[1].strip()) for prop in style_kvpairs] style_map = dict(style_kvpairs) color = style_map['stop-color'].strip() if len(color) == 7 and color[0] == '#': r = float(int(color[1:3], 16)) / 255.0 g = float(int(color[3:5], 16)) / 255.0 b = float(int(color[5:7], 16)) / 255.0 elif color.lower() == 'white': r, g, b = 1, 1, 1 elif color.lower() == 'black': r, g, b = 0, 0, 0 else: mo = re_rgb.match(color) if mo: r = float(mo.group(1)) g = float(mo.group(3)) b = float(mo.group(5)) else: raise ValueError, '\'%s\' is invalid color value.' % (color) pass try: opacity = style_map['stop-opacity'] except: opacity = 1 pass offset = node.getAttribute('offset') stops.append('[COLOR_STOP([%s], %f, %f, %f, %f, %f)]' % ( parent_id, r, g, b, float(opacity), float(offset))) pass pass print >> codefo, '%sdnl' % (', '.join(stops)) pass def translate_linearGradient(linear, codefo, doc): linear_id = _get_id(linear) if linear.hasAttribute('x1'): x1 = float(linear.getAttribute('x1')) y1 = float(linear.getAttribute('y1')) x2 = float(linear.getAttribute('x2')) y2 = float(linear.getAttribute('y2')) else: x1 = y1 = x2 = y2 = 0 pass print >> codefo, 'ADD_LINEAR_PAINT([%s], %f, %f, %f, %f, [' % ( linear_id, x1, y1, x2, y2) translate_stops(linear, codefo, linear_id) print >> codefo, '])dnl' href = linear.getAttributeNS(xlinkns, 'href').strip() if href and href[0] == '#': print >> codefo, 'REF_STOPS_LINEAR([%s], [%s])dnl' % ( linear_id, href[1:]) pass pass def translate_radialGradient(radial, codefo, doc): radial_id = _get_id(radial) try: cx = float(radial.getAttribute('cx')) cy = float(radial.getAttribute('cy')) except: cx = cy = 0 pass try: r = float(radial.getAttribute('r')) except: r = 0.5 pass print >> codefo, 'ADD_RADIAL_PAINT([%s], %f, %f, %f, [' % ( radial_id, cx, cy, r) translate_stops(radial, codefo, radial_id) print >>codefo, '])dnl' href = radial.getAttributeNS(xlinkns, 'href').strip() if href[0] == '#': print >> codefo, 'REF_STOPS_RADIAL([%s], [%s])dnl' % ( radial_id, href[1:]) pass pass def translate_defs(defs, codefo, doc): for node in defs.childNodes: if node.namespaceURI != svgns: continue if node.localName == 'linearGradient': translate_linearGradient(node, codefo, doc) pass elif node.localName == 'radialGradient': translate_radialGradient(node, codefo, doc) pass pass pass def trans_color(code): return int(code[1:3], 16) / 255.0, \ int(code[3:5], 16) / 255.0, \ int(code[5:7], 16) / 255.0 def get_style_map(style_str): prop_strs = [s.strip() for s in style_str.split(';')] prop_kvs = [s.split(':') for s in prop_strs if s] prop_kvs = [(k.strip(), v.strip()) for k, v in prop_kvs] prop_map = dict(prop_kvs) return prop_map def translate_style(node, coord_id, codefo, doc, prefix): node_id = node.getAttribute('id') try: prop_map = node.style_map except: style_str = node.getAttribute('style') prop_map = get_style_map(style_str) pass if node.hasAttribute('fill-opacity'): opacity = float(node.getAttribute('fill-opacity')) elif node.hasAttribute('opacity'): opacity = float(node.getAttribute('opacity')) else: opacity = 1 pass try: opacity = float(prop_map['opacity']) except: pass if prop_map.has_key('fill'): fill = prop_map['fill'].strip() if fill.startswith('#') and len(fill) == 7: r, g, b = trans_color(fill) print >> codefo, 'FILL_SHAPE([%s], %f, %f, %f, %f)dnl' % ( node_id, r, g, b, opacity) elif fill.startswith('url(') and fill.endswith(')'): paint_id = fill[5:-1] print >> codefo, 'FILL_SHAPE_WITH_PAINT([%s], [%s])dnl' % ( node_id, paint_id) elif fill.lower() == 'none': pass else: raise ValueError, '\'%s\' is an invalid value for fill.' % (fill) pass if node.hasAttribute('stroke-opacity'): stroke_opacity = float(node.getAttribute('stroke-opacity')) elif node.hasAttribute('opacity'): stroke_opacity = float(node.getAttribute('opacity')) else: stroke_opacity = 1.0 pass if prop_map.has_key('stroke'): stroke = prop_map['stroke'].strip() if stroke.startswith('#') and len(stroke) == 7: r, g, b = trans_color(stroke) print >> codefo, 'STROKE_SHAPE([%s], %f, %f, %f, %f)dnl' % ( node_id, r, g, b, stroke_opacity) elif stroke.startswith('url(') and stroke.endswith(')'): paint_id = stroke[5:-1] print >> codefo, 'STROKE_SHAPE_WITH_PAINT([%s], [%s])dnl' % ( node_id, paint_id) elif stroke.lower() == 'none': pass else: raise ValueError, '\'%s\' is an invalid value for stroke.' \ % (stroke) pass if prop_map.has_key('stroke-width'): if prop_map['stroke-width'].endswith('px'): stroke_width = float(prop_map['stroke-width'][:-2]) / 2 else: stroke_width = float(prop_map['stroke-width']) / 2 pass print >> codefo, 'STROKE_WIDTH([%s], %f)dnl' % ( node_id, stroke_width) pass elif prop_map.has_key('stroke') and prop_map['stroke'] != 'none': print >> codefo, 'STROKE_WIDTH([%s], %f)dnl' % ( node_id, 0.5) pass if prop_map.has_key('display'): display = prop_map['display'].strip().lower() if display == 'none': print >> codefo, '%sHIDE([%s])dnl' % (prefix, node_id) pass pass pass def translate_shape_transform(shape, coord_id, codefo): shape_id = shape.getAttribute('id') if shape.hasAttribute('transform'): shape_coord_id = shape_id + '_coord' ## \page shape_coord Coordinate Transformation for Shapes. # # svg2code.py add a coord_t for a shape if transform attribute # of it's tag is setted. The name of coord_t object is # <shape_id> + "_coord". print >> codefo, 'dnl' print >> codefo, 'ADD_COORD([%s], [%s])dnl' % ( shape_coord_id, coord_id) transform = shape.getAttribute('transform') translate_transform(shape_coord_id, transform, codefo, 'SHAPE_') coord_id = shape_coord_id pass return coord_id ## \brief Calculate geometry of ellipse where the arc is on. # # This function calculate the ellipse with information from SVG path data. # # \see calc_center_and_x_aix() def _calc_ellipse_of_arc(x0, y0, rx, ry, x_rotate, large, sweep, x, y): import math _sin = math.sin(x_rotate) _cos = math.cos(x_rotate) nrx = x * _cos + y * _sin # Not Rotated X nry = x * -_sin + y * _cos nrx0 = x0 * _cos + y0 * _sin nry0 = x0 * -_sin + y0 * _cos udx = (nrx - nrx0) / 2 / rx # ux - umx udy = (nry - nry0) / 2 / ry # uy - umy umx = (nrx + nrx0) / 2 / rx umy = (nry + nry0) / 2 / ry udx2 = udx * udx udy2 = udy * udy udl2 = udx2 + udy2 if udl2 > 1: # make sure never > 1 udl2 = 1 pass if udy != 0: # center is at left-side of arc udcx = -math.sqrt((1 - udl2) * udl2) / (udy + udx2 / udy) udcy = -udcx * udx / udy else: # center is at down-side of arc udcx = 0 udcy = math.sqrt((1 - udl2) * udl2) / udx pass reflect = 0 if large: reflect ^= 1 pass if sweep != 1: reflect ^= 1 pass if reflect: udcx = -udcx udcy = -udcy pass nrcx = rx * (udcx + umx) nrcy = ry * (udcy + umy) cx = nrcx * _cos - nrcy * _sin cy = nrcx * _sin + nrcy * _cos return cx, cy # M x y : Move to (x,y) # Z : close path # L x y : lineto (x,y) # H x : horizontal line to x # V y : Vertical line to y # C x1 y1 x2 y2 x y : Draw a segment of bezier curve # S x2 y2 x t : Draw a segment of bezier curve from the last # control point # Q x1 y1 x y : Draw a segment of quadratic curve # T x y : Draw a segment of quadratic curve from the last # control pint # A x y r f s x y : Draw an arc # translate the path data into two arrays. The first is an integer whose # upper 8 bits are the command type The second array hold all arguments. command_length={'M': 2, 'm':2, 'Z': 0, 'z':0, 'L': 2, 'l':2, 'H': 1, 'h':1, 'V': 1, 'v':1, 'C': 6, 'c':6, 'S': 4, 's':4, 'Q': 4, 'q':4, 'T': 2, 't':2, 'A': 7, 'a':7} def _angle_rotated_ellipse(x, y, rx, ry, x_rotate): import math _cos = math.cos(x_rotate) _sin = math.sin(x_rotate) nrx = (x * _cos + y * _sin) / rx nry = (-x * _sin + y * _cos) / ry xy_tan = nry / nrx xy_angle = math.atan(xy_tan) if nrx < 0: xy_angle = math.pi + xy_angle pass return xy_angle def rotate(x, y, angle): import math _cos = math.cos(angle) _sin = math.sin(angle) nx = x * _cos - y * _sin ny = x * _sin + y * _cos return nx, ny def translate_path_data(data, codefo): import string import math temp = data.split() fields=[] for f in temp: for s in f.split(','): if s != '': fields.append(s) cmd = '' cmd_args=0 commands='' pnts=[] float_args=[] for f in fields: if f in command_length: if cmd_args != 0 and (narg % cmd_args) != 0: raise ValueError, 'invalid path data %s' % (repr(fields)) cmd = f cmd_args = command_length[f] narg = 0 continue if (narg % cmd_args) == 0: commands = commands + cmd pass if cmd == 'H': arg = float(f) pnts.append(arg) pnts.append(pnts[-2]) continue if cmd == 'h': arg = float(f) pnts.append(arg + pnts[-2]) pnts.append(pnts[-2]) continue if cmd == 'V': arg = float(f) pnts.append(pnts[-2]) pnts.append(arg) continue if cmd == 'v': arg = float(f) pnts.append(pnts[-2]) pnts.append(arg + pnts[-2]) continue arg = float(f) if (cmd not in 'am') and (cmd in string.lowercase): # relative and not arc or moveto arg = arg + pnts[-2] pass pnts.append(arg) narg = narg + 1 # For arc curve if (narg % cmd_args) == 0 and (cmd in 'Aa'): x0, y0, rx, ry, x_rotate, large, sweep, x, y = \ tuple(pnts[-9:]) if cmd == 'a': # relative position abs_x = x + x0 abs_y = y + y0 else: abs_x = x abs_y = y pass x_rotate = int(x_rotate) large = int(large) sweep = int(sweep) cx, cy = _calc_ellipse_of_arc(x0, y0, rx, ry, x_rotate, large, sweep, abs_x, abs_y) # Corners c0x, c0y = rotate(-rx, -ry, x_rotate) c0x, c0y = c0x + cx, c0y + cy c1x, c1y = rotate(rx, -ry, x_rotate) c1x, c1y = c1x + cx, c1y + cy c2x, c2y = rotate(rx, ry, x_rotate) c2x, c2y = c2x + cx, c2y + cy c3x, c3y = rotate(-rx, ry, x_rotate) c3x, c3y = c3x + cx, c3y + cy pnts[-7:] = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y, abs_x, abs_y] start_angle = _angle_rotated_ellipse(x0 - cx, y0 - cy, rx, ry, x_rotate) stop_angle = _angle_rotated_ellipse(x - cx, y - cy, rx, ry, x_rotate) # sweep == 1 for positive-angle direction # sweep == 0 for negative-angle direction if start_angle > stop_angle and sweep: stop_angle = math.pi * 2 + stop_angle elif start_angle < stop_angle and not sweep: start_angle = math.pi * 2 + start_angle pass float_args.extend([cx, cy, rx, ry, start_angle, stop_angle, x_rotate]) pass pass return commands, pnts, float_args _id_sn = 0 def _get_id(obj): global _id_sn if obj.hasAttribute('id'): oid = obj.getAttribute('id') else: oid = '_MB_RAND_%s_' % (_id_sn) obj.setAttribute('id', oid) _id_sn = _id_sn + 1 pass return oid ## # Decorator that check if objects have attribute 'mbname'. # def check_mbname(func): def deco(obj, coord_id, codefo, doc): if obj.hasAttribute('mbname') and obj.getAttribute('mbname'): ## \note mbname declare that this node should be in the # symbol table. mbname = obj.getAttribute('mbname') id = obj.getAttribute('id') print >> codefo, 'ADD_SYMBOL([%s],[%s])dnl' % (id,mbname) pass func(obj, coord_id, codefo, doc) pass return deco @check_mbname def translate_path(path, coord_id, codefo, doc): coord_id = translate_shape_transform(path, coord_id, codefo) path_id = path.getAttribute('id') d = path.getAttribute('d') (commands, pnts, float_args) = translate_path_data(d, codefo) print >> codefo, 'dnl' #print >> codefo, 'ADD_PATH([%s], [%s], [%s])dnl' % (path_id, d, coord_id) spnts='' for c in pnts: spnts = spnts + "%f," % c s_float_arg='' for c in float_args: s_float_arg = s_float_arg + ("%f," % c) print >> codefo, 'ADD_PATH([%s], [%s], [%s], [%s], [%d], [%s], [%d])dnl' % ( path_id, coord_id, commands, spnts, len(pnts), s_float_arg, len(float_args)) translate_style(path, coord_id, codefo, doc, 'PATH_') pass @check_mbname def translate_rect(rect, coord_id, codefo, doc): coord_id = translate_shape_transform(rect, coord_id, codefo) rect_id = _get_id(rect) x = float(rect.getAttribute('x')) y = float(rect.getAttribute('y')) rx = 0.0 if rect.hasAttribute('rx'): rx = float(rect.getAttribute('rx')) pass ry = 0.0 if rect.hasAttribute('ry'): ry = float(rect.getAttribute('ry')) pass width = float(rect.getAttribute('width')) height = float(rect.getAttribute('height')) print >> codefo, 'dnl' print >> codefo, 'ADD_RECT([%s], %f, %f, %f, %f, %f, %f, [%s])dnl' % ( rect_id, x, y, width, height, rx, ry, coord_id) translate_style(rect, coord_id, codefo, doc, 'RECT_') pass def translate_font_style(text, codefo): text_id = _get_id(text) style_str = text.getAttribute('style') style_map = get_style_map(style_str) return style_map def merge_style(tspan, text): newmap = tspan.style_map map = text.style_map for k,v in text.style_map.items(): if not newmap.has_key(k): newmap[k] = v pass pass pass def translate_tspan(tspan, text, coord_id, codefo, doc, txt_strs, attrs): try: map = tspan.style_map except: map = translate_font_style(tspan, codefo) tspan.style_map = map pass if tspan.hasAttribute('x'): # Render the tspan as an independent text if the x # attribute is defined. All elements inside # the tspan will be ignore by the outter text or tspan elements. # FIXME: We need to apply the style map recursively. merge_style(tspan, text) translate_text(tspan, coord_id, codefo, doc) return '' attr = [len(txt_strs.encode('utf8')) - 1, 0, tspan] attrs.append(attr) for node in tspan.childNodes: if node.localName == None: txt_strs = txt_strs + node.data elif node.localName == 'tspan': txt_strs = translate_tspan(node, tspan, coord_id, codefo, doc, txt_strs, attrs) pass pass attr[1] = len(txt_strs.encode('utf8')) return txt_strs def pango_generate_font_attributes(attrs,coord_id, codefo,doc): for a in attrs: start = a[0] end = a[1] node = a[2] #print "generate attributes from %d to %d" %(start,end) style_map = node.style_map #print [style_map] if style_map.has_key('font-size'): # FIXME: Implement all units here if style_map['font-size'].endswith('px'): font_sz = float(style_map['font-size'][:-2]) print >> codefo, 'PANGO_SIZE(%d,%d,%d)dnl' % (font_sz*1024,start,end) else: font_sz = float(style_map['font-size']) print >> codefo, 'PANGO_SIZE(%d,%d,%d)dnl' % (font_sz*1024,start,end) pass pass if style_map.has_key('font-style'): font_style = style_map['font-style'].lower() if font_style == 'normal': print >> codefo, 'PANGO_STYLE(PANGO_STYLE_NORMAL,%d,%d)dnl' % (start,end) elif font_style == 'italic': print >> codefo, 'PANGO_STYLE(PANGO_STYLE_ITALIC,%d,%d)dnl' % (start,end) elif font_style == 'oblique': print >> codefo, 'PANGO_STYLE(PANGO_STYLE_OBLIQUE,%d,%d)dnl' % (start,end) pass pass if style_map.has_key('font-family'): font_family = style_map['font-family'] print >> codefo, 'PANGO_FAMILY(%s,%d,%d)dnl' % (font_family,start,end) pass if style_map.has_key('text-anchor'): text_anchor = style_map['text-anchor'].lower() # FIXME: We need to implement a mb_text_set_aligment to implement SVG-styled alignment. print "The text-anchor is not implemented yet" pass if style_map.has_key('font-variant'): font_variant = style_map['font-variant'].lower() print "The font-variant is not implemented yet" pass if style_map.has_key('font-weight'): font_weight = style_map['font-weight'].lower() if font_weight == 'normal': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_NORMAL,%d,%d)dnl' % (start,end) elif font_weight == 'bold': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_BOLD,%d,%d)dnl' % (start,end) elif font_weight == 'bolder': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_HEAVY,%d,%d)dnl' % (start,end) elif font_weight == 'lighter': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_ULTRALIGHT,%d,%d)dnl' % (start,end) elif font_weight == '100': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_ULTRALIGHT,%d,%d)dnl' % (start,end) elif font_weight == '200': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_ULTRALIGHT,%d,%d)dnl' % (start,end) elif font_weight == '300': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_LIGHT,%d,%d)dnl' % (start,end) elif font_weight == '400': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_NORMAL,%d,%d)dnl' % (start,end) elif font_weight == '500': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_NORMAL,%d,%d)dnl' % (start,end) elif font_weight == '600': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_SEMIBOLD,%d,%d)dnl' % (start,end) elif font_weight == '700': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_BOLD,%d,%d)dnl' % (start,end) elif font_weight == '800': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_ULTRABOLD,%d,%d)dnl' % (start,end) elif font_weight == '900': print >> codefo, 'PANGO_STYLE(PANGO_WEIGHT_HEAVY,%d,%d)dnl' % (start,end) else: print "The font-weight %s is not supported" % font_weight pass pass if style_map.has_key('direction'): direction = style_map['direction'].lower() print "The direction is not implemented yet" pass if style_map.has_key('unicode-bidi'): bidi = style_map['unicode-bidi'].lower() print "The bidi is not implemented yet" pass pass pass def pango_gen_text(text, coord_id, codefo, doc, txt_strs, attrs): if txt_strs: text_id = _get_id(text) x = float(text.getAttribute('x')) y = float(text.getAttribute('y')) print >> codefo, 'dnl' print >> codefo, \ 'PANGO_BEGIN_TEXT([%s], [%s], %f, %f, 16, [%s])dnl' % ( text_id.encode('utf8'), u''.join(txt_strs).encode('utf8'), x, y, coord_id.encode('utf8')) pango_generate_font_attributes(attrs, coord_id, codefo, doc) print >> codefo, \ 'PANGO_END_TEXT([%s], [%s], %f, %f, 16, [%s])dnl' % ( text_id.encode('utf8'), u''.join(txt_strs).encode('utf8'), x, y, coord_id.encode('utf8')) translate_style(text, coord_id, codefo, doc, 'TEXT_') pass pass def stext_generate_font_attributes(text, attrs, coord_id, codefo, doc): text_id = _get_id(text) for start, end, node in attrs: style_map = node.style_map font_sz = 10 if style_map.has_key('font-size'): fsz = style_map['font-size'] if fsz.endswith('px'): font_sz = float(fsz[:-2]) else: font_sz = float(fsz) pass pass if style_map.has_key('font-family'): font_family = style_map['font-family'] else: font_family = 'serif' pass font_slant = 0 if style_map.has_key('font-style'): fn_style = style_map['font-style'] if fn_style == 'normal': font_slant = 0 elif fn_style == 'italic': font_slant = 100 elif fn_style == 'oblique': font_slant = 110 else: raise ValueError, '%s is not a valid font-style' % (fn_style) pass font_weight = 80 if style_map.has_key('font-weight'): fn_weight = style_map['font-weight'] if fn_weight == 'normal': font_weight = 80 elif fn_weight == 'medium': font_weight = 100 elif fn_weight == 'bold': font_weight = 200 elif fn_weight == 'bolder': font_weight = 150 elif fn_weight == 'light': font_weight = 50 elif fn_weight == 'lighter': font_weight = 70 else: font_weight = int(fn_weight) pass pass print >> codefo, 'STYLE_BLOCK([%s], %d, [%s], %f, %d, %d)dnl' % ( text_id, end - start, font_family, font_sz, font_slant, font_weight) pass pass def stext_gen_text(text, coord_id, codefo, doc, txt_strs, attrs): if not txt_strs: return text_id = _get_id(text) x = float(text.getAttribute('x')) y = float(text.getAttribute('y')) print >> codefo, 'dnl' print >> codefo, \ 'ADD_STEXT([%s], [%s], %f, %f, [%s])dnl' % \ (text_id, txt_strs.encode('utf8'), x, y, coord_id) translate_style(text, coord_id, codefo, doc, 'STEXT_') stext_generate_font_attributes(text, attrs, coord_id, codefo, doc) pass def gen_text(text, coord_id, codefo, doc, txt_strs, attrs): raise NotImplementedError, \ 'gen_text should be assigned to an implementation' @check_mbname def translate_text(text, coord_id, codefo, doc): coord_id = translate_shape_transform(text, coord_id, codefo) try: map = text.style_map except: map = translate_font_style(text, codefo) text.style_map = map pass attrs = [] attr = [0, 0, text] attrs.append(attr) txt_strs = '' for node in text.childNodes: if node.localName == None: txt_strs = txt_strs + node.data elif node.localName == 'tspan': txt_strs = translate_tspan(node, text, coord_id, codefo, doc,txt_strs, attrs) pass pass attr[1] = len(txt_strs.encode('utf8')) gen_text(text, coord_id, codefo, doc, txt_strs, attrs) pass @check_mbname def translate_image(image, coord_id, codefo, doc): coord_id = translate_shape_transform(image, coord_id, codefo) image_id = _get_id(image) if not image.hasAttributeNS(xlinkns, 'href'): raise ValueError, 'image %s must has a href attribute.' % (image_id) href = image.getAttributeNS(xlinkns, 'href') if image.hasAttribute('x'): x_str = image.getAttribute('x') x = float(x_str) else: x = 0 pass if image.hasAttribute('y'): y_str = image.getAttribute('y') y = float(y_str) else: y = 0 pass if image.hasAttribute('width'): width_str = image.getAttribute('width') width = float(width_str) else: width = -1 pass if image.hasAttribute('height'): height_str = image.getAttribute('height') height = float(height_str) else: height = -1 pass print >> codefo, 'dnl' print >> codefo, \ 'ADD_IMAGE([%s], [%s], %f, %f, %f, %f, [%s])dnl' % ( image_id, href, x, y, width, height, coord_id) pass reo_func = re.compile('([a-zA-Z]+)\\([^\\)]*\\)') reo_translate = re.compile('translate\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)') reo_matrix = re.compile('matrix\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)') def translate_transform(coord_id, transform, codefo, prefix): transform = transform.strip() mo = reo_func.match(transform) if not mo: return name = mo.group(1) if name == 'translate': mo = reo_translate.match(transform) if mo: x = float(mo.group(1)) y = float(mo.group(3)) print >> codefo, '%sTRANSLATE([%s], %f, %f)dnl' % ( prefix, coord_id, x, y) pass elif name == 'matrix': mo = reo_matrix.match(transform) if mo: r10, r11, r12 = \ float(mo.group(1)), float(mo.group(3)), float(mo.group(5)) r20, r21, r22 = \ float(mo.group(7)), float(mo.group(9)), float(mo.group(11)) print >> codefo, \ '%sMATRIX([%s], %f, %f, %f, %f, %f, %f)dnl' % ( prefix, coord_id, r10, r11, r12, r20, r21, r22) pass pass pass @check_mbname def translate_group(group, parent_id, codefo, doc): group_id = _get_id(group) print >> codefo, 'dnl' print >> codefo, 'ADD_COORD([%s], [%s])dnl' % (group_id, parent_id) if group.hasAttribute('transform'): transform = group.getAttribute('transform') translate_transform(group_id, transform, codefo, 'COORD_') pass mock_sn = 0 translate_style(group, group_id, codefo, doc, 'GROUP_') for node in group.childNodes: if node.namespaceURI != svgns: continue if node.localName == 'g': translate_group(node, group_id, codefo, doc) elif node.localName == 'path': translate_path(node, group_id, codefo, doc) elif node.localName == 'rect': translate_rect(node, group_id, codefo, doc) elif node.localName == 'text': translate_text(node, group_id, codefo, doc) elif node.localName == 'image': translate_image(node, group_id, codefo, doc) elif node.localName == 'textarea': translate_textarea(node, group_id, codefo, doc) pass pass pass ## \brief Translate "scenes" tag in "metadata" tag. # def translate_scenes(scenes_node, codefo, doc): scenes = [] for scene in scenes_node.childNodes: if scene.localName != 'scene' or \ not scene.hasAttribute('ref') or \ not scene.hasAttribute('start'): continue start_str = scene.getAttribute('start') start = end = int(start_str) if scene.hasAttribute('end'): end_str = scene.getAttribute('end') end = int(end_str) pass ref = scene.getAttribute('ref') while len(scenes) <= end: scenes.append([]) pass for i in range(start, end + 1): scenes[i].append(ref) pass pass for scene_idx, groups_in_scene in enumerate(scenes): if groups_in_scene: groups_str = '[' + '],['.join(groups_in_scene) + ']' else: groups_str = '' pass print >> codefo, \ 'SCENE(%d, [%s])dnl' % (scene_idx, groups_str) pass pass def svg_2_code(dom, codefo): for node in dom.childNodes: if node.localName == 'svg' and node.namespaceURI == svgns: break; pass else: raise ValueErr, 'no any svg tag node.' svg = node for node in svg.childNodes: if node.localName == 'defs' and node.namespaceURI == svgns: translate_defs(node, codefo, dom) elif node.localName == 'metadata' and node.namespaceURI == svgns: for meta_node in node.childNodes: if meta_node.localName == 'scenes': translate_scenes(meta_node, codefo, dom) pass pass pass elif node.localName == 'g' and node.namespaceURI == svgns: translate_group(node, 'root_coord', codefo, dom) pass pass pass if __name__ == '__main__': from os import path import optparse usage='usage: %prog [options] <SVG file> [<output>]' parser = optparse.OptionParser(usage=usage) parser.add_option('-s', '--stext', dest='stext', action='store_true', default=False, help='Use sh_stext instead of sh_text'); options, args = parser.parse_args() if len(args) == 2: svgfn = args[0] codefn = args[1] elif len(args) == 1: svgfn = args[0] codefn = 'out.mb' else: parser.print_help() sys.exit(1) pass struct_name = path.basename(codefn).split('.')[0] if options.stext: gen_text = stext_gen_text else: gen_text = pango_gen_text pass dom = parse(svgfn) codefo = file(codefn, 'w+') print >> codefo, 'MADBUTTERFLY([%s],[dnl' % (struct_name) svg_2_code(dom, codefo) print >> codefo, '])dnl' pass