'Inserting librsvg loaded image as transformed vector image on cairo SVG?

Say I have this infile.svg:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   id="svg2"
   viewBox="0 0 4 4"
   version="1.1"
   width="4cm"
   height="4cm"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <defs
     id="defs486" />
  <path
     id="path1408"
     style="fill:#2a9595;stroke:#000000;stroke-width:0.01;stroke-dasharray:0.04,0.02;stop-color:#000000;stroke-miterlimit:4;stroke-dashoffset:0"
     d="M 2.6571041,1.1924639 A 0.69555329,0.72946234 0 0 1 1.9615507,1.9219262 0.69555329,0.72946234 0 0 1 1.2659974,1.1924639 0.69555329,0.72946234 0 0 1 1.9615507,0.46300158 0.69555329,0.72946234 0 0 1 2.6571041,1.1924639 Z" />
  <rect
     style="fill:none;stroke:#000000;stroke-width:0.01;stroke-miterlimit:4;stroke-dasharray:0.001, 0.001;stroke-dashoffset:0;stop-color:#000000"
     id="rect844"
     width="4"
     height="4"
     x="2.7755576e-16"
     y="-2.220446e-16" />
  <path
     style="fill:#00ff00;stroke:#000000;stroke-width:0.005;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
     d="M 0.51253109,2.2402314 1.1612342,3.0528093 3.1454609,1.7890126 1.7175135,2.9468611 2.6602104,2.6097986 1.9087936,3.0836403 2.0136521,3.873634 1.2805142,3.3970356 0.09047392,3.1962115 0.97719683,3.179429 Z"
     id="path1182" />
</svg>

As it can be seen, this SVG has no groups or layers - just paths.

I would now like to load this document, as an SVG vector, into a new .svg that I want to draw in C using cairo.

As per Convert Surface to vectorized SVG instead of embedded PNG, a cairo "recording surface" needs to be used for that purpose, otherwise the loaded SVG is rasterized into pixels.

So consider the following C code which demonstrates that, test.c:

#include <stdio.h>
#include <stdlib.h>

#include <math.h>
#include <cairo.h>
#include <cairo-svg.h>
#include <librsvg/rsvg.h>


int
main(int argc, const char **argv)
{
  cairo_surface_t *surface;
  cairo_t *cr;
  float pagesize = 10.0;
  float halfpage = pagesize/2;
  surface = cairo_svg_surface_create("outfile.svg", pagesize, pagesize);
  cairo_svg_surface_set_document_unit(surface, CAIRO_SVG_UNIT_CM);
  cr = cairo_create(surface);

  // draw a circle on page
  double radius = halfpage;
  cairo_set_source_rgb(cr, 0, 0, 0.9);  // set pen color to blue
  cairo_set_line_width(cr, 0.3);      // 3 mm stroke, since units are cm
  cairo_move_to(cr, halfpage+radius, halfpage);
  cairo_arc(cr, halfpage, halfpage, radius, 0, 2 * M_PI);
  cairo_stroke(cr);

  // load and insert SVG via cairo_recording_surface_create
  GError* error = NULL;
  RsvgHandle* handle = rsvg_handle_new_from_file("infile.svg", &error);
  if (error != NULL) {
    printf ("error! %s\n", error->message);
    return 1;
  }

  gboolean has_width, has_height, has_viewbox;
  RsvgLength rwidth, rheight;
  RsvgRectangle rviewbox;
  rsvg_handle_get_intrinsic_dimensions(handle, &has_width, &rwidth, &has_height, &rheight, &has_viewbox, &rviewbox);

  cairo_surface_t* rsurface = cairo_recording_surface_create(CAIRO_CONTENT_COLOR_ALPHA, NULL);
  cairo_t* rcr = cairo_create(rsurface);
  RsvgRectangle viewport = {
    .x = 0.0,
    .y = 0.0,
    .width = rwidth.length,
    .height = rheight.length,
  };
  rsvg_handle_render_document(handle, rcr, &viewport, NULL);

  // "paste" the loaded SVH by painting it
  //cairo_move_to(cr, halfpage, halfpage); // no effect, loaded still drawn at 0,0 upper left corner
  cairo_set_source_surface(cr, rsurface, halfpage, halfpage); // here the last two arguments do displace the "pasted" image
  cairo_paint(cr);
  cairo_surface_flush(rsurface);
  cairo_surface_finish(rsurface);
  cairo_surface_destroy(rsurface);
  cairo_destroy(rcr);

  cairo_surface_destroy(surface);
  cairo_destroy(cr);

  return 0;
}

