X-Git-Url: http://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=example.c;h=aa71e233cee108f95056f3d6d9edd18371c5fbb2;hb=f9d9d432a8511172a75e0ebc12eb2ab32bb75b8d;hp=bc09e4c6236c0383d7a4cf92d624e14b968b32d2;hpb=6b08d4c36787505216607ecee1ad433ff72816b6;p=libsvgtiny-pixbuf.git diff --git a/example.c b/example.c index bc09e4c..aa71e23 100644 --- a/example.c +++ b/example.c @@ -6,14 +6,32 @@ #include #include +/* + * The width and height of the viewport that we'll render the SVG + * into. The final "picture" may not actually be this size; based on + * the height, width, viewBox, and preserveAspectRatio attributes in + * the SVG itself, libsvgtiny may scale, stretch, offset, etc. the + * paths to make them fit nicely into the viewport. + */ +#define VIEWPORT_WIDTH 512 +#define VIEWPORT_HEIGHT 512 + /* Convenient typedefs for libsvgtiny */ typedef struct svgtiny_diagram diagram_t; +typedef struct svgtiny_shape shape_t; /** - * Render an svgtiny path using cairo. + * @brief Render an svgtiny path using cairo. + * + * @param cr + * A pointer to a valid cairo context. + * + * @param path + * A pointer to an svgtiny shape that will be rendered on the + * cairo context's target surface. */ -void render_path(cairo_t *cr, struct svgtiny_shape *path) { +static void render_path(cairo_t* cr, shape_t* path) { unsigned int j; cairo_new_path(cr); @@ -51,23 +69,25 @@ void render_path(cairo_t *cr, struct svgtiny_shape *path) { } } if (path->fill != svgtiny_TRANSPARENT) { - cairo_set_source_rgb(cr, - svgtiny_RED(path->fill) / 255.0, - svgtiny_GREEN(path->fill) / 255.0, - svgtiny_BLUE(path->fill) / 255.0); + cairo_set_source_rgba(cr, + svgtiny_RED(path->fill) / 255.0, + svgtiny_GREEN(path->fill) / 255.0, + svgtiny_BLUE(path->fill) / 255.0, + 1); cairo_fill_preserve(cr); } if (path->stroke != svgtiny_TRANSPARENT) { - cairo_set_source_rgb(cr, - svgtiny_RED(path->stroke) / 255.0, - svgtiny_GREEN(path->stroke) / 255.0, - svgtiny_BLUE(path->stroke) / 255.0); + cairo_set_source_rgba(cr, + svgtiny_RED(path->stroke) / 255.0, + svgtiny_GREEN(path->stroke) / 255.0, + svgtiny_BLUE(path->stroke) / 255.0, + 1); cairo_set_line_width(cr, path->stroke_width); cairo_stroke_preserve(cr); } } -/* +/** * @brief Parse an SVG file into a diagram_t structure. * * @param fp @@ -77,11 +97,11 @@ void render_path(cairo_t *cr, struct svgtiny_shape *path) { * returned; if not, @c NULL is returned. You are expected to @c * svgtiny_free the result if it is valid. */ -diagram_t* svgtiny_diagram_from_file(FILE* fp, int width, int height) { - diagram_t *diagram; +static diagram_t* svgtiny_diagram_from_file(FILE* fp, int width, int height) { + diagram_t* diagram; size_t bytecount; - char *buffer; + char* buffer; size_t bytesread; svgtiny_code code; @@ -141,7 +161,7 @@ diagram_t* svgtiny_diagram_from_file(FILE* fp, int width, int height) { return diagram; } -/* +/** * @brief Create a cairo context from a libsvgtiny diagram. * * @param diagram @@ -151,13 +171,13 @@ diagram_t* svgtiny_diagram_from_file(FILE* fp, int width, int height) { * is returned; if not, @c NULL is returned. You are expected to @c * cairo_destroy the result if it is valid. */ -cairo_t* cairo_context_from_diagram(diagram_t* diagram) { +static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { cairo_t* cr; cairo_surface_t* surface; cairo_status_t crs; unsigned int i; - surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, + surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, diagram->width, diagram->height); @@ -185,7 +205,7 @@ cairo_t* cairo_context_from_diagram(diagram_t* diagram) { return NULL; } - cairo_set_source_rgb(cr, 1, 1, 1); + cairo_set_source_rgba(cr, 0, 0, 0, 0); cairo_paint(cr); /* Loop through the shapes in the diagram... */ @@ -200,10 +220,11 @@ cairo_t* cairo_context_from_diagram(diagram_t* diagram) { if (diagram->shape[i].text) { /* Figure out what color to use from the R/G/B components of the shape's stroke. */ - cairo_set_source_rgb(cr, - svgtiny_RED(diagram->shape[i].stroke) / 255.0, - svgtiny_GREEN(diagram->shape[i].stroke) / 255.0, - svgtiny_BLUE(diagram->shape[i].stroke) / 255.0); + cairo_set_source_rgba(cr, + svgtiny_RED(diagram->shape[i].stroke) / 255.0, + svgtiny_GREEN(diagram->shape[i].stroke) / 255.0, + svgtiny_BLUE(diagram->shape[i].stroke) / 255.0, + 1); /* Then move to the actual position of the text within the shape... */ cairo_move_to(cr, @@ -232,11 +253,10 @@ cairo_t* cairo_context_from_diagram(diagram_t* diagram) { int main(int argc, char** argv) { char* svgpath; char* pngpath; - int pngwidth = 1024, pngheight = 1024; FILE* fp; diagram_t* diagram; - cairo_t *cr = 0; + cairo_t* cr = 0; GdkPixbuf* pb; @@ -256,7 +276,7 @@ int main(int argc, char** argv) { return 1; } - diagram = svgtiny_diagram_from_file(fp, pngwidth, pngheight); + diagram = svgtiny_diagram_from_file(fp, VIEWPORT_WIDTH, VIEWPORT_HEIGHT); if (!diagram) { return 1; } @@ -267,11 +287,21 @@ int main(int argc, char** argv) { return 1; } + /* We're using the viewport width and height and not the diagram + * width/height for the image. The diagram can be of a different + * size and aspect ratio than the viewport, and our main use case is + * for icons that are generally square and reasonably sized. If the + * diagram is "small," then we want to scale it up until it fits + * nicely in the viewport before rendering it. That's as opposed to + * rendering the image small, and letting GDK scale it up. Of course + * this reasoning makes the assumption that the viewport is usually + * larger than the diagram. + */ pb = gdk_pixbuf_get_from_surface(cairo_get_target(cr), 0, 0, - pngwidth, - pngheight); + VIEWPORT_WIDTH, + VIEWPORT_HEIGHT); if (pb) { @@ -281,3 +311,89 @@ int main(int argc, char** argv) { return 0; } + + +static GdkPixbuf* gdk_pixbuf_from_svg_file_stream(FILE *fp, GError **error) { + diagram_t* diagram; + cairo_t* cr = 0; + + GdkPixbuf* pb; + + diagram = svgtiny_diagram_from_file(fp, VIEWPORT_WIDTH, VIEWPORT_HEIGHT); + if (!diagram) { + return NULL; + } + + cr = cairo_context_from_diagram(diagram); + if (!cr) { + svgtiny_free(diagram); + return NULL; + } + + + /* We're using the viewport width and height and not the diagram + * width/height for the image. The diagram can be of a different + * size and aspect ratio than the viewport, and our main use case is + * for icons that are generally square and reasonably sized. If the + * diagram is "small," then we want to scale it up until it fits + * nicely in the viewport before rendering it. That's as opposed to + * rendering the image small, and letting GDK scale it up. Of course + * this reasoning makes the assumption that the viewport is usually + * larger than the diagram. + */ + pb = gdk_pixbuf_get_from_surface(cairo_get_target(cr), + 0, + 0, + VIEWPORT_WIDTH, + VIEWPORT_HEIGHT); + + + if (!pb) { + fprintf(stderr, "gdk_pixbuf_get_from_surface failed!\n"); + } + + return pb; +} + + +G_MODULE_EXPORT void fill_vtable(GdkPixbufModule* module); +void fill_vtable(GdkPixbufModule* module) { + module->load = gdk_pixbuf_from_svg_file_stream; +} + +G_MODULE_EXPORT void fill_info(GdkPixbufFormat *info); +void fill_info(GdkPixbufFormat* info) { + /* Borrowed from librsvg-2.40.21 */ + static const GdkPixbufModulePattern signature[] = { + { " name = "svg"; + info->signature = (GdkPixbufModulePattern*) signature; + info->description = "Scalable Vector Graphics"; + info->mime_types = (gchar**) mime_types; + info->extensions = (gchar**) extensions; + info->flags = GDK_PIXBUF_FORMAT_SCALABLE; + info->license = "AGPL3"; +} +