Example #1
0
def svg_xml_rotated(xml, **kwargs):
    """
	Returns a pygame.Surface list from the given xml.
	For kwargs, see "rotated_svg"
	"""
    degrees = kwargs.pop("degrees", None)
    images = kwargs.pop("images", None)
    frames = kwargs.pop("frames", images)
    rotations = kwargs.pop("rotations", None)
    center_x = kwargs.pop("center_x", None)
    center_y = kwargs.pop("center_y", None)
    if center_x and not center_y or center_y and not center_x:
        raise Exception(
            "Invalid center - must provide both center_x and center_y, or none"
        )
    if len(kwargs):
        logging.warning("Unexpected keyword arguments: %s" % kwargs)

    if rotations:
        if degrees or frames: raise Exception("Incompatible arguments")
    else:
        if degrees:
            if frames: raise Exception("Incompatible arguments")
            frames = floor(360 / degrees)
        elif frames:
            if degrees: raise Exception("Incompatible arguments")
            degrees = 360 / frames
        else:
            raise Exception("No rotation spec!")
        rotations = [degrees * i for i in range(frames)]

    images = []

    # Read the svg into ElementTree:
    svg_node = ET.fromstring(xml)
    # Create group with transform to contain rest of svg:
    wrapper = ET.SubElement(svg_node, "g", {
        "id": "legame-image-rotator",
        "transform": ""
    })
    # Move all nodes not the wrapper to inside the wrapper:
    for e in svg_node:
        if e is not wrapper:
            wrapper.append(e)
    # Create cairosvg.Tree to be rendered
    # use the cairosvg.surface.helpers.node_format() func to get width, height:
    cairosvg_tree = Tree(bytestring=ET.tostring(svg_node.getroottree()))
    width, height, viewbox = node_format(None, cairosvg_tree)
    if center_x is None: center_x = width / 2
    if center_y is None: center_y = height / 2

    for degrees in rotations:
        # Modify "transform" attribute of wrapper node:
        cairosvg_tree.children[0]["transform"] = "rotate({}, {}, {})".format(
            degrees, center_x, center_y)
        # Render modified cairosvg Tree:
        images.append(surf_from_cairosvgtree(cairosvg_tree, width, height))
    return images
Example #2
0
    def convert(cls, bytestring=None, **kwargs):
        """Convert a SVG document to the format for this class.

        Specify the input by passing one of these:

        :param bytestring: The SVG source as a byte-string.
        :param file_obj: A file-like object.
        :param url: A filename.

        And the output with:

        :param write_to: The filename of file-like object where to write the
                         output. If None or not provided, return a byte string.

        Only ``bytestring`` can be passed as a positional argument, other
        parameters are keyword-only.

        """
        dpi = kwargs.pop('dpi', 96)
        parent_width = kwargs.pop('parent_width', None)
        parent_height = kwargs.pop('parent_height', None)
        scale = kwargs.pop('scale', 1)
        write_to = kwargs.pop('write_to', None)
        kwargs['bytestring'] = bytestring
        tree = Tree(**kwargs)
        output = write_to or io.BytesIO()
        instance = cls(tree, output, dpi, None, parent_width, parent_height,
                       scale)
        instance.finish()
        if write_to is None:
            return output.getvalue()
Example #3
0
def convertList(urls, writeTo, dpi=72):

    #see https://github.com/Kozea/CairoSVG/issues/200
    import cairocffi
    from cairosvg.parser import Tree
    from cairosvg.surface import PDFSurface

    class RecordingPDFSurface(PDFSurface):
        surface_class = cairocffi.RecordingSurface

        def _create_surface(self, width, height):
            cairo_surface = cairocffi.RecordingSurface(
                cairocffi.CONTENT_COLOR_ALPHA, (0, 0, width, height))
            return cairo_surface, width, height

    surface = cairocffi.PDFSurface(writeTo, 1, 1)
    context = cairocffi.Context(surface)
    for url in urls:
        if os.name == 'nt':
            url = url.replace('\\', '/')
            url = 'file:///{}'.format(url)
        image_surface = RecordingPDFSurface(Tree(url=url), None, dpi)
        surface.set_size(image_surface.width, image_surface.height)
        context.set_source_surface(image_surface.cairo, 0, 0)
        context.paint()
        surface.show_page()
    surface.finish()
Example #4
0
def generate_award_pdf_svg(output, data, template_prefix, dpi=96):
    svgs = []
    surface = cairocffi.PDFSurface(output, 1, 1)
    context = cairocffi.Context(surface)
    for d in data:
        t = d['template']
        if len(t) < 1:
            continue
        text_template_filename = os.path.join(template_prefix, t + '.svg')
        with open(text_template_filename, 'r') as f:
            svg = etree.parse(f)
        svg = _data_into_svg(svg, d)
        svg_str = etree.tostring(svg)
        tree = Tree(bytestring=svg_str)
        svgs.append(svg_str)
        image_surface = PDFSurface(tree, None, dpi)
        surface.set_size(image_surface.width, image_surface.height)
        context.set_source_surface(image_surface.cairo, 0, 0)
        context.paint()
        surface.show_page()
        # with open(text_template_filename, 'r') as f:
        #    svgs.append(_data_into_svg(etree.parse(f), d))
    # svgs += b'</svg>'
    surface.finish()
    with open(output + '.svg', 'wb') as f:
        f.write(b"\n".join(svgs))
