def process(self): kwargs = dict(self.getAttributeValues(ignore=('points',))) # Start the path and set the cursor to the start location. canvas = attr.getManager(self, interfaces.ICanvasManager).canvas self.path = canvas.beginPath() self.path.moveTo(kwargs.pop('x'), kwargs.pop('y')) # Process the text before the first sub-directive. if self.element.text is not None: self.processPoints(self.element.text) # Handle each sub-directive. for directive in self.element.getchildren(): if directive.tag in self.factories: self.factories[directive.tag](directive, self).process() # If there is more text after sub-directive, process it. if directive.tail is not None: self.processPoints(directive.tail) if kwargs.pop('close', False): self.path.close() if kwargs.pop('clip', False): canvas.clipPath(self.path, **kwargs) else: canvas.drawPath(self.path, **kwargs)
def process(self): kwargs = dict(self.getAttributeValues(ignore=('points', ))) # Start the path and set the cursor to the start location. canvas = attr.getManager(self, interfaces.ICanvasManager).canvas self.path = canvas.beginPath() self.path.moveTo(kwargs.pop('x'), kwargs.pop('y')) # Process the text before the first sub-directive. if self.element.text is not None: self.processPoints(self.element.text) # Handle each sub-directive. for directive in self.element.getchildren(): if directive.tag in self.factories: self.factories[directive.tag](directive, self).process() # If there is more text after sub-directive, process it. if directive.tail is not None: self.processPoints(directive.tail) if kwargs.pop('close', False): self.path.close() if kwargs.pop('clip', False): canvas.clipPath(self.path, **kwargs) else: canvas.drawPath(self.path, **kwargs)
def _draw_single_background(self, canvas, x, margins, width, height): canvas.saveState() clipping_mask = canvas.beginPath() clipping_mask.roundRect( x + margins[Border.LEFT], margins[Border.BOTTOM], width - margins[Border.RIGHT] - margins[Border.LEFT], height - margins[Border.TOP] - margins[Border.BOTTOM], self.BACKGROUND_CORNER_DIAMETER) canvas.clipPath(clipping_mask, stroke=0, fill=0) # get optimum background orientation background_orientation = best_orientation(self.background_image_path, width, height) if background_orientation == Orientation.TURN90: canvas.rotate(90) canvas.translate(0, -self.WIDTH * 2) canvas.drawImage(self.background_image_path, 0, 0, width=height, height=width, mask=None) else: canvas.drawImage(self.background_image_path, x, 0, width=width, height=height, mask=None) canvas.restoreState()
def _draw_single_background(self, canvas, x, margins, width, height, orientation=Orientation.NORMAL): canvas.saveState() canvas.setFillColor("white") clipping_mask = canvas.beginPath() if orientation == Orientation.TURN90: clipping_mask.roundRect( x + margins[Border.BOTTOM], margins[Border.LEFT], width - margins[Border.TOP] - margins[Border.BOTTOM], height - margins[Border.RIGHT] - margins[Border.LEFT], self.BACKGROUND_CORNER_DIAMETER, ) else: clipping_mask.roundRect( x + margins[Border.LEFT], margins[Border.BOTTOM], width - margins[Border.RIGHT] - margins[Border.LEFT], height - margins[Border.TOP] - margins[Border.BOTTOM], self.BACKGROUND_CORNER_DIAMETER, ) canvas.clipPath(clipping_mask, stroke=0, fill=1) if self.background_image_path is not None: canvas.drawImage(self.background_image_path, x, 0, width=width, height=height, mask=None) canvas.restoreState()
def pageCanvas(self, canvas, doc): """ Forming of the page layout (backround color...) """ canvas.saveState() canvas.setFont(self.FONTNAME, self.FONTSIZE) canvas.setFillColorRGB( self.BCKGRDCOLOR[0], self.BCKGRDCOLOR[1], self.BCKGRDCOLOR[2]) canvas.rect(0, 0, self.WIDTH, self.HEIGHT, stroke=0, fill=1) canvas.restoreState() canvas.saveState() p = canvas.beginPath() p.rect(0, self.HEIGHT - 80, self.WIDTH, 80) canvas.clipPath(p, stroke=0) canvas.linearGradient( 0, self.HEIGHT - 80, self.WIDTH, self.HEIGHT - 80, (black, blue), extend=False) canvas.restoreState() canvas.saveState() canvas.setFillColorRGB(1, 1, 1) canvas.setFont(self.FONTNAME, self.FONTSIZE) canvas.drawString(40, 714, "%s.%s:%s" % (self.PASSAGE[0], self.PASSAGE[1], self.PASSAGE[2])) canvas.restoreState()
def render_element(root, element, canvas, styles): canvas.saveState() current_style = {} if len(styles): current_style.update(styles[-1]) for declaration in element.get("style", "").split(";"): if declaration == "": continue key, value = declaration.split(":") current_style[key] = value styles.append(current_style) if "stroke-width" in current_style: canvas.setLineWidth(float(current_style["stroke-width"])) if "stroke-dasharray" in current_style: canvas.setDash([ float(length) for length in current_style["stroke-dasharray"].split(",") ]) if current_style.get("visibility") != "hidden": if "transform" in element.attrib: for transformation in element.get("transform").split(")")[::1]: if transformation: transform, arguments = transformation.split("(") arguments = arguments.split(",") if transform.strip() == "translate": if len(arguments) == 2: canvas.translate(float(arguments[0]), float(arguments[1])) elif transform.strip() == "rotate": if len(arguments) == 1: canvas.rotate(float(arguments[0])) if len(arguments) == 3: canvas.translate(float(arguments[1]), float(arguments[2])) canvas.rotate(float(arguments[0])) canvas.translate(-float(arguments[1]), -float(arguments[2])) if element.tag == "svg": if "background-color" in current_style: set_fill_color( canvas, toyplot.color.css(current_style["background-color"])) canvas.rect( 0, 0, float(element.get("width")[:-2]), float(element.get("height")[:-2]), stroke=0, fill=1, ) for child in element: render_element(root, child, canvas, styles) elif element.tag == "g": if element.get("clip-path", None) is not None: clip_id = element.get("clip-path")[5:-1] clip_path = root.find(".//*[@id='%s']" % clip_id) for child in clip_path: if child.tag == "rect": x = float(child.get("x")) y = float(child.get("y")) width = float(child.get("width")) height = float(child.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() canvas.clipPath(path, stroke=0, fill=1) else: toyplot.log.error("Unhandled clip tag: %s", child.tag) # pragma: no cover for child in element: render_element(root, child, canvas, styles) elif element.tag == "clipPath": pass elif element.tag == "line": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) canvas.setLineCap(get_line_cap(current_style)) canvas.line( float(element.get("x1", 0)), float(element.get("y1", 0)), float(element.get("x2", 0)), float(element.get("y2", 0)), ) elif element.tag == "path": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) canvas.setLineCap(get_line_cap(current_style)) path = canvas.beginPath() commands = element.get("d").split() while len(commands): command = commands.pop(0) if command == "L": path.lineTo(float(commands.pop(0)), float(commands.pop(0))) elif command == "M": path.moveTo(float(commands.pop(0)), float(commands.pop(0))) canvas.drawPath(path) elif element.tag == "polygon": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError( "Gradient <polygon> not implemented." ) # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) points = [ point.split(",") for point in element.get("points").split() ] path = canvas.beginPath() for point in points[:1]: path.moveTo(float(point[0]), float(point[1])) for point in points[1:]: path.lineTo(float(point[0]), float(point[1])) path.close() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "rect": fill, fill_gradient = get_fill(root, current_style) if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) x = float(element.get("x", 0)) y = float(element.get("y", 0)) width = float(element.get("width")) height = float(element.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() if fill_gradient is not None: pdf_colors = [] pdf_offsets = [] for stop in fill_gradient: offset = float(stop.get("offset")) color = toyplot.color.css(stop.get("stop-color")) opacity = float(stop.get("stop-opacity")) pdf_colors.append( reportlab.lib.colors.Color(color["r"], color["g"], color["b"], color["a"] * opacity)) pdf_offsets.append(offset) canvas.saveState() canvas.clipPath(path, stroke=0, fill=1) canvas.setFillAlpha(1) canvas.linearGradient( float(fill_gradient.get("x1")), float(fill_gradient.get("y1")), float(fill_gradient.get("x2")), float(fill_gradient.get("y2")), pdf_colors, pdf_offsets, ) canvas.restoreState() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "circle": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError( "Gradient <circle> not implemented." ) # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) cx = float(element.get("cx", 0)) cy = float(element.get("cy", 0)) r = float(element.get("r")) canvas.circle(cx, cy, r, stroke=stroke is not None, fill=fill is not None) elif element.tag == "text": x = float(element.get("x", 0)) y = float(element.get("y", 0)) fill, fill_gradient = get_fill(element, current_style) stroke = get_stroke(current_style) font_family = get_font_family(current_style) font_size = toyplot.units.convert(current_style["font-size"], target="px") text = element.text canvas.saveState() canvas.setFont(font_family, font_size) if fill is not None: set_fill_color(canvas, fill) if stroke is not None: set_stroke_color(canvas, stroke) canvas.translate(x, y) canvas.scale(1, -1) canvas.drawString(0, 0, text) canvas.restoreState() elif element.tag == "image": # pylint: disable=redefined-variable-type import PIL.Image image = element.get("xlink:href") if not image.startswith("data:image/png;base64,"): raise ValueError( "Unsupported image type.") # pragma: no cover image = base64.standard_b64decode(image[22:]) image = io.BytesIO(image) image = PIL.Image.open(image) image = reportlab.lib.utils.ImageReader(image) x = float(element.get("x", 0)) y = float(element.get("y", 0)) width = float(element.get("width")) height = float(element.get("height")) canvas.saveState() path = canvas.beginPath() set_fill_color(canvas, toyplot.color.rgb(1, 1, 1)) canvas.rect(x, y, width, height, stroke=0, fill=1) canvas.translate(x, y + height) canvas.scale(1, -1) canvas.drawImage(image=image, x=0, y=0, width=width, height=height, mask=None) canvas.restoreState() elif element.tag in ["defs", "title"]: pass else: raise Exception("unhandled tag: %s" % element.tag) # pragma: no cover styles.pop() canvas.restoreState()
def render_element(root, element, canvas, styles, text_state=None): canvas.saveState() current_style = {} if len(styles): current_style.update(styles[-1]) for declaration in element.get("style", "").split(";"): if declaration == "": continue key, value = declaration.split(":") if key == "dominant-baseline" and value == "inherit": continue current_style[key] = value styles.append(current_style) if "stroke-width" in current_style: canvas.setLineWidth(float(current_style["stroke-width"])) if "stroke-dasharray" in current_style: canvas.setDash([ float(length) for length in current_style["stroke-dasharray"].split(",") ]) if current_style.get("visibility") != "hidden": if "transform" in element.attrib: for transformation in element.get("transform").split(")")[::1]: if transformation: type, arguments = transformation.split("(") arguments = arguments.split(",") if type.strip() == "translate": if len(arguments) == 2: canvas.translate(float(arguments[0]), float(arguments[1])) elif type.strip() == "rotate": if len(arguments) == 1: canvas.rotate(float(arguments[0])) if len(arguments) == 3: canvas.translate(float(arguments[1]), float(arguments[2])) canvas.rotate(float(arguments[0])) canvas.translate(-float(arguments[1]), -float(arguments[2])) if element.tag == "svg": if "background-color" in current_style: set_fill_color( canvas, toyplot.color.css(current_style["background-color"])) canvas.rect( 0, 0, float(element.get("width")[:-2]), float(element.get("height")[:-2]), stroke=0, fill=1, ) for child in element: render_element(root, child, canvas, styles) elif element.tag == "g": if element.get("clip-path", None) is not None: clip_id = element.get("clip-path")[5:-1] clip_path = root.find(".//*[@id='%s']" % clip_id) for child in clip_path: if child.tag == "rect": x = float(child.get("x")) y = float(child.get("y")) width = float(child.get("width")) height = float(child.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() canvas.clipPath(path, stroke=0, fill=1) else: toyplot.log.error("Unhandled clip tag: %s" % child.tag) # pragma: no cover for child in element: render_element(root, child, canvas, styles) elif element.tag == "clipPath": pass elif element.tag == "line": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) canvas.line( float(element.get("x1")), float(element.get("y1")), float(element.get("x2")), float(element.get("y2")), ) elif element.tag == "path": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) path = canvas.beginPath() commands = element.get("d").split() while len(commands): command = commands.pop(0) if command == "L": path.lineTo(float(commands.pop(0)), float(commands.pop(0))) elif command == "M": path.moveTo(float(commands.pop(0)), float(commands.pop(0))) canvas.drawPath(path) elif element.tag == "polygon": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError( "Gradient <polygon> not implemented." ) # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) points = [ point.split(",") for point in element.get("points").split() ] path = canvas.beginPath() for point in points[:1]: path.moveTo(float(point[0]), float(point[1])) for point in points[1:]: path.lineTo(float(point[0]), float(point[1])) path.close() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "rect": fill, fill_gradient = get_fill(root, current_style) if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) x = float(element.get("x")) y = float(element.get("y")) width = float(element.get("width")) height = float(element.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() if fill_gradient is not None: pdf_colors = [] pdf_offsets = [] for stop in fill_gradient: offset = float(stop.get("offset")) color = toyplot.color.css(stop.get("stop-color")) opacity = float(stop.get("stop-opacity")) pdf_colors.append( reportlab.lib.colors.Color(color["r"], color["g"], color["b"], color["a"])) pdf_offsets.append(offset) canvas.saveState() canvas.clipPath(path, stroke=0, fill=1) canvas.setFillAlpha(1) canvas.linearGradient( float(fill_gradient.get("x1")), float(fill_gradient.get("y1")), float(fill_gradient.get("x2")), float(fill_gradient.get("y2")), pdf_colors, pdf_offsets, ) canvas.restoreState() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "circle": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError( "Gradient <circle> not implemented." ) # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) cx = float(element.get("cx")) cy = float(element.get("cy")) r = float(element.get("r")) canvas.circle(cx, cy, r, stroke=stroke is not None, fill=fill is not None) elif element.tag == "text": text_state = {"x": 0, "y": 0, "chunks": [[]]} for child in element: render_element(root, child, canvas, styles, text_state) for chunk in text_state["chunks"]: width = sum([span[7] for span in chunk]) dx = 0 text_anchor = current_style.get("text-anchor", "start") if text_anchor == "middle": dx = -width * 0.5 elif text_anchor == "end": dx = -width for x, y, fill, stroke, font_family, font_size, text, width in chunk: canvas.saveState() canvas.setFont(font_family, font_size) if fill is not None: set_fill_color(canvas, fill) if stroke is not None: set_stroke_color(canvas, stroke) canvas.translate(x + dx, y) canvas.scale(1, -1) canvas.drawString(0, 0, text) canvas.restoreState() elif element.tag == "tspan": # if "font-weight" in current_style: # font_description.set_weight( # pango.WEIGHT_BOLD if current_style["font-weight"] == "bold" else pango.WEIGHT_NORMAL) font_family = get_font_family(current_style) font_size = toyplot.units.convert( current_style["font-size"].strip(), "px") string_width = reportlab.pdfbase.pdfmetrics.stringWidth( element.text, font_family, font_size) ascent, descent = reportlab.pdfbase.pdfmetrics.getAscentDescent( font_family, font_size) if "x" in element.attrib: text_state["x"] = float(element.get("x")) text_state["chunks"].append([]) if "dy" in element.attrib: text_state["y"] += float(element.get("dy")) x = text_state["x"] y = text_state["y"] alignment_baseline = current_style.get("alignment-baseline", "middle") if alignment_baseline == "hanging": y += ascent elif alignment_baseline == "central": y += ascent * 0.5 elif alignment_baseline == "middle": y += (ascent + descent) * 0.5 elif alignment_baseline == "alphabetic": pass else: raise ValueError("Unsupported alignment-baseline: %s" % alignment_baseline) # pragma: no cover baseline_shift = current_style.get("baseline-shift", "0").strip() baseline_shift = toyplot.units.convert(baseline_shift, "px", "px", ascent - descent) y -= baseline_shift fill, fill_gradient = get_fill(root, current_style) stroke = get_stroke(current_style) text_state["chunks"][-1].append( (x, y, fill, stroke, font_family, font_size, element.text, string_width)) text_state["x"] += string_width elif element.tag in ["defs", "title"]: pass else: raise Exception("unhandled tag: %s" % element.tag) # pragma: no cover styles.pop() canvas.restoreState()
def drawFirstPage(canvas, doc): canvas.saveState() # Title text tobj = canvas.beginText() tobj.setTextOrigin(doc.leftMargin, doc.pagesize[1] - doc.topMargin - 24) tobj.setFont('Helvetica-Bold', 32) tobj.setLeading(22) tobj.textLine('NavPlot') tobj.setFont('Helvetica', 16) tobj.textLine('Navigation warnings for: %s' % doc.dateStr) canvas.drawText(tobj) # Small print canvas.setFont('Helvetica', 10) canvas.drawString(doc.leftMargin, doc.bottomMargin, "THIS IS AN UNOFFICAL BRIEFING. Use at your own risk.") #canvas.drawRightString(doc.pagesize[0] - doc.rightMargin, doc.bottomMargin, # "Data \N{COPYRIGHT SIGN} NATS Ltd.") # Clipping rectangle for the map path = canvas.beginPath() path.rect(doc.leftMargin, doc.bottomMargin + doc.bottomOffset, doc.mapwidth, doc.mapheight) canvas.clipPath(path) # Drawing style for the map canvas.setLineWidth(0.5) canvas.setFillColor(gray) # Draw the other map stuff. Coordinate file must be in mapinfo format. # Coast line from http://rimmer.ngdc.noaa.gov/mgg/coast/getcoast.html moveFlag = True path = canvas.beginPath() map_data = doc.map_data for lin in map_data.splitlines(): try: lon, lat = map(float, lin.split()) except: moveFlag = True continue x, y = doc.latlon2xy(lat, lon) if moveFlag: path.moveTo(x, y) moveFlag = False else: path.lineTo(x, y) canvas.setStrokeColor(darkgray) canvas.drawPath(path) # Draw some gliding sites canvas.setStrokeColor(gray) delta = 2.5 * mm for gs in GLIDING_SITES: x, y = doc.latlon2xy(*GLIDING_SITES[gs]) canvas.lines( ((x, y + delta, x, y - delta), (x - delta, y, x + delta, y))) canvas.drawString(x + mm, y + mm, gs) # Draw NOTAM areas canvas.setStrokeColor(blue) canvas.setFillColor(black) canvas.setLineWidth(0.5) for n, notam in enumerate(doc.notams): x, y = doc.latlon2xy(notam[0], notam[1]) radius = notam[2] / 60.0 * doc.scale canvas.circle(x, y, radius) if radius / mm < 3: x1 = x + radius / 1.41 + mm / 2 y1 = y + radius / 1.41 + mm / 2 canvas.line(x, y, x1, y1) canvas.drawString(x1, y1, str(n + 1)) else: canvas.drawCentredString(x, y - 3, str(n + 1)) canvas.restoreState()
def drawFirstPage(canvas, doc): canvas.saveState() # Title text tobj = canvas.beginText() tobj.setTextOrigin(doc.leftMargin, doc.pagesize[1] - doc.topMargin - 24) tobj.setFont('Helvetica-Bold', 32) tobj.setLeading(22) firstr = '/'.join(doc.firs) tobj.textLine('NavPlot') tobj.setFont('Helvetica', 16) tobj.textLine('%s Navigation warnings for: %s' % (firstr, doc.dateStr)) canvas.drawText(tobj) # Small print canvas.setFont('Helvetica', 10) canvas.drawString(doc.leftMargin, doc.bottomMargin, "IMPORTANT: Do not rely on this map - check NOTAM's from an official "\ "source. Data "+UTF8_COPYRIGHT_SIGN+' '+doc.copyright_holder) # Clipping rectangle for the map path = canvas.beginPath() path.rect(doc.leftMargin, doc.bottomMargin + doc.bottomOffset, doc.mapwidth, doc.mapheight) canvas.clipPath(path) # Drawing style for the map canvas.setLineWidth(0.5) canvas.setFillColor(gray) # Draw the other map stuff. Coordinate file must be in mapinfo format. # Coast line from http://rimmer.ngdc.noaa.gov/mgg/coast/getcoast.html moveFlag = True path = canvas.beginPath() map_data = doc.map_data for lin in map_data.splitlines(): if lin[0] != '#': lon, lat = map(float, lin.split('\t')) x, y = doc.latlon2xy(lat, lon) if moveFlag: path.moveTo(x, y) moveFlag = False else: path.lineTo(x, y) else: moveFlag = True canvas.setStrokeColor(darkgray) canvas.drawPath(path) # Draw some gliding sites canvas.setStrokeColor(gray) delta = 2.5 * mm for gs in GLIDING_SITES: x, y = doc.latlon2xy(*GLIDING_SITES[gs]) canvas.lines( ((x, y + delta, x, y - delta), (x - delta, y, x + delta, y))) canvas.drawString(x + mm, y + mm, gs) # Draw NOTAM areas canvas.setStrokeColor(blue) canvas.setFillColor(black) canvas.setLineWidth(0.5) for n, notam in enumerate(doc.notams): x, y = doc.latlon2xy(notam[0], notam[1]) radius = notam[2] / 60.0 * doc.scale canvas.circle(x, y, radius) if radius / mm < 3: x1 = x + radius / 1.41 + mm / 2 y1 = y + radius / 1.41 + mm / 2 canvas.line(x, y, x1, y1) canvas.drawString(x1, y1, str(n + 1)) else: canvas.drawCentredString(x, y - 3, str(n + 1)) canvas.restoreState()
def drawFirstPage(canvas, doc): canvas.saveState() # Title text tobj = canvas.beginText() tobj.setTextOrigin(doc.leftMargin, doc.pagesize[1]-doc.topMargin-24) tobj.setFont('Helvetica-Bold', 32) tobj.setLeading(22) firstr = '/'.join(doc.firs) tobj.textLine('NavPlot') tobj.setFont('Helvetica', 16) tobj.textLine('%s Navigation warnings for: %s' % (firstr, doc.dateStr)) canvas.drawText(tobj) # Small print canvas.setFont('Helvetica', 10) canvas.drawString(doc.leftMargin, doc.bottomMargin, "IMPORTANT: Do not rely on this map - check NOTAM's from an official "\ "source. Data "+UTF8_COPYRIGHT_SIGN+' '+doc.copyright_holder) # Clipping rectangle for the map path = canvas.beginPath() path.rect(doc.leftMargin, doc.bottomMargin+doc.bottomOffset, doc.mapwidth, doc.mapheight) canvas.clipPath(path) # Drawing style for the map canvas.setLineWidth(0.5) canvas.setFillColor(gray) # Draw the other map stuff. Coordinate file must be in mapinfo format. # Coast line from http://rimmer.ngdc.noaa.gov/mgg/coast/getcoast.html moveFlag = True path = canvas.beginPath() map_data = doc.map_data for lin in map_data.splitlines(): if lin[0] != '#': lon, lat = map(float, lin.split('\t')) x, y = doc.latlon2xy(lat, lon) if moveFlag: path.moveTo(x, y) moveFlag = False else: path.lineTo(x, y) else: moveFlag = True canvas.setStrokeColor(darkgray) canvas.drawPath(path) # Draw some gliding sites canvas.setStrokeColor(gray) delta = 2.5*mm for gs in GLIDING_SITES: x, y = doc.latlon2xy(*GLIDING_SITES[gs]) canvas.lines(((x, y+delta, x, y-delta), (x-delta, y, x+delta, y))) canvas.drawString(x+mm, y+mm, gs) # Draw NOTAM areas canvas.setStrokeColor(blue) canvas.setFillColor(black) canvas.setLineWidth(0.5) for n, notam in enumerate(doc.notams): x, y = doc.latlon2xy(notam[0], notam[1]) radius = notam[2]/60.0*doc.scale canvas.circle(x, y, radius) if radius/mm < 3: x1 = x + radius/1.41 + mm/2 y1 = y + radius/1.41 + mm/2 canvas.line(x, y, x1, y1) canvas.drawString(x1, y1, str(n+1)) else: canvas.drawCentredString(x, y-3, str(n+1)) canvas.restoreState()
def render_element(root, element, canvas, styles, text_state=None): canvas.saveState() current_style = {} if len(styles): current_style.update(styles[-1]) for declaration in element.get("style", "").split(";"): if declaration == "": continue key, value = declaration.split(":") if key == "dominant-baseline" and value == "inherit": continue current_style[key] = value styles.append(current_style) if "stroke-width" in current_style: canvas.setLineWidth(float(current_style["stroke-width"])) if "stroke-dasharray" in current_style: canvas.setDash([float(length) for length in current_style["stroke-dasharray"].split(",")]) if current_style.get("visibility") != "hidden": if "transform" in element.attrib: for transformation in element.get("transform").split(")")[::1]: if transformation: type, arguments = transformation.split("(") arguments = arguments.split(",") if type.strip() == "translate": if len(arguments) == 2: canvas.translate(float(arguments[0]), float(arguments[1])) elif type.strip() == "rotate": if len(arguments) == 1: canvas.rotate(float(arguments[0])) if len(arguments) == 3: canvas.translate(float(arguments[1]), float(arguments[2])) canvas.rotate(float(arguments[0])) canvas.translate(-float(arguments[1]), -float(arguments[2])) if element.tag == "svg": if "background-color" in current_style: set_fill_color(canvas, toyplot.color.css(current_style["background-color"])) canvas.rect( 0, 0, float(element.get("width")[:-2]), float(element.get("height")[:-2]), stroke=0, fill=1 ) for child in element: render_element(root, child, canvas, styles) elif element.tag == "g": if element.get("clip-path", None) is not None: clip_id = element.get("clip-path")[5:-1] clip_path = root.find(".//*[@id='%s']" % clip_id) for child in clip_path: if child.tag == "rect": x = float(child.get("x")) y = float(child.get("y")) width = float(child.get("width")) height = float(child.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() canvas.clipPath(path, stroke=0, fill=1) else: toyplot.log.error("Unhandled clip tag: %s" % child.tag) # pragma: no cover for child in element: render_element(root, child, canvas, styles) elif element.tag == "clipPath": pass elif element.tag == "line": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) canvas.line( float(element.get("x1")), float(element.get("y1")), float(element.get("x2")), float(element.get("y2")), ) elif element.tag == "path": stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) path = canvas.beginPath() commands = element.get("d").split() while len(commands): command = commands.pop(0) if command == "L": path.lineTo(float(commands.pop(0)), float(commands.pop(0))) elif command == "M": path.moveTo(float(commands.pop(0)), float(commands.pop(0))) canvas.drawPath(path) elif element.tag == "polygon": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError("Gradient <polygon> not implemented.") # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) points = [point.split(",") for point in element.get("points").split()] path = canvas.beginPath() for point in points[:1]: path.moveTo(float(point[0]), float(point[1])) for point in points[1:]: path.lineTo(float(point[0]), float(point[1])) path.close() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "rect": fill, fill_gradient = get_fill(root, current_style) if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) x = float(element.get("x")) y = float(element.get("y")) width = float(element.get("width")) height = float(element.get("height")) path = canvas.beginPath() path.moveTo(x, y) path.lineTo(x + width, y) path.lineTo(x + width, y + height) path.lineTo(x, y + height) path.close() if fill_gradient is not None: pdf_colors = [] pdf_offsets = [] for stop in fill_gradient: offset = float(stop.get("offset")) color = toyplot.color.css(stop.get("stop-color")) opacity = float(stop.get("stop-opacity")) pdf_colors.append(reportlab.lib.colors.Color(color["r"], color["g"], color["b"], color["a"])) pdf_offsets.append(offset) canvas.saveState() canvas.clipPath(path, stroke=0, fill=1) canvas.setFillAlpha(1) canvas.linearGradient( float(fill_gradient.get("x1")), float(fill_gradient.get("y1")), float(fill_gradient.get("x2")), float(fill_gradient.get("y2")), pdf_colors, pdf_offsets, ) canvas.restoreState() canvas.drawPath(path, stroke=stroke is not None, fill=fill is not None) elif element.tag == "circle": fill, fill_gradient = get_fill(root, current_style) if fill_gradient is not None: raise NotImplementedError("Gradient <circle> not implemented.") # pragma: no cover if fill is not None: set_fill_color(canvas, fill) stroke = get_stroke(current_style) if stroke is not None: set_stroke_color(canvas, stroke) cx = float(element.get("cx")) cy = float(element.get("cy")) r = float(element.get("r")) canvas.circle(cx, cy, r, stroke=stroke is not None, fill=fill is not None) elif element.tag == "text": text_state = {"x": 0, "y": 0, "chunks": [[]]} for child in element: render_element(root, child, canvas, styles, text_state) for chunk in text_state["chunks"]: width = sum([span[7] for span in chunk]) dx = 0 text_anchor = current_style.get("text-anchor", "start") if text_anchor == "middle": dx = -width * 0.5 elif text_anchor == "end": dx = -width for x, y, fill, stroke, font_family, font_size, text, width in chunk: canvas.saveState() canvas.setFont(font_family, font_size) if fill is not None: set_fill_color(canvas, fill) if stroke is not None: set_stroke_color(canvas, stroke) canvas.translate(x + dx, y) canvas.scale(1, -1) canvas.drawString(0, 0, text) canvas.restoreState() elif element.tag == "tspan": # if "font-weight" in current_style: # font_description.set_weight( # pango.WEIGHT_BOLD if current_style["font-weight"] == "bold" else pango.WEIGHT_NORMAL) font_family = get_font_family(current_style) font_size = toyplot.units.convert(current_style["font-size"].strip(), "px") string_width = reportlab.pdfbase.pdfmetrics.stringWidth(element.text, font_family, font_size) ascent, descent = reportlab.pdfbase.pdfmetrics.getAscentDescent(font_family, font_size) if "x" in element.attrib: text_state["x"] = float(element.get("x")) text_state["chunks"].append([]) if "dy" in element.attrib: text_state["y"] += float(element.get("dy")) x = text_state["x"] y = text_state["y"] alignment_baseline = current_style.get("alignment-baseline", "middle") if alignment_baseline == "hanging": y += ascent elif alignment_baseline == "central": y += ascent * 0.5 elif alignment_baseline == "middle": y += (ascent + descent) * 0.5 elif alignment_baseline == "alphabetic": pass else: raise ValueError("Unsupported alignment-baseline: %s" % alignment_baseline) # pragma: no cover baseline_shift = current_style.get("baseline-shift", "0").strip() baseline_shift = toyplot.units.convert(baseline_shift, "px", "px", ascent - descent) y -= baseline_shift fill, fill_gradient = get_fill(root, current_style) stroke = get_stroke(current_style) text_state["chunks"][-1].append( (x, y, fill, stroke, font_family, font_size, element.text, string_width) ) text_state["x"] += string_width elif element.tag in ["defs", "title"]: pass else: raise Exception("unhandled tag: %s" % element.tag) # pragma: no cover styles.pop() canvas.restoreState()