📄 xo-file.c
字号:
#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <signal.h>#include <memory.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <gtk/gtk.h>#include <libgnomecanvas/libgnomecanvas.h>#include <zlib.h>#include <math.h>#include <gdk/gdkx.h>#include <X11/Xlib.h>#include <locale.h>#include "xournal.h"#include "xo-interface.h"#include "xo-support.h"#include "xo-callbacks.h"#include "xo-misc.h"#include "xo-file.h"#include "xo-paint.h"const char *tool_names[NUM_TOOLS] = {"pen", "eraser", "highlighter", "text", "", "selectrect", "vertspace", "hand"};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"};const char *bgcolor_names[COLOR_MAX] = {"", "blue", "pink", "green", "", "", "", "", "orange", "yellow", "white"};const char *bgstyle_names[4] = {"plain", "lined", "ruled", "graph"};const char *file_domain_names[3] = {"absolute", "attach", "clone"};const char *unit_names[4] = {"cm", "in", "px", "pt"};int PDFTOPPM_PRINTING_DPI, GS_BITMAP_DPI;// creates a new empty journalvoid new_journal(void){ journal.npages = 1; journal.pages = g_list_append(NULL, new_page(&ui.default_page)); journal.last_attach_no = 0; ui.pageno = 0; ui.layerno = 0; ui.cur_page = (struct Page *) journal.pages->data; ui.cur_layer = (struct Layer *) ui.cur_page->layers->data; ui.saved = TRUE; ui.filename = NULL; update_file_name(NULL);}// check attachment namesvoid chk_attach_names(void){ GList *list; struct Background *bg; for (list = journal.pages; list!=NULL; list = list->next) { bg = ((struct Page *)list->data)->bg; if (bg->type == BG_SOLID || bg->file_domain != DOMAIN_ATTACH || bg->filename->s != NULL) continue; bg->filename->s = g_strdup_printf("bg_%d.png", ++journal.last_attach_no); }}// saves the journal to a file: returns true on success, false on errorgboolean save_journal(const char *filename){ gzFile f; struct Page *pg, *tmppg; struct Layer *layer; struct Item *item; int i, is_clone; char *tmpfn, *tmpstr; gchar *pdfbuf; gsize pdflen; gboolean success; FILE *tmpf; GList *pagelist, *layerlist, *itemlist, *list; GtkWidget *dialog; f = gzopen(filename, "w"); if (f==NULL) return FALSE; chk_attach_names(); setlocale(LC_NUMERIC, "C"); gzprintf(f, "<?xml version=\"1.0\" standalone=\"no\"?>\n" "<xournal version=\"" VERSION "\">\n" "<title>Xournal document - see http://math.mit.edu/~auroux/software/xournal/</title>\n"); for (pagelist = journal.pages; pagelist!=NULL; pagelist = pagelist->next) { pg = (struct Page *)pagelist->data; gzprintf(f, "<page width=\"%.2f\" height=\"%.2f\">\n", pg->width, pg->height); gzprintf(f, "<background type=\"%s\" ", bgtype_names[pg->bg->type]); if (pg->bg->type == BG_SOLID) { gzputs(f, "color=\""); if (pg->bg->color_no >= 0) gzputs(f, bgcolor_names[pg->bg->color_no]); else gzprintf(f, "#%08x", pg->bg->color_rgba); gzprintf(f, "\" style=\"%s\" ", bgstyle_names[pg->bg->ruling]); } else if (pg->bg->type == BG_PIXMAP) { is_clone = -1; for (list = journal.pages, i = 0; list!=pagelist; list = list->next, i++) { tmppg = (struct Page *)list->data; if (tmppg->bg->type == BG_PIXMAP && tmppg->bg->pixbuf == pg->bg->pixbuf && tmppg->bg->filename == pg->bg->filename) { is_clone = i; break; } } if (is_clone >= 0) gzprintf(f, "domain=\"clone\" filename=\"%d\" ", is_clone); else { if (pg->bg->file_domain == DOMAIN_ATTACH) { tmpfn = g_strdup_printf("%s.%s", filename, pg->bg->filename->s); if (!gdk_pixbuf_save(pg->bg->pixbuf, tmpfn, "png", NULL, NULL)) { dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not write background '%s'. Continuing anyway.", tmpfn); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } g_free(tmpfn); } gzprintf(f, "domain=\"%s\" filename=\"%s\" ", file_domain_names[pg->bg->file_domain], pg->bg->filename->s); } } else if (pg->bg->type == BG_PDF) { is_clone = 0; for (list = journal.pages; list!=pagelist; list = list->next) { tmppg = (struct Page *)list->data; if (tmppg->bg->type == BG_PDF) { is_clone = 1; break; } } if (!is_clone) { if (pg->bg->file_domain == DOMAIN_ATTACH) { tmpfn = g_strdup_printf("%s.%s", filename, pg->bg->filename->s); success = FALSE; if (bgpdf.status != STATUS_NOT_INIT && g_file_get_contents(bgpdf.tmpfile_copy, &pdfbuf, &pdflen, NULL)) { tmpf = fopen(tmpfn, "w"); if (tmpf != NULL && fwrite(pdfbuf, 1, pdflen, tmpf) == pdflen) success = TRUE; g_free(pdfbuf); fclose(tmpf); } if (!success) { dialog = gtk_message_dialog_new(GTK_WINDOW(winMain), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Could not write background '%s'. Continuing anyway.", tmpfn); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } g_free(tmpfn); } gzprintf(f, "domain=\"%s\" filename=\"%s\" ", file_domain_names[pg->bg->file_domain], pg->bg->filename->s); } gzprintf(f, "pageno=\"%d\" ", pg->bg->file_page_seq); } gzprintf(f, "/>\n"); for (layerlist = pg->layers; layerlist!=NULL; layerlist = layerlist->next) { layer = (struct Layer *)layerlist->data; gzprintf(f, "<layer>\n"); for (itemlist = layer->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (item->type == ITEM_STROKE) { gzprintf(f, "<stroke tool=\"%s\" color=\"", tool_names[item->brush.tool_type]); if (item->brush.color_no >= 0) gzputs(f, color_names[item->brush.color_no]); else gzprintf(f, "#%08x", item->brush.color_rgba); gzprintf(f, "\" width=\"%.2f\">\n", item->brush.thickness); for (i=0;i<2*item->path->num_points;i++) gzprintf(f, "%.2f ", item->path->coords[i]); gzprintf(f, "\n</stroke>\n"); } if (item->type == ITEM_TEXT) { gzprintf(f, "<text font=\"%s\" size=\"%.2f\" x=\"%.2f\" y=\"%.2f\" color=\"", item->font_name, item->font_size, item->bbox.left, item->bbox.top); if (item->brush.color_no >= 0) gzputs(f, color_names[item->brush.color_no]); else gzprintf(f, "#%08x", item->brush.color_rgba); tmpstr = g_markup_escape_text(item->text, -1); gzprintf(f, "\">%s</text>\n", tmpstr); g_free(tmpstr); } } gzprintf(f, "</layer>\n"); } gzprintf(f, "</page>\n"); } gzprintf(f, "</xournal>\n"); gzclose(f); setlocale(LC_NUMERIC, ""); return TRUE;}// closes a journal: returns true on success, false on abortgboolean close_journal(void){ if (!ok_to_close()) return FALSE; // free everything... reset_selection(); clear_redo_stack(); clear_undo_stack(); shutdown_bgpdf(); delete_journal(&journal); return TRUE; /* note: various members of ui and journal are now in invalid states, use new_journal() to reinitialize them */}// sanitize a string containing floats, in case it may have , instead of .void cleanup_numeric(char *s){ while (*s!=0) { if (*s==',') *s='.'; s++; }}// the XML parser functions for open_journal()struct Journal tmpJournal;struct Page *tmpPage;struct Layer *tmpLayer;struct Item *tmpItem;char *tmpFilename;struct Background *tmpBg_pdf;GError *xoj_invalid(void){ return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Invalid file contents");}void xoj_parser_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error){ int has_attr, i; char *ptr; struct Background *tmpbg; char *tmpbg_filename; GtkWidget *dialog; if (!strcmp(element_name, "title") || !strcmp(element_name, "xournal")) { if (tmpPage != NULL) { *error = xoj_invalid(); return; } // nothing special to do } else if (!strcmp(element_name, "page")) { // start of a page if (tmpPage != NULL) { *error = xoj_invalid(); return; } tmpPage = (struct Page *)g_malloc(sizeof(struct Page)); tmpPage->layers = NULL; tmpPage->nlayers = 0; tmpPage->group = NULL; tmpPage->bg = g_new(struct Background, 1); tmpPage->bg->type = -1; tmpPage->bg->canvas_item = NULL; tmpPage->bg->pixbuf = NULL; tmpPage->bg->filename = NULL; tmpJournal.pages = g_list_append(tmpJournal.pages, tmpPage); tmpJournal.npages++; // scan for height and width attributes has_attr = 0; while (*attribute_names!=NULL) { if (!strcmp(*attribute_names, "width")) { if (has_attr & 1) *error = xoj_invalid(); cleanup_numeric((gchar *)*attribute_values); tmpPage->width = g_ascii_strtod(*attribute_values, &ptr); if (ptr == *attribute_values) *error = xoj_invalid(); has_attr |= 1; } else if (!strcmp(*attribute_names, "height")) { if (has_attr & 2) *error = xoj_invalid(); cleanup_numeric((gchar *)*attribute_values); tmpPage->height = g_ascii_strtod(*attribute_values, &ptr); if (ptr == *attribute_values) *error = xoj_invalid(); has_attr |= 2; } else *error = xoj_invalid(); attribute_names++; attribute_values++; } if (has_attr!=3) *error = xoj_invalid(); } else if (!strcmp(element_name, "background")) { if (tmpPage == NULL || tmpLayer !=NULL || tmpPage->bg->type >= 0) { *error = xoj_invalid(); return; } has_attr = 0; while (*attribute_names!=NULL) { if (!strcmp(*attribute_names, "type")) { if (has_attr) *error = xoj_invalid(); for (i=0; i<3; i++) if (!strcmp(*attribute_values, bgtype_names[i])) tmpPage->bg->type = i; if (tmpPage->bg->type < 0) *error = xoj_invalid(); has_attr |= 1; if (tmpPage->bg->type == BG_PDF) { if (tmpBg_pdf == NULL) tmpBg_pdf = tmpPage->bg; else { has_attr |= 24; tmpPage->bg->filename = refstring_ref(tmpBg_pdf->filename); tmpPage->bg->file_domain = tmpBg_pdf->file_domain; } } } else if (!strcmp(*attribute_names, "color")) { if (tmpPage->bg->type != BG_SOLID) *error = xoj_invalid(); if (has_attr & 2) *error = xoj_invalid(); tmpPage->bg->color_no = COLOR_OTHER; for (i=0; i<COLOR_MAX; i++) if (!strcmp(*attribute_values, bgcolor_names[i])) { tmpPage->bg->color_no = i; tmpPage->bg->color_rgba = predef_bgcolors_rgba[i]; } // there's also the case of hex (#rrggbbaa) colors if (tmpPage->bg->color_no == COLOR_OTHER && **attribute_values == '#') { tmpPage->bg->color_rgba = strtol(*attribute_values + 1, &ptr, 16); if (*ptr!=0) *error = xoj_invalid(); } has_attr |= 2; } else if (!strcmp(*attribute_names, "style")) { if (tmpPage->bg->type != BG_SOLID) *error = xoj_invalid(); if (has_attr & 4) *error = xoj_invalid(); tmpPage->bg->ruling = -1; for (i=0; i<4; i++) if (!strcmp(*attribute_values, bgstyle_names[i])) tmpPage->bg->ruling = i; if (tmpPage->bg->ruling < 0) *error = xoj_invalid(); has_attr |= 4; } else if (!strcmp(*attribute_names, "domain")) { if (tmpPage->bg->type <= BG_SOLID || (has_attr & 8)) { *error = xoj_invalid(); return; } tmpPage->bg->file_domain = -1; for (i=0; i<3; i++) if (!strcmp(*attribute_values, file_domain_names[i])) tmpPage->bg->file_domain = i; if (tmpPage->bg->file_domain < 0) { *error = xoj_invalid(); return; } has_attr |= 8; } else if (!strcmp(*attribute_names, "filename")) { if (tmpPage->bg->type <= BG_SOLID || (has_attr != 9)) { *error = xoj_invalid(); return; } if (tmpPage->bg->file_domain == DOMAIN_CLONE) { // filename is a page number i = strtol(*attribute_values, &ptr, 10); if (ptr == *attribute_values || i < 0 || i > tmpJournal.npages-2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -