📄 xo-print.c
字号:
#ifdef HAVE_CONFIG_H# include <config.h>#endif#define PANGO_ENABLE_BACKEND /* to access PangoFcFont.font_pattern */#include <gtk/gtk.h>#include <libgnomecanvas/libgnomecanvas.h>#include <libgnomeprint/gnome-print-job.h>#include <libgnomeprint/gnome-print-pango.h>#include <zlib.h>#include <string.h>#include <locale.h>#include <pango/pango.h>#include <pango/pangofc-font.h>#include <fontconfig/fontconfig.h>#include <ft2build.h>#include FT_FREETYPE_H#include "sft.h" /* Sun Font Tools, embedded in libgnomeprint */#include "xournal.h"#include "xo-misc.h"#include "xo-paint.h"#include "xo-print.h"#include "xo-file.h"#define RGBA_RED(rgba) (((rgba>>24)&0xff)/255.0)#define RGBA_GREEN(rgba) (((rgba>>16)&0xff)/255.0)#define RGBA_BLUE(rgba) (((rgba>>8)&0xff)/255.0)#define RGBA_ALPHA(rgba) (((rgba>>0)&0xff)/255.0)#define RGBA_RGB(rgba) RGBA_RED(rgba), RGBA_GREEN(rgba), RGBA_BLUE(rgba)/*********** Printing to PDF ************/gboolean ispdfspace(char c){ return (c==0 || c==9 || c==10 || c==12 || c==13 || c==' ');}gboolean ispdfdelim(char c){ return (c=='(' || c==')' || c=='<' || c=='>' || c=='[' || c==']' || c=='{' || c=='}' || c=='/' || c=='%');}void skipspace(char **p, char *eof){ while (ispdfspace(**p) || **p=='%') { if (**p=='%') while (*p!=eof && **p!=10 && **p!=13) (*p)++; if (*p==eof) return; (*p)++; }}void free_pdfobj(struct PdfObj *obj){ int i; if (obj==NULL) return; if ((obj->type == PDFTYPE_STRING || obj->type == PDFTYPE_NAME || obj->type == PDFTYPE_STREAM) && obj->str!=NULL) g_free(obj->str); if ((obj->type == PDFTYPE_ARRAY || obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) { for (i=0; i<obj->num; i++) free_pdfobj(obj->elts[i]); g_free(obj->elts); } if ((obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) { for (i=0; i<obj->num; i++) g_free(obj->names[i]); g_free(obj->names); } g_free(obj);}struct PdfObj *dup_pdfobj(struct PdfObj *obj){ struct PdfObj *dup; int i; if (obj==NULL) return NULL; dup = g_memdup(obj, sizeof(struct PdfObj)); if ((obj->type == PDFTYPE_STRING || obj->type == PDFTYPE_NAME || obj->type == PDFTYPE_STREAM) && obj->str!=NULL) { if (obj->type == PDFTYPE_NAME) obj->len = strlen(obj->str); dup->str = g_memdup(obj->str, obj->len+1); } if ((obj->type == PDFTYPE_ARRAY || obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) { dup->elts = g_malloc(obj->num*sizeof(struct PdfObj *)); for (i=0; i<obj->num; i++) dup->elts[i] = dup_pdfobj(obj->elts[i]); } if ((obj->type == PDFTYPE_DICT || obj->type == PDFTYPE_STREAM) && obj->num>0) { dup->names = g_malloc(obj->num*sizeof(char *)); for (i=0; i<obj->num; i++) dup->names[i] = g_strdup(obj->names[i]); } return dup;}void show_pdfobj(struct PdfObj *obj, GString *str){ int i; if (obj==NULL) return; switch(obj->type) { case PDFTYPE_CST: if (obj->intval==1) g_string_append(str, "true"); if (obj->intval==0) g_string_append(str, "false"); if (obj->intval==-1) g_string_append(str, "null"); break; case PDFTYPE_INT: g_string_append_printf(str, "%d", obj->intval); break; case PDFTYPE_REAL: g_string_append_printf(str, "%f", obj->realval); break; case PDFTYPE_STRING: g_string_append_len(str, obj->str, obj->len); break; case PDFTYPE_NAME: g_string_append(str, obj->str); break; case PDFTYPE_ARRAY: g_string_append_c(str, '['); for (i=0;i<obj->num;i++) { if (i) g_string_append_c(str, ' '); show_pdfobj(obj->elts[i], str); } g_string_append_c(str, ']'); break; case PDFTYPE_DICT: g_string_append(str, "<<"); for (i=0;i<obj->num;i++) { g_string_append_printf(str, " %s ", obj->names[i]); show_pdfobj(obj->elts[i], str); } g_string_append(str, " >>"); break; case PDFTYPE_REF: g_string_append_printf(str, "%d %d R", obj->intval, obj->num); break; }}void DEBUG_PRINTOBJ(struct PdfObj *obj){ GString *s = g_string_new(""); show_pdfobj(obj, s); puts(s->str); g_string_free(s, TRUE);}// parse a PDF object; returns NULL if fails// THIS PARSER DOES NOT RECOGNIZE STREAMS YETstruct PdfObj *parse_pdf_object(char **ptr, char *eof){ struct PdfObj *obj, *elt; char *p, *q, *r, *eltname; int stack; obj = g_malloc(sizeof(struct PdfObj)); p = *ptr; skipspace(&p, eof); if (p==eof) { g_free(obj); return NULL; } // maybe a constant if (!strncmp(p, "true", 4)) { obj->type = PDFTYPE_CST; obj->intval = 1; *ptr = p+4; return obj; } if (!strncmp(p, "false", 5)) { obj->type = PDFTYPE_CST; obj->intval = 0; *ptr = p+5; return obj; } if (!strncmp(p, "null", 4)) { obj->type = PDFTYPE_CST; obj->intval = -1; *ptr = p+4; return obj; } // or a number ? obj->intval = strtol(p, &q, 10); *ptr = q; if (q!=p) { if (*q == '.') { obj->type = PDFTYPE_REAL; obj->realval = g_ascii_strtod(p, ptr); return obj; } if (ispdfspace(*q)) { // check for indirect reference skipspace(&q, eof); obj->num = strtol(q, &r, 10); if (r!=q) { skipspace(&r, eof); if (*r=='R') { *ptr = r+1; obj->type = PDFTYPE_REF; return obj; } } } obj->type = PDFTYPE_INT; return obj; } // a string ? if (*p=='(') { q=p+1; stack=1; while (stack>0 && q!=eof) { if (*q=='(') stack++; if (*q==')') stack--; if (*q=='\\') q++; if (q!=eof) q++; } if (q==eof) { g_free(obj); return NULL; } obj->type = PDFTYPE_STRING; obj->len = q-p; obj->str = g_malloc(obj->len+1); obj->str[obj->len] = 0; g_memmove(obj->str, p, obj->len); *ptr = q; return obj; } if (*p=='<' && p[1]!='<') { q=p+1; while (*q!='>' && q!=eof) q++; if (q==eof) { g_free(obj); return NULL; } q++; obj->type = PDFTYPE_STRING; obj->len = q-p; obj->str = g_malloc(obj->len+1); obj->str[obj->len] = 0; g_memmove(obj->str, p, obj->len); *ptr = q; return obj; } // a name ? if (*p=='/') { q=p+1; while (!ispdfspace(*q) && !ispdfdelim(*q)) q++; obj->type = PDFTYPE_NAME; obj->str = g_strndup(p, q-p); *ptr = q; return obj; } // an array ? if (*p=='[') { obj->type = PDFTYPE_ARRAY; obj->num = 0; obj->elts = NULL; q=p+1; skipspace(&q, eof); while (*q!=']') { elt = parse_pdf_object(&q, eof); if (elt==NULL) { free_pdfobj(obj); return NULL; } obj->num++; obj->elts = g_realloc(obj->elts, obj->num*sizeof(struct PdfObj *)); obj->elts[obj->num-1] = elt; skipspace(&q, eof); } *ptr = q+1; return obj; } // a dictionary ? if (*p=='<' && p[1]=='<') { obj->type = PDFTYPE_DICT; obj->num = 0; obj->elts = NULL; obj->names = NULL; q=p+2; skipspace(&q, eof); while (*q!='>' || q[1]!='>') { if (*q!='/') { free_pdfobj(obj); return NULL; } r=q+1; while (!ispdfspace(*r) && !ispdfdelim(*r)) r++; eltname = g_strndup(q, r-q); q=r; skipspace(&q, eof); elt = parse_pdf_object(&q, eof); if (elt==NULL) { g_free(eltname); free_pdfobj(obj); return NULL; } obj->num++; obj->elts = g_realloc(obj->elts, obj->num*sizeof(struct PdfObj *)); obj->names = g_realloc(obj->names, obj->num*sizeof(char *)); obj->elts[obj->num-1] = elt; obj->names[obj->num-1] = eltname; skipspace(&q, eof); } *ptr = q+2; return obj; } // DOES NOT RECOGNIZE STREAMS YET (handle as subcase of dictionary) g_free(obj); return NULL;}struct PdfObj *get_dict_entry(struct PdfObj *dict, char *name){ int i; if (dict==NULL) return NULL; if (dict->type != PDFTYPE_DICT) return NULL; for (i=0; i<dict->num; i++) if (!strcmp(dict->names[i], name)) return dict->elts[i]; return NULL;}struct PdfObj *get_pdfobj(GString *pdfbuf, struct XrefTable *xref, struct PdfObj *obj){ char *p, *eof; int offs, n; if (obj==NULL) return NULL; if (obj->type!=PDFTYPE_REF) return dup_pdfobj(obj); if (obj->intval>xref->last) return NULL; offs = xref->data[obj->intval]; if (offs<=0 || offs >= pdfbuf->len) return NULL; p = pdfbuf->str + offs; eof = pdfbuf->str + pdfbuf->len; n = strtol(p, &p, 10); if (n!=obj->intval) return NULL; skipspace(&p, eof); n = strtol(p, &p, 10); skipspace(&p, eof); if (strncmp(p, "obj", 3)) return NULL; p+=3; return parse_pdf_object(&p, eof);}// read the xref table of a PDF file in memory, and return the trailerdictstruct PdfObj *parse_xref_table(GString *pdfbuf, struct XrefTable *xref, int offs){ char *p, *q, *eof; struct PdfObj *trailerdict, *obj; int start, len, i; if (strncmp(pdfbuf->str+offs, "xref", 4)) return NULL; p = strstr(pdfbuf->str+offs, "trailer"); eof = pdfbuf->str + pdfbuf->len; if (p==NULL) return NULL; p+=8; trailerdict = parse_pdf_object(&p, eof); obj = get_dict_entry(trailerdict, "/Size"); if (obj!=NULL && obj->type == PDFTYPE_INT && obj->intval-1>xref->last) make_xref(xref, obj->intval-1, 0); obj = get_dict_entry(trailerdict, "/Prev"); if (obj!=NULL && obj->type == PDFTYPE_INT && obj->intval>0 && obj->intval!=offs) { // recurse into older xref table obj = parse_xref_table(pdfbuf, xref, obj->intval); free_pdfobj(obj); } p = pdfbuf->str+offs+4; skipspace(&p, eof); if (*p<'0' || *p>'9') { free_pdfobj(trailerdict); return NULL; } while (*p>='0' && *p<='9') { start = strtol(p, &p, 10); skipspace(&p, eof); len = strtol(p, &p, 10); skipspace(&p, eof); if (len <= 0 || 20*len > eof-p) break; if (start+len-1 > xref->last) make_xref(xref, start+len-1, 0); for (i=start; i<start+len; i++) { xref->data[i] = strtol(p, NULL, 10); p+=20; } skipspace(&p, eof); } if (*p!='t') { free_pdfobj(trailerdict); return NULL; } return trailerdict;}// parse the page treeint pdf_getpageinfo(GString *pdfbuf, struct XrefTable *xref, struct PdfObj *pgtree, int nmax, struct PdfPageDesc *pages){ struct PdfObj *obj, *kid; int i, count, j; obj = get_pdfobj(pdfbuf, xref, get_dict_entry(pgtree, "/Type")); if (obj == NULL || obj->type != PDFTYPE_NAME) return 0; if (!strcmp(obj->str, "/Page")) { free_pdfobj(obj); pages->contents = dup_pdfobj(get_dict_entry(pgtree, "/Contents"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -