def __init__(self, tree, surface, context, dpi, parent_surface=None, parent_width=None, parent_height=None, scale=1): """Create the surface from a filename or a file-like object. The rendered content is written to ``output`` which can be a filename, a file-like object, ``None`` (render in memory but do not write anything) or the built-in ``bytes`` as a marker. Call the ``.finish()`` method to make sure that the output is actually written. """ self.cairo = None self.context_width, self.context_height = parent_width, parent_height self.cursor_position = [0, 0] self.cursor_d_position = [0, 0] self.text_path_width = 0 self.tree_cache = {(tree.url, tree.get('id')): tree} if parent_surface: self.markers = parent_surface.markers self.gradients = parent_surface.gradients self.patterns = parent_surface.patterns self.masks = parent_surface.masks self.paths = parent_surface.paths self.filters = parent_surface.filters else: self.markers = {} self.gradients = {} self.patterns = {} self.masks = {} self.paths = {} self.filters = {} self._old_parent_node = self.parent_node = None self.dpi = dpi self.font_size = size(self, '12pt') self.stroke_and_fill = True width, height, viewbox = node_format(self, tree) width *= scale height *= scale # Actual surface dimensions: may be rounded on raster surfaces types self.cairo = surface self.width = width self.height = height self.context = context # We must scale the context as the surface size is using physical units self.context.scale(self.device_units_per_user_units, self.device_units_per_user_units) # Initial, non-rounded dimensions self.set_context_size(width, height, viewbox, scale, preserved_ratio(tree)) self.context.move_to(0, 0) self.draw(tree)
def read_dimensions_from_svg(self, tree): """ :param tree: :return: Returns the size of the image in pixels. If the image is measured in points, it will error. """ svg_width_px, svg_height_px, _ = node_format(self, tree) self.svg_width = CanvasUnit.from_px(svg_width_px).pt self.svg_height = CanvasUnit.from_px(svg_height_px).pt
def image(surface, node): """Draw an image ``node``.""" base_url = node.get('{http://www.w3.org/XML/1998/namespace}base') if not base_url and node.url: base_url = os.path.dirname(node.url) + '/' url = parse_url(node.get('{http://www.w3.org/1999/xlink}href'), base_url) if "href" in node and node["href"].startswith("data:image/"): # gif, etc image_bytes = uri2image_bytes(node["href"]) else: image_bytes = node.fetch_url(url, 'image/*') if len(image_bytes) < 5: return x, y = size(surface, node.get('x'), 'x'), size(surface, node.get('y'), 'y') width = size(surface, node.get('width'), 'x') height = size(surface, node.get('height'), 'y') if image_bytes[:4] == b'\x89PNG': png_file = BytesIO(image_bytes) elif (image_bytes[:5] in (b'<svg ', b'<?xml', b'<!DOC') or image_bytes[:2] == b'\x1f\x8b'): if 'x' in node: del node['x'] if 'y' in node: del node['y'] tree = Tree(url=url.geturl(), url_fetcher=node.url_fetcher, bytestring=image_bytes, tree_cache=surface.tree_cache, unsafe=node.unsafe) tree_width, tree_height, viewbox = node_format(surface, tree, reference=False) if not viewbox: tree_width = tree['width'] = width tree_height = tree['height'] = height node.image_width = tree_width or width node.image_height = tree_height or height scale_x, scale_y, translate_x, translate_y = preserve_ratio( surface, node) # Clip image region surface.context.rectangle(x, y, width, height) surface.context.clip() # Draw image surface.context.save() surface.context.translate(x, y) surface.set_context_size(*node_format(surface, tree, reference=False), scale=1, preserved_ratio=preserved_ratio(tree)) surface.context.translate(*surface.context.get_current_point()) surface.context.scale(scale_x, scale_y) surface.context.translate(translate_x, translate_y) surface.draw(tree) surface.context.restore() return else: png_file = BytesIO() Image.open(BytesIO(image_bytes)).save(png_file, 'PNG') png_file.seek(0) image_surface = cairo.ImageSurface.create_from_png(png_file) ### DSB ## Added: image_surface.pattern = cairo.SurfacePattern(image_surface) image_surface.pattern.set_filter(cairo.FILTER_NEAREST) ### DSB node.image_width = image_surface.get_width() node.image_height = image_surface.get_height() scale_x, scale_y, translate_x, translate_y = preserve_ratio(surface, node) # Clip image region (if necessary) if not (translate_x == 0 and translate_y == 0 and width == scale_x * node.image_width and height == scale_y * node.image_height): surface.context.rectangle(x, y, width, height) surface.context.clip() # Paint raster image surface.context.save() surface.context.translate(x, y) surface.context.scale(scale_x, scale_y) surface.context.translate(translate_x, translate_y) ### DSB ## Removed: #surface.context.set_source_surface(image_surface) ## Added: surface.context.set_source(image_surface.pattern) ### DSB surface.context.paint() surface.context.restore()
def __init__(self, tree, output, dpi, parent_surface=None, parent_width=None, parent_height=None, scale=1, output_width=None, output_height=None, background_color=None, map_rgba=None, map_image=None, output_cairo=None, output_cairo_context=None): # ## END OF FORK ## # """Create the surface from a filename or a file-like object. The rendered content is written to ``output`` which can be a filename, a file-like object, ``None`` (render in memory but do not write anything) or the built-in ``bytes`` as a marker. Call the ``.finish()`` method to make sure that the output is actually written. """ self.cairo = None self.context_width, self.context_height = parent_width, parent_height self.cursor_position = [0, 0] self.cursor_d_position = [0, 0] self.text_path_width = 0 self.tree_cache = {(tree.url, tree.get('id')): tree} if parent_surface: self.markers = parent_surface.markers self.gradients = parent_surface.gradients self.patterns = parent_surface.patterns self.masks = parent_surface.masks self.paths = parent_surface.paths self.filters = parent_surface.filters self.images = parent_surface.images else: self.markers = {} self.gradients = {} self.patterns = {} self.masks = {} self.paths = {} self.filters = {} self.images = {} self._old_parent_node = self.parent_node = None self.output = output self.dpi = dpi self.font_size = size(self, '12pt') self.stroke_and_fill = True width, height, viewbox = node_format(self, tree) if viewbox is None: viewbox = (0, 0, width, height) if output_width and output_height: width, height = output_width, output_height elif output_width: if width: # Keep the aspect ratio height *= output_width / width width = output_width elif output_height: if height: # Keep the aspect ratio width *= output_height / height height = output_height else: width *= scale height *= scale # ## START OF FORK ## # # Actual surface dimensions: may be rounded on raster surfaces types self.width = width * self.device_units_per_user_units self.height = height * self.device_units_per_user_units if output_cairo is not None: self.cairo = output_cairo else: self.cairo = self._create_surface(self.width, self.height) # ## END OF FORK ## # if 0 in (self.width, self.height): raise ValueError('The SVG size is undefined') # ## START OF FORK ## # if output_cairo_context is not None: self.context = output_cairo_context else: self.context = cairo.Context(self.cairo) # ## END OF FORK ## # # We must scale the context as the surface size is using physical units self.context.scale(self.device_units_per_user_units, self.device_units_per_user_units) # Initial, non-rounded dimensions self.set_context_size(width, height, viewbox, tree) self.context.move_to(0, 0) if background_color: self.context.set_source_rgba(*color(background_color)) self.context.paint() self.map_rgba = map_rgba self.map_image = map_image self.draw(tree)
def read_dimensions_from_svg(self, tree): self.svg_width, self.svg_height, _ = node_format(self, tree)
def __init__( self, surface, x, y, tree, dpi, output=None, parent_surface=None, parent_width=None, parent_height=None, scale=1, output_width=None, output_height=None, background_color=None, map_rgba=None, map_image=None, rotation=None, ): self.surface = surface self.cairo = None self.context_width, self.context_height = parent_width, parent_height self.cursor_position = [0, 0] self.cursor_d_position = [0, 0] self.text_path_width = 0 self.tree_cache = {(tree.url, tree.get("id")): tree} if parent_surface: self.markers = parent_surface.markers self.gradients = parent_surface.gradients self.patterns = parent_surface.patterns self.masks = parent_surface.masks self.paths = parent_surface.paths self.filters = parent_surface.filters self.images = parent_surface.images else: self.markers = {} self.gradients = {} self.patterns = {} self.masks = {} self.paths = {} self.filters = {} self.images = {} self._old_parent_node = self.parent_node = None self.output = output self.dpi = dpi self.font_size = size(self, "12pt") self.stroke_and_fill = True width, height, viewbox = node_format(self, tree) if viewbox is None: viewbox = (0, 0, width, height) if output_width and output_height: width, height = output_width, output_height elif output_width: if width: # Keep the aspect ratio height *= output_width / width width = output_width elif output_height: if height: # Keep the aspect ratio width *= output_height / height height = output_height else: width *= scale height *= scale # Actual surface dimensions: may be rounded on raster surfaces types self.cairo, self.width, self.height = self._create_surface( width * self.device_units_per_user_units, height * self.device_units_per_user_units, ) if 0 in (self.width, self.height): raise ValueError("The SVG size is undefined") self.context = cairo.Context(self.cairo) # We must scale the context as the surface size is using physical units self.context.scale(self.device_units_per_user_units, self.device_units_per_user_units) center = (x + width / 2, y + height / 2) transform(self.context, center, rotation=rotation) self.context.translate(x, y) # Initial, non-rounded dimensions self.set_context_size(width, height, viewbox, tree) if background_color: self.context.set_source_rgba(*color(background_color)) self.context.paint() self.map_rgba = map_rgba self.map_image = map_image