#!/usr/bin/env python from __future__ import print_function from __future__ import with_statement import os import math from xml.dom.minidom import parse from optparse import OptionParser import scalergba try: import rsvg import cairo except ImportError as e: print("Rendering SVG resources requires PyGTK. Exiting...") exit(1) cursorList = { "cursor_up": ["circleOuter"], "cursor_poised": ["circleOuter", "circleInnerOpen"], "cursor_clicked": ["circleOuter", "circleInnerClosed"], "cursor_disabled": ["cross"], "cursor_open": ["circleOuter", "arrowTranslucentUpper", "arrowTranslucentLower"], "cursor_grab": ["circleOuter", "circleInnerOpen", "arrowTranslucentUpper", "arrowTranslucentLower"], "cursor_updown_open": ["circleOuter", "circleInnerOpen", "arrowTranslucentUpper", "arrowTranslucentLower"], "cursor_updown_closed": ["circleOuter", "circleInnerClosed", "arrowOpaqueUpper", "arrowOpaqueLower"], "cursor_leftright_open": ["circleOuter", "circleInnerOpen", "arrowTranslucentLeft", "arrowTranslucentRight"], "cursor_leftright_closed": ["circleOuter", "circleInnerClosed", "arrowOpaqueLeft", "arrowOpaqueRight"], "cursor_4way_open": ["circleOuter", "circleInnerOpen", "arrowTranslucentUpper", "arrowTranslucentRight", "arrowTranslucentLower", "arrowTranslucentLeft"], "cursor_4way_closed": ["circleOuter", "circleInnerClosed", "arrowOpaqueUpper", "arrowOpaqueRight", "arrowOpaqueLower", "arrowOpaqueLeft"], "cursor_upward": ["circleOuter", "arrowOpaqueUpper"], "cursor_right": ["circleOuter", "arrowOpaqueRight"], "cursor_down": ["circleOuter", "arrowOpaqueLower"], "cursor_left": ["circleOuter", "arrowOpaqueLeft"], "cursor_book": ["circleOuter", "book"], "cursor_book_poised": ["circleOuter", "circleInnerOpen", "book"], "cursor_book_clicked": ["circleOuter", "circleInnerClosed", "book"], } cursorOffsetList = { "cursor_book": [7, 7], "cursor_book_poised": [7, 7], "cursor_book_clicked": [7, 7] } textList = { "xLoading_Linking_Text": ["background", "circles", "textLinking"], "xLoading_Updating_Text": ["background", "circles", "textUpdating"] } voiceList = { "ui_speaker": ["speakerGrille", "speakerIndicator", "speakerOuterRing"], "ui_microphone": ["microphoneGrille", "microphoneIndicator", "microphoneOuterRing"] } def enable_only_layers(layerlist, layers): for layer in layers: if layer in layerlist: layers[layer].setAttribute("style","") else: layers[layer].setAttribute("style","display:none") # sanity check for layer in layerlist: if layer not in layers: print("warning: unknown layer", layer) def shift_all_layers(layers, shiftx, shifty): # note: this assumes that all layers start out with no transform of their own for layer in layers: layers[layer].setAttribute("transform", "translate(%g,%g)" % (shiftx, shifty)) def get_layers_from_svg(svgData): inkscapeNS = "http://www.inkscape.org/namespaces/inkscape" layers = {} groups = svgData.getElementsByTagName("g") for group in groups: if group.getAttributeNS(inkscapeNS,"groupmode") == "layer": layers[group.getAttribute("id")] = group return layers def render_cursors(inpath, outpath): scalefactor = 4 with open(os.path.join(inpath,"Cursor_Base.svg"), "r") as svgFile: cursorSVG = parse(svgFile) layers = get_layers_from_svg(cursorSVG) svgwidth = float(cursorSVG.documentElement.getAttribute("width")) svgheight = float(cursorSVG.documentElement.getAttribute("height")) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(math.ceil(scalefactor*svgwidth)), int(math.ceil(scalefactor*svgheight))) for cursor in cursorList: ctx = cairo.Context(surface) ctx.save() ctx.set_operator(cairo.OPERATOR_CLEAR) ctx.paint() ctx.restore() enabledlayers = cursorList[cursor] enabledlayers = enabledlayers + [l + "Shadow" for l in enabledlayers] enable_only_layers(enabledlayers, layers) shift_all_layers(layers, *cursorOffsetList.get(cursor, [0, 0])) svg = rsvg.Handle(data=cursorSVG.toxml()) ctx.scale(scalefactor, scalefactor) svg.render_cairo(ctx) outfile = os.path.join(outpath, cursor + ".png") surface.write_to_png(outfile) scalergba.scale(outfile, outfile, scalefactor) def render_loading_books(inpath, outpath): resSize = {"width":256, "height":256} with open(os.path.join(inpath,"Linking_Book.svg"), "r") as svgFile: bookSVG = parse(svgFile) layers = get_layers_from_svg(bookSVG) ratioW = resSize["width"] / float(bookSVG.documentElement.getAttribute("width")) ratioH = resSize["height"] / float(bookSVG.documentElement.getAttribute("height")) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, resSize["width"], resSize["height"]) for angle in range(0, 18): ctx = cairo.Context(surface) # Draw Book and Black Background enable_only_layers(["background", "book"],layers) svg = rsvg.Handle(data=bookSVG.toxml()) ctx.save() ctx.scale(ratioW, ratioH) svg.render_cairo(ctx) ctx.restore() # Draw Circles at appropriate angle enable_only_layers(["circles"],layers) svg = rsvg.Handle(data=bookSVG.toxml()) ctx.translate(resSize["height"] / 2, resSize["width"] / 2) ctx.rotate(math.radians(angle*(5))) ctx.translate(-resSize["width"] / 2, -resSize["height"] / 2) ctx.scale(ratioW, ratioH) svg.render_cairo(ctx) surface.write_to_png(os.path.join(outpath, "xLoading_Linking.{0:02}.png".format(angle))) def render_loading_text(inpath, outpath): resSize = {"width":192, "height":41} with open(os.path.join(inpath,"Loading_Text_rasterfont.svg"), "r") as svgFile: textSVG = parse(svgFile) layers = get_layers_from_svg(textSVG) ratioW = resSize["width"] / float(textSVG.documentElement.getAttribute("width")) ratioH = resSize["height"] / float(textSVG.documentElement.getAttribute("height")) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, resSize["width"], resSize["height"]) for textEntry in textList: ctx = cairo.Context(surface) ctx.save() ctx.set_operator(cairo.OPERATOR_CLEAR) ctx.paint() ctx.restore() enable_only_layers(textList[textEntry], layers) svg = rsvg.Handle(data=textSVG.toxml()) ctx.scale(ratioW, ratioH) svg.render_cairo(ctx) surface.write_to_png(os.path.join(outpath, textEntry + ".png")) def render_voice_icons(inpath, outpath): resSize = {"width":32, "height":32} with open(os.path.join(inpath,"Voice_Chat.svg"), "r") as svgFile: uiSVG = parse(svgFile) layers = get_layers_from_svg(uiSVG) ratioW = resSize["width"] / float(uiSVG.documentElement.getAttribute("width")) ratioH = resSize["height"] / float(uiSVG.documentElement.getAttribute("height")) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, resSize["width"], resSize["height"]) for voiceUI in voiceList: ctx = cairo.Context(surface) ctx.save() ctx.set_operator(cairo.OPERATOR_CLEAR) ctx.paint() ctx.restore() enable_only_layers(voiceList[voiceUI], layers) svg = rsvg.Handle(data=uiSVG.toxml()) ctx.scale(ratioW, ratioH) svg.render_cairo(ctx) surface.write_to_png(os.path.join(outpath, voiceUI + ".png")) if __name__ == '__main__': parser = OptionParser(usage="usage: %prog [options]") parser.add_option("-q", "--quiet", dest="verbose", default=True, action="store_false", help="Don't print status messages") parser.add_option("-o", "--outpath", dest="outpath", default="./out", help="Sets output path for rendered images") parser.add_option("-i", "--inpath", dest="inpath", default=".", help="Sets input path for SVG files") (options, args) = parser.parse_args() ## Send output to OS's null if unwanted if not options.verbose: sys.stdout = open(os.devnull,"w") sys.stderr = open(os.devnull,"w") ## Compute Paths outpath = os.path.expanduser(options.outpath) inpath = os.path.expanduser(options.inpath) if not os.path.exists(outpath): os.mkdir(outpath) ## Do the work! print("Rendering SVGs...") render_cursors(inpath, outpath) render_loading_books(inpath, outpath) render_loading_text(inpath, outpath) render_voice_icons(inpath, outpath)