X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=io-svg.c;h=543162f6c0b21f8357679f3e03ce76f408e91da9;hb=96deefceb53d73852b56ca0c71c08ba9abc758ca;hp=750ea254b22bd945a7e2d707d1f2302987308d96;hpb=ce61daf00d9a18bcbbbff7709d9c59c3c0d2dbbb;p=libsvgtiny-pixbuf.git diff --git a/io-svg.c b/io-svg.c index 750ea25..543162f 100644 --- a/io-svg.c +++ b/io-svg.c @@ -1,4 +1,4 @@ -#include /* fopen, fprintf, fread, printf */ +#include /* fprintf, printf */ #include /* memcpy */ #include @@ -16,8 +16,6 @@ #define VIEWPORT_WIDTH 512 #define VIEWPORT_HEIGHT 512 -#define SVG_BUFFER_INCREMENT (size_t)4194304 - /* Convenient typedefs for libsvgtiny */ typedef struct svgtiny_diagram diagram_t; typedef struct svgtiny_shape shape_t; @@ -29,10 +27,13 @@ typedef struct { GdkPixbufModuleSizeFunc size_func; gpointer user_data; - /* The "file" */ + /* The SVG "file" that we're building in memory. */ char* svg_data; - size_t svg_data_size; - size_t svg_data_max; + + /* How far into svg_data are we? This should always point to the + next empty byte. If (for example) svg_data_size is 2, then + svg_data[0] and svg_data[1] are used, but svg_data[2] is free. */ + size_t svg_data_size; } SvgTinyContext; @@ -55,8 +56,8 @@ static void render_path(cairo_t* cr, shape_t* path) { switch ((int) path->path[j]) { case svgtiny_PATH_MOVE: cairo_move_to(cr, - path->path[j + 1], - path->path[j + 2]); + path->path[j + 1], + path->path[j + 2]); j += 3; break; case svgtiny_PATH_CLOSE: @@ -113,24 +114,23 @@ static void render_path(cairo_t* cr, shape_t* path) { * svgtiny_free the result if it is valid. */ static diagram_t* svgtiny_diagram_from_buffer(char* buffer, - size_t bytecount, - int width, - int height, - GError** error) { + size_t bytecount, + int width, + int height, + GError** error) { diagram_t* diagram; svgtiny_code code; diagram = svgtiny_create(); if (!diagram) { g_set_error_literal(error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - "svgtiny_create() failed"); + G_FILE_ERROR, + G_FILE_ERROR_NOMEM, + "out of memory in svgtiny_create()"); return NULL; } code = svgtiny_parse(diagram, buffer, bytecount, "", width, height); - free(buffer); if (code != svgtiny_OK) { switch (code) { @@ -144,19 +144,19 @@ static diagram_t* svgtiny_diagram_from_buffer(char* buffer, g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "libdom error in svgtiny_parse()"); + "invalid XML DOM in svgtiny_parse()"); break; case svgtiny_NOT_SVG: g_set_error_literal(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "encountered svgtiny_NOT_SVG in svgtiny_parse()"); + "missing element in svgtiny_parse()"); break; case svgtiny_SVG_ERROR: g_set_error(error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "SVG error in svgtiny_parse() on line %i: %s", + "SVG format error in svgtiny_parse() on line %i: %s", diagram->error_line, diagram->error_message); break; @@ -247,8 +247,8 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { crs = cairo_status(cr); if (crs != CAIRO_STATUS_SUCCESS) { fprintf(stderr, - "cairo error: %s\n", - cairo_status_to_string(crs)); + "cairo error: %s\n", + cairo_status_to_string(crs)); cairo_destroy(cr); return NULL; } @@ -272,18 +272,18 @@ static cairo_t* cairo_context_from_diagram(diagram_t* diagram) { * returned; if not, @c NULL is returned and @c error is populated. */ static GdkPixbuf* gdk_pixbuf_from_svg_buffer(char* buffer, - size_t bytecount, - GError** error) { + size_t bytecount, + GError** error) { diagram_t* diagram; cairo_t* cr = 0; GdkPixbuf* pb; GError* sub_error = NULL; diagram = svgtiny_diagram_from_buffer(buffer, - bytecount, - VIEWPORT_WIDTH, - VIEWPORT_HEIGHT, - &sub_error); + bytecount, + VIEWPORT_WIDTH, + VIEWPORT_HEIGHT, + &sub_error); if (!diagram) { g_propagate_error(error, sub_error); return NULL; @@ -293,88 +293,44 @@ static GdkPixbuf* gdk_pixbuf_from_svg_buffer(char* buffer, if (!cr) { svgtiny_free(diagram); g_set_error_literal(error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - "could not create Cairo surface from SVG diagram"); + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_CORRUPT_IMAGE, + "could not create Cairo surface from SVG 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. - */ + /* I've gone back and forth on this about five times: we use the + * diagram width and height, and not the viewport width and height. + * This can ultimately render an image that's larger than the + * viewport size, but I think GDK will resize the final pixbuf + * anyway. More importantly, rendering small icons at a larger + * (viewport) size seems to make the whole thing go ape-shit. + * So for now I'm back in the diagram camp. + */ pb = gdk_pixbuf_get_from_surface(cairo_get_target(cr), - 0, - 0, - VIEWPORT_WIDTH, - VIEWPORT_HEIGHT); + 0, + 0, + diagram->width, + diagram->height); if (!pb) { g_set_error_literal(error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_FAILED, - "failed to obtain a GdkPixbuf from Cairo surface"); + GDK_PIXBUF_ERROR, + GDK_PIXBUF_ERROR_FAILED, + "failed to obtain a GdkPixbuf from Cairo surface"); } return pb; } -/** - * @brief Create a GdkPixbuf from an SVG filestream. - * - * This is essentially a wrapper around @gdk_pixbuf_from_svg_buffer - * that reads a @c FILE pointer into a buffer. - * - * @param fp - * A pointer to a @c FILE containing the SVG document. - * - * @param error - * The address of a @c GError pointer that we use to return errors. - * - * @return If successful, a valid pointer to a @c GdkPixbuf is - * returned; if not, @c NULL is returned and @c error is populated. - */ -static GdkPixbuf* gdk_pixbuf_from_svg_file_stream(FILE *fp, GError** error) { - size_t bytecount, bytesread; - char* buffer; - - /* Find the size of the file stream */ - fseek(fp, 0L, SEEK_END); - bytecount = ftell(fp); - rewind(fp); - - /* YOLO, no error checking */ - buffer = g_malloc(bytecount); - - bytesread = fread(buffer, 1, bytecount, fp); - if (bytesread != bytecount) { - g_set_error(error, - G_FILE_ERROR, - G_FILE_ERROR_FAILED, - "read only %zd of %zd bytes from stream", - bytesread, - bytecount); - return NULL; - } - - return gdk_pixbuf_from_svg_buffer(buffer, bytecount, error); -} - - static gpointer gdk_pixbuf_begin_load(GdkPixbufModuleSizeFunc size_func, - GdkPixbufModulePreparedFunc prep_func, - GdkPixbufModuleUpdatedFunc updated_func, - gpointer user_data, - GError **error) { + GdkPixbufModulePreparedFunc prep_func, + GdkPixbufModuleUpdatedFunc updated_func, + gpointer user_data, + GError **error) { SvgTinyContext* context = g_new(SvgTinyContext, 1); @@ -383,37 +339,24 @@ static gpointer gdk_pixbuf_begin_load(GdkPixbufModuleSizeFunc size_func, context->updated_func = updated_func; context->user_data = user_data; - /* YOLO, no error checking */ - context->svg_data = g_malloc(SVG_BUFFER_INCREMENT); + context->svg_data = NULL; context->svg_data_size = 0; return context; } static gboolean gdk_pixbuf_load_increment(gpointer data, - const guchar* buf, - guint size, - GError** error) { + const guchar* buf, + guint buf_size, + GError** error) { size_t increment = 0; SvgTinyContext* context = (SvgTinyContext*)data; - if (context->svg_data_size + size > context->svg_data_max) { - if (size > SVG_BUFFER_INCREMENT) { - increment = size; - } - else { - increment = SVG_BUFFER_INCREMENT; - } - - /* YOLO, no error checking */ - context->svg_data = g_realloc(context->svg_data, - context->svg_data_max + increment); - - context->svg_data_max += increment; - } - - memcpy(context->svg_data + context->svg_data_size, buf, size); - context->svg_data_size += size; + /* YOLO, no error checking */ + context->svg_data = g_realloc(context->svg_data, + context->svg_data_size + buf_size); + memcpy(context->svg_data + context->svg_data_size, buf, buf_size); + context->svg_data_size += buf_size; return TRUE; } @@ -421,11 +364,11 @@ static gboolean gdk_pixbuf_load_increment(gpointer data, static void emit_updated(SvgTinyContext* context, GdkPixbuf* pixbuf) { if (context->updated_func != NULL) { (*context->updated_func)(pixbuf, - 0, - 0, - gdk_pixbuf_get_width(pixbuf), - gdk_pixbuf_get_height(pixbuf), - context->user_data); + 0, + 0, + gdk_pixbuf_get_width(pixbuf), + gdk_pixbuf_get_height(pixbuf), + context->user_data); } } @@ -436,17 +379,6 @@ static void emit_prepared(SvgTinyContext* context, GdkPixbuf* pixbuf) { } -/* -static void emit_size(SvgTinyContext* context, GdkPixbuf* pixbuf) { - int w = gdk_pixbuf_get_width(pixbuf); - int h = gdk_pixbuf_get_height(pixbuf); - if (context->size_func != NULL) { - (*context->size_func)(&w, &h, context->user_data); - } -} -*/ - - static gboolean gdk_pixbuf_stop_load(gpointer data, GError **error) { SvgTinyContext* context = (SvgTinyContext*)data; GdkPixbuf* pixbuf = NULL; @@ -454,11 +386,10 @@ static gboolean gdk_pixbuf_stop_load(gpointer data, GError **error) { GError* sub_error = NULL; pixbuf = gdk_pixbuf_from_svg_buffer(context->svg_data, - context->svg_data_size, - &sub_error); + context->svg_data_size, + &sub_error); if (pixbuf != NULL) { - /*emit_size(context, pixbuf);*/ emit_prepared(context, pixbuf); emit_updated(context, pixbuf); g_object_unref(pixbuf); @@ -467,6 +398,7 @@ static gboolean gdk_pixbuf_stop_load(gpointer data, GError **error) { g_propagate_error(error, sub_error); result = FALSE; } + g_free(context->svg_data); g_free(context); return result; @@ -478,7 +410,6 @@ void fill_vtable(GdkPixbufModule* module) { module->begin_load = gdk_pixbuf_begin_load; module->load_increment = gdk_pixbuf_load_increment; module->stop_load = gdk_pixbuf_stop_load; - module->load = gdk_pixbuf_from_svg_file_stream; } G_MODULE_EXPORT void fill_info(GdkPixbufFormat *info); @@ -535,16 +466,10 @@ int main(int argc, char** argv) { svgpath = argv[1]; pngpath = argv[2]; - fp = fopen(svgpath, "rb"); - if (!fp) { - perror(svgpath); - return 1; - } - - pb = gdk_pixbuf_from_svg_file_stream(fp, &err); + pb = gdk_pixbuf_new_from_file(svgpath, &err); if (!pb) { fprintf(stderr, - "Error %d in gdk_pixbuf_from_svg_file_stream: %s\n", + "Error %d in gdk_pixbuf_new_from_file: %s\n", err->code, err->message); g_error_free(err);