📄 pdf_function.c
字号:
#include "fitz.h"#include "mupdf.h"/* this mess is seokgyo's doing */enum{ MAXN = FZ_MAXCOLORS, MAXM = FZ_MAXCOLORS, MAXK = 32};typedef struct psobj_s psobj;enum{ SAMPLE = 0, EXPONENTIAL = 2, STITCHING = 3, POSTSCRIPT = 4};struct pdf_function_s{ int refs; int type; /* 0=sample 2=exponential 3=stitching 4=postscript */ int m; /* number of input values */ int n; /* number of output values */ float domain[MAXM][2]; /* even index : min value, odd index : max value */ float range[MAXN][2]; /* even index : min value, odd index : max value */ int hasrange; union { struct { unsigned short bps; int size[MAXM]; float encode[MAXM][2]; float decode[MAXN][2]; int *samples; } sa; struct { float n; float c0[MAXN]; float c1[MAXN]; } e; struct { int k; pdf_function *funcs[MAXK]; float bounds[MAXK-1]; float encode[MAXK][2]; } st; struct { psobj *code; int cap; } p; } u;};/* * PostScript calculator */#define RADIAN 57.2957795#define LERP(x, xmin, xmax, ymin, ymax) \ (ymin) + ((x) - (xmin)) * ((ymax) - (ymin)) / ((xmax) - (xmin))enum { PSBOOL, PSINT, PSREAL, PSOPERATOR, PSBLOCK };enum{ PSOABS, PSOADD, PSOAND, PSOATAN, PSOBITSHIFT, PSOCEILING, PSOCOPY, PSOCOS, PSOCVI, PSOCVR, PSODIV, PSODUP, PSOEQ, PSOEXCH, PSOEXP, PSOFALSE, PSOFLOOR, PSOGE, PSOGT, PSOIDIV, PSOINDEX, PSOLE, PSOLN, PSOLOG, PSOLT, PSOMOD, PSOMUL, PSONE, PSONEG, PSONOT, PSOOR, PSOPOP, PSOROLL, PSOROUND, PSOSIN, PSOSQRT, PSOSUB, PSOTRUE, PSOTRUNCATE, PSOXOR, PSOIF, PSOIFELSE, PSORETURN};static char *psopnames[] ={ "abs", "add", "and", "atan", "bitshift", "ceiling", "copy", "cos", "cvi", "cvr", "div", "dup", "eq", "exch", "exp", "false", "floor", "ge", "gt", "idiv", "index", "le", "ln", "log", "lt", "mod", "mul", "ne", "neg", "not", "or", "pop", "roll", "round", "sin", "sqrt", "sub", "true", "truncate", "xor", "if", "ifelse", "return"};struct psobj_s{ int type; union { int b; /* boolean (stack only) */ int i; /* integer (stack and code) */ float f; /* real (stack and code) */ int op; /* operator (code only) */ int block; /* if/ifelse block pointer (code only) */ } u;};enum { PSSTACKSIZE = 100 };#define fz_stackoverflow fz_throw("stack overflow in calculator function")#define fz_stackunderflow fz_throw("stack underflow in calculator function")#define fz_stacktypemismatch fz_throw("type mismatch in calculator function")typedef struct psstack_s psstack;struct psstack_s{ psobj stack[PSSTACKSIZE]; int sp;};static voidpsinitstack(psstack *st){ memset(st->stack, 0, sizeof(st->stack)); st->sp = PSSTACKSIZE;}static intpscheckoverflow(psstack *st, int n){ return st->sp >= n;}static intpscheckunderflow(psstack *st){ return st->sp != PSSTACKSIZE;}static intpschecktype(psstack *st, unsigned short type){ return st->stack[st->sp].type == type;}static fz_error *pspushbool(psstack *st, int booln){ if (!pscheckoverflow(st, 1)) return fz_stackoverflow; st->stack[--st->sp].type = PSBOOL; st->stack[st->sp].u.b = booln; return fz_okay;}static fz_error *pspushint(psstack *st, int intg){ if (!pscheckoverflow(st, 1)) return fz_stackoverflow; st->stack[--st->sp].type = PSINT; st->stack[st->sp].u.i = intg; return fz_okay;}static fz_error *pspushreal(psstack *st, float real){ if (!pscheckoverflow(st, 1)) return fz_stackoverflow; st->stack[--st->sp].type = PSREAL; st->stack[st->sp].u.f = real; return fz_okay;}static fz_error *pspopbool(psstack *st, int *booln){ if (!pscheckunderflow(st)) return fz_stackunderflow; if (!pschecktype(st, PSBOOL)) return fz_stacktypemismatch; *booln = st->stack[st->sp++].u.b; return fz_okay;}static fz_error *pspopint(psstack *st, int *intg){ if (!pscheckunderflow(st)) return fz_stackunderflow; if (!pschecktype(st, PSINT)) return fz_stacktypemismatch; *intg = st->stack[st->sp++].u.i; return fz_okay;}static fz_error *pspopnum(psstack *st, float *real){ if (!pscheckunderflow(st)) return fz_stackunderflow; if (!pschecktype(st, PSINT) && !pschecktype(st, PSREAL)) return fz_stacktypemismatch; *real = (st->stack[st->sp].type == PSINT) ? st->stack[st->sp].u.i : st->stack[st->sp].u.f; ++st->sp; return fz_okay;}static intpstopisint(psstack *st){ return st->sp < PSSTACKSIZE && st->stack[st->sp].type == PSINT;}static intpstoptwoareints(psstack *st){ return st->sp < PSSTACKSIZE - 1 && st->stack[st->sp].type == PSINT && st->stack[st->sp + 1].type == PSINT;}static intpstopisreal(psstack *st){ return st->sp < PSSTACKSIZE && st->stack[st->sp].type == PSREAL;}static intpstoptwoarenums(psstack *st){ return st->sp < PSSTACKSIZE - 1 && (st->stack[st->sp].type == PSINT || st->stack[st->sp].type == PSREAL) && (st->stack[st->sp + 1].type == PSINT || st->stack[st->sp + 1].type == PSREAL);}static fz_error *pscopy(psstack *st, int n){ int i; if (!pscheckoverflow(st, n)) return fz_stackoverflow; for (i = 0; i < n; i++) { st->stack[st->sp - n + i] = st->stack[st->sp + i]; } st->sp -= n; return fz_okay;}static voidpsroll(psstack *st, int n, int j){ psobj obj; int i, k; if (j >= 0) { j %= n; } else { j = -j % n; if (j != 0) { j = n - j; } } if (n <= 0 || j == 0) { return; } for (i = 0; i < j; ++i) { /* FIXME check for underflow? */ obj = st->stack[st->sp]; for (k = st->sp; k < st->sp + n - 1; ++k) { st->stack[k] = st->stack[k + 1]; } st->stack[st->sp + n - 1] = obj; }}static fz_error *psindex(psstack *st, int i){ if (!pscheckoverflow(st, 1)) return fz_stackoverflow; --st->sp; st->stack[st->sp] = st->stack[st->sp + 1 + i]; return fz_okay;}static fz_error *pspop(psstack *st){ if (!pscheckoverflow(st, 1)) return fz_stackoverflow; ++st->sp; return fz_okay;}static fz_error *resizecode(pdf_function *func, int newsize){ if (newsize >= func->u.p.cap) { int newcodecap = func->u.p.cap + 64; psobj *newcode; newcode = fz_realloc(func->u.p.code, newcodecap * sizeof(psobj)); if (!newcode) return fz_throw("outofmem: calculator function code"); func->u.p.cap = newcodecap; func->u.p.code = newcode; } return fz_okay;}static fz_error *parsecode(pdf_function *func, fz_stream *stream, int *codeptr){ fz_error *error; char buf[64]; int len; pdf_token_e tok; int opptr, elseptr; int a, b, mid, cmp; memset(buf, 0, sizeof(buf)); while (1) { error = pdf_lex(&tok, stream, buf, sizeof buf, &len); if (error) return fz_rethrow(error, "calculator function lexical error"); switch(tok) { case PDF_TEOF: return fz_throw("truncated calculator function"); case PDF_TINT: error = resizecode(func, *codeptr); if (error) return fz_rethrow(error, "resize calculator function code"); func->u.p.code[*codeptr].type = PSINT; func->u.p.code[*codeptr].u.i = atoi(buf); ++*codeptr; break; case PDF_TREAL: error = resizecode(func, *codeptr); if (error) return fz_rethrow(error, "resize calculator function code"); func->u.p.code[*codeptr].type = PSREAL; func->u.p.code[*codeptr].u.f = atof(buf); ++*codeptr; break; case PDF_TOBRACE: opptr = *codeptr; *codeptr += 3; error = resizecode(func, opptr + 2); if (error) return fz_rethrow(error, "resize calculator function code"); error = parsecode(func, stream, codeptr); if (error) return fz_rethrow(error, "error in 'if' branch"); error = pdf_lex(&tok, stream, buf, sizeof buf, &len); if (error) return fz_rethrow(error, "calculator function syntax error"); if (tok == PDF_TOBRACE) { elseptr = *codeptr; error = parsecode(func, stream, codeptr); if (error) return fz_rethrow(error, "error in 'else' branch"); error = pdf_lex(&tok, stream, buf, sizeof buf, &len); if (error) return fz_rethrow(error, "calculator function syntax error"); } else { elseptr = -1; } if (tok == PDF_TKEYWORD) { if (!strcmp(buf, "if")) { if (elseptr >= 0) return fz_throw("too many branches for 'if'"); func->u.p.code[opptr].type = PSOPERATOR; func->u.p.code[opptr].u.op = PSOIF; func->u.p.code[opptr+2].type = PSBLOCK; func->u.p.code[opptr+2].u.block = *codeptr; } else if (!strcmp(buf, "ifelse")) { if (elseptr < 0) return fz_throw("not enough branches for 'ifelse'"); func->u.p.code[opptr].type = PSOPERATOR; func->u.p.code[opptr].u.op = PSOIFELSE; func->u.p.code[opptr+1].type = PSBLOCK; func->u.p.code[opptr+1].u.block = elseptr; func->u.p.code[opptr+2].type = PSBLOCK; func->u.p.code[opptr+2].u.block = *codeptr; } else { return fz_throw("unknown keyword in 'if-else' context: '%s'", buf); } } else { return fz_throw("missing keyword in 'if-else' context"); } break; case PDF_TCBRACE: error = resizecode(func, *codeptr); if (error) return fz_rethrow(error, "resize calculator function code"); func->u.p.code[*codeptr].type = PSOPERATOR; func->u.p.code[*codeptr].u.op = PSORETURN; ++*codeptr; return fz_okay; case PDF_TKEYWORD: cmp = -1; a = -1; b = sizeof(psopnames) / sizeof(psopnames[0]); while (b - a > 1) { mid = (a + b) / 2; cmp = strcmp(buf, psopnames[mid]); if (cmp > 0) a = mid; else if (cmp < 0) b = mid; else a = b = mid; } if (cmp != 0) return fz_throw("unknown operator: '%s'", buf); error = resizecode(func, *codeptr); if (error) return fz_rethrow(error, "resize calculator function code"); func->u.p.code[*codeptr].type = PSOPERATOR; func->u.p.code[*codeptr].u.op = a; ++*codeptr; break; default: return fz_throw("calculator function syntax error"); } }}static fz_error *loadpostscriptfunc(pdf_function *func, pdf_xref *xref, fz_obj *dict, int oid, int gen){ fz_error *error; fz_stream *stream; int codeptr; pdf_logrsrc("load postscript function (%d %d R)\n", oid, gen); error = pdf_openstream(&stream, xref, oid, gen); if (error) return fz_rethrow(error, "cannot open calculator function stream"); if (fz_readbyte(stream) != '{') { fz_dropstream(stream); return fz_throw("stream is not a calculator function"); } func->u.p.code = nil; func->u.p.cap = 0; codeptr = 0; error = parsecode(func, stream, &codeptr); if (error) { fz_dropstream(stream); return fz_rethrow(error, "cannot parse calculator function"); } fz_dropstream(stream); return fz_okay;}#define SAFE_RETHROW if (error) fz_rethrow(error, "runtime error in calculator function")#define SAFE_PUSHINT(st, a) { error = pspushint(st, a); SAFE_RETHROW; }#define SAFE_PUSHREAL(st, a) { error = pspushreal(st, a); SAFE_RETHROW; }#define SAFE_PUSHBOOL(st, a) { error = pspushbool(st, a); SAFE_RETHROW; }#define SAFE_POPINT(st, a) { error = pspopint(st, a); SAFE_RETHROW; }#define SAFE_POPNUM(st, a) { error = pspopnum(st, a); SAFE_RETHROW; }#define SAFE_POPBOOL(st, a) { error = pspopbool(st, a); SAFE_RETHROW; }#define SAFE_POP(st) { error = pspop(st); SAFE_RETHROW; }#define SAFE_INDEX(st, i) { error = psindex(st, i); SAFE_RETHROW; }#define SAFE_COPY(st, n) { error = pscopy(st, n); SAFE_RETHROW; }static fz_error *evalpostscriptfunc(pdf_function *func, psstack *st, int codeptr){ fz_error *error; int i1, i2; float r1, r2; int b1, b2; while (1) { switch (func->u.p.code[codeptr].type) { case PSINT: SAFE_PUSHINT(st, func->u.p.code[codeptr++].u.i); break; case PSREAL: SAFE_PUSHREAL(st, func->u.p.code[codeptr++].u.f); break; case PSOPERATOR: switch (func->u.p.code[codeptr++].u.op) { case PSOABS: if (pstopisint(st)) { SAFE_POPINT(st, &i1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -