'''Name''' ''svgconvert'' - [Critcl] code to convert svg images into png images or pdf files '''Description''' This is a short example on how to use the [Cairo] library with [Critcl]. The C code is wrapped in a namespace and only used internally by the Tcl procedures svg2pdf and svg2png. ====== # file svgconvert.tcl package require critcl package provide svgconvert 1.0 if {![critcl::compiling]} { puts stderr "This extension cannot be compiled without critcl enabled" exit 1 } namespace eval svgconvert { # how to get all the include directories otherwise? set options [regsub -all -- -I [exec pkg-config --cflags --libs cairo --libs librsvg-2.0] "I "] set dirs [list] foreach {i dir} $options { if {$i eq "I"} { lappend dirs $dir } } critcl::clibraries -lrsvg-2 -lm -lgio-2.0 -lgdk_pixbuf-2.0 -lgobject-2.0 -lglib-2.0 -lcairo -pthread critcl::config I $dirs critcl::ccode { #include #include #include #include #include } critcl::cproc svgconvert {char* svgfile char* outfile double scalex double scaley} void { char *ext = ".pdf"; char *pdf = strstr(outfile, ext); RsvgHandle *handle; RsvgDimensionData dimension_data; GError* err = NULL; handle = rsvg_handle_new_from_file(svgfile, &err); if (err != NULL) { fprintf(stderr, "libsvgconv: Failed to load svg: '%s'; %s\n", svgfile, (char*) err->message); g_error_free(err); err = NULL; } cairo_surface_t *surface; cairo_t *ctx; rsvg_handle_get_dimensions(handle, &dimension_data); double resx = ((double) dimension_data.width) * scalex; double resy = ((double) dimension_data.height) * scaley; if (pdf) { surface = cairo_pdf_surface_create(outfile, (int) resx, (int) resy); } else { surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int) resx, (int) resy); } ctx = cairo_create(surface); cairo_set_source_rgba(ctx, 255, 255, 255, 0); cairo_scale(ctx, scalex, scaley); rsvg_handle_render_cairo(handle, ctx); cairo_paint(ctx); cairo_show_page(ctx); cairo_destroy(ctx); // Destroying cairo context cairo_surface_flush(surface); if (pdf) { // Destroying PDF surface cairo_surface_destroy(surface); } else { cairo_surface_write_to_png(surface, outfile); cairo_surface_destroy(surface); } } proc svg2pdf {svgfile pdffile {scalex 1.0} {scaley 1.0}} { if {$scalex != $scaley} { set scaley $scalex } if {![file exists $svgfile]} { error "Error: File $svgfile does not exist!" } if {[file extension $pdffile] ne ".pdf"} { error "Error: File extension for $pdffile is not .pdf!" } svgconvert::svgconvert $svgfile $pdffile $scalex $scaley } proc svg2png {svgfile pngfile {scalex 1.0} {scaley 1.0}} { if {$scalex != $scaley} { set scaley $scalex } if {![file exists $svgfile]} { error "Error: File $svgfile does not exist!" } if {[file extension $pngfile] ne ".png"} { error "Error: File extension for $pngfile is not .png!" } svgconvert::svgconvert $svgfile $pngfile $scalex $scaley } namespace export svg2pdf svg2png } ====== '''Test''' ====== source svgconvert.tcl namespace import svgconvert::* svg2pdf infile.svg outfile.pdf svg2png infile.svg outfile.png ====== '''Todos/Ideas''' * Parsing command line arguments to make it an convert application * Postscript output (?) * width and height in pixels * embedding into [tsvg9 as alternative to cairosvg if this is not available * using cairo xrender to a Tk widget(?) * svg widget (displays actually the converted png in an label widget) '''See also''' * [Cairo] * [tclcairo] * [tsvg] ---- '''Discussion''' Please discuss here. [DDG] - 2021-12-01 - Initial release, ideas welcome. <> Critcl | Development | Graphics | SVG | PDF