📄 pdf_function.c.svn-base
字号:
/* encode input coordinates */ for (i = 0; i < func->m; i++) { x = CLAMP(in[i], func->domain[i][0], func->domain[i][1]); x = LERP(x, func->domain[i][0], func->domain[i][1], func->u.sa.encode[i][0], func->u.sa.encode[i][1]); x = CLAMP(x, 0, func->u.sa.size[i] - 1); e[0][i] = floor(x); e[1][i] = ceil(x); efrac[i] = x - floor(x); } if (func->m > 4) { s0 = fz_malloc((1 << func->m) * 2 * sizeof(float)); s1 = s0 + (1 << func->m); if (!s0) return fz_throw("outofmem: scratch buffer"); } /* FIXME i think this is wrong... test with 2 samples it gets wrong idxs */ for (i = 0; i < func->n; i++) { /* pull 2^m values out of the sample array */ for (j = 0; j < (1 << func->m); ++j) { idx = 0; for (k = func->m - 1; k >= 0; --k) idx = idx * func->u.sa.size[k] + e[(j >> k) & 1][k]; idx = idx * func->n + i; s0[j] = func->u.sa.samples[idx]; } /* do m sets of interpolations */ for (j = 0; j < func->m; ++j) { for (k = 0; k < (1 << (func->m - j)); k += 2) s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1]; memcpy(s0, s1, (1 << (func->m - j - 1)) * sizeof(float)); } /* decode output values */ out[i] = LERP(s0[0], 0, (1 << func->u.sa.bps) - 1, func->u.sa.decode[i][0], func->u.sa.decode[i][1]); out[i] = CLAMP(out[i], func->range[i][0], func->range[i][1]); } if (func->m > 4) fz_free(s0); return fz_okay;}/* * Exponential function */static fz_error *loadexponentialfunc(pdf_function *func, fz_obj *dict){ fz_obj *obj; int i; pdf_logrsrc("exponential function {\n"); if (func->m != 1) return fz_throw("/Domain must be one dimension (%d)", func->m); obj = fz_dictgets(dict, "N"); if (!fz_isint(obj) && !fz_isreal(obj)) return fz_throw("malformed /N"); func->u.e.n = fz_toreal(obj); pdf_logrsrc("n %g\n", func->u.e.n); obj = fz_dictgets(dict, "C0"); if (fz_isarray(obj)) { func->n = fz_arraylen(obj); for (i = 0; i < func->n; ++i) func->u.e.c0[i] = fz_toreal(fz_arrayget(obj, i)); pdf_logrsrc("c0 %d\n", func->n); } else { func->n = 1; func->u.e.c0[0] = 0; } obj = fz_dictgets(dict, "C1"); if (fz_isarray(obj)) { if (fz_arraylen(obj) != func->n) return fz_throw("/C1 must match /C0 length"); for (i = 0; i < func->n; ++i) func->u.e.c1[i] = fz_toreal(fz_arrayget(obj, i)); pdf_logrsrc("c1 %d\n", func->n); } else { if (func->n != 1) return fz_throw("/C1 must match /C0 length"); func->u.e.c1[0] = 1; } pdf_logrsrc("}\n"); return fz_okay;}static fz_error *evalexponentialfunc(pdf_function *func, float in, float *out){ float x = in; float tmp; int i; x = CLAMP(x, func->domain[0][0], func->domain[0][1]); /* constraint */ if (func->u.e.n != (int)func->u.e.n && x < 0) return fz_throw("constraint error"); if (func->u.e.n < 0 && x == 0) return fz_throw("constraint error"); tmp = pow(x, func->u.e.n); for (i = 0; i < func->n; ++i) { out[i] = func->u.e.c0[i] + tmp * (func->u.e.c1[i] - func->u.e.c0[i]); if (func->hasrange) out[i] = CLAMP(out[i], func->range[i][0], func->range[i][1]); } return fz_okay;}/* * Stitching function */static fz_error *loadstitchingfunc(pdf_function *func, pdf_xref *xref, fz_obj *dict){ pdf_function **funcs = func->u.st.funcs; fz_error *error; fz_obj *obj; fz_obj *sub; fz_obj *num; int k; int i; pdf_logrsrc("stitching {\n"); func->u.st.k = 0; if (func->m != 1) return fz_throw("/Domain must be one dimension (%d)", func->m); obj = fz_dictgets(dict, "Functions"); { error = pdf_resolve(&obj, xref); if (error) return fz_rethrow(error, "cannot resolve /Functions"); k = fz_arraylen(obj); func->u.st.k = k; pdf_logrsrc("k %d\n", func->u.st.k); if (k >= MAXK) { fz_dropobj(obj); return fz_throw("assert: /K too big (%d)", k); } for (i = 0; i < k; ++i) { sub = fz_arrayget(obj, i); error = pdf_loadfunction(funcs + i, xref, sub); if (error) { fz_dropobj(obj); return fz_rethrow(error, "cannot load sub function %d", i); } if (funcs[i]->m != 1 || funcs[i]->n != funcs[0]->n) { fz_dropobj(obj); return fz_rethrow(error, "sub function %d /Domain or /Range mismatch", i); } } if (!func->n) { func->n = funcs[0]->n; } else if (func->n != funcs[0]->n) { fz_dropobj(obj); return fz_rethrow(error, "sub function /Domain or /Range mismatch"); } fz_dropobj(obj); } obj = fz_dictgets(dict, "Bounds"); { error = pdf_resolve(&obj, xref); if (error) return fz_rethrow(error, "cannot resolve /Bounds"); if (!fz_isarray(obj) || fz_arraylen(obj) != k - 1) { fz_dropobj(obj); return fz_throw("malformed /Bounds (not array or wrong length)"); } for (i = 0; i < k-1; ++i) { num = fz_arrayget(obj, i); if (!fz_isint(num) && !fz_isreal(num)) { fz_dropobj(obj); return fz_throw("malformed /Bounds (item not number)"); } func->u.st.bounds[i] = fz_toreal(num); if (i && func->u.st.bounds[i-1] > func->u.st.bounds[i]) { fz_dropobj(obj); return fz_throw("malformed /Bounds (item not monotonic)"); } } if (k != 1 && (func->domain[0][0] > func->u.st.bounds[0] || func->domain[0][1] < func->u.st.bounds[k-2])) fz_warn("malformed shading function bounds (domain mismatch), proceeding anyway."); fz_dropobj(obj); } obj = fz_dictgets(dict, "Encode"); { error = pdf_resolve(&obj, xref); if (error) return fz_rethrow(error, "cannot resolve /Encode"); if (!fz_isarray(obj) || fz_arraylen(obj) != k * 2) { fz_dropobj(obj); return fz_throw("malformed /Encode"); } for (i = 0; i < k; ++i) { func->u.st.encode[i][0] = fz_toreal(fz_arrayget(obj, i*2+0)); func->u.st.encode[i][1] = fz_toreal(fz_arrayget(obj, i*2+1)); } fz_dropobj(obj); } pdf_logrsrc("}\n"); return fz_okay;}static fz_error*evalstitchingfunc(pdf_function *func, float in, float *out){ fz_error *error; float low, high; int k = func->u.st.k; float *bounds = func->u.st.bounds; int i; in = CLAMP(in, func->domain[0][0], func->domain[0][1]); for (i = 0; i < k - 1; ++i) { if (in < bounds[i]) break; } if (i == 0 && k == 1) { low = func->domain[0][0]; high = func->domain[0][1]; } else if (i == 0) { low = func->domain[0][0]; high = bounds[0]; } else if (i == k - 1) { low = bounds[k-2]; high = func->domain[0][1]; } else { low = bounds[i-1]; high = bounds[i]; } in = LERP(in, low, high, func->u.st.encode[i][0], func->u.st.encode[i][1]); error = pdf_evalfunction(func->u.st.funcs[i], &in, 1, out, func->n); if (error) return fz_rethrow(error, "cannot evaluate sub function %d", i); return fz_okay;}/* * Common */pdf_function *pdf_keepfunction(pdf_function *func){ func->refs ++; return func;}voidpdf_dropfunction(pdf_function *func){ int i; if (--func->refs == 0) { switch(func->type) { case SAMPLE: fz_free(func->u.sa.samples); break; case EXPONENTIAL: break; case STITCHING: for (i = 0; i < func->u.st.k; ++i) pdf_dropfunction(func->u.st.funcs[i]); break; case POSTSCRIPT: fz_free(func->u.p.code); break; } fz_free(func); }}fz_error *pdf_loadfunction(pdf_function **funcp, pdf_xref *xref, fz_obj *ref){ fz_error *error; pdf_function *func; fz_obj *dict; fz_obj *obj; int i; if ((*funcp = pdf_finditem(xref->store, PDF_KFUNCTION, ref))) { pdf_keepfunction(*funcp); return fz_okay; } pdf_logrsrc("load function (%d %d R) {\n", fz_tonum(ref), fz_togen(ref)); func = fz_malloc(sizeof(pdf_function)); if (!func) return fz_throw("outofmem: function struct"); memset(func, 0, sizeof(pdf_function)); func->refs = 1; dict = ref; error = pdf_resolve(&dict, xref); if (error) { fz_free(func); return fz_rethrow(error, "cannot resolve function object"); } obj = fz_dictgets(dict, "FunctionType"); func->type = fz_toint(obj); pdf_logrsrc("type %d\n", func->type); /* required for all */ obj = fz_dictgets(dict, "Domain"); func->m = fz_arraylen(obj) / 2; for (i = 0; i < func->m; i++) { func->domain[i][0] = fz_toreal(fz_arrayget(obj, i * 2 + 0)); func->domain[i][1] = fz_toreal(fz_arrayget(obj, i * 2 + 1)); } pdf_logrsrc("domain %d\n", func->m); /* required for type0 and type4, optional otherwise */ obj = fz_dictgets(dict, "Range"); if (fz_isarray(obj)) { func->hasrange = 1; func->n = fz_arraylen(obj) / 2; for (i = 0; i < func->n; i++) { func->range[i][0] = fz_toreal(fz_arrayget(obj, i * 2 + 0)); func->range[i][1] = fz_toreal(fz_arrayget(obj, i * 2 + 1)); } pdf_logrsrc("range %d\n", func->n); } else { func->hasrange = 0; func->n = 0; } if (func->m >= MAXM || func->n >= MAXN) { fz_free(func); fz_dropobj(dict); return fz_throw("assert: /Domain or /Range too big"); } switch(func->type) { case SAMPLE: error = loadsamplefunc(func, xref, dict, fz_tonum(ref), fz_togen(ref)); if (error) { pdf_dropfunction(func); fz_dropobj(dict); return fz_rethrow(error, "cannot load sampled function (%d %d R)", fz_tonum(ref), fz_togen(ref)); } break; case EXPONENTIAL: error = loadexponentialfunc(func, dict); if (error) { pdf_dropfunction(func); fz_dropobj(dict); return fz_rethrow(error, "cannot load exponential function (%d %d R)", fz_tonum(ref), fz_togen(ref)); } break; case STITCHING: error = loadstitchingfunc(func, xref, dict); if (error) { pdf_dropfunction(func); fz_dropobj(dict); return fz_rethrow(error, "cannot load stitching function (%d %d R)", fz_tonum(ref), fz_togen(ref)); } break; case POSTSCRIPT: error = loadpostscriptfunc(func, xref, dict, fz_tonum(ref), fz_togen(ref)); if (error) { pdf_dropfunction(func); fz_dropobj(dict); return fz_rethrow(error, "cannot load calculator function (%d %d R)", fz_tonum(ref), fz_togen(ref)); } break; default: fz_free(func); fz_dropobj(dict); return fz_throw("unknown function type %d (%d %d R)", func->type, fz_tonum(ref), fz_togen(ref)); } fz_dropobj(dict); pdf_logrsrc("}\n"); error = pdf_storeitem(xref->store, PDF_KFUNCTION, ref, func); if (error) { pdf_dropfunction(func); fz_dropobj(dict); return fz_rethrow(error, "cannot store function resource"); } *funcp = func; return fz_okay;}fz_error *pdf_evalfunction(pdf_function *func, float *in, int inlen, float *out, int outlen){ fz_error *error; float r; int i; if (func->m != inlen || func->n != outlen) return fz_throw("function argument count mismatch"); switch(func->type) { case SAMPLE: error = evalsamplefunc(func, in, out); if (error) return fz_rethrow(error, "cannot evaluate sampled function"); break; case EXPONENTIAL: error = evalexponentialfunc(func, *in, out); if (error) return fz_rethrow(error, "cannot evaluate exponential function"); break; case STITCHING: error = evalstitchingfunc(func, *in, out); if (error) return fz_rethrow(error, "cannot evaluate stitching function"); break; case POSTSCRIPT: { psstack st; psinitstack(&st); for (i = 0; i < func->m; ++i) SAFE_PUSHREAL(&st, in[i]); error = evalpostscriptfunc(func, &st, 0); if (error) return fz_rethrow(error, "cannot evaluate calculator function"); for (i = func->n - 1; i >= 0; --i) { SAFE_POPNUM(&st, &r); out[i] = CLAMP(r, func->range[i][0], func->range[i][1]); } } break; default: return fz_throw("assert: unknown function type"); } return fz_okay;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -