Mercurial > MadButterfly
view tools/svg2code.py @ 1339:20cf3e2a0a9d
Fix weir behavior for tweening for opacity.
- The opacity is not work for more than one object been tweening.
- cause by the buggy style parser.
- It is fixed by a better style parser.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sun, 06 Feb 2011 22:57:33 +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