Mercurial > MadButterfly
comparison tools/svg2code.py @ 822:586e50f82c1f
Unify coding style tag for emacs and vim.
author | Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com> |
---|---|
date | Tue, 14 Sep 2010 01:08:39 +0800 |
parents | bb4f651090bf |
children |
comparison
equal
deleted
inserted
replaced
821:bfdc82bbd6e4 | 822:586e50f82c1f |
---|---|
1 #! /usr/bin/env python | 1 #! /usr/bin/env python |
2 # -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*- | |
3 # vim: sw=4:ts=8:sts=4 | |
2 from xml.dom.minidom import parse | 4 from xml.dom.minidom import parse |
3 import sys | 5 import sys |
4 import re | 6 import re |
5 | 7 |
6 svgns='http://www.w3.org/2000/svg' | 8 svgns='http://www.w3.org/2000/svg' |
129 prop_map = node.style_map | 131 prop_map = node.style_map |
130 except: | 132 except: |
131 style_str = node.getAttribute('style') | 133 style_str = node.getAttribute('style') |
132 prop_map = get_style_map(style_str) | 134 prop_map = get_style_map(style_str) |
133 pass | 135 pass |
134 | 136 |
135 if node.hasAttribute('fill-opacity'): | 137 if node.hasAttribute('fill-opacity'): |
136 opacity = float(node.getAttribute('fill-opacity')) | 138 opacity = float(node.getAttribute('fill-opacity')) |
137 elif node.hasAttribute('opacity'): | 139 elif node.hasAttribute('opacity'): |
138 opacity = float(node.getAttribute('opacity')) | 140 opacity = float(node.getAttribute('opacity')) |
139 else: | 141 else: |
232 # This function calculate the ellipse with information from SVG path data. | 234 # This function calculate the ellipse with information from SVG path data. |
233 # | 235 # |
234 # \see calc_center_and_x_aix() | 236 # \see calc_center_and_x_aix() |
235 def _calc_ellipse_of_arc(x0, y0, rx, ry, x_rotate, large, sweep, x, y): | 237 def _calc_ellipse_of_arc(x0, y0, rx, ry, x_rotate, large, sweep, x, y): |
236 import math | 238 import math |
237 | 239 |
238 _sin = math.sin(x_rotate) | 240 _sin = math.sin(x_rotate) |
239 _cos = math.cos(x_rotate) | 241 _cos = math.cos(x_rotate) |
240 | 242 |
241 nrx = x * _cos + y * _sin # Not Rotated X | 243 nrx = x * _cos + y * _sin # Not Rotated X |
242 nry = x * -_sin + y * _cos | 244 nry = x * -_sin + y * _cos |
243 nrx0 = x0 * _cos + y0 * _sin | 245 nrx0 = x0 * _cos + y0 * _sin |
244 nry0 = x0 * -_sin + y0 * _cos | 246 nry0 = x0 * -_sin + y0 * _cos |
245 | 247 |
246 udx = (nrx - nrx0) / 2 / rx # ux - umx | 248 udx = (nrx - nrx0) / 2 / rx # ux - umx |
247 udy = (nry - nry0) / 2 / ry # uy - umy | 249 udy = (nry - nry0) / 2 / ry # uy - umy |
248 umx = (nrx + nrx0) / 2 / rx | 250 umx = (nrx + nrx0) / 2 / rx |
249 umy = (nry + nry0) / 2 / ry | 251 umy = (nry + nry0) / 2 / ry |
250 | 252 |
277 udcy = -udcy | 279 udcy = -udcy |
278 pass | 280 pass |
279 | 281 |
280 nrcx = rx * (udcx + umx) | 282 nrcx = rx * (udcx + umx) |
281 nrcy = ry * (udcy + umy) | 283 nrcy = ry * (udcy + umy) |
282 | 284 |
283 cx = nrcx * _cos - nrcy * _sin | 285 cx = nrcx * _cos - nrcy * _sin |
284 cy = nrcx * _sin + nrcy * _cos | 286 cy = nrcx * _sin + nrcy * _cos |
285 | 287 |
286 return cx, cy | 288 return cx, cy |
287 | 289 |
288 # M x y : Move to (x,y) | 290 # M x y : Move to (x,y) |
289 # Z : close path | 291 # Z : close path |
290 # L x y : lineto (x,y) | 292 # L x y : lineto (x,y) |
311 'T': 2, 't':2, | 313 'T': 2, 't':2, |
312 'A': 7, 'a':7} | 314 'A': 7, 'a':7} |
313 | 315 |
314 def _angle_rotated_ellipse(x, y, rx, ry, x_rotate): | 316 def _angle_rotated_ellipse(x, y, rx, ry, x_rotate): |
315 import math | 317 import math |
316 | 318 |
317 _cos = math.cos(x_rotate) | 319 _cos = math.cos(x_rotate) |
318 _sin = math.sin(x_rotate) | 320 _sin = math.sin(x_rotate) |
319 | 321 |
320 nrx = (x * _cos + y * _sin) / rx | 322 nrx = (x * _cos + y * _sin) / rx |
321 nry = (-x * _sin + y * _cos) / ry | 323 nry = (-x * _sin + y * _cos) / ry |
322 | 324 |
323 xy_tan = nry / nrx | 325 xy_tan = nry / nrx |
324 xy_angle = math.atan(xy_tan) | 326 xy_angle = math.atan(xy_tan) |
325 | 327 |
326 if nrx < 0: | 328 if nrx < 0: |
327 xy_angle = math.pi + xy_angle | 329 xy_angle = math.pi + xy_angle |
328 pass | 330 pass |
329 | 331 |
330 return xy_angle | 332 return xy_angle |
331 | 333 |
332 def rotate(x, y, angle): | 334 def rotate(x, y, angle): |
333 import math | 335 import math |
334 _cos = math.cos(angle) | 336 _cos = math.cos(angle) |
338 return nx, ny | 340 return nx, ny |
339 | 341 |
340 def translate_path_data(data, codefo): | 342 def translate_path_data(data, codefo): |
341 import string | 343 import string |
342 import math | 344 import math |
343 | 345 |
344 temp = data.split() | 346 temp = data.split() |
345 fields=[] | 347 fields=[] |
346 for f in temp: | 348 for f in temp: |
347 for s in f.split(','): | 349 for s in f.split(','): |
348 if s != '': | 350 if s != '': |
383 if cmd == 'v': | 385 if cmd == 'v': |
384 arg = float(f) | 386 arg = float(f) |
385 pnts.append(pnts[-2]) | 387 pnts.append(pnts[-2]) |
386 pnts.append(arg + pnts[-2]) | 388 pnts.append(arg + pnts[-2]) |
387 continue | 389 continue |
388 | 390 |
389 arg = float(f) | 391 arg = float(f) |
390 if (cmd not in 'am') and (cmd in string.lowercase): | 392 if (cmd not in 'am') and (cmd in string.lowercase): |
391 # relative and not arc or moveto | 393 # relative and not arc or moveto |
392 arg = arg + pnts[-2] | 394 arg = arg + pnts[-2] |
393 pass | 395 pass |
422 c2x, c2y = rotate(rx, ry, x_rotate) | 424 c2x, c2y = rotate(rx, ry, x_rotate) |
423 c2x, c2y = c2x + cx, c2y + cy | 425 c2x, c2y = c2x + cx, c2y + cy |
424 | 426 |
425 c3x, c3y = rotate(-rx, ry, x_rotate) | 427 c3x, c3y = rotate(-rx, ry, x_rotate) |
426 c3x, c3y = c3x + cx, c3y + cy | 428 c3x, c3y = c3x + cx, c3y + cy |
427 | 429 |
428 pnts[-7:] = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y, abs_x, abs_y] | 430 pnts[-7:] = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y, abs_x, abs_y] |
429 | 431 |
430 start_angle = _angle_rotated_ellipse(x0 - cx, y0 - cy, | 432 start_angle = _angle_rotated_ellipse(x0 - cx, y0 - cy, |
431 rx, ry, x_rotate) | 433 rx, ry, x_rotate) |
432 stop_angle = _angle_rotated_ellipse(x - cx, y - cy, | 434 stop_angle = _angle_rotated_ellipse(x - cx, y - cy, |
433 rx, ry, x_rotate) | 435 rx, ry, x_rotate) |
434 | 436 |
435 # sweep == 1 for positive-angle direction | 437 # sweep == 1 for positive-angle direction |
436 # sweep == 0 for negative-angle direction | 438 # sweep == 0 for negative-angle direction |
437 if start_angle > stop_angle and sweep: | 439 if start_angle > stop_angle and sweep: |
438 stop_angle = math.pi * 2 + stop_angle | 440 stop_angle = math.pi * 2 + stop_angle |
439 elif start_angle < stop_angle and not sweep: | 441 elif start_angle < stop_angle and not sweep: |
440 start_angle = math.pi * 2 + start_angle | 442 start_angle = math.pi * 2 + start_angle |
441 pass | 443 pass |
442 | 444 |
443 float_args.extend([cx, cy, rx, ry, | 445 float_args.extend([cx, cy, rx, ry, |
444 start_angle, stop_angle, x_rotate]) | 446 start_angle, stop_angle, x_rotate]) |
445 pass | 447 pass |
446 pass | 448 pass |
447 return commands, pnts, float_args | 449 return commands, pnts, float_args |
546 map = translate_font_style(tspan, codefo) | 548 map = translate_font_style(tspan, codefo) |
547 tspan.style_map = map | 549 tspan.style_map = map |
548 pass | 550 pass |
549 if tspan.hasAttribute('x'): | 551 if tspan.hasAttribute('x'): |
550 # Render the tspan as an independent text if the x | 552 # Render the tspan as an independent text if the x |
551 # attribute is defined. All elements inside | 553 # attribute is defined. All elements inside |
552 # the tspan will be ignore by the outter text or tspan elements. | 554 # the tspan will be ignore by the outter text or tspan elements. |
553 # FIXME: We need to apply the style map recursively. | 555 # FIXME: We need to apply the style map recursively. |
554 merge_style(tspan, text) | 556 merge_style(tspan, text) |
555 translate_text(tspan, coord_id, codefo, doc) | 557 translate_text(tspan, coord_id, codefo, doc) |
556 return '' | 558 return '' |
583 else: | 585 else: |
584 font_sz = float(style_map['font-size']) | 586 font_sz = float(style_map['font-size']) |
585 print >> codefo, 'PANGO_SIZE(%d,%d,%d)dnl' % (font_sz*1024,start,end) | 587 print >> codefo, 'PANGO_SIZE(%d,%d,%d)dnl' % (font_sz*1024,start,end) |
586 pass | 588 pass |
587 pass | 589 pass |
588 | 590 |
589 if style_map.has_key('font-style'): | 591 if style_map.has_key('font-style'): |
590 font_style = style_map['font-style'].lower() | 592 font_style = style_map['font-style'].lower() |
591 if font_style == 'normal': | 593 if font_style == 'normal': |
592 print >> codefo, 'PANGO_STYLE(PANGO_STYLE_NORMAL,%d,%d)dnl' % (start,end) | 594 print >> codefo, 'PANGO_STYLE(PANGO_STYLE_NORMAL,%d,%d)dnl' % (start,end) |
593 elif font_style == 'italic': | 595 elif font_style == 'italic': |
672 pass | 674 pass |
673 pass | 675 pass |
674 | 676 |
675 def stext_generate_font_attributes(text, attrs, coord_id, codefo, doc): | 677 def stext_generate_font_attributes(text, attrs, coord_id, codefo, doc): |
676 text_id = _get_id(text) | 678 text_id = _get_id(text) |
677 | 679 |
678 for start, end, node in attrs: | 680 for start, end, node in attrs: |
679 style_map = node.style_map | 681 style_map = node.style_map |
680 | 682 |
681 font_sz = 10 | 683 font_sz = 10 |
682 if style_map.has_key('font-size'): | 684 if style_map.has_key('font-size'): |
683 fsz = style_map['font-size'] | 685 fsz = style_map['font-size'] |
684 if fsz.endswith('px'): | 686 if fsz.endswith('px'): |
685 font_sz = float(fsz[:-2]) | 687 font_sz = float(fsz[:-2]) |
686 else: | 688 else: |
687 font_sz = float(fsz) | 689 font_sz = float(fsz) |
688 pass | 690 pass |
689 pass | 691 pass |
690 | 692 |
691 if style_map.has_key('font-family'): | 693 if style_map.has_key('font-family'): |
692 font_family = style_map['font-family'] | 694 font_family = style_map['font-family'] |
693 else: | 695 else: |
694 font_family = 'serif' | 696 font_family = 'serif' |
695 pass | 697 pass |
696 | 698 |
697 font_slant = 0 | 699 font_slant = 0 |
698 if style_map.has_key('font-style'): | 700 if style_map.has_key('font-style'): |
699 fn_style = style_map['font-style'] | 701 fn_style = style_map['font-style'] |
700 if fn_style == 'normal': | 702 if fn_style == 'normal': |
701 font_slant = 0 | 703 font_slant = 0 |
704 elif fn_style == 'oblique': | 706 elif fn_style == 'oblique': |
705 font_slant = 110 | 707 font_slant = 110 |
706 else: | 708 else: |
707 raise ValueError, '%s is not a valid font-style' % (fn_style) | 709 raise ValueError, '%s is not a valid font-style' % (fn_style) |
708 pass | 710 pass |
709 | 711 |
710 font_weight = 80 | 712 font_weight = 80 |
711 if style_map.has_key('font-weight'): | 713 if style_map.has_key('font-weight'): |
712 fn_weight = style_map['font-weight'] | 714 fn_weight = style_map['font-weight'] |
713 if fn_weight == 'normal': | 715 if fn_weight == 'normal': |
714 font_weight = 80 | 716 font_weight = 80 |
724 font_weight = 70 | 726 font_weight = 70 |
725 else: | 727 else: |
726 font_weight = int(fn_weight) | 728 font_weight = int(fn_weight) |
727 pass | 729 pass |
728 pass | 730 pass |
729 | 731 |
730 print >> codefo, 'STYLE_BLOCK([%s], %d, [%s], %f, %d, %d)dnl' % ( | 732 print >> codefo, 'STYLE_BLOCK([%s], %d, [%s], %f, %d, %d)dnl' % ( |
731 text_id, end - start, font_family, font_sz, | 733 text_id, end - start, font_family, font_sz, |
732 font_slant, font_weight) | 734 font_slant, font_weight) |
733 pass | 735 pass |
734 pass | 736 pass |
735 | 737 |
736 def stext_gen_text(text, coord_id, codefo, doc, txt_strs, attrs): | 738 def stext_gen_text(text, coord_id, codefo, doc, txt_strs, attrs): |
737 if not txt_strs: | 739 if not txt_strs: |
738 return | 740 return |
739 | 741 |
740 text_id = _get_id(text) | 742 text_id = _get_id(text) |
741 x = float(text.getAttribute('x')) | 743 x = float(text.getAttribute('x')) |
742 y = float(text.getAttribute('y')) | 744 y = float(text.getAttribute('y')) |
743 print >> codefo, 'dnl' | 745 print >> codefo, 'dnl' |
744 print >> codefo, \ | 746 print >> codefo, \ |
755 @check_mbname | 757 @check_mbname |
756 def translate_text(text, coord_id, codefo, doc): | 758 def translate_text(text, coord_id, codefo, doc): |
757 coord_id = translate_shape_transform(text, coord_id, codefo) | 759 coord_id = translate_shape_transform(text, coord_id, codefo) |
758 try: | 760 try: |
759 map = text.style_map | 761 map = text.style_map |
760 except: | 762 except: |
761 map = translate_font_style(text, codefo) | 763 map = translate_font_style(text, codefo) |
762 text.style_map = map | 764 text.style_map = map |
763 pass | 765 pass |
764 attrs = [] | 766 attrs = [] |
765 attr = [0, 0, text] | 767 attr = [0, 0, text] |
779 pass | 781 pass |
780 | 782 |
781 @check_mbname | 783 @check_mbname |
782 def translate_image(image, coord_id, codefo, doc): | 784 def translate_image(image, coord_id, codefo, doc): |
783 coord_id = translate_shape_transform(image, coord_id, codefo) | 785 coord_id = translate_shape_transform(image, coord_id, codefo) |
784 | 786 |
785 image_id = _get_id(image) | 787 image_id = _get_id(image) |
786 if not image.hasAttributeNS(xlinkns, 'href'): | 788 if not image.hasAttributeNS(xlinkns, 'href'): |
787 raise ValueError, 'image %s must has a href attribute.' % (image_id) | 789 raise ValueError, 'image %s must has a href attribute.' % (image_id) |
788 href = image.getAttributeNS(xlinkns, 'href') | 790 href = image.getAttributeNS(xlinkns, 'href') |
789 if image.hasAttribute('x'): | 791 if image.hasAttribute('x'): |
813 print >> codefo, 'dnl' | 815 print >> codefo, 'dnl' |
814 print >> codefo, \ | 816 print >> codefo, \ |
815 'ADD_IMAGE([%s], [%s], %f, %f, %f, %f, [%s])dnl' % ( | 817 'ADD_IMAGE([%s], [%s], %f, %f, %f, %f, [%s])dnl' % ( |
816 image_id, href, x, y, width, height, coord_id) | 818 image_id, href, x, y, width, height, coord_id) |
817 pass | 819 pass |
818 | 820 |
819 | 821 |
820 reo_func = re.compile('([a-zA-Z]+)\\([^\\)]*\\)') | 822 reo_func = re.compile('([a-zA-Z]+)\\([^\\)]*\\)') |
821 reo_translate = re.compile('translate\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)') | 823 reo_translate = re.compile('translate\\(([-+]?[0-9]+(\\.[0-9]+)?),([-+]?[0-9]+(\\.[0-9]+)?)\\)') |
822 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]+)?)\\)') | 824 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]+)?)\\)') |
823 def translate_transform(coord_id, transform, codefo, prefix): | 825 def translate_transform(coord_id, transform, codefo, prefix): |
887 for scene in scenes_node.childNodes: | 889 for scene in scenes_node.childNodes: |
888 if scene.localName != 'scene' or \ | 890 if scene.localName != 'scene' or \ |
889 not scene.hasAttribute('ref') or \ | 891 not scene.hasAttribute('ref') or \ |
890 not scene.hasAttribute('start'): | 892 not scene.hasAttribute('start'): |
891 continue | 893 continue |
892 | 894 |
893 start_str = scene.getAttribute('start') | 895 start_str = scene.getAttribute('start') |
894 start = end = int(start_str) | 896 start = end = int(start_str) |
895 if scene.hasAttribute('end'): | 897 if scene.hasAttribute('end'): |
896 end_str = scene.getAttribute('end') | 898 end_str = scene.getAttribute('end') |
897 end = int(end_str) | 899 end = int(end_str) |
898 pass | 900 pass |
899 ref = scene.getAttribute('ref') | 901 ref = scene.getAttribute('ref') |
900 | 902 |
901 while len(scenes) <= end: | 903 while len(scenes) <= end: |
902 scenes.append([]) | 904 scenes.append([]) |
903 pass | 905 pass |
904 | 906 |
905 for i in range(start, end + 1): | 907 for i in range(start, end + 1): |
906 scenes[i].append(ref) | 908 scenes[i].append(ref) |
907 pass | 909 pass |
908 pass | 910 pass |
909 | 911 |
923 if node.localName == 'svg' and node.namespaceURI == svgns: | 925 if node.localName == 'svg' and node.namespaceURI == svgns: |
924 break; | 926 break; |
925 pass | 927 pass |
926 else: | 928 else: |
927 raise ValueErr, 'no any svg tag node.' | 929 raise ValueErr, 'no any svg tag node.' |
928 | 930 |
929 svg = node | 931 svg = node |
930 for node in svg.childNodes: | 932 for node in svg.childNodes: |
931 if node.localName == 'defs' and node.namespaceURI == svgns: | 933 if node.localName == 'defs' and node.namespaceURI == svgns: |
932 translate_defs(node, codefo, dom) | 934 translate_defs(node, codefo, dom) |
933 elif node.localName == 'metadata' and node.namespaceURI == svgns: | 935 elif node.localName == 'metadata' and node.namespaceURI == svgns: |
944 pass | 946 pass |
945 | 947 |
946 if __name__ == '__main__': | 948 if __name__ == '__main__': |
947 from os import path | 949 from os import path |
948 import optparse | 950 import optparse |
949 | 951 |
950 usage='usage: %prog [options] <SVG file> [<output>]' | 952 usage='usage: %prog [options] <SVG file> [<output>]' |
951 parser = optparse.OptionParser(usage=usage) | 953 parser = optparse.OptionParser(usage=usage) |
952 parser.add_option('-s', '--stext', dest='stext', | 954 parser.add_option('-s', '--stext', dest='stext', |
953 action='store_true', default=False, | 955 action='store_true', default=False, |
954 help='Use sh_stext instead of sh_text'); | 956 help='Use sh_stext instead of sh_text'); |
955 options, args = parser.parse_args() | 957 options, args = parser.parse_args() |
956 | 958 |
957 if len(args) == 2: | 959 if len(args) == 2: |
958 svgfn = args[0] | 960 svgfn = args[0] |
959 codefn = args[1] | 961 codefn = args[1] |
960 elif len(args) == 1: | 962 elif len(args) == 1: |
961 svgfn = args[0] | 963 svgfn = args[0] |
962 codefn = 'out.mb' | 964 codefn = 'out.mb' |
963 else: | 965 else: |
964 parser.print_help() | 966 parser.print_help() |
965 sys.exit(1) | 967 sys.exit(1) |
966 pass | 968 pass |
967 | 969 |
968 struct_name = path.basename(codefn).split('.')[0] | 970 struct_name = path.basename(codefn).split('.')[0] |
969 | 971 |
970 if options.stext: | 972 if options.stext: |
971 gen_text = stext_gen_text | 973 gen_text = stext_gen_text |
972 else: | 974 else: |