Example #5
0
def load_svg(svg: bytes, width: float = None, height: float = None) -> ImageSurface:
    """
    Load a SVG image to an Cairo ImageSurface.
    :param svg: Plain SVG data
    :param width: Designated with of the image. If None, it will be determined from the svg data.
    :param height:  Designated height of the image. If None, it will be determined from the svg data.
    :return: ImageSurface that contains the image from the SVG data.
    """
    return PNGSurface(Tree(bytestring=svg), None, 1, parent_width=width, parent_height=height).cairo
Example #6
0
 def draw_svg():
     # Draw to a cairo surface but do not write to a file
     tree = Tree(bytestring=string, url=uri)
     surface = ScaledSVGSurface(tree, output=None, dpi=96)
     if not (surface.width > 0 and surface.height > 0):
         raise ValueError(
             'Images without an intrinsic size are not supported.')
     pattern = cairo.SurfacePattern(surface.cairo)
     return pattern, surface.width, surface.height
Example #7
0
def loadsvg(name, dpi=72., keep_colors=True):
    assert name.endswith(".svg")
    s = open(name).read()
    tree = Tree(bytestring=s)
    if keep_colors:
        context = Flatten()
    else:
        context = SkipColors()
    dummy = DummySurf(tree, None, dpi, context=context)
    item = back.Compound(dummy.paths)
    return item
Example #8
0
def render_svg(surface: cairo.Surface,
               svg: str,
               x,
               y,
               width,
               height,
               rotation=None,
               dpi=96):
    tree = Tree(bytestring=svg.encode())
    instance = CairoSurface(
        surface=surface,
        rotation=rotation,
        x=x,
        y=y,
        tree=tree,
        dpi=dpi,
        output_width=width,
        output_height=height,
    )
    instance.draw(tree)
Example #9
0
def from_xml(xml):
    cairosvg_tree = Tree(bytestring=xml)
    width, height, viewbox = node_format(None, cairosvg_tree)
    return surf_from_cairosvgtree(cairosvg_tree, width, height)
Example #10
0
        self.paths = self.context.paths


class SkipColors(Flatten):
    def set_source_rgba(self, r, g, b, a):
        pass


def loadsvg(name, dpi=72., keep_colors=True):
    assert name.endswith(".svg")
    s = open(name).read()
    tree = Tree(bytestring=s)
    if keep_colors:
        context = Flatten()
    else:
        context = SkipColors()
    dummy = DummySurf(tree, None, dpi, context=context)
    item = back.Compound(dummy.paths)
    return item


if __name__ == "__main__":

    name = argv.next()
    s = open(name).read()
    tree = Tree(bytestring=s)
    my = DummySurf(tree, None, 72.)
    cvs = back.Canvas(my.paths)
    cvs.writePDFfile("output.pdf")
Example #11
0
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 convert(cls,
                bytestring=None,
                *,
                file_obj=None,
                url=None,
                dpi=96,
                parent_width=None,
                parent_height=None,
                scale=1,
                unsafe=False,
                background_color=None,
                negate_colors=False,
                invert_images=False,
                write_to=None,
                output_width=None,
                output_height=None,
                **kwargs):
        """Convert an SVG document to the format for this class.

        Specify the input by passing one of these:

        :param bytestring: The SVG source as a byte-string.
        :param file_obj: A file-like object.
        :param url: A filename.

        Give some options:

        :param dpi: The ratio between 1 inch and 1 pixel.
        :param parent_width: The width of the parent container in pixels.
        :param parent_height: The height of the parent container in pixels.
        :param scale: The ouptut scaling factor.
        :param unsafe: A boolean allowing XML entities and very large files
                       (WARNING: vulnerable to XXE attacks and various DoS).

        Specifiy the output with:

        :param write_to: The filename of file-like object where to write the
                         output. If None or not provided, return a byte string.

        Only ``bytestring`` can be passed as a positional argument, other
        parameters are keyword-only.

        """
        tree = Tree(bytestring=bytestring,
                    file_obj=file_obj,
                    url=url,
                    unsafe=unsafe,
                    **kwargs)
        output = write_to or io.BytesIO()
        instance = cls(tree,
                       output,
                       dpi,
                       None,
                       parent_width,
                       parent_height,
                       scale,
                       output_width,
                       output_height,
                       background_color,
                       map_rgba=negate_color if negate_colors else None,
                       map_image=invert_image if invert_images else None)
        instance.finish()
        if write_to is None:
            return output.getvalue()