filters

Function.cc

00001 //========================================================================
00002 //
00003 // Function.cc
00004 //
00005 // Copyright 2001-2002 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <ctype.h>
00018 #include <math.h>
00019 #include "gmem.h"
00020 #include "Object.h"
00021 #include "Dict.h"
00022 #include "Stream.h"
00023 #include "Error.h"
00024 #include "Function.h"
00025 
00026 //------------------------------------------------------------------------
00027 // Function
00028 //------------------------------------------------------------------------
00029 
00030 Function::Function() {
00031 }
00032 
00033 Function::~Function() {
00034 }
00035 
00036 Function *Function::parse(Object *funcObj) {
00037   Function *func;
00038   Dict *dict;
00039   int funcType;
00040   Object obj1;
00041 
00042   if (funcObj->isStream()) {
00043     dict = funcObj->streamGetDict();
00044   } else if (funcObj->isDict()) {
00045     dict = funcObj->getDict();
00046   } else if (funcObj->isName("Identity")) {
00047     return new IdentityFunction();
00048   } else {
00049     error(-1, "Expected function dictionary or stream");
00050     return NULL;
00051   }
00052 
00053   if (!dict->lookup("FunctionType", &obj1)->isInt()) {
00054     error(-1, "Function type is missing or wrong type");
00055     obj1.free();
00056     return NULL;
00057   }
00058   funcType = obj1.getInt();
00059   obj1.free();
00060 
00061   if (funcType == 0) {
00062     func = new SampledFunction(funcObj, dict);
00063   } else if (funcType == 2) {
00064     func = new ExponentialFunction(funcObj, dict);
00065   } else if (funcType == 3) {
00066     func = new StitchingFunction(funcObj, dict);
00067   } else if (funcType == 4) {
00068     func = new PostScriptFunction(funcObj, dict);
00069   } else {
00070     error(-1, "Unimplemented function type (%d)", funcType);
00071     return NULL;
00072   }
00073   if (!func->isOk()) {
00074     delete func;
00075     return NULL;
00076   }
00077 
00078   return func;
00079 }
00080 
00081 GBool Function::init(Dict *dict) {
00082   Object obj1, obj2;
00083   int i;
00084 
00085   //----- Domain
00086   if (!dict->lookup("Domain", &obj1)->isArray()) {
00087     error(-1, "Function is missing domain");
00088     goto err2;
00089   }
00090   m = obj1.arrayGetLength() / 2;
00091   if (m > funcMaxInputs) {
00092     error(-1, "Functions with more than %d inputs are unsupported",
00093       funcMaxInputs);
00094     goto err2;
00095   }
00096   for (i = 0; i < m; ++i) {
00097     obj1.arrayGet(2*i, &obj2);
00098     if (!obj2.isNum()) {
00099       error(-1, "Illegal value in function domain array");
00100       goto err1;
00101     }
00102     domain[i][0] = obj2.getNum();
00103     obj2.free();
00104     obj1.arrayGet(2*i+1, &obj2);
00105     if (!obj2.isNum()) {
00106       error(-1, "Illegal value in function domain array");
00107       goto err1;
00108     }
00109     domain[i][1] = obj2.getNum();
00110     obj2.free();
00111   }
00112   obj1.free();
00113 
00114   //----- Range
00115   hasRange = gFalse;
00116   n = 0;
00117   if (dict->lookup("Range", &obj1)->isArray()) {
00118     hasRange = gTrue;
00119     n = obj1.arrayGetLength() / 2;
00120     if (n > funcMaxOutputs) {
00121       error(-1, "Functions with more than %d outputs are unsupported",
00122         funcMaxOutputs);
00123       goto err2;
00124     }
00125     for (i = 0; i < n; ++i) {
00126       obj1.arrayGet(2*i, &obj2);
00127       if (!obj2.isNum()) {
00128     error(-1, "Illegal value in function range array");
00129     goto err1;
00130       }
00131       range[i][0] = obj2.getNum();
00132       obj2.free();
00133       obj1.arrayGet(2*i+1, &obj2);
00134       if (!obj2.isNum()) {
00135     error(-1, "Illegal value in function range array");
00136     goto err1;
00137       }
00138       range[i][1] = obj2.getNum();
00139       obj2.free();
00140     }
00141   }
00142   obj1.free();
00143 
00144   return gTrue;
00145 
00146  err1:
00147   obj2.free();
00148  err2:
00149   obj1.free();
00150   return gFalse;
00151 }
00152 
00153 //------------------------------------------------------------------------
00154 // IdentityFunction
00155 //------------------------------------------------------------------------
00156 
00157 IdentityFunction::IdentityFunction() {
00158   int i;
00159 
00160   // fill these in with arbitrary values just in case they get used
00161   // somewhere
00162   m = funcMaxInputs;
00163   n = funcMaxOutputs;
00164   for (i = 0; i < funcMaxInputs; ++i) {
00165     domain[i][0] = 0;
00166     domain[i][1] = 1;
00167   }
00168   hasRange = gFalse;
00169 }
00170 
00171 IdentityFunction::~IdentityFunction() {
00172 }
00173 
00174 void IdentityFunction::transform(const double *in, double *out) const {
00175   int i;
00176 
00177   for (i = 0; i < funcMaxOutputs; ++i) {
00178     out[i] = in[i];
00179   }
00180 }
00181 
00182 //------------------------------------------------------------------------
00183 // SampledFunction
00184 //------------------------------------------------------------------------
00185 
00186 SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
00187   Stream *str;
00188   int nSamples, sampleBits;
00189   double sampleMul;
00190   Object obj1, obj2;
00191   Guint buf, bitMask;
00192   int bits;
00193   int s;
00194   int i;
00195 
00196   samples = NULL;
00197   ok = gFalse;
00198 
00199   //----- initialize the generic stuff
00200   if (!init(dict)) {
00201     goto err1;
00202   }
00203   if (!hasRange) {
00204     error(-1, "Type 0 function is missing range");
00205     goto err1;
00206   }
00207 
00208   //----- get the stream
00209   if (!funcObj->isStream()) {
00210     error(-1, "Type 0 function isn't a stream");
00211     goto err1;
00212   }
00213   str = funcObj->getStream();
00214 
00215   //----- Size
00216   if (!dict->lookup("Size", &obj1)->isArray() ||
00217       obj1.arrayGetLength() != m) {
00218     error(-1, "Function has missing or invalid size array");
00219     goto err2;
00220   }
00221   for (i = 0; i < m; ++i) {
00222     obj1.arrayGet(i, &obj2);
00223     if (!obj2.isInt()) {
00224       error(-1, "Illegal value in function size array");
00225       goto err3;
00226     }
00227     sampleSize[i] = obj2.getInt();
00228     obj2.free();
00229   }
00230   obj1.free();
00231 
00232   //----- BitsPerSample
00233   if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
00234     error(-1, "Function has missing or invalid BitsPerSample");
00235     goto err2;
00236   }
00237   sampleBits = obj1.getInt();
00238   sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
00239   obj1.free();
00240 
00241   //----- Encode
00242   if (dict->lookup("Encode", &obj1)->isArray() &&
00243       obj1.arrayGetLength() == 2*m) {
00244     for (i = 0; i < m; ++i) {
00245       obj1.arrayGet(2*i, &obj2);
00246       if (!obj2.isNum()) {
00247     error(-1, "Illegal value in function encode array");
00248     goto err3;
00249       }
00250       encode[i][0] = obj2.getNum();
00251       obj2.free();
00252       obj1.arrayGet(2*i+1, &obj2);
00253       if (!obj2.isNum()) {
00254     error(-1, "Illegal value in function encode array");
00255     goto err3;
00256       }
00257       encode[i][1] = obj2.getNum();
00258       obj2.free();
00259     }
00260   } else {
00261     for (i = 0; i < m; ++i) {
00262       encode[i][0] = 0;
00263       encode[i][1] = sampleSize[i] - 1;
00264     }
00265   }
00266   obj1.free();
00267 
00268   //----- Decode
00269   if (dict->lookup("Decode", &obj1)->isArray() &&
00270       obj1.arrayGetLength() == 2*n) {
00271     for (i = 0; i < n; ++i) {
00272       obj1.arrayGet(2*i, &obj2);
00273       if (!obj2.isNum()) {
00274     error(-1, "Illegal value in function decode array");
00275     goto err3;
00276       }
00277       decode[i][0] = obj2.getNum();
00278       obj2.free();
00279       obj1.arrayGet(2*i+1, &obj2);
00280       if (!obj2.isNum()) {
00281     error(-1, "Illegal value in function decode array");
00282     goto err3;
00283       }
00284       decode[i][1] = obj2.getNum();
00285       obj2.free();
00286     }
00287   } else {
00288     for (i = 0; i < n; ++i) {
00289       decode[i][0] = range[i][0];
00290       decode[i][1] = range[i][1];
00291     }
00292   }
00293   obj1.free();
00294 
00295   //----- samples
00296   nSamples = n;
00297   for (i = 0; i < m; ++i)
00298     nSamples *= sampleSize[i];
00299   samples = (double *)gmalloc(nSamples * sizeof(double));
00300   buf = 0;
00301   bits = 0;
00302   bitMask = (1 << sampleBits) - 1;
00303   str->reset();
00304   for (i = 0; i < nSamples; ++i) {
00305     if (sampleBits == 8) {
00306       s = str->getChar();
00307     } else if (sampleBits == 16) {
00308       s = str->getChar();
00309       s = (s << 8) + str->getChar();
00310     } else if (sampleBits == 32) {
00311       s = str->getChar();
00312       s = (s << 8) + str->getChar();
00313       s = (s << 8) + str->getChar();
00314       s = (s << 8) + str->getChar();
00315     } else {
00316       while (bits < sampleBits) {
00317     buf = (buf << 8) | (str->getChar() & 0xff);
00318     bits += 8;
00319       }
00320       s = (buf >> (bits - sampleBits)) & bitMask;
00321       bits -= sampleBits;
00322     }
00323     samples[i] = (double)s * sampleMul;
00324   }
00325   str->close();
00326 
00327   ok = gTrue;
00328   return;
00329 
00330  err3:
00331   obj2.free();
00332  err2:
00333   obj1.free();
00334  err1:
00335   return;
00336 }
00337 
00338 SampledFunction::~SampledFunction() {
00339   if (samples) {
00340     gfree(samples);
00341   }
00342 }
00343 
00344 SampledFunction::SampledFunction(const SampledFunction *func) {
00345   int nSamples, i;
00346 
00347   memcpy(this, func, sizeof(SampledFunction));
00348 
00349   nSamples = n;
00350   for (i = 0; i < m; ++i) {
00351     nSamples *= sampleSize[i];
00352   }
00353   samples = (double *)gmalloc(nSamples * sizeof(double));
00354   memcpy(samples, func->samples, nSamples * sizeof(double));
00355 }
00356 
00357 void SampledFunction::transform(const double *in, double *out) const {
00358   double x;
00359   int e[2][funcMaxInputs];
00360   double efrac[funcMaxInputs];
00361   double s0[1 << funcMaxInputs], s1[1 << funcMaxInputs];
00362   int i, j, k, idx;
00363 
00364   // map input values into sample array
00365   for (i = 0; i < m; ++i) {
00366     x = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
00367         (encode[i][1] - encode[i][0]) + encode[i][0];
00368     if (x < 0) {
00369       x = 0;
00370     } else if (x > sampleSize[i] - 1) {
00371       x = sampleSize[i] - 1;
00372     }
00373     e[0][i] = (int)floor(x);
00374     e[1][i] = (int)ceil(x);
00375     efrac[i] = x - e[0][i];
00376   }
00377 
00378   // for each output, do m-linear interpolation
00379   for (i = 0; i < n; ++i) {
00380 
00381     // pull 2^m values out of the sample array
00382     for (j = 0; j < (1<<m); ++j) {
00383       idx = e[j & 1][m - 1];
00384       for (k = m - 2; k >= 0; --k) {
00385     idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
00386       }
00387       idx = idx * n + i;
00388       s0[j] = samples[idx];
00389     }
00390 
00391     // do m sets of interpolations
00392     for (j = 0; j < m; ++j) {
00393       for (k = 0; k < (1 << (m - j)); k += 2) {
00394     s1[k >> 1] = (1 - efrac[j]) * s0[k] + efrac[j] * s0[k+1];
00395       }
00396       memcpy(s0, s1, (1 << (m - j - 1)) * sizeof(double));
00397     }
00398 
00399     // map output value to range
00400     out[i] = s0[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
00401     if (out[i] < range[i][0]) {
00402       out[i] = range[i][0];
00403     } else if (out[i] > range[i][1]) {
00404       out[i] = range[i][1];
00405     }
00406   }
00407 }
00408 
00409 //------------------------------------------------------------------------
00410 // ExponentialFunction
00411 //------------------------------------------------------------------------
00412 
00413 ExponentialFunction::ExponentialFunction(Object */*funcObj*/, Dict *dict) {
00414   Object obj1, obj2;
00415   GBool hasN;
00416   int i;
00417 
00418   ok = gFalse;
00419 
00420   //----- initialize the generic stuff
00421   if (!init(dict)) {
00422     goto err1;
00423   }
00424   if (m != 1) {
00425     error(-1, "Exponential function with more than one input");
00426     goto err1;
00427   }
00428   hasN = hasRange;
00429 
00430   //----- default values
00431   for (i = 0; i < funcMaxOutputs; ++i) {
00432     c0[i] = 0;
00433     c1[i] = 1;
00434   }
00435 
00436   //----- C0
00437   if (dict->lookup("C0", &obj1)->isArray()) {
00438     if (!hasN) {
00439       n = obj1.arrayGetLength();
00440       hasN = gTrue;
00441     } else if (obj1.arrayGetLength() != n) {
00442       error(-1, "Function's C0 array is wrong length");
00443       goto err2;
00444     }
00445     for (i = 0; i < n; ++i) {
00446       obj1.arrayGet(i, &obj2);
00447       if (!obj2.isNum()) {
00448     error(-1, "Illegal value in function C0 array");
00449     goto err3;
00450       }
00451       c0[i] = obj2.getNum();
00452       obj2.free();
00453     }
00454   }
00455   obj1.free();
00456 
00457   //----- C1
00458   if (dict->lookup("C1", &obj1)->isArray()) {
00459     if (!hasN) {
00460       n = obj1.arrayGetLength();
00461       hasN = gTrue;
00462     } else if (obj1.arrayGetLength() != n) {
00463       error(-1, "Function's C1 array is wrong length");
00464       goto err2;
00465     }
00466     for (i = 0; i < n; ++i) {
00467       obj1.arrayGet(i, &obj2);
00468       if (!obj2.isNum()) {
00469     error(-1, "Illegal value in function C1 array");
00470     goto err3;
00471       }
00472       c1[i] = obj2.getNum();
00473       obj2.free();
00474     }
00475   }
00476   obj1.free();
00477 
00478   //----- N (exponent)
00479   if (!dict->lookup("N", &obj1)->isNum()) {
00480     error(-1, "Function has missing or invalid N");
00481     goto err2;
00482   }
00483   e = obj1.getNum();
00484   obj1.free();
00485 
00486   // this isn't supposed to happen, but I've run into (broken) PDF
00487   // files where it does
00488   if (!hasN) {
00489     error(-1, "Exponential function does not define number of output values");
00490     n = 1;
00491   }
00492 
00493   ok = gTrue;
00494   return;
00495 
00496  err3:
00497   obj2.free();
00498  err2:
00499   obj1.free();
00500  err1:
00501   return;
00502 }
00503 
00504 ExponentialFunction::~ExponentialFunction() {
00505 }
00506 
00507 ExponentialFunction::ExponentialFunction(const ExponentialFunction *func) {
00508   memcpy(this, func, sizeof(ExponentialFunction));
00509 }
00510 
00511 void ExponentialFunction::transform(const double *in, double *out) const {
00512   double x;
00513   int i;
00514 
00515   if (in[0] < domain[0][0]) {
00516     x = domain[0][0];
00517   } else if (in[0] > domain[0][1]) {
00518     x = domain[0][1];
00519   } else {
00520     x = in[0];
00521   }
00522   for (i = 0; i < n; ++i) {
00523     out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
00524     if (hasRange) {
00525       if (out[i] < range[i][0]) {
00526     out[i] = range[i][0];
00527       } else if (out[i] > range[i][1]) {
00528     out[i] = range[i][1];
00529       }
00530     }
00531   }
00532   return;
00533 }
00534 
00535 //------------------------------------------------------------------------
00536 // StitchingFunction
00537 //------------------------------------------------------------------------
00538 
00539 StitchingFunction::StitchingFunction(Object */*funcObj*/, Dict *dict) {
00540   Object obj1, obj2;
00541   int i;
00542 
00543   ok = gFalse;
00544   funcs = NULL;
00545   bounds = NULL;
00546   encode = NULL;
00547 
00548   //----- initialize the generic stuff
00549   if (!init(dict)) {
00550     goto err1;
00551   }
00552   if (m != 1) {
00553     error(-1, "Stitching function with more than one input");
00554     goto err1;
00555   }
00556 
00557   //----- Functions
00558   if (!dict->lookup("Functions", &obj1)->isArray()) {
00559     error(-1, "Missing 'Functions' entry in stitching function");
00560     goto err1;
00561   }
00562   k = obj1.arrayGetLength();
00563   funcs = (Function **)gmalloc(k * sizeof(Function *));
00564   bounds = (double *)gmalloc((k + 1) * sizeof(double));
00565   encode = (double *)gmalloc(2 * k * sizeof(double));
00566   for (i = 0; i < k; ++i) {
00567     funcs[i] = NULL;
00568   }
00569   for (i = 0; i < k; ++i) {
00570     if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
00571       goto err2;
00572     }
00573     if (i > 0 && (funcs[i]->getInputSize() != 1 ||
00574           funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
00575       error(-1, "Incompatible subfunctions in stitching function");
00576       goto err2;
00577     }
00578     obj2.free();
00579   }
00580   obj1.free();
00581 
00582   //----- Bounds
00583   if (!dict->lookup("Bounds", &obj1)->isArray() ||
00584       obj1.arrayGetLength() != k - 1) {
00585     error(-1, "Missing or invalid 'Bounds' entry in stitching function");
00586     goto err1;
00587   }
00588   bounds[0] = domain[0][0];
00589   for (i = 1; i < k; ++i) {
00590     if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
00591       error(-1, "Invalid type in 'Bounds' array in stitching function");
00592       goto err2;
00593     }
00594     bounds[i] = obj2.getNum();
00595     obj2.free();
00596   }
00597   bounds[k] = domain[0][1];
00598   obj1.free();
00599 
00600   //----- Encode
00601   if (!dict->lookup("Encode", &obj1)->isArray() ||
00602       obj1.arrayGetLength() != 2 * k) {
00603     error(-1, "Missing or invalid 'Encode' entry in stitching function");
00604     goto err1;
00605   }
00606   for (i = 0; i < 2 * k; ++i) {
00607     if (!obj1.arrayGet(i, &obj2)->isNum()) {
00608       error(-1, "Invalid type in 'Encode' array in stitching function");
00609       goto err2;
00610     }
00611     encode[i] = obj2.getNum();
00612     obj2.free();
00613   }
00614   obj1.free();
00615 
00616   ok = gTrue;
00617   return;
00618 
00619  err2:
00620   obj2.free();
00621  err1:
00622   obj1.free();
00623 }
00624 
00625 StitchingFunction::StitchingFunction(const StitchingFunction *func) {
00626   k = func->k;
00627   funcs = (Function **)gmalloc(k * sizeof(Function *));
00628   memcpy(funcs, func->funcs, k * sizeof(Function *));
00629   bounds = (double *)gmalloc((k + 1) * sizeof(double));
00630   memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
00631   encode = (double *)gmalloc(2 * k * sizeof(double));
00632   memcpy(encode, func->encode, 2 * k * sizeof(double));
00633   ok = gTrue;
00634 }
00635 
00636 StitchingFunction::~StitchingFunction() {
00637   int i;
00638 
00639   for (i = 0; i < k; ++i) {
00640     if (funcs[i]) {
00641       delete funcs[i];
00642     }
00643   }
00644   gfree(funcs);
00645   gfree(bounds);
00646   gfree(encode);
00647 }
00648 
00649 void StitchingFunction::transform(const double *in, double *out) const {
00650   double x;
00651   int i;
00652 
00653   if (in[0] < domain[0][0]) {
00654     x = domain[0][0];
00655   } else if (in[0] > domain[0][1]) {
00656     x = domain[0][1];
00657   } else {
00658     x = in[0];
00659   }
00660   for (i = 0; i < k - 1; ++i) {
00661     if (x < bounds[i+1]) {
00662       break;
00663     }
00664   }
00665   x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) *
00666                     (encode[2*i+1] - encode[2*i]);
00667   funcs[i]->transform(&x, out);
00668 }
00669 
00670 //------------------------------------------------------------------------
00671 // PostScriptFunction
00672 //------------------------------------------------------------------------
00673 
00674 enum PSOp {
00675   psOpAbs,
00676   psOpAdd,
00677   psOpAnd,
00678   psOpAtan,
00679   psOpBitshift,
00680   psOpCeiling,
00681   psOpCopy,
00682   psOpCos,
00683   psOpCvi,
00684   psOpCvr,
00685   psOpDiv,
00686   psOpDup,
00687   psOpEq,
00688   psOpExch,
00689   psOpExp,
00690   psOpFalse,
00691   psOpFloor,
00692   psOpGe,
00693   psOpGt,
00694   psOpIdiv,
00695   psOpIndex,
00696   psOpLe,
00697   psOpLn,
00698   psOpLog,
00699   psOpLt,
00700   psOpMod,
00701   psOpMul,
00702   psOpNe,
00703   psOpNeg,
00704   psOpNot,
00705   psOpOr,
00706   psOpPop,
00707   psOpRoll,
00708   psOpRound,
00709   psOpSin,
00710   psOpSqrt,
00711   psOpSub,
00712   psOpTrue,
00713   psOpTruncate,
00714   psOpXor,
00715   psOpIf,
00716   psOpIfelse,
00717   psOpReturn
00718 };
00719 
00720 // Note: 'if' and 'ifelse' are parsed separately.
00721 // The rest are listed here in alphabetical order.
00722 // The index in this table is equivalent to the entry in PSOp.
00723 const char *psOpNames[] = {
00724   "abs",
00725   "add",
00726   "and",
00727   "atan",
00728   "bitshift",
00729   "ceiling",
00730   "copy",
00731   "cos",
00732   "cvi",
00733   "cvr",
00734   "div",
00735   "dup",
00736   "eq",
00737   "exch",
00738   "exp",
00739   "false",
00740   "floor",
00741   "ge",
00742   "gt",
00743   "idiv",
00744   "index",
00745   "le",
00746   "ln",
00747   "log",
00748   "lt",
00749   "mod",
00750   "mul",
00751   "ne",
00752   "neg",
00753   "not",
00754   "or",
00755   "pop",
00756   "roll",
00757   "round",
00758   "sin",
00759   "sqrt",
00760   "sub",
00761   "true",
00762   "truncate",
00763   "xor"
00764 };
00765 
00766 #define nPSOps (sizeof(psOpNames) / sizeof(char *))
00767 
00768 enum PSObjectType {
00769   psBool,
00770   psInt,
00771   psReal,
00772   psOperator,
00773   psBlock
00774 };
00775 
00776 // In the code array, 'if'/'ifelse' operators take up three slots
00777 // plus space for the code in the subclause(s).
00778 //
00779 //         +---------------------------------+
00780 //         | psOperator: psOpIf / psOpIfelse |
00781 //         +---------------------------------+
00782 //         | psBlock: ptr=<A>                |
00783 //         +---------------------------------+
00784 //         | psBlock: ptr=<B>                |
00785 //         +---------------------------------+
00786 //         | if clause                       |
00787 //         | ...                             |
00788 //         | psOperator: psOpReturn          |
00789 //         +---------------------------------+
00790 //     <A> | else clause                     |
00791 //         | ...                             |
00792 //         | psOperator: psOpReturn          |
00793 //         +---------------------------------+
00794 //     <B> | ...                             |
00795 //
00796 // For 'if', pointer <A> is present in the code stream but unused.
00797 
00798 struct PSObject {
00799   PSObjectType type;
00800   union {
00801     GBool booln;        // boolean (stack only)
00802     int intg;           // integer (stack and code)
00803     double real;        // real (stack and code)
00804     PSOp op;            // operator (code only)
00805     int blk;            // if/ifelse block pointer (code only)
00806   };
00807 };
00808 
00809 #define psStackSize 100
00810 
00811 class PSStack {
00812 public:
00813 
00814   PSStack() { sp = psStackSize; }
00815   void pushBool(GBool booln);
00816   void pushInt(int intg);
00817   void pushReal(double real);
00818   GBool popBool();
00819   int popInt();
00820   double popNum();
00821   GBool empty() { return sp == psStackSize; }
00822   GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
00823   GBool topTwoAreInts()
00824     { return sp < psStackSize - 1 &&
00825          stack[sp].type == psInt &&
00826              stack[sp+1].type == psInt; }
00827   GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
00828   GBool topTwoAreNums()
00829     { return sp < psStackSize - 1 &&
00830          (stack[sp].type == psInt || stack[sp].type == psReal) &&
00831          (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
00832   void copy(int n);
00833   void roll(int n, int j);
00834   void index(int i);
00835   void pop();
00836 
00837 private:
00838 
00839   GBool checkOverflow(int n = 1);
00840   GBool checkUnderflow();
00841   GBool checkType(PSObjectType t1, PSObjectType t2);
00842 
00843   PSObject stack[psStackSize];
00844   int sp;
00845 };
00846 
00847 GBool PSStack::checkOverflow(int n) {
00848   if (sp - n < 0) {
00849     error(-1, "Stack overflow in PostScript function");
00850     return gFalse;
00851   }
00852   return gTrue;
00853 }
00854 
00855 GBool PSStack::checkUnderflow() {
00856   if (sp == psStackSize) {
00857     error(-1, "Stack underflow in PostScript function");
00858     return gFalse;
00859   }
00860   return gTrue;
00861 }
00862 
00863 GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
00864   if (stack[sp].type != t1 && stack[sp].type != t2) {
00865     error(-1, "Type mismatch in PostScript function");
00866     return gFalse;
00867   }
00868   return gTrue;
00869 }
00870 
00871 void PSStack::pushBool(GBool booln) {
00872   if (checkOverflow()) {
00873     stack[--sp].type = psBool;
00874     stack[sp].booln = booln;
00875   }
00876 }
00877 
00878 void PSStack::pushInt(int intg) {
00879   if (checkOverflow()) {
00880     stack[--sp].type = psInt;
00881     stack[sp].intg = intg;
00882   }
00883 }
00884 
00885 void PSStack::pushReal(double real) {
00886   if (checkOverflow()) {
00887     stack[--sp].type = psReal;
00888     stack[sp].real = real;
00889   }
00890 }
00891 
00892 GBool PSStack::popBool() {
00893   if (checkUnderflow() && checkType(psBool, psBool)) {
00894     return stack[sp++].booln;
00895   }
00896   return gFalse;
00897 }
00898 
00899 int PSStack::popInt() {
00900   if (checkUnderflow() && checkType(psInt, psInt)) {
00901     return stack[sp++].intg;
00902   }
00903   return 0;
00904 }
00905 
00906 double PSStack::popNum() {
00907   double ret;
00908 
00909   if (checkUnderflow() && checkType(psInt, psReal)) {
00910     ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
00911     ++sp;
00912     return ret;
00913   }
00914   return 0;
00915 }
00916 
00917 void PSStack::copy(int n) {
00918   int i;
00919 
00920   if (!checkOverflow(n)) {
00921     return;
00922   }
00923   for (i = sp + n - 1; i <= sp; ++i) {
00924     stack[i - n] = stack[i];
00925   }
00926   sp -= n;
00927 }
00928 
00929 void PSStack::roll(int n, int j) {
00930   PSObject obj;
00931   int i, k;
00932 
00933   if (j >= 0) {
00934     j %= n;
00935   } else {
00936     j = -j % n;
00937     if (j != 0) {
00938       j = n - j;
00939     }
00940   }
00941   if (n <= 0 || j == 0) {
00942     return;
00943   }
00944   for (i = 0; i < j; ++i) {
00945     obj = stack[sp];
00946     for (k = sp; k < sp + n - 1; ++k) {
00947       stack[k] = stack[k+1];
00948     }
00949     stack[sp + n - 1] = obj;
00950   }
00951 }
00952 
00953 void PSStack::index(int i) {
00954   if (!checkOverflow()) {
00955     return;
00956   }
00957   --sp;
00958   stack[sp] = stack[sp + 1 + i];
00959 }
00960 
00961 void PSStack::pop() {
00962   if (!checkUnderflow()) {
00963     return;
00964   }
00965   ++sp;
00966 }
00967 
00968 PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
00969   Stream *str;
00970   int codePtr;
00971   GString *tok;
00972 
00973   code = NULL;
00974   codeSize = 0;
00975   ok = gFalse;
00976 
00977   //----- initialize the generic stuff
00978   if (!init(dict)) {
00979     goto err1;
00980   }
00981   if (!hasRange) {
00982     error(-1, "Type 4 function is missing range");
00983     goto err1;
00984   }
00985 
00986   //----- get the stream
00987   if (!funcObj->isStream()) {
00988     error(-1, "Type 4 function isn't a stream");
00989     goto err1;
00990   }
00991   str = funcObj->getStream();
00992 
00993   //----- parse the function
00994   str->reset();
00995   if (!(tok = getToken(str)) || tok->cmp("{")) {
00996     error(-1, "Expected '{' at start of PostScript function");
00997     if (tok) {
00998       delete tok;
00999     }
01000     goto err1;
01001   }
01002   delete tok;
01003   codePtr = 0;
01004   if (!parseCode(str, &codePtr)) {
01005     goto err2;
01006   }
01007   str->close();
01008 
01009   ok = gTrue;
01010 
01011  err2:
01012   str->close();
01013  err1:
01014   return;
01015 }
01016 
01017 PostScriptFunction::PostScriptFunction(const PostScriptFunction *func) {
01018   memcpy(this, func, sizeof(PostScriptFunction));
01019   code = (PSObject *)gmalloc(codeSize * sizeof(PSObject));
01020   memcpy(code, func->code, codeSize * sizeof(PSObject));
01021 }
01022 
01023 PostScriptFunction::~PostScriptFunction() {
01024   gfree(code);
01025 }
01026 
01027 void PostScriptFunction::transform(const double *in, double *out) const {
01028   PSStack *stack;
01029   int i;
01030 
01031   stack = new PSStack();
01032   for (i = 0; i < m; ++i) {
01033     //~ may need to check for integers here
01034     stack->pushReal(in[i]);
01035   }
01036   exec(stack, 0);
01037   for (i = n - 1; i >= 0; --i) {
01038     out[i] = stack->popNum();
01039     if (out[i] < range[i][0]) {
01040       out[i] = range[i][0];
01041     } else if (out[i] > range[i][1]) {
01042       out[i] = range[i][1];
01043     }
01044   }
01045   // if (!stack->empty()) {
01046   //   error(-1, "Extra values on stack at end of PostScript function");
01047   // }
01048   delete stack;
01049 }
01050 
01051 GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
01052   GString *tok;
01053   char *p;
01054   GBool isReal;
01055   int opPtr, elsePtr;
01056   int a, b, mid, cmp;
01057 
01058   while (1) {
01059     if (!(tok = getToken(str))) {
01060       error(-1, "Unexpected end of PostScript function stream");
01061       return gFalse;
01062     }
01063     p = tok->getCString();
01064     if (isdigit(*p) || *p == '.' || *p == '-') {
01065       isReal = gFalse;
01066       for (++p; *p; ++p) {
01067     if (*p == '.') {
01068       isReal = gTrue;
01069       break;
01070     }
01071       }
01072       resizeCode(*codePtr);
01073       if (isReal) {
01074     code[*codePtr].type = psReal;
01075     code[*codePtr].real = atof(tok->getCString());
01076       } else {
01077     code[*codePtr].type = psInt;
01078     code[*codePtr].intg = atoi(tok->getCString());
01079       }
01080       ++*codePtr;
01081       delete tok;
01082     } else if (!tok->cmp("{")) {
01083       delete tok;
01084       opPtr = *codePtr;
01085       *codePtr += 3;
01086       resizeCode(opPtr + 2);
01087       if (!parseCode(str, codePtr)) {
01088     return gFalse;
01089       }
01090       if (!(tok = getToken(str))) {
01091     error(-1, "Unexpected end of PostScript function stream");
01092     return gFalse;
01093       }
01094       if (!tok->cmp("{")) {
01095     elsePtr = *codePtr;
01096     if (!parseCode(str, codePtr)) {
01097       return gFalse;
01098     }
01099     delete tok;
01100     if (!(tok = getToken(str))) {
01101       error(-1, "Unexpected end of PostScript function stream");
01102       return gFalse;
01103     }
01104       } else {
01105     elsePtr = -1;
01106       }
01107       if (!tok->cmp("if")) {
01108     if (elsePtr >= 0) {
01109       error(-1, "Got 'if' operator with two blocks in PostScript function");
01110       return gFalse;
01111     }
01112     code[opPtr].type = psOperator;
01113     code[opPtr].op = psOpIf;
01114     code[opPtr+2].type = psBlock;
01115     code[opPtr+2].blk = *codePtr;
01116       } else if (!tok->cmp("ifelse")) {
01117     if (elsePtr < 0) {
01118       error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
01119       return gFalse;
01120     }
01121     code[opPtr].type = psOperator;
01122     code[opPtr].op = psOpIfelse;
01123     code[opPtr+1].type = psBlock;
01124     code[opPtr+1].blk = elsePtr;
01125     code[opPtr+2].type = psBlock;
01126     code[opPtr+2].blk = *codePtr;
01127       } else {
01128     error(-1, "Expected if/ifelse operator in PostScript function");
01129     delete tok;
01130     return gFalse;
01131       }
01132       delete tok;
01133     } else if (!tok->cmp("}")) {
01134       delete tok;
01135       resizeCode(*codePtr);
01136       code[*codePtr].type = psOperator;
01137       code[*codePtr].op = psOpReturn;
01138       ++*codePtr;
01139       break;
01140     } else {
01141       a = -1;
01142       b = nPSOps;
01143       // invariant: psOpNames[a] < tok < psOpNames[b]
01144       while (b - a > 1) {
01145     mid = (a + b) / 2;
01146     cmp = tok->cmp(psOpNames[mid]);
01147     if (cmp > 0) {
01148       a = mid;
01149     } else if (cmp < 0) {
01150       b = mid;
01151     } else {
01152       a = b = mid;
01153     }
01154       }
01155       if (cmp != 0) {
01156     error(-1, "Unknown operator '%s' in PostScript function",
01157           tok->getCString());
01158     delete tok;
01159     return gFalse;
01160       }
01161       delete tok;
01162       resizeCode(*codePtr);
01163       code[*codePtr].type = psOperator;
01164       code[*codePtr].op = (PSOp)a;
01165       ++*codePtr;
01166     }
01167   }
01168   return gTrue;
01169 }
01170 
01171 GString *PostScriptFunction::getToken(Stream *str) {
01172   GString *s;
01173   int c;
01174 
01175   s = new GString();
01176   do {
01177     c = str->getChar();
01178   } while (c != EOF && isspace(c));
01179   if (c == '{' || c == '}') {
01180     s->append((char)c);
01181   } else if (isdigit(c) || c == '.' || c == '-') {
01182     while (1) {
01183       s->append((char)c);
01184       c = str->lookChar();
01185       if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
01186     break;
01187       }
01188       str->getChar();
01189     }
01190   } else {
01191     while (1) {
01192       s->append((char)c);
01193       c = str->lookChar();
01194       if (c == EOF || !isalnum(c)) {
01195     break;
01196       }
01197       str->getChar();
01198     }
01199   }
01200   return s;
01201 }
01202 
01203 void PostScriptFunction::resizeCode(int newSize) {
01204   if (newSize >= codeSize) {
01205     codeSize += 64;
01206     code = (PSObject *)grealloc(code, codeSize * sizeof(PSObject));
01207   }
01208 }
01209 
01210 void PostScriptFunction::exec(PSStack *stack, int codePtr) const {
01211   int i1, i2;
01212   double r1, r2;
01213   GBool b1, b2;
01214 
01215   while (1) {
01216     switch (code[codePtr].type) {
01217     case psInt:
01218       stack->pushInt(code[codePtr++].intg);
01219       break;
01220     case psReal:
01221       stack->pushReal(code[codePtr++].real);
01222       break;
01223     case psOperator:
01224       switch (code[codePtr++].op) {
01225       case psOpAbs:
01226     if (stack->topIsInt()) {
01227       stack->pushInt(abs(stack->popInt()));
01228     } else {
01229       stack->pushReal(fabs(stack->popNum()));
01230     }
01231     break;
01232       case psOpAdd:
01233     if (stack->topTwoAreInts()) {
01234       i2 = stack->popInt();
01235       i1 = stack->popInt();
01236       stack->pushInt(i1 + i2);
01237     } else {
01238       r2 = stack->popNum();
01239       r1 = stack->popNum();
01240       stack->pushReal(r1 + r2);
01241     }
01242     break;
01243       case psOpAnd:
01244     if (stack->topTwoAreInts()) {
01245       i2 = stack->popInt();
01246       i1 = stack->popInt();
01247       stack->pushInt(i1 & i2);
01248     } else {
01249       b2 = stack->popBool();
01250       b1 = stack->popBool();
01251       stack->pushReal(b1 && b2);
01252     }
01253     break;
01254       case psOpAtan:
01255     r2 = stack->popNum();
01256     r1 = stack->popNum();
01257     stack->pushReal(atan2(r1, r2));
01258     break;
01259       case psOpBitshift:
01260     i2 = stack->popInt();
01261     i1 = stack->popInt();
01262     if (i2 > 0) {
01263       stack->pushInt(i1 << i2);
01264     } else if (i2 < 0) {
01265       stack->pushInt((int)((Guint)i1 >> i2));
01266     } else {
01267       stack->pushInt(i1);
01268     }
01269     break;
01270       case psOpCeiling:
01271     if (!stack->topIsInt()) {
01272       stack->pushReal(ceil(stack->popNum()));
01273     }
01274     break;
01275       case psOpCopy:
01276     stack->copy(stack->popInt());
01277     break;
01278       case psOpCos:
01279     stack->pushReal(cos(stack->popNum()));
01280     break;
01281       case psOpCvi:
01282     if (!stack->topIsInt()) {
01283       stack->pushInt((int)stack->popNum());
01284     }
01285     break;
01286       case psOpCvr:
01287     if (!stack->topIsReal()) {
01288       stack->pushReal(stack->popNum());
01289     }
01290     break;
01291       case psOpDiv:
01292     r2 = stack->popNum();
01293     r1 = stack->popNum();
01294     stack->pushReal(r1 / r2);
01295     break;
01296       case psOpDup:
01297     stack->copy(1);
01298     break;
01299       case psOpEq:
01300     if (stack->topTwoAreInts()) {
01301       i2 = stack->popInt();
01302       i1 = stack->popInt();
01303       stack->pushBool(i1 == i2);
01304     } else if (stack->topTwoAreNums()) {
01305       r2 = stack->popNum();
01306       r1 = stack->popNum();
01307       stack->pushBool(r1 == r2);
01308     } else {
01309       b2 = stack->popBool();
01310       b1 = stack->popBool();
01311       stack->pushBool(b1 == b2);
01312     }
01313     break;
01314       case psOpExch:
01315     stack->roll(2, 1);
01316     break;
01317       case psOpExp:
01318     r2 = stack->popInt();
01319     r1 = stack->popInt();
01320     stack->pushReal(pow(r1, r2));
01321     break;
01322       case psOpFalse:
01323     stack->pushBool(gFalse);
01324     break;
01325       case psOpFloor:
01326     if (!stack->topIsInt()) {
01327       stack->pushReal(floor(stack->popNum()));
01328     }
01329     break;
01330       case psOpGe:
01331     if (stack->topTwoAreInts()) {
01332       i2 = stack->popInt();
01333       i1 = stack->popInt();
01334       stack->pushBool(i1 >= i2);
01335     } else {
01336       r2 = stack->popNum();
01337       r1 = stack->popNum();
01338       stack->pushBool(r1 >= r2);
01339     }
01340     break;
01341       case psOpGt:
01342     if (stack->topTwoAreInts()) {
01343       i2 = stack->popInt();
01344       i1 = stack->popInt();
01345       stack->pushBool(i1 > i2);
01346     } else {
01347       r2 = stack->popNum();
01348       r1 = stack->popNum();
01349       stack->pushBool(r1 > r2);
01350     }
01351     break;
01352       case psOpIdiv:
01353     i2 = stack->popInt();
01354     i1 = stack->popInt();
01355     stack->pushInt(i1 / i2);
01356     break;
01357       case psOpIndex:
01358     stack->index(stack->popInt());
01359     break;
01360       case psOpLe:
01361     if (stack->topTwoAreInts()) {
01362       i2 = stack->popInt();
01363       i1 = stack->popInt();
01364       stack->pushBool(i1 <= i2);
01365     } else {
01366       r2 = stack->popNum();
01367       r1 = stack->popNum();
01368       stack->pushBool(r1 <= r2);
01369     }
01370     break;
01371       case psOpLn:
01372     stack->pushReal(log(stack->popNum()));
01373     break;
01374       case psOpLog:
01375     stack->pushReal(log10(stack->popNum()));
01376     break;
01377       case psOpLt:
01378     if (stack->topTwoAreInts()) {
01379       i2 = stack->popInt();
01380       i1 = stack->popInt();
01381       stack->pushBool(i1 < i2);
01382     } else {
01383       r2 = stack->popNum();
01384       r1 = stack->popNum();
01385       stack->pushBool(r1 < r2);
01386     }
01387     break;
01388       case psOpMod:
01389     i2 = stack->popInt();
01390     i1 = stack->popInt();
01391     stack->pushInt(i1 % i2);
01392     break;
01393       case psOpMul:
01394     if (stack->topTwoAreInts()) {
01395       i2 = stack->popInt();
01396       i1 = stack->popInt();
01397       //~ should check for out-of-range, and push a real instead
01398       stack->pushInt(i1 * i2);
01399     } else {
01400       r2 = stack->popNum();
01401       r1 = stack->popNum();
01402       stack->pushReal(r1 * r2);
01403     }
01404     break;
01405       case psOpNe:
01406     if (stack->topTwoAreInts()) {
01407       i2 = stack->popInt();
01408       i1 = stack->popInt();
01409       stack->pushBool(i1 != i2);
01410     } else if (stack->topTwoAreNums()) {
01411       r2 = stack->popNum();
01412       r1 = stack->popNum();
01413       stack->pushBool(r1 != r2);
01414     } else {
01415       b2 = stack->popBool();
01416       b1 = stack->popBool();
01417       stack->pushBool(b1 != b2);
01418     }
01419     break;
01420       case psOpNeg:
01421     if (stack->topIsInt()) {
01422       stack->pushInt(-stack->popInt());
01423     } else {
01424       stack->pushReal(-stack->popNum());
01425     }
01426     break;
01427       case psOpNot:
01428     if (stack->topIsInt()) {
01429       stack->pushInt(~stack->popInt());
01430     } else {
01431       stack->pushReal(!stack->popBool());
01432     }
01433     break;
01434       case psOpOr:
01435     if (stack->topTwoAreInts()) {
01436       i2 = stack->popInt();
01437       i1 = stack->popInt();
01438       stack->pushInt(i1 | i2);
01439     } else {
01440       b2 = stack->popBool();
01441       b1 = stack->popBool();
01442       stack->pushReal(b1 || b2);
01443     }
01444     break;
01445       case psOpPop:
01446     stack->pop();
01447     break;
01448       case psOpRoll:
01449     i2 = stack->popInt();
01450     i1 = stack->popInt();
01451     stack->roll(i1, i2);
01452     break;
01453       case psOpRound:
01454     if (!stack->topIsInt()) {
01455       r1 = stack->popNum();
01456       stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
01457     }
01458     break;
01459       case psOpSin:
01460     stack->pushReal(cos(stack->popNum()));
01461     break;
01462       case psOpSqrt:
01463     stack->pushReal(sqrt(stack->popNum()));
01464     break;
01465       case psOpSub:
01466     if (stack->topTwoAreInts()) {
01467       i2 = stack->popInt();
01468       i1 = stack->popInt();
01469       stack->pushInt(i1 - i2);
01470     } else {
01471       r2 = stack->popNum();
01472       r1 = stack->popNum();
01473       stack->pushReal(r1 - r2);
01474     }
01475     break;
01476       case psOpTrue:
01477     stack->pushBool(gTrue);
01478     break;
01479       case psOpTruncate:
01480     if (!stack->topIsInt()) {
01481       r1 = stack->popNum();
01482       stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
01483     }
01484     break;
01485       case psOpXor:
01486     if (stack->topTwoAreInts()) {
01487       i2 = stack->popInt();
01488       i1 = stack->popInt();
01489       stack->pushInt(i1 ^ i2);
01490     } else {
01491       b2 = stack->popBool();
01492       b1 = stack->popBool();
01493       stack->pushReal(b1 ^ b2);
01494     }
01495     break;
01496       case psOpIf:
01497     b1 = stack->popBool();
01498     if (b1) {
01499       exec(stack, codePtr + 2);
01500     }
01501     codePtr = code[codePtr + 1].blk;
01502     break;
01503       case psOpIfelse:
01504     b1 = stack->popBool();
01505     if (b1) {
01506       exec(stack, codePtr + 2);
01507     } else {
01508       exec(stack, code[codePtr].blk);
01509     }
01510     codePtr = code[codePtr + 1].blk;
01511     break;
01512       case psOpReturn:
01513     return;
01514       }
01515       break;
01516     default:
01517       error(-1, "Internal: bad object in PostScript function code");
01518       break;
01519     }
01520   }
01521 }
KDE Home | KDE Accessibility Home | Description of Access Keys