📄 pdf_interpret.c
字号:
#include "fitz.h"#include "mupdf.h"fz_error *pdf_newcsi(pdf_csi **csip, int maskonly){ fz_error *error; pdf_csi *csi; fz_node *node; csi = fz_malloc(sizeof(pdf_csi)); if (!csi) return fz_throw("outofmem: interpreter struct"); pdf_initgstate(&csi->gstate[0]); csi->gtop = 0; csi->top = 0; csi->array = nil; csi->xbalance = 0; error = fz_newpathnode(&csi->path); if (error) { fz_free(csi); return fz_rethrow(error, "cannot create path node"); } error = fz_newtree(&csi->tree); if (error) { fz_dropnode((fz_node*)csi->path); fz_free(csi); return fz_rethrow(error, "cannot create tree"); } error = fz_newovernode(&node); csi->tree->root = node; csi->gstate[0].head = node; if (maskonly) { csi->gstate[0].fill.kind = PDF_MNONE; csi->gstate[0].stroke.kind = PDF_MNONE; } csi->clip = 0; csi->clipevenodd = 0; csi->textclip = nil; csi->textmode = 0; csi->text = nil; csi->tm = fz_identity(); csi->tlm = fz_identity(); *csip = csi; return fz_okay;}static voidclearstack(pdf_csi *csi){ int i; for (i = 0; i < csi->top; i++) fz_dropobj(csi->stack[i]); csi->top = 0;}static pdf_material *pdf_keepmaterial(pdf_material *mat){ if (mat->cs) fz_keepcolorspace(mat->cs); if (mat->indexed) fz_keepcolorspace(&mat->indexed->super); if (mat->pattern) pdf_keeppattern(mat->pattern); if (mat->shade) fz_keepshade(mat->shade); return mat;}static pdf_material *pdf_dropmaterial(pdf_material *mat){ if (mat->cs) fz_dropcolorspace(mat->cs); if (mat->indexed) fz_dropcolorspace(&mat->indexed->super); if (mat->pattern) pdf_droppattern(mat->pattern); if (mat->shade) fz_dropshade(mat->shade); return mat;}static fz_error *gsave(pdf_csi *csi){ pdf_gstate *gs = csi->gstate + csi->gtop; if (csi->gtop == 31) return fz_throw("gstate overflow in content stream"); memcpy(&csi->gstate[csi->gtop + 1], &csi->gstate[csi->gtop], sizeof(pdf_gstate)); csi->gtop ++; pdf_keepmaterial(&gs->stroke); pdf_keepmaterial(&gs->fill); return fz_okay;}static fz_error *grestore(pdf_csi *csi){ pdf_gstate *gs = csi->gstate + csi->gtop; if (csi->gtop == 0) return fz_throw("gstate underflow in content stream"); pdf_dropmaterial(&gs->stroke); pdf_dropmaterial(&gs->fill); csi->gtop --; return fz_okay;}voidpdf_dropcsi(pdf_csi *csi){ while (csi->gtop) grestore(csi); /* no need to check for impossible errors */ if (csi->gstate[csi->gtop].fill.cs) fz_dropcolorspace(csi->gstate[csi->gtop].fill.cs); if (csi->gstate[csi->gtop].stroke.cs) fz_dropcolorspace(csi->gstate[csi->gtop].stroke.cs); if (csi->path) fz_dropnode((fz_node*)csi->path); if (csi->textclip) fz_dropnode((fz_node*)csi->textclip); if (csi->text) fz_dropnode((fz_node*)csi->text); if (csi->array) fz_dropobj(csi->array); clearstack(csi); fz_free(csi);}/* * Do some magic to call the xobject subroutine. * Push gstate, set transform, clip, run, pop gstate. */static fz_error *runxobject(pdf_csi *csi, pdf_xref *xref, pdf_xobject *xobj, int istransparency){ fz_error *error; fz_node *transform; fz_node *blend; fz_stream *file; pdf_gstate *gstate; /* gsave */ error = gsave(csi); if (error) return fz_rethrow(error, "cannot push graphics state"); gstate = csi->gstate + csi->gtop; /* reset alpha to 1.0 when starting a new Transparency group */ if (istransparency) { gstate->stroke.alpha = 1.0; gstate->fill.alpha = 1.0; } /* push transform */ error = fz_newtransformnode(&transform, xobj->matrix); if (error) return fz_rethrow(error, "cannot create transform node"); error = pdf_addtransform(gstate, transform); if (error) { fz_dropnode(transform); return fz_rethrow(error, "cannot add transform node"); } if (xobj->isolated || xobj->knockout) { error = fz_newblendnode(&blend, FZ_BNORMAL, xobj->isolated, xobj->knockout); if (error) return fz_rethrow(error, "cannot create blend node"); fz_insertnodelast(gstate->head, blend); gstate->head = blend; } /* run contents */ xobj->contents->rp = xobj->contents->bp; error = fz_openrbuffer(&file, xobj->contents); if (error) return fz_rethrow(error, "cannot open XObject stream"); error = pdf_runcsi(csi, xref, xobj->resources, file); fz_dropstream(file); if (error) return fz_rethrow(error, "cannot interpret XObject stream"); /* grestore */ error = grestore(csi); if (error) return fz_rethrow(error, "cannot pop graphics state"); return fz_okay;}/* * Decode inline image and insert into page. */static fz_error *runinlineimage(pdf_csi *csi, pdf_xref *xref, fz_obj *rdb, fz_stream *file, fz_obj *dict){ fz_error *error; pdf_image *img; char buf[256]; pdf_token_e tok; int len; error = pdf_loadinlineimage(&img, xref, rdb, dict, file); if (error) return fz_rethrow(error, "cannot load inline image"); error = pdf_lex(&tok, file, buf, sizeof buf, &len); if (error) { fz_dropimage((fz_image*)img); return fz_rethrow(error, "syntax error after inline image"); } if (tok != PDF_TKEYWORD || strcmp("EI", buf)) { fz_dropimage((fz_image*)img); return fz_throw("syntax error after inline image"); } error = pdf_showimage(csi, img); if (error) { fz_dropimage((fz_image*)img); return fz_rethrow(error, "cannot draw image"); } fz_dropimage((fz_image*)img); return fz_okay;}/* * Set gstate params from an ExtGState dictionary. */static fz_error *runextgstate(pdf_gstate *gstate, pdf_xref *xref, fz_obj *extgstate){ int i, k; for (i = 0; i < fz_dictlen(extgstate); i++) { fz_obj *key = fz_dictgetkey(extgstate, i); fz_obj *val = fz_dictgetval(extgstate, i); char *s = fz_toname(key); if (!strcmp(s, "Font")) { if (fz_isarray(val) && fz_arraylen(val) == 2) { gstate->font = pdf_finditem(xref->store, PDF_KFONT, fz_arrayget(val, 0)); if (!gstate->font) return fz_throw("cannot find font in store"); gstate->size = fz_toreal(fz_arrayget(val, 1)); } else return fz_throw("malformed /Font"); } else if (!strcmp(s, "LW")) gstate->linewidth = fz_toreal(val); else if (!strcmp(s, "LC")) gstate->linecap = fz_toint(val); else if (!strcmp(s, "LJ")) gstate->linejoin = fz_toint(val); else if (!strcmp(s, "ML")) gstate->miterlimit = fz_toreal(val); else if (!strcmp(s, "D")) { if (fz_isarray(val) && fz_arraylen(val) == 2) { fz_obj *dashes = fz_arrayget(val, 0); gstate->dashlen = MAX(fz_arraylen(dashes), 32); for (k = 0; k < gstate->dashlen; k++) gstate->dashlist[k] = fz_toreal(fz_arrayget(dashes, k)); gstate->dashphase = fz_toreal(fz_arrayget(val, 1)); } else return fz_throw("malformed /D"); } else if (!strcmp(s, "CA")) gstate->stroke.alpha = fz_toreal(val); else if (!strcmp(s, "ca")) gstate->fill.alpha = fz_toreal(val); else if (!strcmp(s, "BM")) { fz_error *error; fz_node *blend; static const struct { const char *name; fz_blendkind mode; } bm[] = { { "Normal", FZ_BNORMAL }, { "Multiply", FZ_BMULTIPLY }, { "Screen", FZ_BSCREEN }, { "Overlay", FZ_BOVERLAY }, { "Darken", FZ_BDARKEN }, { "Lighten", FZ_BLIGHTEN }, { "Colordodge", FZ_BCOLORDODGE }, { "Hardlight", FZ_BHARDLIGHT }, { "Softlight", FZ_BSOFTLIGHT }, { "Difference", FZ_BDIFFERENCE }, { "Exclusion", FZ_BEXCLUSION }, { "Hue", FZ_BHUE }, { "Saturation", FZ_BSATURATION }, { "Color", FZ_BCOLOR }, { "Luminosity", FZ_BLUMINOSITY } }; char *n = fz_toname(val); gstate->blendmode = FZ_BNORMAL; for (k = 0; k < nelem(bm); k++) { if (!strcmp(bm[k].name, n)) { gstate->blendmode = bm[k].mode; /* printf("blend mode %s:%d\n", n, gstate->blendmode); */ break; } } if (gstate->blendmode == FZ_BNORMAL) error = fz_newovernode(&blend); else error = fz_newblendnode(&blend, gstate->blendmode, 0, 0); if (error) return fz_rethrow(error, "cannot create blend node"); fz_insertnodelast(gstate->head, blend); gstate->head = blend; } else if (!strcmp(s, "SMask")) { fz_error *error = pdf_resolve(&val, xref); if (error) return error; if (fz_isdict(val)) { fz_obj *g = fz_dictgets(val, "G"); error = pdf_resolve(&g, xref); if (error) return error; /* TODO: we should do something here, like inserting a mask node for the S key in val */ /* TODO: how to deal with the non-recursive nature of pdf soft masks? */ /*puts("we encountered a soft mask");*/ } fz_dropobj(val); } } return fz_okay;}/* * The meat of the interpreter... */static fz_error *runkeyword(pdf_csi *csi, pdf_xref *xref, fz_obj *rdb, char *buf){ pdf_gstate *gstate = csi->gstate + csi->gtop; fz_error *error; float a, b, c, d, e, f; float x, y, w, h; fz_matrix m; float v[FZ_MAXCOLORS]; int what; int i; if (strlen(buf) > 1) { if (!strcmp(buf, "BX")) { if (csi->top != 0) goto syntaxerror; csi->xbalance ++; } else if (!strcmp(buf, "EX")) { if (csi->top != 0) goto syntaxerror; csi->xbalance --; } else if (!strcmp(buf, "MP")) { if (csi->top != 1) goto syntaxerror; } else if (!strcmp(buf, "DP")) { if (csi->top != 2) goto syntaxerror; } else if (!strcmp(buf, "BMC")) { if (csi->top != 1) goto syntaxerror; } else if (!strcmp(buf, "BDC")) { if (csi->top != 2) goto syntaxerror; } else if (!strcmp(buf, "EMC")) { if (csi->top != 0) goto syntaxerror; } else if (!strcmp(buf, "cm")) { fz_matrix m; fz_node *transform; if (csi->top != 6) goto syntaxerror; m.a = fz_toreal(csi->stack[0]); m.b = fz_toreal(csi->stack[1]); m.c = fz_toreal(csi->stack[2]); m.d = fz_toreal(csi->stack[3]); m.e = fz_toreal(csi->stack[4]); m.f = fz_toreal(csi->stack[5]); error = fz_newtransformnode(&transform, m); if (error) return fz_rethrow(error, "cannot concatenate matrix");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -