| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760 |
- #include "fitz-internal.h"
- #include "mupdf-internal.h"
- enum
- {
- MAXN = FZ_MAX_COLORS,
- MAXM = FZ_MAX_COLORS,
- };
- typedef struct psobj_s psobj;
- enum
- {
- SAMPLE = 0,
- EXPONENTIAL = 2,
- STITCHING = 3,
- POSTSCRIPT = 4
- };
- struct pdf_function_s
- {
- fz_storable storable;
- unsigned int size;
- 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 has_range;
- union
- {
- struct {
- unsigned short bps;
- int size[MAXM];
- float encode[MAXM][2];
- float decode[MAXN][2];
- float *samples;
- } sa;
- struct {
- float n;
- float c0[MAXN];
- float c1[MAXN];
- } e;
- struct {
- int k;
- pdf_function **funcs; /* k */
- float *bounds; /* k - 1 */
- float *encode; /* k * 2 */
- } st;
- struct {
- psobj *code;
- int cap;
- } p;
- } u;
- };
- #define RADIAN 57.2957795
- static inline float lerp(float x, float xmin, float xmax, float ymin, float ymax)
- {
- if (xmin == xmax)
- return ymin;
- if (ymin == ymax)
- return ymin;
- return ymin + (x - xmin) * (ymax - ymin) / (xmax - xmin);
- }
- /*
- * PostScript calculator
- */
- enum { PS_BOOL, PS_INT, PS_REAL, PS_OPERATOR, PS_BLOCK };
- enum
- {
- PS_OP_ABS, PS_OP_ADD, PS_OP_AND, PS_OP_ATAN, PS_OP_BITSHIFT,
- PS_OP_CEILING, PS_OP_COPY, PS_OP_COS, PS_OP_CVI, PS_OP_CVR,
- PS_OP_DIV, PS_OP_DUP, PS_OP_EQ, PS_OP_EXCH, PS_OP_EXP,
- PS_OP_FALSE, PS_OP_FLOOR, PS_OP_GE, PS_OP_GT, PS_OP_IDIV, PS_OP_IF,
- PS_OP_IFELSE, PS_OP_INDEX, PS_OP_LE, PS_OP_LN, PS_OP_LOG, PS_OP_LT,
- PS_OP_MOD, PS_OP_MUL, PS_OP_NE, PS_OP_NEG, PS_OP_NOT, PS_OP_OR,
- PS_OP_POP, PS_OP_RETURN, PS_OP_ROLL, PS_OP_ROUND, PS_OP_SIN,
- PS_OP_SQRT, PS_OP_SUB, PS_OP_TRUE, PS_OP_TRUNCATE, PS_OP_XOR
- };
- static char *ps_op_names[] =
- {
- "abs", "add", "and", "atan", "bitshift", "ceiling", "copy",
- "cos", "cvi", "cvr", "div", "dup", "eq", "exch", "exp",
- "false", "floor", "ge", "gt", "idiv", "if", "ifelse", "index", "le", "ln",
- "log", "lt", "mod", "mul", "ne", "neg", "not", "or", "pop", "return",
- "roll", "round", "sin", "sqrt", "sub", "true", "truncate", "xor"
- };
- 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;
- };
- typedef struct ps_stack_s ps_stack;
- struct ps_stack_s
- {
- psobj stack[100];
- int sp;
- };
- #ifndef NDEBUG
- void
- pdf_debug_ps_stack(ps_stack *st)
- {
- int i;
- printf("stack: ");
- for (i = 0; i < st->sp; i++)
- {
- switch (st->stack[i].type)
- {
- case PS_BOOL:
- if (st->stack[i].u.b)
- printf("true ");
- else
- printf("false ");
- break;
- case PS_INT:
- printf("%d ", st->stack[i].u.i);
- break;
- case PS_REAL:
- printf("%g ", st->stack[i].u.f);
- break;
- }
- }
- printf("\n");
- }
- #endif
- static void
- ps_init_stack(ps_stack *st)
- {
- memset(st->stack, 0, sizeof(st->stack));
- st->sp = 0;
- }
- static inline int ps_overflow(ps_stack *st, int n)
- {
- return n < 0 || st->sp + n >= nelem(st->stack);
- }
- static inline int ps_underflow(ps_stack *st, int n)
- {
- return n < 0 || st->sp - n < 0;
- }
- static inline int ps_is_type(ps_stack *st, int t)
- {
- return !ps_underflow(st, 1) && st->stack[st->sp - 1].type == t;
- }
- static inline int ps_is_type2(ps_stack *st, int t)
- {
- return !ps_underflow(st, 2) && st->stack[st->sp - 1].type == t && st->stack[st->sp - 2].type == t;
- }
- static void
- ps_push_bool(ps_stack *st, int b)
- {
- if (!ps_overflow(st, 1))
- {
- st->stack[st->sp].type = PS_BOOL;
- st->stack[st->sp].u.b = b;
- st->sp++;
- }
- }
- static void
- ps_push_int(ps_stack *st, int n)
- {
- if (!ps_overflow(st, 1))
- {
- st->stack[st->sp].type = PS_INT;
- st->stack[st->sp].u.i = n;
- st->sp++;
- }
- }
- static void
- ps_push_real(ps_stack *st, float n)
- {
- if (!ps_overflow(st, 1))
- {
- st->stack[st->sp].type = PS_REAL;
- if (isnan(n))
- {
- /* Push 1.0, as it's a small known value that won't
- * cause a divide by 0. Same reason as in fz_atof. */
- n = 1.0;
- }
- st->stack[st->sp].u.f = fz_clamp(n, -FLT_MAX, FLT_MAX);
- st->sp++;
- }
- }
- static int
- ps_pop_bool(ps_stack *st)
- {
- if (!ps_underflow(st, 1))
- {
- if (ps_is_type(st, PS_BOOL))
- return st->stack[--st->sp].u.b;
- }
- return 0;
- }
- static int
- ps_pop_int(ps_stack *st)
- {
- if (!ps_underflow(st, 1))
- {
- if (ps_is_type(st, PS_INT))
- return st->stack[--st->sp].u.i;
- if (ps_is_type(st, PS_REAL))
- return st->stack[--st->sp].u.f;
- }
- return 0;
- }
- static float
- ps_pop_real(ps_stack *st)
- {
- if (!ps_underflow(st, 1))
- {
- if (ps_is_type(st, PS_INT))
- return st->stack[--st->sp].u.i;
- if (ps_is_type(st, PS_REAL))
- return st->stack[--st->sp].u.f;
- }
- return 0;
- }
- static void
- ps_copy(ps_stack *st, int n)
- {
- if (!ps_underflow(st, n) && !ps_overflow(st, n))
- {
- memcpy(st->stack + st->sp, st->stack + st->sp - n, n * sizeof(psobj));
- st->sp += n;
- }
- }
- static void
- ps_roll(ps_stack *st, int n, int j)
- {
- psobj tmp;
- int i;
- if (ps_underflow(st, n) || j == 0 || n == 0)
- return;
- if (j >= 0)
- {
- j %= n;
- }
- else
- {
- j = -j % n;
- if (j != 0)
- j = n - j;
- }
- for (i = 0; i < j; i++)
- {
- tmp = st->stack[st->sp - 1];
- memmove(st->stack + st->sp - n + 1, st->stack + st->sp - n, n * sizeof(psobj));
- st->stack[st->sp - n] = tmp;
- }
- }
- static void
- ps_index(ps_stack *st, int n)
- {
- if (!ps_overflow(st, 1) && !ps_underflow(st, n))
- {
- st->stack[st->sp] = st->stack[st->sp - n - 1];
- st->sp++;
- }
- }
- static void
- ps_run(fz_context *ctx, psobj *code, ps_stack *st, int pc)
- {
- int i1, i2;
- float r1, r2;
- int b1, b2;
- while (1)
- {
- switch (code[pc].type)
- {
- case PS_INT:
- ps_push_int(st, code[pc++].u.i);
- break;
- case PS_REAL:
- ps_push_real(st, code[pc++].u.f);
- break;
- case PS_OPERATOR:
- switch (code[pc++].u.op)
- {
- case PS_OP_ABS:
- if (ps_is_type(st, PS_INT))
- ps_push_int(st, abs(ps_pop_int(st)));
- else
- ps_push_real(st, fabsf(ps_pop_real(st)));
- break;
- case PS_OP_ADD:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 + i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_real(st, r1 + r2);
- }
- break;
- case PS_OP_AND:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 & i2);
- }
- else {
- b2 = ps_pop_bool(st);
- b1 = ps_pop_bool(st);
- ps_push_bool(st, b1 && b2);
- }
- break;
- case PS_OP_ATAN:
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- r1 = atan2f(r1, r2) * RADIAN;
- if (r1 < 0)
- r1 += 360;
- ps_push_real(st, r1);
- break;
- case PS_OP_BITSHIFT:
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- if (i2 > 0 && i2 < 8 * sizeof (i2))
- ps_push_int(st, i1 << i2);
- else if (i2 < 0 && i2 > -8 * (int)sizeof (i2))
- ps_push_int(st, (int)((unsigned int)i1 >> -i2));
- else
- ps_push_int(st, i1);
- break;
- case PS_OP_CEILING:
- r1 = ps_pop_real(st);
- ps_push_real(st, ceilf(r1));
- break;
- case PS_OP_COPY:
- ps_copy(st, ps_pop_int(st));
- break;
- case PS_OP_COS:
- r1 = ps_pop_real(st);
- ps_push_real(st, cosf(r1/RADIAN));
- break;
- case PS_OP_CVI:
- ps_push_int(st, ps_pop_int(st));
- break;
- case PS_OP_CVR:
- ps_push_real(st, ps_pop_real(st));
- break;
- case PS_OP_DIV:
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- if (fabsf(r2) >= FLT_EPSILON)
- ps_push_real(st, r1 / r2);
- else
- ps_push_real(st, DIV_BY_ZERO(r1, r2, -FLT_MAX, FLT_MAX));
- break;
- case PS_OP_DUP:
- ps_copy(st, 1);
- break;
- case PS_OP_EQ:
- if (ps_is_type2(st, PS_BOOL)) {
- b2 = ps_pop_bool(st);
- b1 = ps_pop_bool(st);
- ps_push_bool(st, b1 == b2);
- }
- else if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 == i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 == r2);
- }
- break;
- case PS_OP_EXCH:
- ps_roll(st, 2, 1);
- break;
- case PS_OP_EXP:
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_real(st, powf(r1, r2));
- break;
- case PS_OP_FALSE:
- ps_push_bool(st, 0);
- break;
- case PS_OP_FLOOR:
- r1 = ps_pop_real(st);
- ps_push_real(st, floorf(r1));
- break;
- case PS_OP_GE:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 >= i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 >= r2);
- }
- break;
- case PS_OP_GT:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 > i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 > r2);
- }
- break;
- case PS_OP_IDIV:
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- if (i2 != 0)
- ps_push_int(st, i1 / i2);
- else
- ps_push_int(st, DIV_BY_ZERO(i1, i2, INT_MIN, INT_MAX));
- break;
- case PS_OP_INDEX:
- ps_index(st, ps_pop_int(st));
- break;
- case PS_OP_LE:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 <= i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 <= r2);
- }
- break;
- case PS_OP_LN:
- r1 = ps_pop_real(st);
- /* Bug 692941 - logf as separate statement */
- r2 = logf(r1);
- ps_push_real(st, r2);
- break;
- case PS_OP_LOG:
- r1 = ps_pop_real(st);
- ps_push_real(st, log10f(r1));
- break;
- case PS_OP_LT:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 < i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 < r2);
- }
- break;
- case PS_OP_MOD:
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- if (i2 != 0)
- ps_push_int(st, i1 % i2);
- else
- ps_push_int(st, DIV_BY_ZERO(i1, i2, INT_MIN, INT_MAX));
- break;
- case PS_OP_MUL:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 * i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_real(st, r1 * r2);
- }
- break;
- case PS_OP_NE:
- if (ps_is_type2(st, PS_BOOL)) {
- b2 = ps_pop_bool(st);
- b1 = ps_pop_bool(st);
- ps_push_bool(st, b1 != b2);
- }
- else if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_bool(st, i1 != i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_bool(st, r1 != r2);
- }
- break;
- case PS_OP_NEG:
- if (ps_is_type(st, PS_INT))
- ps_push_int(st, -ps_pop_int(st));
- else
- ps_push_real(st, -ps_pop_real(st));
- break;
- case PS_OP_NOT:
- if (ps_is_type(st, PS_BOOL))
- ps_push_bool(st, !ps_pop_bool(st));
- else
- ps_push_int(st, ~ps_pop_int(st));
- break;
- case PS_OP_OR:
- if (ps_is_type2(st, PS_BOOL)) {
- b2 = ps_pop_bool(st);
- b1 = ps_pop_bool(st);
- ps_push_bool(st, b1 || b2);
- }
- else {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 | i2);
- }
- break;
- case PS_OP_POP:
- if (!ps_underflow(st, 1))
- st->sp--;
- break;
- case PS_OP_ROLL:
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_roll(st, i1, i2);
- break;
- case PS_OP_ROUND:
- if (!ps_is_type(st, PS_INT)) {
- r1 = ps_pop_real(st);
- ps_push_real(st, (r1 >= 0) ? floorf(r1 + 0.5f) : ceilf(r1 - 0.5f));
- }
- break;
- case PS_OP_SIN:
- r1 = ps_pop_real(st);
- ps_push_real(st, sinf(r1/RADIAN));
- break;
- case PS_OP_SQRT:
- r1 = ps_pop_real(st);
- ps_push_real(st, sqrtf(r1));
- break;
- case PS_OP_SUB:
- if (ps_is_type2(st, PS_INT)) {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 - i2);
- }
- else {
- r2 = ps_pop_real(st);
- r1 = ps_pop_real(st);
- ps_push_real(st, r1 - r2);
- }
- break;
- case PS_OP_TRUE:
- ps_push_bool(st, 1);
- break;
- case PS_OP_TRUNCATE:
- if (!ps_is_type(st, PS_INT)) {
- r1 = ps_pop_real(st);
- ps_push_real(st, (r1 >= 0) ? floorf(r1) : ceilf(r1));
- }
- break;
- case PS_OP_XOR:
- if (ps_is_type2(st, PS_BOOL)) {
- b2 = ps_pop_bool(st);
- b1 = ps_pop_bool(st);
- ps_push_bool(st, b1 ^ b2);
- }
- else {
- i2 = ps_pop_int(st);
- i1 = ps_pop_int(st);
- ps_push_int(st, i1 ^ i2);
- }
- break;
- case PS_OP_IF:
- b1 = ps_pop_bool(st);
- if (b1)
- ps_run(ctx, code, st, code[pc + 1].u.block);
- pc = code[pc + 2].u.block;
- break;
- case PS_OP_IFELSE:
- b1 = ps_pop_bool(st);
- if (b1)
- ps_run(ctx, code, st, code[pc + 1].u.block);
- else
- ps_run(ctx, code, st, code[pc + 0].u.block);
- pc = code[pc + 2].u.block;
- break;
- case PS_OP_RETURN:
- return;
- default:
- fz_warn(ctx, "foreign operator in calculator function");
- return;
- }
- break;
- default:
- fz_warn(ctx, "foreign object in calculator function");
- return;
- }
- }
- }
- static void
- resize_code(fz_context *ctx, pdf_function *func, int newsize)
- {
- if (newsize >= func->u.p.cap)
- {
- int new_cap = func->u.p.cap + 64;
- func->u.p.code = fz_resize_array(ctx, func->u.p.code, new_cap, sizeof(psobj));
- func->u.p.cap = new_cap;
- }
- }
- static void
- parse_code(pdf_function *func, fz_stream *stream, int *codeptr, pdf_lexbuf *buf)
- {
- pdf_token tok;
- int opptr, elseptr, ifptr;
- int a, b, mid, cmp;
- fz_context *ctx = stream->ctx;
- while (1)
- {
- tok = pdf_lex(stream, buf);
- switch(tok)
- {
- case PDF_TOK_EOF:
- fz_throw(ctx, "truncated calculator function");
- case PDF_TOK_INT:
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_INT;
- func->u.p.code[*codeptr].u.i = buf->i;
- ++*codeptr;
- break;
- case PDF_TOK_TRUE:
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_BOOL;
- func->u.p.code[*codeptr].u.b = 1;
- ++*codeptr;
- break;
- case PDF_TOK_FALSE:
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_BOOL;
- func->u.p.code[*codeptr].u.b = 0;
- ++*codeptr;
- break;
- case PDF_TOK_REAL:
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_REAL;
- func->u.p.code[*codeptr].u.f = buf->f;
- ++*codeptr;
- break;
- case PDF_TOK_OPEN_BRACE:
- opptr = *codeptr;
- *codeptr += 4;
- resize_code(ctx, func, *codeptr);
- ifptr = *codeptr;
- parse_code(func, stream, codeptr, buf);
- tok = pdf_lex(stream, buf);
- if (tok == PDF_TOK_OPEN_BRACE)
- {
- elseptr = *codeptr;
- parse_code(func, stream, codeptr, buf);
- tok = pdf_lex(stream, buf);
- }
- else
- {
- elseptr = -1;
- }
- if (tok != PDF_TOK_KEYWORD)
- fz_throw(ctx, "missing keyword in 'if-else' context");
- if (!strcmp(buf->scratch, "if"))
- {
- if (elseptr >= 0)
- fz_throw(ctx, "too many branches for 'if'");
- func->u.p.code[opptr].type = PS_OPERATOR;
- func->u.p.code[opptr].u.op = PS_OP_IF;
- func->u.p.code[opptr+2].type = PS_BLOCK;
- func->u.p.code[opptr+2].u.block = ifptr;
- func->u.p.code[opptr+3].type = PS_BLOCK;
- func->u.p.code[opptr+3].u.block = *codeptr;
- }
- else if (!strcmp(buf->scratch, "ifelse"))
- {
- if (elseptr < 0)
- fz_throw(ctx, "not enough branches for 'ifelse'");
- func->u.p.code[opptr].type = PS_OPERATOR;
- func->u.p.code[opptr].u.op = PS_OP_IFELSE;
- func->u.p.code[opptr+1].type = PS_BLOCK;
- func->u.p.code[opptr+1].u.block = elseptr;
- func->u.p.code[opptr+2].type = PS_BLOCK;
- func->u.p.code[opptr+2].u.block = ifptr;
- func->u.p.code[opptr+3].type = PS_BLOCK;
- func->u.p.code[opptr+3].u.block = *codeptr;
- }
- else
- {
- fz_throw(ctx, "unknown keyword in 'if-else' context: '%s'", buf->scratch);
- }
- break;
- case PDF_TOK_CLOSE_BRACE:
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_OPERATOR;
- func->u.p.code[*codeptr].u.op = PS_OP_RETURN;
- ++*codeptr;
- return;
- case PDF_TOK_KEYWORD:
- cmp = -1;
- a = -1;
- b = nelem(ps_op_names);
- while (b - a > 1)
- {
- mid = (a + b) / 2;
- cmp = strcmp(buf->scratch, ps_op_names[mid]);
- if (cmp > 0)
- a = mid;
- else if (cmp < 0)
- b = mid;
- else
- a = b = mid;
- }
- if (cmp != 0)
- fz_throw(ctx, "unknown operator: '%s'", buf->scratch);
- resize_code(ctx, func, *codeptr);
- func->u.p.code[*codeptr].type = PS_OPERATOR;
- func->u.p.code[*codeptr].u.op = a;
- ++*codeptr;
- break;
- default:
- fz_throw(ctx, "calculator function syntax error");
- }
- }
- }
- static void
- load_postscript_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, int gen)
- {
- fz_stream *stream = NULL;
- int codeptr;
- pdf_lexbuf buf;
- pdf_token tok;
- fz_context *ctx = xref->ctx;
- int locked = 0;
- pdf_lexbuf_init(ctx, &buf, PDF_LEXBUF_SMALL);
- fz_var(stream);
- fz_var(locked);
- fz_try(ctx)
- {
- stream = pdf_open_stream(xref, num, gen);
- tok = pdf_lex(stream, &buf);
- if (tok != PDF_TOK_OPEN_BRACE)
- {
- fz_throw(ctx, "stream is not a calculator function");
- }
- func->u.p.code = NULL;
- func->u.p.cap = 0;
- codeptr = 0;
- parse_code(func, stream, &codeptr, &buf);
- }
- fz_always(ctx)
- {
- fz_close(stream);
- pdf_lexbuf_fin(&buf);
- }
- fz_catch(ctx)
- {
- fz_throw(ctx, "cannot parse calculator function (%d %d R)", num, gen);
- }
- func->size += func->u.p.cap * sizeof(psobj);
- }
- static void
- eval_postscript_func(fz_context *ctx, pdf_function *func, float *in, float *out)
- {
- ps_stack st;
- float x;
- int i;
- ps_init_stack(&st);
- for (i = 0; i < func->m; i++)
- {
- x = fz_clamp(in[i], func->domain[i][0], func->domain[i][1]);
- ps_push_real(&st, x);
- }
- ps_run(ctx, func->u.p.code, &st, 0);
- for (i = func->n - 1; i >= 0; i--)
- {
- x = ps_pop_real(&st);
- out[i] = fz_clamp(x, func->range[i][0], func->range[i][1]);
- }
- }
- /*
- * Sample function
- */
- #define MAX_SAMPLE_FUNCTION_SIZE (100 << 20)
- static void
- load_sample_func(pdf_function *func, pdf_document *xref, pdf_obj *dict, int num, int gen)
- {
- fz_context *ctx = xref->ctx;
- fz_stream *stream;
- pdf_obj *obj;
- int samplecount;
- int bps;
- int i;
- func->u.sa.samples = NULL;
- obj = pdf_dict_gets(dict, "Size");
- if (pdf_array_len(obj) < func->m)
- fz_throw(ctx, "too few sample function dimension sizes");
- if (pdf_array_len(obj) > func->m)
- fz_warn(ctx, "too many sample function dimension sizes");
- for (i = 0; i < func->m; i++)
- {
- func->u.sa.size[i] = pdf_to_int(pdf_array_get(obj, i));
- if (func->u.sa.size[i] <= 0)
- {
- fz_warn(ctx, "non-positive sample function dimension size");
- func->u.sa.size[i] = 1;
- }
- }
- obj = pdf_dict_gets(dict, "BitsPerSample");
- func->u.sa.bps = bps = pdf_to_int(obj);
- for (i = 0; i < func->m; i++)
- {
- func->u.sa.encode[i][0] = 0;
- func->u.sa.encode[i][1] = func->u.sa.size[i] - 1;
- }
- obj = pdf_dict_gets(dict, "Encode");
- if (pdf_is_array(obj))
- {
- int ranges = fz_mini(func->m, pdf_array_len(obj) / 2);
- if (ranges != func->m)
- fz_warn(ctx, "wrong number of sample function input mappings");
- for (i = 0; i < ranges; i++)
- {
- func->u.sa.encode[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0));
- func->u.sa.encode[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1));
- }
- }
- for (i = 0; i < func->n; i++)
- {
- func->u.sa.decode[i][0] = func->range[i][0];
- func->u.sa.decode[i][1] = func->range[i][1];
- }
- obj = pdf_dict_gets(dict, "Decode");
- if (pdf_is_array(obj))
- {
- int ranges = fz_mini(func->n, pdf_array_len(obj) / 2);
- if (ranges != func->n)
- fz_warn(ctx, "wrong number of sample function output mappings");
- for (i = 0; i < ranges; i++)
- {
- func->u.sa.decode[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0));
- func->u.sa.decode[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1));
- }
- }
- for (i = 0, samplecount = func->n; i < func->m; i++)
- samplecount *= func->u.sa.size[i];
- if (samplecount > MAX_SAMPLE_FUNCTION_SIZE)
- fz_throw(ctx, "sample function too large");
- func->u.sa.samples = fz_malloc_array(ctx, samplecount, sizeof(float));
- func->size += samplecount * sizeof(float);
- stream = pdf_open_stream(xref, num, gen);
- /* read samples */
- for (i = 0; i < samplecount; i++)
- {
- unsigned int x;
- float s;
- if (fz_is_eof_bits(stream))
- {
- fz_close(stream);
- fz_throw(ctx, "truncated sample function stream");
- }
- switch (bps)
- {
- case 1: s = fz_read_bits(stream, 1); break;
- case 2: s = fz_read_bits(stream, 2) / 3.0f; break;
- case 4: s = fz_read_bits(stream, 4) / 15.0f; break;
- case 8: s = fz_read_byte(stream) / 255.0f; break;
- case 12: s = fz_read_bits(stream, 12) / 4095.0f; break;
- case 16:
- x = fz_read_byte(stream) << 8;
- x |= fz_read_byte(stream);
- s = x / 65535.0f;
- break;
- case 24:
- x = fz_read_byte(stream) << 16;
- x |= fz_read_byte(stream) << 8;
- x |= fz_read_byte(stream);
- s = x / 16777215.0f;
- break;
- case 32:
- x = fz_read_byte(stream) << 24;
- x |= fz_read_byte(stream) << 16;
- x |= fz_read_byte(stream) << 8;
- x |= fz_read_byte(stream);
- s = x / 4294967295.0f;
- break;
- default:
- fz_close(stream);
- fz_throw(ctx, "sample stream bit depth %d unsupported", bps);
- }
- func->u.sa.samples[i] = s;
- }
- fz_close(stream);
- }
- static float
- interpolate_sample(pdf_function *func, int *scale, int *e0, int *e1, float *efrac, int dim, int idx)
- {
- float a, b;
- int idx0, idx1;
- idx0 = e0[dim] * scale[dim] + idx;
- idx1 = e1[dim] * scale[dim] + idx;
- if (dim == 0)
- {
- a = func->u.sa.samples[idx0];
- b = func->u.sa.samples[idx1];
- }
- else
- {
- a = interpolate_sample(func, scale, e0, e1, efrac, dim - 1, idx0);
- b = interpolate_sample(func, scale, e0, e1, efrac, dim - 1, idx1);
- }
- return a + (b - a) * efrac[dim];
- }
- static void
- eval_sample_func(fz_context *ctx, pdf_function *func, float *in, float *out)
- {
- int e0[MAXM], e1[MAXM], scale[MAXM];
- float efrac[MAXM];
- float x;
- int i;
- /* encode input coordinates */
- for (i = 0; i < func->m; i++)
- {
- x = fz_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 = fz_clamp(x, 0, func->u.sa.size[i] - 1);
- e0[i] = floorf(x);
- e1[i] = ceilf(x);
- efrac[i] = x - floorf(x);
- }
- scale[0] = func->n;
- for (i = 1; i < func->m; i++)
- scale[i] = scale[i - 1] * func->u.sa.size[i];
- for (i = 0; i < func->n; i++)
- {
- if (func->m == 1)
- {
- float a = func->u.sa.samples[e0[0] * func->n + i];
- float b = func->u.sa.samples[e1[0] * func->n + i];
- float ab = a + (b - a) * efrac[0];
- out[i] = lerp(ab, 0, 1, func->u.sa.decode[i][0], func->u.sa.decode[i][1]);
- out[i] = fz_clamp(out[i], func->range[i][0], func->range[i][1]);
- }
- else if (func->m == 2)
- {
- int s0 = func->n;
- int s1 = s0 * func->u.sa.size[0];
- float a = func->u.sa.samples[e0[0] * s0 + e0[1] * s1 + i];
- float b = func->u.sa.samples[e1[0] * s0 + e0[1] * s1 + i];
- float c = func->u.sa.samples[e0[0] * s0 + e1[1] * s1 + i];
- float d = func->u.sa.samples[e1[0] * s0 + e1[1] * s1 + i];
- float ab = a + (b - a) * efrac[0];
- float cd = c + (d - c) * efrac[0];
- float abcd = ab + (cd - ab) * efrac[1];
- out[i] = lerp(abcd, 0, 1, func->u.sa.decode[i][0], func->u.sa.decode[i][1]);
- out[i] = fz_clamp(out[i], func->range[i][0], func->range[i][1]);
- }
- else
- {
- float x = interpolate_sample(func, scale, e0, e1, efrac, func->m - 1, i);
- out[i] = lerp(x, 0, 1, func->u.sa.decode[i][0], func->u.sa.decode[i][1]);
- out[i] = fz_clamp(out[i], func->range[i][0], func->range[i][1]);
- }
- }
- }
- /*
- * Exponential function
- */
- static void
- load_exponential_func(fz_context *ctx, pdf_function *func, pdf_obj *dict)
- {
- pdf_obj *obj;
- int i;
- if (func->m > 1)
- fz_warn(ctx, "exponential functions have at most one input");
- func->m = 1;
- obj = pdf_dict_gets(dict, "N");
- func->u.e.n = pdf_to_real(obj);
- /* See exponential functions (PDF 1.7 section 3.9.2) */
- if (func->u.e.n != (int) func->u.e.n)
- {
- /* If N is non-integer, input values may never be negative */
- for (i = 0; i < func->m; i++)
- if (func->domain[i][0] < 0 || func->domain[i][1] < 0)
- fz_warn(ctx, "exponential function input domain includes illegal negative input values");
- }
- else if (func->u.e.n < 0)
- {
- /* if N is negative, input values may never be zero */
- for (i = 0; i < func->m; i++)
- if (func->domain[i][0] == 0 || func->domain[i][1] == 0 ||
- (func->domain[i][0] < 0 && func->domain[i][1] > 0))
- fz_warn(ctx, "exponential function input domain includes illegal input value zero");
- }
- for (i = 0; i < func->n; i++)
- {
- func->u.e.c0[i] = 0;
- func->u.e.c1[i] = 1;
- }
- obj = pdf_dict_gets(dict, "C0");
- if (pdf_is_array(obj))
- {
- int ranges = fz_mini(func->n, pdf_array_len(obj));
- if (ranges != func->n)
- fz_warn(ctx, "wrong number of C0 constants for exponential function");
- for (i = 0; i < ranges; i++)
- func->u.e.c0[i] = pdf_to_real(pdf_array_get(obj, i));
- }
- obj = pdf_dict_gets(dict, "C1");
- if (pdf_is_array(obj))
- {
- int ranges = fz_mini(func->n, pdf_array_len(obj));
- if (ranges != func->n)
- fz_warn(ctx, "wrong number of C1 constants for exponential function");
- for (i = 0; i < ranges; i++)
- func->u.e.c1[i] = pdf_to_real(pdf_array_get(obj, i));
- }
- }
- static void
- eval_exponential_func(fz_context *ctx, pdf_function *func, float in, float *out)
- {
- float x = in;
- float tmp;
- int i;
- x = fz_clamp(x, func->domain[0][0], func->domain[0][1]);
- /* Default output is zero, which is suitable for violated constraints */
- if ((func->u.e.n != (int)func->u.e.n && x < 0) || (func->u.e.n < 0 && x == 0))
- return;
- tmp = powf(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->has_range)
- out[i] = fz_clamp(out[i], func->range[i][0], func->range[i][1]);
- }
- }
- /*
- * Stitching function
- */
- static void
- load_stitching_func(pdf_function *func, pdf_document *xref, pdf_obj *dict)
- {
- fz_context *ctx = xref->ctx;
- pdf_function **funcs;
- pdf_obj *obj;
- pdf_obj *sub;
- pdf_obj *num;
- int k;
- int i;
- func->u.st.k = 0;
- if (func->m > 1)
- fz_warn(ctx, "stitching functions have at most one input");
- func->m = 1;
- obj = pdf_dict_gets(dict, "Functions");
- if (!pdf_is_array(obj))
- fz_throw(ctx, "stitching function has no input functions");
- fz_try(ctx)
- {
- pdf_obj_mark(obj);
- k = pdf_array_len(obj);
- func->u.st.funcs = fz_malloc_array(ctx, k, sizeof(pdf_function*));
- func->u.st.bounds = fz_malloc_array(ctx, k - 1, sizeof(float));
- func->u.st.encode = fz_malloc_array(ctx, k * 2, sizeof(float));
- funcs = func->u.st.funcs;
- for (i = 0; i < k; i++)
- {
- sub = pdf_array_get(obj, i);
- funcs[i] = pdf_load_function(xref, sub, 1, func->n);
- func->size += pdf_function_size(funcs[i]);
- func->u.st.k ++;
- if (funcs[i]->m != func->m)
- fz_warn(ctx, "wrong number of inputs for sub function %d", i);
- if (funcs[i]->n != func->n)
- fz_warn(ctx, "wrong number of outputs for sub function %d", i);
- }
- }
- fz_always(ctx)
- {
- pdf_obj_unmark(obj);
- }
- fz_catch(ctx)
- {
- fz_rethrow(ctx);
- }
- obj = pdf_dict_gets(dict, "Bounds");
- if (!pdf_is_array(obj))
- fz_throw(ctx, "stitching function has no bounds");
- {
- if (pdf_array_len(obj) < k - 1)
- fz_throw(ctx, "too few subfunction boundaries");
- if (pdf_array_len(obj) > k)
- fz_warn(ctx, "too many subfunction boundaries");
- for (i = 0; i < k - 1; i++)
- {
- num = pdf_array_get(obj, i);
- func->u.st.bounds[i] = pdf_to_real(num);
- if (i && func->u.st.bounds[i - 1] > func->u.st.bounds[i])
- fz_throw(ctx, "subfunction %d boundary out of range", i);
- }
- if (k > 1 && (func->domain[0][0] > func->u.st.bounds[0] ||
- func->domain[0][1] < func->u.st.bounds[k - 2]))
- fz_warn(ctx, "subfunction boundaries outside of input mapping");
- }
- for (i = 0; i < k; i++)
- {
- func->u.st.encode[i * 2 + 0] = 0;
- func->u.st.encode[i * 2 + 1] = 0;
- }
- obj = pdf_dict_gets(dict, "Encode");
- if (pdf_is_array(obj))
- {
- int ranges = fz_mini(k, pdf_array_len(obj) / 2);
- if (ranges != k)
- fz_warn(ctx, "wrong number of stitching function input mappings");
- for (i = 0; i < ranges; i++)
- {
- func->u.st.encode[i * 2 + 0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0));
- func->u.st.encode[i * 2 + 1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1));
- }
- }
- }
- static void
- eval_stitching_func(fz_context *ctx, pdf_function *func, float in, float *out)
- {
- float low, high;
- int k = func->u.st.k;
- float *bounds = func->u.st.bounds;
- int i;
- in = fz_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 * 2 + 0], func->u.st.encode[i * 2 + 1]);
- pdf_eval_function(ctx, func->u.st.funcs[i], &in, 1, out, func->n);
- }
- /*
- * Common
- */
- pdf_function *
- pdf_keep_function(fz_context *ctx, pdf_function *func)
- {
- return (pdf_function *)fz_keep_storable(ctx, &func->storable);
- }
- void
- pdf_drop_function(fz_context *ctx, pdf_function *func)
- {
- fz_drop_storable(ctx, &func->storable);
- }
- static void
- pdf_free_function_imp(fz_context *ctx, fz_storable *func_)
- {
- pdf_function *func = (pdf_function *)func_;
- int i;
- switch(func->type)
- {
- case SAMPLE:
- fz_free(ctx, func->u.sa.samples);
- break;
- case EXPONENTIAL:
- break;
- case STITCHING:
- for (i = 0; i < func->u.st.k; i++)
- pdf_drop_function(ctx, func->u.st.funcs[i]);
- fz_free(ctx, func->u.st.funcs);
- fz_free(ctx, func->u.st.bounds);
- fz_free(ctx, func->u.st.encode);
- break;
- case POSTSCRIPT:
- fz_free(ctx, func->u.p.code);
- break;
- }
- fz_free(ctx, func);
- }
- unsigned int
- pdf_function_size(pdf_function *func)
- {
- return (func ? func->size : 0);
- }
- pdf_function *
- pdf_load_function(pdf_document *xref, pdf_obj *dict, int in, int out)
- {
- fz_context *ctx = xref->ctx;
- pdf_function *func;
- pdf_obj *obj;
- int i;
- if (pdf_obj_marked(dict))
- fz_throw(ctx, "Recursion in function definition");
- if ((func = pdf_find_item(ctx, pdf_free_function_imp, dict)))
- {
- return func;
- }
- func = fz_malloc_struct(ctx, pdf_function);
- FZ_INIT_STORABLE(func, 1, pdf_free_function_imp);
- func->size = sizeof(*func);
- obj = pdf_dict_gets(dict, "FunctionType");
- func->type = pdf_to_int(obj);
- /* required for all */
- obj = pdf_dict_gets(dict, "Domain");
- func->m = fz_clampi(pdf_array_len(obj) / 2, 1, MAXM);
- for (i = 0; i < func->m; i++)
- {
- func->domain[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0));
- func->domain[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1));
- }
- /* required for type0 and type4, optional otherwise */
- obj = pdf_dict_gets(dict, "Range");
- if (pdf_is_array(obj))
- {
- func->has_range = 1;
- func->n = fz_clampi(pdf_array_len(obj) / 2, 1, MAXN);
- for (i = 0; i < func->n; i++)
- {
- func->range[i][0] = pdf_to_real(pdf_array_get(obj, i * 2 + 0));
- func->range[i][1] = pdf_to_real(pdf_array_get(obj, i * 2 + 1));
- }
- }
- else
- {
- func->has_range = 0;
- func->n = out;
- }
- if (func->m != in)
- fz_warn(ctx, "wrong number of function inputs");
- if (func->n != out)
- fz_warn(ctx, "wrong number of function outputs");
- fz_try(ctx)
- {
- switch(func->type)
- {
- case SAMPLE:
- load_sample_func(func, xref, dict, pdf_to_num(dict), pdf_to_gen(dict));
- break;
- case EXPONENTIAL:
- load_exponential_func(ctx, func, dict);
- break;
- case STITCHING:
- load_stitching_func(func, xref, dict);
- break;
- case POSTSCRIPT:
- load_postscript_func(func, xref, dict, pdf_to_num(dict), pdf_to_gen(dict));
- break;
- default:
- fz_free(ctx, func);
- fz_throw(ctx, "unknown function type (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict));
- }
- pdf_store_item(ctx, dict, func, func->size);
- }
- fz_catch(ctx)
- {
- int type = func->type;
- pdf_drop_function(ctx, func);
- fz_throw(ctx, "cannot load %s function (%d %d R)",
- type == SAMPLE ? "sampled" :
- type == EXPONENTIAL ? "exponential" :
- type == STITCHING ? "stitching" :
- type == POSTSCRIPT ? "calculator" :
- "unknown",
- pdf_to_num(dict), pdf_to_gen(dict));
- }
- return func;
- }
- void
- pdf_eval_function(fz_context *ctx, pdf_function *func, float *in_, int inlen, float *out_, int outlen)
- {
- float fakein[MAXM];
- float fakeout[MAXN];
- float *in = in_;
- float *out = out_;
- if (inlen < func->m)
- {
- in = fakein;
- memset(in, 0, sizeof(float) * func->m);
- memcpy(in, in_, sizeof(float) * inlen);
- }
- if (outlen < func->n)
- {
- out = fakeout;
- memset(out, 0, sizeof(float) * func->n);
- }
- else
- memset(out, 0, sizeof(float) * outlen);
- switch(func->type)
- {
- case SAMPLE: eval_sample_func(ctx, func, in, out); break;
- case EXPONENTIAL: eval_exponential_func(ctx, func, *in, out); break;
- case STITCHING: eval_stitching_func(ctx, func, *in, out); break;
- case POSTSCRIPT: eval_postscript_func(ctx, func, in, out); break;
- }
- if (outlen < func->n)
- memcpy(out_, out, sizeof(float) * outlen);
- }
- /*
- * Debugging prints
- */
- #ifndef NDEBUG
- static void
- pdf_debug_indent(char *prefix, int level, char *suffix)
- {
- int i;
- printf("%s", prefix);
- for (i = 0; i < level; i++)
- printf("\t");
- printf("%s", suffix);
- }
- static void
- pdf_debug_ps_func_code(psobj *funccode, psobj *code, int level)
- {
- int eof, wasop;
- pdf_debug_indent("", level, "{");
- /* Print empty blocks as { }, instead of separating braces on different lines. */
- if (code->type == PS_OPERATOR && code->u.op == PS_OP_RETURN)
- {
- printf(" } ");
- return;
- }
- pdf_debug_indent("\n", ++level, "");
- eof = 0;
- wasop = 0;
- while (!eof)
- {
- switch (code->type)
- {
- case PS_INT:
- if (wasop)
- pdf_debug_indent("\n", level, "");
- printf("%d ", code->u.i);
- wasop = 0;
- code++;
- break;
- case PS_REAL:
- if (wasop)
- pdf_debug_indent("\n", level, "");
- printf("%g ", code->u.f);
- wasop = 0;
- code++;
- break;
- case PS_OPERATOR:
- if (code->u.op == PS_OP_RETURN)
- {
- printf("\n");
- eof = 1;
- }
- else if (code->u.op == PS_OP_IF)
- {
- printf("\n");
- pdf_debug_ps_func_code(funccode, &funccode[(code + 2)->u.block], level);
- printf("%s", ps_op_names[code->u.op]);
- code = &funccode[(code + 3)->u.block];
- if (code->type != PS_OPERATOR || code->u.op != PS_OP_RETURN)
- pdf_debug_indent("\n", level, "");
- wasop = 0;
- }
- else if (code->u.op == PS_OP_IFELSE)
- {
- printf("\n");
- pdf_debug_ps_func_code(funccode, &funccode[(code + 2)->u.block], level);
- printf("\n");
- pdf_debug_ps_func_code(funccode, &funccode[(code + 1)->u.block], level);
- printf("%s", ps_op_names[code->u.op]);
- code = &funccode[(code + 3)->u.block];
- if (code->type != PS_OPERATOR || code->u.op != PS_OP_RETURN)
- pdf_debug_indent("\n", level, "");
- wasop = 0;
- }
- else
- {
- printf("%s ", ps_op_names[code->u.op]);
- code++;
- wasop = 1;
- }
- break;
- }
- }
- pdf_debug_indent("", --level, "} ");
- }
- static void
- pdf_debug_function_imp(pdf_function *func, int level)
- {
- int i;
- pdf_debug_indent("", level, "function {\n");
- pdf_debug_indent("", ++level, "");
- switch (func->type)
- {
- case SAMPLE:
- printf("sampled");
- break;
- case EXPONENTIAL:
- printf("exponential");
- break;
- case STITCHING:
- printf("stitching");
- break;
- case POSTSCRIPT:
- printf("postscript");
- break;
- }
- pdf_debug_indent("\n", level, "");
- printf("%d input -> %d output\n", func->m, func->n);
- pdf_debug_indent("", level, "domain ");
- for (i = 0; i < func->m; i++)
- printf("%g %g ", func->domain[i][0], func->domain[i][1]);
- printf("\n");
- if (func->has_range)
- {
- pdf_debug_indent("", level, "range ");
- for (i = 0; i < func->n; i++)
- printf("%g %g ", func->range[i][0], func->range[i][1]);
- printf("\n");
- }
- switch (func->type)
- {
- case SAMPLE:
- pdf_debug_indent("", level, "");
- printf("bps: %d\n", func->u.sa.bps);
- pdf_debug_indent("", level, "");
- printf("size: [ ");
- for (i = 0; i < func->m; i++)
- printf("%d ", func->u.sa.size[i]);
- printf("]\n");
- pdf_debug_indent("", level, "");
- printf("encode: [ ");
- for (i = 0; i < func->m; i++)
- printf("%g %g ", func->u.sa.encode[i][0], func->u.sa.encode[i][1]);
- printf("]\n");
- pdf_debug_indent("", level, "");
- printf("decode: [ ");
- for (i = 0; i < func->m; i++)
- printf("%g %g ", func->u.sa.decode[i][0], func->u.sa.decode[i][1]);
- printf("]\n");
- break;
- case EXPONENTIAL:
- pdf_debug_indent("", level, "");
- printf("n: %g\n", func->u.e.n);
- pdf_debug_indent("", level, "");
- printf("c0: [ ");
- for (i = 0; i < func->n; i++)
- printf("%g ", func->u.e.c0[i]);
- printf("]\n");
- pdf_debug_indent("", level, "");
- printf("c1: [ ");
- for (i = 0; i < func->n; i++)
- printf("%g ", func->u.e.c1[i]);
- printf("]\n");
- break;
- case STITCHING:
- pdf_debug_indent("", level, "");
- printf("%d functions\n", func->u.st.k);
- pdf_debug_indent("", level, "");
- printf("bounds: [ ");
- for (i = 0; i < func->u.st.k - 1; i++)
- printf("%g ", func->u.st.bounds[i]);
- printf("]\n");
- pdf_debug_indent("", level, "");
- printf("encode: [ ");
- for (i = 0; i < func->u.st.k * 2; i++)
- printf("%g ", func->u.st.encode[i]);
- printf("]\n");
- for (i = 0; i < func->u.st.k; i++)
- pdf_debug_function_imp(func->u.st.funcs[i], level);
- break;
- case POSTSCRIPT:
- pdf_debug_ps_func_code(func->u.p.code, func->u.p.code, level);
- printf("\n");
- break;
- }
- pdf_debug_indent("", --level, "}\n");
- }
- void
- pdf_debug_function(pdf_function *func)
- {
- pdf_debug_function_imp(func, 0);
- }
- #endif
|