def __addRadialGradient(self, element, fill): root = fill.getRoot() stops = fill while len(stops) == 0 and stops.href: stops = root.getElementById(stops.href[1:]) background = [] #座標補正 gradientTransform = fill.gradientTransform.toMatrix() center = svg.Point(fill.cx, fill.cy) finish = svg.Point(fill.fx, fill.fy) center = gradientTransform * center finish = gradientTransform * finish if fill.gradientUnits == "userSpaceOnUse": stroke = svg.Length(element.style.get("stroke-width", 0)) center = svg.Point(center.x - svg.Length(self["left"]) - stroke, center.y - svg.Length(self["top"]) - stroke) finish = svg.Point(finish.x - svg.Length(self["left"]) - stroke, finish.y - svg.Length(self["top"]) - stroke) #半径の決定 zero = svg.Length("0") point0 = gradientTransform * svg.Point(zero, zero) rx = svg.Length( abs(gradientTransform * svg.Point(fill.r, zero) - point0), "px") ry = svg.Length( abs(gradientTransform * svg.Point(zero, fill.r) - point0), "px") r = fill.r gradient = "" for stop in stops: color = svg.Color(stop.style["stop-color"]) if float(stop.style.get("stop-opacity", "1")) <= 0.999: color.a = float(stop.style.get("stop-opacity", "1")) gradient += ",%s %.1f%%" % (color, stop.offset * 100) background.append("radial-gradient(%s %s,%s %s%s)" % (center.x, center.y, rx, ry, gradient)) background.append("-o-radial-gradient(%s %s,%s %s%s)" % (center.x, center.y, rx, ry, gradient)) background.append("-moz-radial-gradient(%s %s,circle%s)" % (center.x, center.y, gradient)) background.append("-moz-radial-gradient(%s %s,%s %s%s)" % (center.x, center.y, rx, ry, gradient)) background.append("-ms-radial-gradient(%s %s,%s %s%s)" % (center.x, center.y, rx, ry, gradient)) background.append("-webkit-radial-gradient(%s %s,%s %s%s)" % (center.x, center.y, rx, ry, gradient)) self["background"] = background
def image(self, x): name = self.newName(x) if name not in self._css_classes: self._css_classes.add(name) css = CSSStyle() stroke = svg.Length(0) #クリップパスの設定 self.__clipPath(name, x) #位置と大きさの設定 css["position"] = "absolute" css["left"] = x.x css["top"] = x.y css["width"] = x.width css["height"] = x.height #変形 if x.transform: #CSSとSVGの原点の違いを補正 transform = x.transform.toMatrix() transform = transform * svg.Transform.Translate( x.x + x.width / 2, x.y + x.height / 2) transform = svg.Transform.Translate( -x.x - x.width / 2, -x.y - x.height / 2) * transform css["transform"] = transform #出力 self._css(cls=name, style=css) #クリップの設定 if name in self.__clipnames: clipname = self.__clipnames[name] self._html( '<div class="%s"><div class="%sinverse"><image class="%s" src=%s /></div></div>\n' % (clipname, clipname, name, quoteattr(os.path.basename( x.href)))) return self._html('<image class="%s" src=%s />\n' % (name, quoteattr(os.path.basename(x.href))))
def __text_contents(self, x, x0=0, y0=0, blur=0): name = self.newName(x) if name not in self._css_classes: self._css_classes.add(name) css = CSSStyle() #フォントに関する属性をコピー if "font-size" in x.style: css["font-size"] = svg.Length(x.style["font-size"]) if "fill" in x.style: css["color"] = svg.Color(x.style["fill"]) if "fill-opacity" in x.style: css["color"].a = float(x.style["fill-opacity"]) if blur > 0.001: css["text-shadow"] = "0px 0px %s %s" % (blur, css["color"]) css["color"] = [css["color"], svg.Color(0, 0, 0, 0)] for stylename in ["font-style", "font-weight", "font-family"]: if stylename in x.style: css[stylename] = x.style[stylename] if x.role == "line": css["display"] = "block" if x.x or x.y: css["position"] = "absolute" css["left"] = x.x - x0 css["top"] = x.y - y0 #出力 self._css(cls=name, style=css) self._html('<span class="%s">' % name) if x.x or x.y: self._html('<span class="svg-text-adj"> </span>') for a in x: if isinstance(a, svg.TSpan): self.__text_contents(a, x.x, x.y, blur) elif isinstance(a, svg.Characters): self._html(escape(a.content)) self._html('</span>')
def __addLinearGradient(self, element, fill): root = fill.getRoot() stops = fill while len(stops) == 0 and stops.href: stops = root.getElementById(stops.href[1:]) background = [] #座標補正 point1 = svg.Point(fill.x1, fill.y1) point2 = svg.Point(fill.x2, fill.y2) point1 = fill.gradientTransform.toMatrix() * point1 point2 = fill.gradientTransform.toMatrix() * point2 if fill.gradientUnits == "userSpaceOnUse": stroke = svg.Length(element.style.get("stroke-width", 0)) point1 = svg.Point(point1.x - svg.Length(self["left"]) - stroke, point1.y - svg.Length(self["top"]) - stroke) point2 = svg.Point(point2.x - svg.Length(self["left"]) - stroke, point2.y - svg.Length(self["top"]) - stroke) def svgOffsetToPoint(offset): return point1 * (1 - offset) + point2 * offset #css3のデフォルト rad = -math.atan2(point2.y - point1.y, point2.x - point1.x) vec = svg.Point(math.cos(rad), -math.sin(rad)) deg = rad / math.pi * 180 width = svg.Length(self["width"]) height = svg.Length(self["height"]) point0 = svg.Point(0, 0) if 0 < deg < 90: point0 = svg.Point(0, height) elif 90 <= deg: point0 = svg.Point(width, height) elif deg < -90: point0 = svg.Point(width, 0) gradientlen = (svg.Point(width, height) - point0 * 2) * vec def pointToCSSOffset(point): offset = (point - point0) * vec / gradientlen return offset def svgOffsetToCSSOffset(offset): return pointToCSSOffset(svgOffsetToPoint(offset)) gradient = "(%.1fdeg" % deg color_stops = [] for stop in stops: color = svg.Color(stop.style["stop-color"]) if float(stop.style.get("stop-opacity", "1")) <= 0.999: color.a = float(stop.style.get("stop-opacity", "1")) gradient += ",%s %.1f%%" % ( color, svgOffsetToCSSOffset(stop.offset) * 100) gradient += ")" background.append("linear-gradient" + gradient) background.append("-o-linear-gradient" + gradient) background.append("-moz-linear-gradient" + gradient) background.append("-ms-linear-gradient" + gradient) background.append("-webkit-linear-gradient" + gradient) #webkit webkit = "-webkit-gradient(linear,%f %f,%f %f," % ( point1.x.px(), point1.y.px(), point2.x.px(), point2.y.px()) color = svg.Color(stops[0].style["stop-color"]) if float(stops[0].style.get("stop-opacity", "1")) <= 0.999: color.a = float(stops[0].style.get("stop-opacity", "1")) webkit += "from(%s)," % color if len(stops) > 2: for stop in stops[1:-1]: color = svg.Color(stop.style["stop-color"]) if float(stop.style.get("stop-opacity", "1")) <= 0.999: color.a = float(stop.style.get("stop-opacity", "1")) webkit += "color-stop(%f,%s)," % (stop.offset, color) color = svg.Color(stops[-1].style["stop-color"]) if float(stops[-1].style.get("stop-opacity", "1")) <= 0.999: color.a = float(stops[-1].style.get("stop-opacity", "1")) webkit += "to(%s))" % color background.append(webkit) self["background"] = background
def text(self, x): name = self.newName(x) if name in self.__clipnames: clipname = self.__clipnames[name] self._html('<div class="%s"><div class="%sinverse">\n' % (clipname, clipname)) blur = 0 filterURL = getURL(x.style.get("filter", "")) if filterURL: filter = x.getRoot().getElementById(filterURL) if filter and isinstance(filter[0], svg.FEGaussianBlur): blur = filter[0].stdDeviation * 1.7 self._html('<div class="%s"><span class="svg-text-adj"> </span>' % name) for a in x: if isinstance(a, svg.TSpan): self.__text_contents(a, x.x, x.y, blur) elif isinstance(a, svg.Characters): self._html(a.content) self._html('</div>\n') if name in self.__clipnames: clipname = self.__clipnames[name] self._html('</div></div>\n') #スタイル定義を出力 if name not in self._css_classes: self._css_classes.add(name) css = CSSStyle() #クリップパスの設定 self.__clipPath(name, x) css["position"] = "absolute" css["margin"] = "0px" #フォントに関する属性をコピー if "font-size" in x.style: css["font-size"] = svg.Length(x.style["font-size"]) if "fill" in x.style: css["color"] = svg.Color(x.style["fill"]) if "fill-opacity" in x.style: css["color"].a = float(x.style["fill-opacity"]) if blur > 0.001: css["text-shadow"] = "0px 0px %s %s" % (blur, css["color"]) css["color"] = [css["color"], svg.Color(0, 0, 0, 0)] for stylename in ["font-style", "font-weight", "font-family"]: if stylename in x.style: css[stylename] = x.style[stylename] css["left"] = x.x css["top"] = x.y - svg.Length("1000px") #変形 if x.transform: transform = x.transform.toMatrix() css["transform"] = transform css["white-space"] = "pre" #出力 self._css(cls=name, style=css) if "svg-text-adj" not in self._css_classes: self._css_classes.add("svg-text-adj") self._css(".svg-text-adj{font-size:0px;vertical-align: 1000px;}\n")
def __blured_round_rect(self, element, x, y, width, height, rx=0, ry=0, blur=0): name = self.newName(element) namefill = name + "-fill" namestroke = name + "-stroke" hasfill = "fill" in element.style and element.style["fill"] != 'none' hasstroke = "stroke" in element.style and element.style[ "stroke"] != 'none' #フィルの描画 if not hasstroke and hasfill: if namefill not in self._css_classes: self._css_classes.add(namefill) css = CSSStyle() #クリップパスの設定 self.__clipPath(namefill, element) #位置と大きさの設定 css["position"] = "absolute" css["left"] = x - 10000 css["top"] = y - 10000 css["width"] = width css["height"] = height #角を丸める if rx and ry: css["border-radius"] = "%s/%s" % (rx, ry) elif rx: css["border-radius"] = rx elif ry: css["border-radius"] = ry #フィルを指定する css.addFill(element) #ぼかしを適用 css["box-shadow"] = "10000px 10000px %s %s" % ( blur, css["background-color"]) css["-webkit-box-shadow"] = "10000px 10000px %s %s" % ( blur * 1.8, css["background-color"]) css["-o-box-shadow"] = "10000px 10000px %s %s" % ( blur * 1.8, css["background-color"]) #変形 if element.transform: #CSSとSVGの原点の違いを補正 transform = element.transform.toMatrix() transform = transform * svg.Transform.Translate( x - 10000 + width / 2, y - 10000 + height / 2) transform = svg.Transform.Translate( -x + 10000 - width / 2, -y + 10000 - height / 2) * transform css["left"] += transform.e css["top"] += transform.f transform.e = 0 transform.f = 0 css["transform"] = transform #透明度を指定 if "opacity" in element.style: css["opacity"] = element.style["opacity"] #出力 self._css(cls=namefill, style=css) #クリップの設定 if namefill in self.__clipnames: clipname = self.__clipnames[namefill] self._html( '<div class="%s"><div class="%sinverse"><div class="%s"></div></div></div>\n' % (clipname, clipname, name)) return self._html('<div class="%s"></div>\n' % namefill) #ストロークの描画 if hasstroke: if namestroke not in self._css_classes: self._css_classes.add(namestroke) css = CSSStyle() #クリップパスの設定 self.__clipPath(namestroke, element) #位置と大きさの設定 css["position"] = "absolute" css["left"] = x css["top"] = y css["width"] = width css["height"] = height #角を丸める if rx and ry: css["border-radius"] = "%s/%s" % (str(rx), str(ry)) elif rx: css["border-radius"] = rx elif ry: css["border-radius"] = ry #ぼかしを適用 stroke = svg.Length(element.style.get("stroke-width", 0)) color = svg.Color(element.style["stroke"]) if "stroke-opacity" in element.style: color.a = float(element.style["stroke-opacity"]) css["box-shadow"] = "0px 0px %s %s %s" % ( blur, stroke / 2, color) + ", 0px 0px %s %s %s inset" % ( blur, stroke / 2, color) #フィルを指定する css.addFill(element) #変形 if element.transform: #CSSとSVGの原点の違いを補正 transform = element.transform.toMatrix() transform = transform * svg.Transform.Translate( x + width / 2, y + height / 2) transform = svg.Transform.Translate( -x - width / 2, -y - height / 2) * transform css["left"] += transform.e css["top"] += transform.f transform.e = 0 transform.f = 0 css["transform"] = transform #透明度を指定 if "opacity" in element.style: css["opacity"] = element.style["opacity"] #出力 self._css(cls=namestroke, style=css) #クリップの設定 if namestroke in self.__clipnames: namestroke = self.__clipnames[name] self._html( '<div class="%s"><div class="%sinverse"><div class="%s"></div></div></div>\n' % (clipname, clipname, name)) return self._html('<div class="%s"></div>\n' % namestroke)
def __round_rect(self, element, x, y, width, height, rx=0, ry=0): blur = 0 filterURL = getURL(element.style.get("filter", "")) if filterURL: filter = element.getRoot().getElementById(filterURL) if filter and isinstance(filter[0], svg.FEGaussianBlur): blur = filter[0].stdDeviation * 1.7 try: self.__blured_round_rect(element, x, y, width, height, rx, ry, blur) return except: pass name = self.newName(element) if name not in self._css_classes: self._css_classes.add(name) css = CSSStyle() stroke = svg.Length(0) #クリップパスの設定 self.__clipPath(name, element) #ストロークの描画 if "stroke" in element.style and element.style["stroke"] != 'none': try: stroke = svg.Length(element.style.get("stroke-width", 0)) css["border-width"] = stroke css["border-style"] = "solid" color = svg.Color(element.style["stroke"]) if "stroke-opacity" in element.style: color.a = float(element.style["stroke-opacity"]) css["border-color"] = color except: pass #位置と大きさの設定 css["position"] = "absolute" css["left"] = x - stroke / 2 css["top"] = y - stroke / 2 css["width"] = width - stroke css["height"] = height - stroke #角を丸める if rx and ry: css["border-radius"] = "%s/%s" % (str(rx + stroke / 2), str(ry + stroke / 2)) elif rx: css["border-radius"] = rx + stroke / 2 elif ry: css["border-radius"] = ry + stroke / 2 #フィルを指定する css.addFill(element) #変形 if element.transform: #CSSとSVGの原点の違いを補正 transform = element.transform.toMatrix() transform = transform * svg.Transform.Translate( x + width / 2, y + height / 2) transform = svg.Transform.Translate( -x - width / 2, -y - height / 2) * transform css["left"] += transform.e css["top"] += transform.f transform.e = 0 transform.f = 0 css["transform"] = transform #透明度を指定 if "opacity" in element.style: css["opacity"] = element.style["opacity"] #出力 self._css(cls=name, style=css) #クリップの設定 if name in self.__clipnames: clipname = self.__clipnames[name] self._html( '<div class="%s"><div class="%sinverse"><div class="%s"></div></div></div>\n' % (clipname, clipname, name)) return self._html('<div class="%s"></div>\n' % name)