'''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 <string.h>
#include <stdio.h> #include <unistd.h>
#include <cairo.h>
#include <cairo/cairo-pdf.h>
#include <librsvg/rsvg.h>
}
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 .pdfng!"
}
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.
<<categories>> Critcl | Development | Graphics | SVG | PDF