I compile this on Ubuntu 20.04 with:

gcc -Wall -c test.c -I/usr/include/glib-2.0/ -I/usr/include/librsvg-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include/ -I/usr/include/gdk-pixbuf-2.0/ -I/usr/include/cairo/ -o test.o
gcc test.o -o test.exe argparse_git/build/libargparse.a /usr/lib/x86_64-linux-gnu/librsvg-2.so.2 /usr/lib/x86_64-linux-gnu/libcairo.so

Now, this works, in the sense that vectors of infile.svg are indeed inserted in outfile.svg - and they are displaced from the coordinate origin 0,0 in the upper left corner of the document.

However, the first problem is visible already in Inkscape:

inkscape-screenshot

The inserted/pasted/loaded SVG graphic is in fact considered to be a clone! (actually, the paths are still present, and grouped, and the "clone" is due to the group not being used "verbatim", but through a <use xlink:href node)

So, my questions are:

  • How can I insert the loaded SVG graphic "as is" in the source document - that is, just as two paths and a rect?
  • How can I insert the loaded SVG graphic "as is" in the source document, but grouped?

Finally, I also noticed cairo_move_to has no influence on the position of the pasted graphic in the final SVG document - only the arguments of cairo_set_source_surface do; so my final question is:

  • How can I both translate and rotate the entire loaded/inserted SVG graphic - again, either as two paths and a rect (with changed, "baked-in" coordinates), or as a group of those?

outfile.svg for reference:

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10cm" height="10cm" viewBox="0 0 10 10" version="1.1">
<defs>
<g id="surface5" clip-path="url(#clip1)">
<path style="fill-rule:nonzero;fill:rgb(16.470589%,58.431375%,58.431375%);fill-opacity:1;stroke-width:0.01;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.0666667,0.0333333;stroke-miterlimit:4;" d="M 2.65625 1.191406 C 2.65625 1.59375 2.34375 1.921875 1.960938 1.921875 C 1.578125 1.921875 1.265625 1.59375 1.265625 1.191406 C 1.265625 0.789062 1.578125 0.464844 1.960938 0.464844 C 2.34375 0.464844 2.65625 0.789062 2.65625 1.191406 Z M 2.65625 1.191406 " transform="matrix(1,0,0,1,-0,-0)"/>
<path style="fill:none;stroke-width:0.01;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:4;" d="M 0 0 L 4 0 L 4 4 L 0 4 Z M 0 0 " transform="matrix(1,0,0,1,-0,-0)"/>
<path style="fill-rule:nonzero;fill:rgb(0%,100%,0%);fill-opacity:1;stroke-width:0.005;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:4;" d="M 0.511719 2.238281 L 1.160156 3.054688 L 3.144531 1.789062 L 1.71875 2.945312 L 2.660156 2.609375 L 1.910156 3.082031 L 2.011719 3.875 L 1.28125 3.398438 L 0.0898438 3.195312 L 0.976562 3.179688 Z M 0.511719 2.238281 " transform="matrix(1,0,0,1,-0,-0)"/>
</g>
</defs>
<g id="surface1">
<path style="fill:none;stroke-width:0.3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,90%);stroke-opacity:1;stroke-miterlimit:10;" d="M 10 5 C 10 11.667969 0 11.667969 0 5 C 0 -1.667969 10 -1.667969 10 5 "/>
<use xlink:href="#surface5" transform="matrix(1,0,0,1,5,5)"/>
</g>
</svg>


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source