#include <stdio.h> /* fopen, fprintf, fread, printf */
-#include <stdlib.h> /* malloc */
+#include <string.h> /* memcpy */
#include <cairo.h>
#include <gdk/gdk.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gdk-pixbuf/gdk-pixbuf.h> /* includes glib.h */
#include <svgtiny.h>
/*
break;
case svgtiny_PATH_LINE:
cairo_line_to(cr,
- path->path[j + 1],
- path->path[j + 2]);
+ path->path[j + 1],
+ path->path[j + 2]);
j += 3;
break;
case svgtiny_PATH_BEZIER:
cairo_curve_to(cr,
- path->path[j + 1],
- path->path[j + 2],
- path->path[j + 3],
- path->path[j + 4],
- path->path[j + 5],
- path->path[j + 6]);
+ path->path[j + 1],
+ path->path[j + 2],
+ path->path[j + 3],
+ path->path[j + 4],
+ path->path[j + 5],
+ path->path[j + 6]);
j += 7;
- break;
- default:
- fprintf(stderr, "error: unmatched case in render_path\n");
- j += 1;
}
}
if (path->fill != svgtiny_TRANSPARENT) {
cairo_set_source_rgba(cr,
- svgtiny_RED(path->fill) / 255.0,
- svgtiny_GREEN(path->fill) / 255.0,
- svgtiny_BLUE(path->fill) / 255.0,
- 1);
+ 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_rgba(cr,
- svgtiny_RED(path->stroke) / 255.0,
- svgtiny_GREEN(path->stroke) / 255.0,
- svgtiny_BLUE(path->stroke) / 255.0,
- 1);
+ 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.
+ * @brief Parse a buffer of SVG data into a diagram_t structure.
*
- * @param fp
- * A pointer to an open file stream.
+ * @param buffer
+ * The buffer containing the SVG document.
+ *
+ * @param bytecount
+ * The number of bytes in @c buffer.
*
* @return If successful, a pointer to a @c diagram_t structure is
* returned; if not, @c NULL is returned. You are expected to @c
* svgtiny_free the result if it is valid.
*/
static diagram_t* svgtiny_diagram_from_buffer(char* buffer,
- size_t bytecount,
- int width,
- int height) {
+ size_t bytecount,
+ int width,
+ int height,
+ GError** error) {
diagram_t* diagram;
svgtiny_code code;
diagram = svgtiny_create();
if (!diagram) {
- fprintf(stderr, "svgtiny_create() failed\n");
+ g_set_error_literal(error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_FAILED,
+ "svgtiny_create() failed");
return NULL;
}
free(buffer);
if (code != svgtiny_OK) {
- fprintf(stderr, "svgtiny_parse failed with ");
switch (code) {
case svgtiny_OUT_OF_MEMORY:
- fprintf(stderr, "svgtiny_OUT_OF_MEMORY");
+ g_set_error_literal(error,
+ G_FILE_ERROR,
+ G_FILE_ERROR_NOMEM,
+ "out of memory in svgtiny_parse()");
break;
case svgtiny_LIBDOM_ERROR:
- fprintf(stderr, "svgtiny_LIBDOM_ERROR");
+ g_set_error_literal(error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ "libdom error in svgtiny_parse()");
break;
case svgtiny_NOT_SVG:
- fprintf(stderr, "svgtiny_NOT_SVG");
+ g_set_error_literal(error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ "encountered svgtiny_NOT_SVG in svgtiny_parse()");
break;
case svgtiny_SVG_ERROR:
- fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s",
- diagram->error_line,
- diagram->error_message);
- break;
- default:
- fprintf(stderr, "unknown svgtiny_code %i", code);
+ g_set_error(error,
+ GDK_PIXBUF_ERROR,
+ GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+ "SVG error in svgtiny_parse() on line %i: %s",
+ diagram->error_line,
+ diagram->error_message);
break;
}
- fprintf(stderr, "\n");
return NULL;
}
unsigned int i;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
- diagram->width,
- diagram->height);
+ diagram->width,
+ diagram->height);
crs = cairo_surface_status(surface);
if (crs != CAIRO_STATUS_SUCCESS) {
fprintf(stderr,
- "cairo_image_surface_create failed: %s\n",
- cairo_status_to_string(crs));
+ "cairo_image_surface_create failed: %s\n",
+ cairo_status_to_string(crs));
cairo_surface_destroy(surface);
return NULL;
}
if (crs != CAIRO_STATUS_SUCCESS) {
fprintf(stderr,
- "cairo_create failed: %s\n",
- cairo_status_to_string(crs));
+ "cairo_create failed: %s\n",
+ cairo_status_to_string(crs));
cairo_destroy(cr);
return NULL;
}
/* If this shape is text... */
if (diagram->shape[i].text) {
/* Figure out what color to use from the R/G/B components of the
- shape's stroke. */
+ shape's stroke. */
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);
+ 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... */
+ shape... */
cairo_move_to(cr,
- diagram->shape[i].text_x,
- diagram->shape[i].text_y);
+ diagram->shape[i].text_x,
+ diagram->shape[i].text_y);
/* and draw it. */
cairo_show_text(cr, diagram->shape[i].text);
return cr;
}
+/**
+ * @brief Create a GdkPixbuf from a buffer of SVG data.
+ *
+ * @param buffer
+ * The buffer containing the SVG document.
+ *
+ * @param bytecount
+ * The number of bytes in @c buffer.
+ *
+ * @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_buffer(char* buffer,
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);
+ VIEWPORT_HEIGHT,
+ &sub_error);
if (!diagram) {
- g_set_error_literal(error,
- GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- "Could not parse SVG diagram from file");
+ g_propagate_error(error, sub_error);
return NULL;
}
g_set_error_literal(error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- "Could not create Cairo surface from SVG diagram");
+ "could not create Cairo surface from SVG diagram");
return NULL;
}
g_set_error_literal(error,
GDK_PIXBUF_ERROR,
GDK_PIXBUF_ERROR_FAILED,
- "Failed to obtain a GdkPixbuf from Cairo surface");
+ "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;
bytecount = ftell(fp);
rewind(fp);
- buffer = malloc(bytecount);
- if (!buffer) {
- fprintf(stderr, "Unable to allocate %zd bytes\n", bytecount);
- return NULL;
- }
+ /* YOLO, no error checking */
+ buffer = g_malloc(bytecount);
bytesread = fread(buffer, 1, bytecount, fp);
if (bytesread != bytecount) {
- fprintf(stderr, "Read only %zd of %zd bytes from stream\n",
- 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;
}
- fclose(fp);
return gdk_pixbuf_from_svg_buffer(buffer, bytecount, error);
}
gpointer user_data,
GError **error) {
- SvgTinyContext* context = g_new0(SvgTinyContext, 1);
+ SvgTinyContext* context = g_new(SvgTinyContext, 1);
context->size_func = size_func;
context->prepared_func = prep_func;
context->updated_func = updated_func;
context->user_data = user_data;
- context->svg_data = malloc(SVG_BUFFER_INCREMENT);
- if (context->svg_data) {
- context->svg_data_size = 0;
- context->svg_data_max = SVG_BUFFER_INCREMENT;
- }
- else {
- fprintf(stderr, "Unable to allocate %zd bytes\n", SVG_BUFFER_INCREMENT);
- return NULL;
- }
+ /* YOLO, no error checking */
+ context->svg_data = g_malloc(SVG_BUFFER_INCREMENT);
+ context->svg_data_size = 0;
return context;
}
const guchar* buf,
guint size,
GError** error) {
+ size_t increment = 0;
SvgTinyContext* context = (SvgTinyContext*)data;
if (context->svg_data_size + size > context->svg_data_max) {
- size_t increment = 0;
if (size > SVG_BUFFER_INCREMENT) {
increment = size;
}
else {
increment = SVG_BUFFER_INCREMENT;
}
- context->svg_data = realloc(context->svg_data,
- context->svg_data_max + increment);
- if (context->svg_data) {
- context->svg_data_max += increment;
- }
- else {
- fprintf(stderr, "Unable to (re)allocate %zd bytes\n", increment);
- return FALSE;
- }
+
+ /* 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;
/*
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) {
}
*/
+
static gboolean gdk_pixbuf_stop_load(gpointer data, GError **error) {
SvgTinyContext* context = (SvgTinyContext*)data;
GdkPixbuf* pixbuf = NULL;
gboolean result = TRUE;
+ GError* sub_error = NULL;
pixbuf = gdk_pixbuf_from_svg_buffer(context->svg_data,
context->svg_data_size,
- error);
+ &sub_error);
if (pixbuf != NULL) {
- /* emit_size(context, pixbuf); */
+ /*emit_size(context, pixbuf);*/
emit_prepared(context, pixbuf);
emit_updated(context, pixbuf);
g_object_unref(pixbuf);
}
else {
+ g_propagate_error(error, sub_error);
result = FALSE;
}
- g_free (context);
+ g_free(context);
return result;
}
pb = gdk_pixbuf_from_svg_file_stream(fp, &err);
if (!pb) {
fprintf(stderr,
- "Error %d in gdk_pixbuf_from_svg_file_stream: %s\n",
- err->code,
- err->message);
+ "Error %d in gdk_pixbuf_from_svg_file_stream: %s\n",
+ err->code,
+ err->message);
g_error_free(err);
return 1;
}