X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=src%2Fxo-file.c;h=082d399f36c3d4d26ae9bc7970d9a685ae091cb6;hb=9f09269d8918dfa930543f4a15de4e7276719e5e;hp=81ce1569453295f2658c307c21bfd0344b7e87dc;hpb=1858c4feaa24e40cea4b1b5ea39a60fb6670f33b;p=xournal.git diff --git a/src/xo-file.c b/src/xo-file.c index 81ce156..082d399 100644 --- a/src/xo-file.c +++ b/src/xo-file.c @@ -43,8 +43,9 @@ #include "xo-misc.h" #include "xo-file.h" #include "xo-paint.h" +#include "xo-image.h" -const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "", "selectrect", "vertspace", "hand"}; +const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "selectregion", "selectrect", "vertspace", "hand", "image"}; const char *color_names[COLOR_MAX] = {"black", "blue", "red", "green", "gray", "lightblue", "lightgreen", "magenta", "orange", "yellow", "white"}; const char *bgtype_names[3] = {"solid", "pixmap", "pdf"}; @@ -86,6 +87,47 @@ void chk_attach_names(void) } } +/* Write image to file: returns true on success, false on error. + The image is written as a base64 encoded PNG. */ + +gboolean write_image(gzFile f, Item *item) +{ + gchar *base64_str; + + if (item->image_png == NULL) { + if (!gdk_pixbuf_save_to_buffer(item->image, &item->image_png, &item->image_png_len, "png", NULL, NULL)) { + item->image_png_len = 0; // failed for some reason, so forget it + return FALSE; + } + } + + base64_str = g_base64_encode(item->image_png, item->image_png_len); + gzputs(f, base64_str); + g_free(base64_str); + return TRUE; +} + +// create pixbuf from base64 encoded PNG, or return NULL on failure + +GdkPixbuf *read_pixbuf(const gchar *base64_str, gsize base64_strlen) +{ + gchar *base64_str2; + gchar *png_buf; + gsize png_buflen; + GdkPixbuf *pixbuf; + + // We have to copy the string in order to null terminate it, sigh. + base64_str2 = g_memdup(base64_str, base64_strlen+1); + base64_str2[base64_strlen] = 0; + png_buf = g_base64_decode(base64_str2, &png_buflen); + + pixbuf = pixbuf_from_buffer(png_buf, png_buflen); + + g_free(png_buf); + g_free(base64_str2); + return pixbuf; +} + // saves the journal to a file: returns true on success, false on error gboolean save_journal(const char *filename) @@ -219,6 +261,12 @@ gboolean save_journal(const char *filename) gzputs(f, "\n"); g_free(tmpstr); } + if (item->type == ITEM_IMAGE) { + gzprintf(f, "", + item->bbox.left, item->bbox.top, item->bbox.right, item->bbox.bottom); + if (!write_image(f, item)) success = FALSE; + gzprintf(f, "\n"); + } } gzprintf(f, "\n"); } @@ -601,6 +649,56 @@ void xoj_parser_start_element(GMarkupParseContext *context, } if (has_attr!=31) *error = xoj_invalid(); } + else if (!strcmp(element_name, "image")) { // start of a image item + if (tmpLayer == NULL || tmpItem != NULL) { + *error = xoj_invalid(); + return; + } + tmpItem = (struct Item *)g_malloc0(sizeof(struct Item)); + tmpItem->type = ITEM_IMAGE; + tmpItem->canvas_item = NULL; + tmpItem->image=NULL; + tmpItem->image_png = NULL; + tmpItem->image_png_len = 0; + tmpLayer->items = g_list_append(tmpLayer->items, tmpItem); + tmpLayer->nitems++; + // scan for x, y + has_attr = 0; + while (*attribute_names!=NULL) { + if (!strcmp(*attribute_names, "left")) { + if (has_attr & 1) *error = xoj_invalid(); + cleanup_numeric((gchar *)*attribute_values); + tmpItem->bbox.left = g_ascii_strtod(*attribute_values, &ptr); + if (ptr == *attribute_values) *error = xoj_invalid(); + has_attr |= 1; + } + else if (!strcmp(*attribute_names, "top")) { + if (has_attr & 2) *error = xoj_invalid(); + cleanup_numeric((gchar *)*attribute_values); + tmpItem->bbox.top = g_ascii_strtod(*attribute_values, &ptr); + if (ptr == *attribute_values) *error = xoj_invalid(); + has_attr |= 2; + } + else if (!strcmp(*attribute_names, "right")) { + if (has_attr & 4) *error = xoj_invalid(); + cleanup_numeric((gchar *)*attribute_values); + tmpItem->bbox.right = g_ascii_strtod(*attribute_values, &ptr); + if (ptr == *attribute_values) *error = xoj_invalid(); + has_attr |= 4; + } + else if (!strcmp(*attribute_names, "bottom")) { + if (has_attr & 8) *error = xoj_invalid(); + cleanup_numeric((gchar *)*attribute_values); + tmpItem->bbox.bottom = g_ascii_strtod(*attribute_values, &ptr); + if (ptr == *attribute_values) *error = xoj_invalid(); + has_attr |= 8; + } + else *error = xoj_invalid(); + attribute_names++; + attribute_values++; + } + if (has_attr!=15) *error = xoj_invalid(); + } } void xoj_parser_end_element(GMarkupParseContext *context, @@ -636,6 +734,13 @@ void xoj_parser_end_element(GMarkupParseContext *context, } tmpItem = NULL; } + if (!strcmp(element_name, "image")) { + if (tmpItem == NULL) { + *error = xoj_invalid(); + return; + } + tmpItem = NULL; + } } void xoj_parser_text(GMarkupParseContext *context, @@ -673,6 +778,9 @@ void xoj_parser_text(GMarkupParseContext *context, g_memmove(tmpItem->text, text, text_len); tmpItem->text[text_len]=0; } + if (!strcmp(element_name, "image")) { + tmpItem->image = read_pixbuf(text, text_len); + } } gboolean user_wants_second_chance(char **filename) @@ -1386,6 +1494,7 @@ void init_config_default(void) ui.print_ruling = TRUE; ui.default_unit = UNIT_CM; ui.default_path = NULL; + ui.default_image = NULL; ui.default_font_name = g_strdup(DEFAULT_FONT); ui.default_font_size = DEFAULT_FONT_SIZE; ui.pressure_sensitivity = FALSE; @@ -1600,7 +1709,7 @@ void save_config_to_file(void) g_strdup_printf("%d", PDFTOPPM_PRINTING_DPI)); update_keyval("tools", "startup_tool", - _(" selected tool at startup (pen, eraser, highlighter, selectrect, vertspace, hand)"), + _(" selected tool at startup (pen, eraser, highlighter, selectregion, selectrect, vertspace, hand, image)"), g_strdup(tool_names[ui.startuptool])); update_keyval("tools", "pen_color", _(" default pen color"), @@ -1637,7 +1746,7 @@ void save_config_to_file(void) _(" default highlighter is in shape recognizer mode (true/false)"), g_strdup(ui.default_brushes[TOOL_HIGHLIGHTER].recognizer?"true":"false")); update_keyval("tools", "btn2_tool", - _(" button 2 tool (pen, eraser, highlighter, text, selectrect, vertspace, hand)"), + _(" button 2 tool (pen, eraser, highlighter, text, selectregion, selectrect, vertspace, hand, image)"), g_strdup(tool_names[ui.toolno[1]])); update_keyval("tools", "btn2_linked", _(" button 2 brush linked to primary brush (true/false) (overrides all other settings)"), @@ -1665,7 +1774,7 @@ void save_config_to_file(void) _(" button 2 eraser mode (eraser only)"), g_strdup_printf("%d", ui.brushes[1][TOOL_ERASER].tool_options)); update_keyval("tools", "btn3_tool", - _(" button 3 tool (pen, eraser, highlighter, text, selectrect, vertspace, hand)"), + _(" button 3 tool (pen, eraser, highlighter, text, selectregion, selectrect, vertspace, hand, image)"), g_strdup(tool_names[ui.toolno[2]])); update_keyval("tools", "btn3_linked", _(" button 3 brush linked to primary brush (true/false) (overrides all other settings)"),