filters

GfxState.cc

00001 //========================================================================
00002 //
00003 // GfxState.cc
00004 //
00005 // Copyright 1996-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 <stddef.h>
00016 #include <math.h>
00017 #include <string.h> // for memcpy()
00018 #include "gmem.h"
00019 #include "Error.h"
00020 #include "Object.h"
00021 #include "Array.h"
00022 #include "Page.h"
00023 #include "GfxState.h"
00024 
00025 //------------------------------------------------------------------------
00026 
00027 static inline double clip01(double x) {
00028   return (x < 0) ? 0 : ((x > 1) ? 1 : x);
00029 }
00030 
00031 //------------------------------------------------------------------------
00032 // GfxColorSpace
00033 //------------------------------------------------------------------------
00034 
00035 GfxColorSpace::GfxColorSpace() {
00036 }
00037 
00038 GfxColorSpace::~GfxColorSpace() {
00039 }
00040 
00041 GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
00042   GfxColorSpace *cs;
00043   Object obj1;
00044 
00045   cs = NULL;
00046   if (csObj->isName()) {
00047     if (csObj->isName("DeviceGray") || csObj->isName("G")) {
00048       cs = new GfxDeviceGrayColorSpace();
00049     } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
00050       cs = new GfxDeviceRGBColorSpace();
00051     } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
00052       cs = new GfxDeviceCMYKColorSpace();
00053     } else if (csObj->isName("Pattern")) {
00054       cs = new GfxPatternColorSpace(NULL);
00055     } else {
00056       error(-1, "Bad color space '%s'", csObj->getName());
00057     }
00058   } else if (csObj->isArray()) {
00059     csObj->arrayGet(0, &obj1);
00060     if (obj1.isName("DeviceGray") || obj1.isName("G")) {
00061       cs = new GfxDeviceGrayColorSpace();
00062     } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
00063       cs = new GfxDeviceRGBColorSpace();
00064     } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
00065       cs = new GfxDeviceCMYKColorSpace();
00066     } else if (obj1.isName("CalGray")) {
00067       cs = GfxCalGrayColorSpace::parse(csObj->getArray());
00068     } else if (obj1.isName("CalRGB")) {
00069       cs = GfxCalRGBColorSpace::parse(csObj->getArray());
00070     } else if (obj1.isName("Lab")) {
00071       cs = GfxLabColorSpace::parse(csObj->getArray());
00072     } else if (obj1.isName("ICCBased")) {
00073       cs = GfxICCBasedColorSpace::parse(csObj->getArray());
00074     } else if (obj1.isName("Indexed") || obj1.isName("I")) {
00075       cs = GfxIndexedColorSpace::parse(csObj->getArray());
00076     } else if (obj1.isName("Separation")) {
00077       cs = GfxSeparationColorSpace::parse(csObj->getArray());
00078     } else if (obj1.isName("DeviceN")) {
00079       cs = GfxDeviceNColorSpace::parse(csObj->getArray());
00080     } else if (obj1.isName("Pattern")) {
00081       cs = GfxPatternColorSpace::parse(csObj->getArray());
00082     } else {
00083       error(-1, "Bad color space '%s'", csObj->getName());
00084     }
00085     obj1.free();
00086   } else {
00087     error(-1, "Bad color space - expected name or array");
00088   }
00089   return cs;
00090 }
00091 
00092 void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
00093                                      int /*maxImgPixel*/) const {
00094   int i;
00095 
00096   for (i = 0; i < getNComps(); ++i) {
00097     decodeLow[i] = 0;
00098     decodeRange[i] = 1;
00099   }
00100 }
00101 
00102 //------------------------------------------------------------------------
00103 // GfxDeviceGrayColorSpace
00104 //------------------------------------------------------------------------
00105 
00106 GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
00107 }
00108 
00109 GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
00110 }
00111 
00112 GfxColorSpace *GfxDeviceGrayColorSpace::copy() const {
00113   return new GfxDeviceGrayColorSpace();
00114 }
00115 
00116 void GfxDeviceGrayColorSpace::getGray(const GfxColor *color, double *gray) const {
00117   *gray = clip01(color->c[0]);
00118 }
00119 
00120 void GfxDeviceGrayColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00121   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
00122 }
00123 
00124 void GfxDeviceGrayColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00125   cmyk->c = cmyk->m = cmyk->y = 0;
00126   cmyk->k = clip01(1 - color->c[0]);
00127 }
00128 
00129 //------------------------------------------------------------------------
00130 // GfxCalGrayColorSpace
00131 //------------------------------------------------------------------------
00132 
00133 GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
00134   whiteX = whiteY = whiteZ = 1;
00135   blackX = blackY = blackZ = 0;
00136   gamma = 1;
00137 }
00138 
00139 GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
00140 }
00141 
00142 GfxColorSpace *GfxCalGrayColorSpace::copy() const {
00143   GfxCalGrayColorSpace *cs;
00144 
00145   cs = new GfxCalGrayColorSpace();
00146   cs->whiteX = whiteX;
00147   cs->whiteY = whiteY;
00148   cs->whiteZ = whiteZ;
00149   cs->blackX = blackX;
00150   cs->blackY = blackY;
00151   cs->blackZ = blackZ;
00152   cs->gamma = gamma;
00153   return cs;
00154 }
00155 
00156 GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
00157   GfxCalGrayColorSpace *cs;
00158   Object obj1, obj2, obj3;
00159 
00160   arr->get(1, &obj1);
00161   if (!obj1.isDict()) {
00162     error(-1, "Bad CalGray color space");
00163     obj1.free();
00164     return NULL;
00165   }
00166   cs = new GfxCalGrayColorSpace();
00167   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
00168       obj2.arrayGetLength() == 3) {
00169     obj2.arrayGet(0, &obj3);
00170     cs->whiteX = obj3.getNum();
00171     obj3.free();
00172     obj2.arrayGet(1, &obj3);
00173     cs->whiteY = obj3.getNum();
00174     obj3.free();
00175     obj2.arrayGet(2, &obj3);
00176     cs->whiteZ = obj3.getNum();
00177     obj3.free();
00178   }
00179   obj2.free();
00180   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
00181       obj2.arrayGetLength() == 3) {
00182     obj2.arrayGet(0, &obj3);
00183     cs->blackX = obj3.getNum();
00184     obj3.free();
00185     obj2.arrayGet(1, &obj3);
00186     cs->blackY = obj3.getNum();
00187     obj3.free();
00188     obj2.arrayGet(2, &obj3);
00189     cs->blackZ = obj3.getNum();
00190     obj3.free();
00191   }
00192   obj2.free();
00193   if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
00194     cs->gamma = obj2.getNum();
00195   }
00196   obj2.free();
00197   obj1.free();
00198   return cs;
00199 }
00200 
00201 void GfxCalGrayColorSpace::getGray(const GfxColor *color, double *gray) const {
00202   *gray = clip01(color->c[0]);
00203 }
00204 
00205 void GfxCalGrayColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00206   rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
00207 }
00208 
00209 void GfxCalGrayColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00210   cmyk->c = cmyk->m = cmyk->y = 0;
00211   cmyk->k = clip01(1 - color->c[0]);
00212 }
00213 
00214 //------------------------------------------------------------------------
00215 // GfxDeviceRGBColorSpace
00216 //------------------------------------------------------------------------
00217 
00218 GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
00219 }
00220 
00221 GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
00222 }
00223 
00224 GfxColorSpace *GfxDeviceRGBColorSpace::copy() const {
00225   return new GfxDeviceRGBColorSpace();
00226 }
00227 
00228 void GfxDeviceRGBColorSpace::getGray(const GfxColor *color, double *gray) const {
00229   *gray = clip01(0.299 * color->c[0] +
00230          0.587 * color->c[1] +
00231          0.114 * color->c[2]);
00232 }
00233 
00234 void GfxDeviceRGBColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00235   rgb->r = clip01(color->c[0]);
00236   rgb->g = clip01(color->c[1]);
00237   rgb->b = clip01(color->c[2]);
00238 }
00239 
00240 void GfxDeviceRGBColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00241   double c, m, y, k;
00242 
00243   c = clip01(1 - color->c[0]);
00244   m = clip01(1 - color->c[1]);
00245   y = clip01(1 - color->c[2]);
00246   k = c;
00247   if (m < k) {
00248     k = m;
00249   }
00250   if (y < k) {
00251     k = y;
00252   }
00253   cmyk->c = c - k;
00254   cmyk->m = m - k;
00255   cmyk->y = y - k;
00256   cmyk->k = k;
00257 }
00258 
00259 //------------------------------------------------------------------------
00260 // GfxCalRGBColorSpace
00261 //------------------------------------------------------------------------
00262 
00263 GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
00264   whiteX = whiteY = whiteZ = 1;
00265   blackX = blackY = blackZ = 0;
00266   gammaR = gammaG = gammaB = 1;
00267   mat[0] = 1; mat[1] = 0; mat[2] = 0;
00268   mat[3] = 0; mat[4] = 1; mat[5] = 0;
00269   mat[6] = 0; mat[7] = 0; mat[8] = 1;
00270 }
00271 
00272 GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
00273 }
00274 
00275 GfxColorSpace *GfxCalRGBColorSpace::copy() const {
00276   GfxCalRGBColorSpace *cs;
00277   int i;
00278 
00279   cs = new GfxCalRGBColorSpace();
00280   cs->whiteX = whiteX;
00281   cs->whiteY = whiteY;
00282   cs->whiteZ = whiteZ;
00283   cs->blackX = blackX;
00284   cs->blackY = blackY;
00285   cs->blackZ = blackZ;
00286   cs->gammaR = gammaR;
00287   cs->gammaG = gammaG;
00288   cs->gammaB = gammaB;
00289   for (i = 0; i < 9; ++i) {
00290     cs->mat[i] = mat[i];
00291   }
00292   return cs;
00293 }
00294 
00295 GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
00296   GfxCalRGBColorSpace *cs;
00297   Object obj1, obj2, obj3;
00298   int i;
00299 
00300   arr->get(1, &obj1);
00301   if (!obj1.isDict()) {
00302     error(-1, "Bad CalRGB color space");
00303     obj1.free();
00304     return NULL;
00305   }
00306   cs = new GfxCalRGBColorSpace();
00307   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
00308       obj2.arrayGetLength() == 3) {
00309     obj2.arrayGet(0, &obj3);
00310     cs->whiteX = obj3.getNum();
00311     obj3.free();
00312     obj2.arrayGet(1, &obj3);
00313     cs->whiteY = obj3.getNum();
00314     obj3.free();
00315     obj2.arrayGet(2, &obj3);
00316     cs->whiteZ = obj3.getNum();
00317     obj3.free();
00318   }
00319   obj2.free();
00320   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
00321       obj2.arrayGetLength() == 3) {
00322     obj2.arrayGet(0, &obj3);
00323     cs->blackX = obj3.getNum();
00324     obj3.free();
00325     obj2.arrayGet(1, &obj3);
00326     cs->blackY = obj3.getNum();
00327     obj3.free();
00328     obj2.arrayGet(2, &obj3);
00329     cs->blackZ = obj3.getNum();
00330     obj3.free();
00331   }
00332   obj2.free();
00333   if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
00334       obj2.arrayGetLength() == 3) {
00335     obj2.arrayGet(0, &obj3);
00336     cs->gammaR = obj3.getNum();
00337     obj3.free();
00338     obj2.arrayGet(1, &obj3);
00339     cs->gammaG = obj3.getNum();
00340     obj3.free();
00341     obj2.arrayGet(2, &obj3);
00342     cs->gammaB = obj3.getNum();
00343     obj3.free();
00344   }
00345   obj2.free();
00346   if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
00347       obj2.arrayGetLength() == 9) {
00348     for (i = 0; i < 9; ++i) {
00349       obj2.arrayGet(i, &obj3);
00350       cs->mat[i] = obj3.getNum();
00351       obj3.free();
00352     }
00353   }
00354   obj2.free();
00355   obj1.free();
00356   return cs;
00357 }
00358 
00359 void GfxCalRGBColorSpace::getGray(const GfxColor *color, double *gray) const {
00360   *gray = clip01(0.299 * color->c[0] +
00361          0.587 * color->c[1] +
00362          0.114 * color->c[2]);
00363 }
00364 
00365 void GfxCalRGBColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00366   rgb->r = clip01(color->c[0]);
00367   rgb->g = clip01(color->c[1]);
00368   rgb->b = clip01(color->c[2]);
00369 }
00370 
00371 void GfxCalRGBColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00372   double c, m, y, k;
00373 
00374   c = clip01(1 - color->c[0]);
00375   m = clip01(1 - color->c[1]);
00376   y = clip01(1 - color->c[2]);
00377   k = c;
00378   if (m < k) {
00379     k = m;
00380   }
00381   if (y < k) {
00382     k = y;
00383   }
00384   cmyk->c = c - k;
00385   cmyk->m = m - k;
00386   cmyk->y = y - k;
00387   cmyk->k = k;
00388 }
00389 
00390 //------------------------------------------------------------------------
00391 // GfxDeviceCMYKColorSpace
00392 //------------------------------------------------------------------------
00393 
00394 GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
00395 }
00396 
00397 GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
00398 }
00399 
00400 GfxColorSpace *GfxDeviceCMYKColorSpace::copy() const {
00401   return new GfxDeviceCMYKColorSpace();
00402 }
00403 
00404 void GfxDeviceCMYKColorSpace::getGray(const GfxColor *color, double *gray) const {
00405   *gray = clip01(1 - color->c[3]
00406          - 0.299 * color->c[0]
00407          - 0.587 * color->c[1]
00408          - 0.114 * color->c[2]);
00409 }
00410 
00411 void GfxDeviceCMYKColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00412   double c, m, y, aw, ac, am, ay, ar, ag, ab;
00413 
00414   c = clip01(color->c[0] + color->c[3]);
00415   m = clip01(color->c[1] + color->c[3]);
00416   y = clip01(color->c[2] + color->c[3]);
00417   aw = (1-c) * (1-m) * (1-y);
00418   ac = c * (1-m) * (1-y);
00419   am = (1-c) * m * (1-y);
00420   ay = (1-c) * (1-m) * y;
00421   ar = (1-c) * m * y;
00422   ag = c * (1-m) * y;
00423   ab = c * m * (1-y);
00424   rgb->r = clip01(aw + 0.9137*am + 0.9961*ay + 0.9882*ar);
00425   rgb->g = clip01(aw + 0.6196*ac + ay + 0.5176*ag);
00426   rgb->b = clip01(aw + 0.7804*ac + 0.5412*am + 0.0667*ar + 0.2118*ag +
00427           0.4863*ab);
00428 }
00429 
00430 void GfxDeviceCMYKColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00431   cmyk->c = clip01(color->c[0]);
00432   cmyk->m = clip01(color->c[1]);
00433   cmyk->y = clip01(color->c[2]);
00434   cmyk->k = clip01(color->c[3]);
00435 }
00436 
00437 //------------------------------------------------------------------------
00438 // GfxLabColorSpace
00439 //------------------------------------------------------------------------
00440 
00441 // This is the inverse of MatrixLMN in Example 4.10 from the PostScript
00442 // Language Reference, Third Edition.
00443 static double xyzrgb[3][3] = {
00444   {  3.240449, -1.537136, -0.498531 },
00445   { -0.969265,  1.876011,  0.041556 },
00446   {  0.055643, -0.204026,  1.057229 }
00447 };
00448 
00449 GfxLabColorSpace::GfxLabColorSpace() {
00450   whiteX = whiteY = whiteZ = 1;
00451   blackX = blackY = blackZ = 0;
00452   aMin = bMin = -100;
00453   aMax = bMax = 100;
00454 }
00455 
00456 GfxLabColorSpace::~GfxLabColorSpace() {
00457 }
00458 
00459 GfxColorSpace *GfxLabColorSpace::copy() const {
00460   GfxLabColorSpace *cs;
00461 
00462   cs = new GfxLabColorSpace();
00463   cs->whiteX = whiteX;
00464   cs->whiteY = whiteY;
00465   cs->whiteZ = whiteZ;
00466   cs->blackX = blackX;
00467   cs->blackY = blackY;
00468   cs->blackZ = blackZ;
00469   cs->aMin = aMin;
00470   cs->aMax = aMax;
00471   cs->bMin = bMin;
00472   cs->bMax = bMax;
00473   cs->kr = kr;
00474   cs->kg = kg;
00475   cs->kb = kb;
00476   return cs;
00477 }
00478 
00479 GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
00480   GfxLabColorSpace *cs;
00481   Object obj1, obj2, obj3;
00482 
00483   arr->get(1, &obj1);
00484   if (!obj1.isDict()) {
00485     error(-1, "Bad Lab color space");
00486     obj1.free();
00487     return NULL;
00488   }
00489   cs = new GfxLabColorSpace();
00490   if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
00491       obj2.arrayGetLength() == 3) {
00492     obj2.arrayGet(0, &obj3);
00493     cs->whiteX = obj3.getNum();
00494     obj3.free();
00495     obj2.arrayGet(1, &obj3);
00496     cs->whiteY = obj3.getNum();
00497     obj3.free();
00498     obj2.arrayGet(2, &obj3);
00499     cs->whiteZ = obj3.getNum();
00500     obj3.free();
00501   }
00502   obj2.free();
00503   if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
00504       obj2.arrayGetLength() == 3) {
00505     obj2.arrayGet(0, &obj3);
00506     cs->blackX = obj3.getNum();
00507     obj3.free();
00508     obj2.arrayGet(1, &obj3);
00509     cs->blackY = obj3.getNum();
00510     obj3.free();
00511     obj2.arrayGet(2, &obj3);
00512     cs->blackZ = obj3.getNum();
00513     obj3.free();
00514   }
00515   obj2.free();
00516   if (obj1.dictLookup("Range", &obj2)->isArray() &&
00517       obj2.arrayGetLength() == 4) {
00518     obj2.arrayGet(0, &obj3);
00519     cs->aMin = obj3.getNum();
00520     obj3.free();
00521     obj2.arrayGet(1, &obj3);
00522     cs->aMax = obj3.getNum();
00523     obj3.free();
00524     obj2.arrayGet(2, &obj3);
00525     cs->bMin = obj3.getNum();
00526     obj3.free();
00527     obj2.arrayGet(3, &obj3);
00528     cs->bMax = obj3.getNum();
00529     obj3.free();
00530   }
00531   obj2.free();
00532   obj1.free();
00533 
00534   cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
00535         xyzrgb[0][1] * cs->whiteY +
00536         xyzrgb[0][2] * cs->whiteZ);
00537   cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
00538         xyzrgb[1][1] * cs->whiteY +
00539         xyzrgb[1][2] * cs->whiteZ);
00540   cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
00541         xyzrgb[2][1] * cs->whiteY +
00542         xyzrgb[2][2] * cs->whiteZ);
00543 
00544   return cs;
00545 }
00546 
00547 void GfxLabColorSpace::getGray(const GfxColor *color, double *gray) const {
00548   GfxRGB rgb;
00549 
00550   getRGB(color, &rgb);
00551   *gray = clip01(0.299 * rgb.r +
00552          0.587 * rgb.g +
00553          0.114 * rgb.b);
00554 }
00555 
00556 void GfxLabColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00557   double X, Y, Z;
00558   double t1, t2;
00559   double r, g, b;
00560 
00561   // convert L*a*b* to CIE 1931 XYZ color space
00562   t1 = (color->c[0] + 16) / 116;
00563   t2 = t1 + color->c[1] / 500;
00564   if (t2 >= (6.0 / 29.0)) {
00565     X = t2 * t2 * t2;
00566   } else {
00567     X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
00568   }
00569   X *= whiteX;
00570   if (t1 >= (6.0 / 29.0)) {
00571     Y = t1 * t1 * t1;
00572   } else {
00573     Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
00574   }
00575   Y *= whiteY;
00576   t2 = t1 - color->c[2] / 200;
00577   if (t2 >= (6.0 / 29.0)) {
00578     Z = t2 * t2 * t2;
00579   } else {
00580     Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
00581   }
00582   Z *= whiteZ;
00583 
00584   // convert XYZ to RGB, including gamut mapping and gamma correction
00585   r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
00586   g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
00587   b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
00588   rgb->r = pow(clip01(r * kr), 0.5);
00589   rgb->g = pow(clip01(g * kg), 0.5);
00590   rgb->b = pow(clip01(b * kb), 0.5);
00591 }
00592 
00593 void GfxLabColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00594   GfxRGB rgb;
00595   double c, m, y, k;
00596 
00597   getRGB(color, &rgb);
00598   c = clip01(1 - rgb.r);
00599   m = clip01(1 - rgb.g);
00600   y = clip01(1 - rgb.b);
00601   k = c;
00602   if (m < k) {
00603     k = m;
00604   }
00605   if (y < k) {
00606     k = y;
00607   }
00608   cmyk->c = c - k;
00609   cmyk->m = m - k;
00610   cmyk->y = y - k;
00611   cmyk->k = k;
00612 }
00613 
00614 void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
00615                                         int /*maxImgPixel*/) const {
00616   decodeLow[0] = 0;
00617   decodeRange[0] = 100;
00618   decodeLow[1] = aMin;
00619   decodeRange[1] = aMax - aMin;
00620   decodeLow[2] = bMin;
00621   decodeRange[2] = bMax - bMin;
00622 }
00623 
00624 //------------------------------------------------------------------------
00625 // GfxICCBasedColorSpace
00626 //------------------------------------------------------------------------
00627 
00628 GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
00629                          const Ref *iccProfileStreamA) {
00630   nComps = nCompsA;
00631   alt = altA;
00632   iccProfileStream = *iccProfileStreamA;
00633   rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
00634   rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
00635 }
00636 
00637 GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
00638   delete alt;
00639 }
00640 
00641 GfxColorSpace *GfxICCBasedColorSpace::copy() const {
00642   GfxICCBasedColorSpace *cs;
00643   int i;
00644 
00645   cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
00646   for (i = 0; i < 4; ++i) {
00647     cs->rangeMin[i] = rangeMin[i];
00648     cs->rangeMax[i] = rangeMax[i];
00649   }
00650   return cs;
00651 }
00652 
00653 GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
00654   GfxICCBasedColorSpace *cs;
00655   Ref iccProfileStreamA;
00656   int nCompsA;
00657   GfxColorSpace *altA;
00658   Dict *dict;
00659   Object obj1, obj2, obj3;
00660   int i;
00661 
00662   arr->getNF(1, &obj1);
00663   if (obj1.isRef()) {
00664     iccProfileStreamA = obj1.getRef();
00665   } else {
00666     iccProfileStreamA.num = 0;
00667     iccProfileStreamA.gen = 0;
00668   }
00669   obj1.free();
00670   arr->get(1, &obj1);
00671   if (!obj1.isStream()) {
00672     error(-1, "Bad ICCBased color space (stream)");
00673     obj1.free();
00674     return NULL;
00675   }
00676   dict = obj1.streamGetDict();
00677   if (!dict->lookup("N", &obj2)->isInt()) {
00678     error(-1, "Bad ICCBased color space (N)");
00679     obj2.free();
00680     obj1.free();
00681     return NULL;
00682   }
00683   nCompsA = obj2.getInt();
00684   obj2.free();
00685   if (nCompsA > gfxColorMaxComps) {
00686     error(-1, "ICCBased color space with too many (%d > %d) components",
00687       nCompsA, gfxColorMaxComps);
00688     nCompsA = gfxColorMaxComps;
00689   }
00690   if (dict->lookup("Alternate", &obj2)->isNull() ||
00691       !(altA = GfxColorSpace::parse(&obj2))) {
00692     switch (nCompsA) {
00693     case 1:
00694       altA = new GfxDeviceGrayColorSpace();
00695       break;
00696     case 3:
00697       altA = new GfxDeviceRGBColorSpace();
00698       break;
00699     case 4:
00700       altA = new GfxDeviceCMYKColorSpace();
00701       break;
00702     default:
00703       error(-1, "Bad ICCBased color space - invalid N");
00704       obj2.free();
00705       obj1.free();
00706       return NULL;
00707     }
00708   }
00709   obj2.free();
00710   cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
00711   if (dict->lookup("Range", &obj2)->isArray() &&
00712       obj2.arrayGetLength() == 2 * nCompsA) {
00713     for (i = 0; i < nCompsA; ++i) {
00714       obj2.arrayGet(2*i, &obj3);
00715       cs->rangeMin[i] = obj3.getNum();
00716       obj3.free();
00717       obj2.arrayGet(2*i+1, &obj3);
00718       cs->rangeMax[i] = obj3.getNum();
00719       obj3.free();
00720     }
00721   }
00722   obj2.free();
00723   obj1.free();
00724   return cs;
00725 }
00726 
00727 void GfxICCBasedColorSpace::getGray(const GfxColor *color, double *gray) const {
00728   alt->getGray(color, gray);
00729 }
00730 
00731 void GfxICCBasedColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00732   alt->getRGB(color, rgb);
00733 }
00734 
00735 void GfxICCBasedColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00736   alt->getCMYK(color, cmyk);
00737 }
00738 
00739 void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
00740                          double *decodeRange,
00741                          int /*maxImgPixel*/) const {
00742   int i;
00743 
00744   for (i = 0; i < nComps; ++i) {
00745     decodeLow[i] = rangeMin[i];
00746     decodeRange[i] = rangeMax[i] - rangeMin[i];
00747   }
00748 }
00749 
00750 //------------------------------------------------------------------------
00751 // GfxIndexedColorSpace
00752 //------------------------------------------------------------------------
00753 
00754 GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
00755                        int indexHighA) {
00756   base = baseA;
00757   indexHigh = indexHighA;
00758   lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
00759                  sizeof(Guchar));
00760 }
00761 
00762 GfxIndexedColorSpace::~GfxIndexedColorSpace() {
00763   delete base;
00764   gfree(lookup);
00765 }
00766 
00767 GfxColorSpace *GfxIndexedColorSpace::copy() const {
00768   GfxIndexedColorSpace *cs;
00769 
00770   cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
00771   memcpy(cs->lookup, lookup,
00772      (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
00773   return cs;
00774 }
00775 
00776 GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
00777   GfxIndexedColorSpace *cs;
00778   GfxColorSpace *baseA;
00779   int indexHighA;
00780   Object obj1;
00781   int x;
00782   char *s;
00783   int n, i, j;
00784 
00785   if (arr->getLength() != 4) {
00786     error(-1, "Bad Indexed color space");
00787     goto err1;
00788   }
00789   arr->get(1, &obj1);
00790   if (!(baseA = GfxColorSpace::parse(&obj1))) {
00791     error(-1, "Bad Indexed color space (base color space)");
00792     goto err2;
00793   }
00794   obj1.free();
00795   if (!arr->get(2, &obj1)->isInt()) {
00796     error(-1, "Bad Indexed color space (hival)");
00797     goto err2;
00798   }
00799   indexHighA = obj1.getInt();
00800   obj1.free();
00801   cs = new GfxIndexedColorSpace(baseA, indexHighA);
00802   arr->get(3, &obj1);
00803   n = baseA->getNComps();
00804   if (obj1.isStream()) {
00805     obj1.streamReset();
00806     for (i = 0; i <= indexHighA; ++i) {
00807       for (j = 0; j < n; ++j) {
00808     if ((x = obj1.streamGetChar()) == EOF) {
00809       error(-1, "Bad Indexed color space (lookup table stream too short)");
00810       goto err3;
00811     }
00812     cs->lookup[i*n + j] = (Guchar)x;
00813       }
00814     }
00815     obj1.streamClose();
00816   } else if (obj1.isString()) {
00817     if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
00818       error(-1, "Bad Indexed color space (lookup table string too short)");
00819       goto err3;
00820     }
00821     s = obj1.getString()->getCString();
00822     for (i = 0; i <= indexHighA; ++i) {
00823       for (j = 0; j < n; ++j) {
00824     cs->lookup[i*n + j] = (Guchar)*s++;
00825       }
00826     }
00827   } else {
00828     error(-1, "Bad Indexed color space (lookup table)");
00829     goto err3;
00830   }
00831   obj1.free();
00832   return cs;
00833 
00834  err3:
00835   delete cs;
00836  err2:
00837   obj1.free();
00838  err1:
00839   return NULL;
00840 }
00841 
00842 void GfxIndexedColorSpace::getGray(const GfxColor *color, double *gray) const {
00843   Guchar *p;
00844   GfxColor color2;
00845   double low[gfxColorMaxComps], range[gfxColorMaxComps];
00846   int n, i;
00847 
00848   n = base->getNComps();
00849   base->getDefaultRanges(low, range, indexHigh);
00850   p = &lookup[(int)(color->c[0] + 0.5) * n];
00851   for (i = 0; i < n; ++i) {
00852     color2.c[i] = low[i] + (p[i] / 255.0) * range[i];
00853   }
00854   base->getGray(&color2, gray);
00855 }
00856 
00857 void GfxIndexedColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00858   Guchar *p;
00859   GfxColor color2;
00860   double low[gfxColorMaxComps], range[gfxColorMaxComps];
00861   int n, i;
00862 
00863   n = base->getNComps();
00864   base->getDefaultRanges(low, range, indexHigh);
00865   p = &lookup[(int)(color->c[0] + 0.5) * n];
00866   for (i = 0; i < n; ++i) {
00867     color2.c[i] = low[i] + (p[i] / 255.0) * range[i];
00868   }
00869   base->getRGB(&color2, rgb);
00870 }
00871 
00872 void GfxIndexedColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00873   Guchar *p;
00874   GfxColor color2;
00875   double low[gfxColorMaxComps], range[gfxColorMaxComps];
00876   int n, i;
00877 
00878   n = base->getNComps();
00879   base->getDefaultRanges(low, range, indexHigh);
00880   p = &lookup[(int)(color->c[0] + 0.5) * n];
00881   for (i = 0; i < n; ++i) {
00882     color2.c[i] = low[i] + (p[i] / 255.0) * range[i];
00883   }
00884   base->getCMYK(&color2, cmyk);
00885 }
00886 
00887 void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
00888                         double *decodeRange,
00889                         int maxImgPixel) const {
00890   decodeLow[0] = 0;
00891   decodeRange[0] = maxImgPixel;
00892 }
00893 
00894 //------------------------------------------------------------------------
00895 // GfxSeparationColorSpace
00896 //------------------------------------------------------------------------
00897 
00898 GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
00899                          GfxColorSpace *altA,
00900                          Function *funcA) {
00901   name = nameA;
00902   alt = altA;
00903   func = funcA;
00904 }
00905 
00906 GfxSeparationColorSpace::~GfxSeparationColorSpace() {
00907   delete name;
00908   delete alt;
00909   delete func;
00910 }
00911 
00912 GfxColorSpace *GfxSeparationColorSpace::copy() const {
00913   return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
00914 }
00915 
00916 //~ handle the 'All' and 'None' colorants
00917 GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
00918   GfxSeparationColorSpace *cs;
00919   GString *nameA;
00920   GfxColorSpace *altA;
00921   Function *funcA;
00922   Object obj1;
00923 
00924   if (arr->getLength() != 4) {
00925     error(-1, "Bad Separation color space");
00926     goto err1;
00927   }
00928   if (!arr->get(1, &obj1)->isName()) {
00929     error(-1, "Bad Separation color space (name)");
00930     goto err2;
00931   }
00932   nameA = new GString(obj1.getName());
00933   obj1.free();
00934   arr->get(2, &obj1);
00935   if (!(altA = GfxColorSpace::parse(&obj1))) {
00936     error(-1, "Bad Separation color space (alternate color space)");
00937     goto err3;
00938   }
00939   obj1.free();
00940   arr->get(3, &obj1);
00941   if (!(funcA = Function::parse(&obj1))) {
00942     goto err4;
00943   }
00944   obj1.free();
00945   cs = new GfxSeparationColorSpace(nameA, altA, funcA);
00946   return cs;
00947 
00948  err4:
00949   delete altA;
00950  err3:
00951   delete nameA;
00952  err2:
00953   obj1.free();
00954  err1:
00955   return NULL;
00956 }
00957 
00958 void GfxSeparationColorSpace::getGray(const GfxColor *color, double *gray) const {
00959   GfxColor color2;
00960 
00961   func->transform(color->c, color2.c);
00962   alt->getGray(&color2, gray);
00963 }
00964 
00965 void GfxSeparationColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
00966   GfxColor color2;
00967 
00968   func->transform(color->c, color2.c);
00969   alt->getRGB(&color2, rgb);
00970 }
00971 
00972 void GfxSeparationColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
00973   GfxColor color2;
00974 
00975   func->transform(color->c, color2.c);
00976   alt->getCMYK(&color2, cmyk);
00977 }
00978 
00979 //------------------------------------------------------------------------
00980 // GfxDeviceNColorSpace
00981 //------------------------------------------------------------------------
00982 
00983 GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
00984                        GfxColorSpace *altA,
00985                        Function *funcA) {
00986   nComps = nCompsA;
00987   alt = altA;
00988   func = funcA;
00989 }
00990 
00991 GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
00992   int i;
00993 
00994   for (i = 0; i < nComps; ++i) {
00995     delete names[i];
00996   }
00997   delete alt;
00998   delete func;
00999 }
01000 
01001 GfxColorSpace *GfxDeviceNColorSpace::copy() const {
01002   GfxDeviceNColorSpace *cs;
01003   int i;
01004 
01005   cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
01006   for (i = 0; i < nComps; ++i) {
01007     cs->names[i] = names[i]->copy();
01008   }
01009   return cs;
01010 }
01011 
01012 //~ handle the 'None' colorant
01013 GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
01014   GfxDeviceNColorSpace *cs;
01015   int nCompsA;
01016   GString *namesA[gfxColorMaxComps];
01017   GfxColorSpace *altA;
01018   Function *funcA;
01019   Object obj1, obj2;
01020   int i;
01021 
01022   if (arr->getLength() != 4 && arr->getLength() != 5) {
01023     error(-1, "Bad DeviceN color space");
01024     goto err1;
01025   }
01026   if (!arr->get(1, &obj1)->isArray()) {
01027     error(-1, "Bad DeviceN color space (names)");
01028     goto err2;
01029   }
01030   nCompsA = obj1.arrayGetLength();
01031   if (nCompsA > gfxColorMaxComps) {
01032     error(-1, "DeviceN color space with too many (%d > %d) components",
01033          nCompsA, gfxColorMaxComps);
01034     nCompsA = gfxColorMaxComps;
01035   }
01036   for (i = 0; i < nCompsA; ++i) {
01037     if (!obj1.arrayGet(i, &obj2)->isName()) {
01038       error(-1, "Bad DeviceN color space (names)");
01039       obj2.free();
01040       goto err2;
01041     }
01042     namesA[i] = new GString(obj2.getName());
01043     obj2.free();
01044   }
01045   obj1.free();
01046   arr->get(2, &obj1);
01047   if (!(altA = GfxColorSpace::parse(&obj1))) {
01048     error(-1, "Bad DeviceN color space (alternate color space)");
01049     goto err3;
01050   }
01051   obj1.free();
01052   arr->get(3, &obj1);
01053   if (!(funcA = Function::parse(&obj1))) {
01054     goto err4;
01055   }
01056   obj1.free();
01057   cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
01058   for (i = 0; i < nCompsA; ++i) {
01059     cs->names[i] = namesA[i];
01060   }
01061   return cs;
01062 
01063  err4:
01064   delete altA;
01065  err3:
01066   for (i = 0; i < nCompsA; ++i) {
01067     delete namesA[i];
01068   }
01069  err2:
01070   obj1.free();
01071  err1:
01072   return NULL;
01073 }
01074 
01075 void GfxDeviceNColorSpace::getGray(const GfxColor *color, double *gray) const {
01076   GfxColor color2;
01077 
01078   func->transform(color->c, color2.c);
01079   alt->getGray(&color2, gray);
01080 }
01081 
01082 void GfxDeviceNColorSpace::getRGB(const GfxColor *color, GfxRGB *rgb) const {
01083   GfxColor color2;
01084 
01085   func->transform(color->c, color2.c);
01086   alt->getRGB(&color2, rgb);
01087 }
01088 
01089 void GfxDeviceNColorSpace::getCMYK(const GfxColor *color, GfxCMYK *cmyk) const {
01090   GfxColor color2;
01091 
01092   func->transform(color->c, color2.c);
01093   alt->getCMYK(&color2, cmyk);
01094 }
01095 
01096 //------------------------------------------------------------------------
01097 // GfxPatternColorSpace
01098 //------------------------------------------------------------------------
01099 
01100 GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
01101   under = underA;
01102 }
01103 
01104 GfxPatternColorSpace::~GfxPatternColorSpace() {
01105   if (under) {
01106     delete under;
01107   }
01108 }
01109 
01110 GfxColorSpace *GfxPatternColorSpace::copy() const {
01111   return new GfxPatternColorSpace(under ? under->copy() :
01112                           (GfxColorSpace *)NULL);
01113 }
01114 
01115 GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
01116   GfxPatternColorSpace *cs;
01117   GfxColorSpace *underA;
01118   Object obj1;
01119 
01120   if (arr->getLength() != 1 && arr->getLength() != 2) {
01121     error(-1, "Bad Pattern color space");
01122     return NULL;
01123   }
01124   underA = NULL;
01125   if (arr->getLength() == 2) {
01126     arr->get(1, &obj1);
01127     if (!(underA = GfxColorSpace::parse(&obj1))) {
01128       error(-1, "Bad Pattern color space (underlying color space)");
01129       obj1.free();
01130       return NULL;
01131     }
01132     obj1.free();
01133   }
01134   cs = new GfxPatternColorSpace(underA);
01135   return cs;
01136 }
01137 
01138 void GfxPatternColorSpace::getGray(const GfxColor */*color*/, double *gray) const {
01139   *gray = 0;
01140 }
01141 
01142 void GfxPatternColorSpace::getRGB(const GfxColor */*color*/, GfxRGB *rgb) const {
01143   rgb->r = rgb->g = rgb->b = 0;
01144 }
01145 
01146 void GfxPatternColorSpace::getCMYK(const GfxColor */*color*/, GfxCMYK *cmyk) const {
01147   cmyk->c = cmyk->m = cmyk->y = 0;
01148   cmyk->k = 1;
01149 }
01150 
01151 //------------------------------------------------------------------------
01152 // Pattern
01153 //------------------------------------------------------------------------
01154 
01155 GfxPattern::GfxPattern(int typeA) {
01156   type = typeA;
01157 }
01158 
01159 GfxPattern::~GfxPattern() {
01160 }
01161 
01162 GfxPattern *GfxPattern::parse(Object *obj) {
01163   GfxPattern *pattern;
01164   Dict *dict;
01165   Object obj1;
01166 
01167   pattern = NULL;
01168   if (obj->isStream()) {
01169     dict = obj->streamGetDict();
01170     dict->lookup("PatternType", &obj1);
01171     if (obj1.isInt() && obj1.getInt() == 1) {
01172       pattern = new GfxTilingPattern(dict, obj);
01173     }
01174     obj1.free();
01175   }
01176   return pattern;
01177 }
01178 
01179 //------------------------------------------------------------------------
01180 // GfxTilingPattern
01181 //------------------------------------------------------------------------
01182 
01183 GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
01184   GfxPattern(1)
01185 {
01186   Object obj1, obj2;
01187   int i;
01188 
01189   if (streamDict->lookup("PaintType", &obj1)->isInt()) {
01190     paintType = obj1.getInt();
01191   } else {
01192     paintType = 1;
01193     error(-1, "Invalid or missing PaintType in pattern");
01194   }
01195   obj1.free();
01196   if (streamDict->lookup("TilingType", &obj1)->isInt()) {
01197     tilingType = obj1.getInt();
01198   } else {
01199     tilingType = 1;
01200     error(-1, "Invalid or missing TilingType in pattern");
01201   }
01202   obj1.free();
01203   bbox[0] = bbox[1] = 0;
01204   bbox[2] = bbox[3] = 1;
01205   if (streamDict->lookup("BBox", &obj1)->isArray() &&
01206       obj1.arrayGetLength() == 4) {
01207     for (i = 0; i < 4; ++i) {
01208       if (obj1.arrayGet(i, &obj2)->isNum()) {
01209     bbox[i] = obj2.getNum();
01210       }
01211       obj2.free();
01212     }
01213   } else {
01214     error(-1, "Invalid or missing BBox in pattern");
01215   }
01216   obj1.free();
01217   if (streamDict->lookup("XStep", &obj1)->isNum()) {
01218     xStep = obj1.getNum();
01219   } else {
01220     xStep = 1;
01221     error(-1, "Invalid or missing XStep in pattern");
01222   }
01223   obj1.free();
01224   if (streamDict->lookup("YStep", &obj1)->isNum()) {
01225     yStep = obj1.getNum();
01226   } else {
01227     yStep = 1;
01228     error(-1, "Invalid or missing YStep in pattern");
01229   }
01230   obj1.free();
01231   if (!streamDict->lookup("Resources", &resDict)->isDict()) {
01232     resDict.free();
01233     resDict.initNull();
01234     error(-1, "Invalid or missing Resources in pattern");
01235   }
01236   matrix[0] = 1; matrix[1] = 0;
01237   matrix[2] = 0; matrix[3] = 1;
01238   matrix[4] = 0; matrix[5] = 0;
01239   if (streamDict->lookup("Matrix", &obj1)->isArray() &&
01240       obj1.arrayGetLength() == 6) {
01241     for (i = 0; i < 6; ++i) {
01242       if (obj1.arrayGet(i, &obj2)->isNum()) {
01243     matrix[i] = obj2.getNum();
01244       }
01245       obj2.free();
01246     }
01247   }
01248   obj1.free();
01249   stream->copy(&contentStream);
01250 }
01251 
01252 GfxTilingPattern::~GfxTilingPattern() {
01253   resDict.free();
01254   contentStream.free();
01255 }
01256 
01257 GfxPattern *GfxTilingPattern::copy() {
01258   return new GfxTilingPattern(this);
01259 }
01260 
01261 GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
01262   GfxPattern(1)
01263 {
01264   memcpy(this, pat, sizeof(GfxTilingPattern));
01265   pat->resDict.copy(&resDict);
01266   pat->contentStream.copy(&contentStream);
01267 }
01268 
01269 //------------------------------------------------------------------------
01270 // GfxShading
01271 //------------------------------------------------------------------------
01272 
01273 GfxShading::GfxShading() {
01274 }
01275 
01276 GfxShading::~GfxShading() {
01277   delete colorSpace;
01278 }
01279 
01280 GfxShading *GfxShading::parse(Object *obj) {
01281   GfxShading *shading;
01282   int typeA;
01283   GfxColorSpace *colorSpaceA;
01284   GfxColor backgroundA;
01285   GBool hasBackgroundA;
01286   double xMinA, yMinA, xMaxA, yMaxA;
01287   GBool hasBBoxA;
01288   Object obj1, obj2;
01289   int i;
01290 
01291   shading = NULL;
01292   if (obj->isDict()) {
01293 
01294     if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
01295       error(-1, "Invalid ShadingType in shading dictionary");
01296       obj1.free();
01297       goto err1;
01298     }
01299     typeA = obj1.getInt();
01300     obj1.free();
01301 
01302     obj->dictLookup("ColorSpace", &obj1);
01303     if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
01304       error(-1, "Bad color space in shading dictionary");
01305       obj1.free();
01306       goto err1;
01307     }
01308     obj1.free();
01309 
01310     for (i = 0; i < gfxColorMaxComps; ++i) {
01311       backgroundA.c[i] = 0;
01312     }
01313     hasBackgroundA = gFalse;
01314     if (obj->dictLookup("Background", &obj1)->isArray()) {
01315       if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
01316     hasBackgroundA = gTrue;
01317     for (i = 0; i < colorSpaceA->getNComps(); ++i) {
01318       backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
01319       obj2.free();
01320     }
01321       } else {
01322     error(-1, "Bad Background in shading dictionary");
01323       }
01324     }
01325     obj1.free();
01326 
01327     xMinA = yMinA = xMaxA = yMaxA = 0;
01328     hasBBoxA = gFalse;
01329     if (obj->dictLookup("BBox", &obj1)->isArray()) {
01330       if (obj1.arrayGetLength() == 4) {
01331     hasBBoxA = gTrue;
01332     xMinA = obj1.arrayGet(0, &obj2)->getNum();
01333     obj2.free();
01334     yMinA = obj1.arrayGet(1, &obj2)->getNum();
01335     obj2.free();
01336     xMaxA = obj1.arrayGet(2, &obj2)->getNum();
01337     obj2.free();
01338     yMaxA = obj1.arrayGet(3, &obj2)->getNum();
01339     obj2.free();
01340       } else {
01341     error(-1, "Bad BBox in shading dictionary");
01342       }
01343     }
01344     obj1.free();
01345 
01346     switch (typeA) {
01347     case 2:
01348       shading = GfxAxialShading::parse(obj->getDict());
01349       break;
01350     case 3:
01351       shading = GfxRadialShading::parse(obj->getDict());
01352       break;
01353     default:
01354       error(-1, "Unimplemented shading type %d", typeA);
01355       goto err1;
01356     }
01357 
01358     if (shading) {
01359       shading->type = typeA;
01360       shading->colorSpace = colorSpaceA;
01361       shading->background = backgroundA;
01362       shading->hasBackground = hasBackgroundA;
01363       shading->xMin = xMinA;
01364       shading->yMin = yMinA;
01365       shading->xMax = xMaxA;
01366       shading->yMax = yMaxA;
01367       shading->hasBBox = hasBBoxA;
01368     } else {
01369       delete colorSpaceA;
01370     }
01371   }
01372 
01373   return shading;
01374 
01375  err1:
01376   return NULL;
01377 }
01378 
01379 //------------------------------------------------------------------------
01380 // GfxAxialShading
01381 //------------------------------------------------------------------------
01382 
01383 GfxAxialShading::GfxAxialShading(double x0A, double y0A,
01384                  double x1A, double y1A,
01385                  double t0A, double t1A,
01386                  Function **funcsA, int nFuncsA,
01387                  GBool extend0A, GBool extend1A) {
01388   int i;
01389 
01390   x0 = x0A;
01391   y0 = y0A;
01392   x1 = x1A;
01393   y1 = y1A;
01394   t0 = t0A;
01395   t1 = t1A;
01396   nFuncs = nFuncsA;
01397   for (i = 0; i < nFuncs; ++i) {
01398     funcs[i] = funcsA[i];
01399   }
01400   extend0 = extend0A;
01401   extend1 = extend1A;
01402 }
01403 
01404 GfxAxialShading::~GfxAxialShading() {
01405   int i;
01406 
01407   for (i = 0; i < nFuncs; ++i) {
01408     delete funcs[i];
01409   }
01410 }
01411 
01412 GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
01413   double x0A, y0A, x1A, y1A;
01414   double t0A, t1A;
01415   Function *funcsA[gfxColorMaxComps];
01416   int nFuncsA;
01417   GBool extend0A, extend1A;
01418   Object obj1, obj2;
01419   int i;
01420 
01421   x0A = y0A = x1A = y1A = 0;
01422   if (dict->lookup("Coords", &obj1)->isArray() &&
01423       obj1.arrayGetLength() == 4) {
01424     x0A = obj1.arrayGet(0, &obj2)->getNum();
01425     obj2.free();
01426     y0A = obj1.arrayGet(1, &obj2)->getNum();
01427     obj2.free();
01428     x1A = obj1.arrayGet(2, &obj2)->getNum();
01429     obj2.free();
01430     y1A = obj1.arrayGet(3, &obj2)->getNum();
01431     obj2.free();
01432   } else {
01433     error(-1, "Missing or invalid Coords in shading dictionary");
01434     goto err1;
01435   }
01436   obj1.free();
01437 
01438   t0A = 0;
01439   t1A = 1;
01440   if (dict->lookup("Domain", &obj1)->isArray() &&
01441       obj1.arrayGetLength() == 2) {
01442     t0A = obj1.arrayGet(0, &obj2)->getNum();
01443     obj2.free();
01444     t1A = obj1.arrayGet(1, &obj2)->getNum();
01445     obj2.free();
01446   }
01447   obj1.free();
01448 
01449   dict->lookup("Function", &obj1);
01450   if (obj1.isArray()) {
01451     nFuncsA = obj1.arrayGetLength();
01452     for (i = 0; i < nFuncsA; ++i) {
01453       obj1.arrayGet(i, &obj2);
01454       if (!(funcsA[i] = Function::parse(&obj2))) {
01455     obj1.free();
01456     obj2.free();
01457     goto err1;
01458       }
01459       obj2.free();
01460     }
01461   } else {
01462     nFuncsA = 1;
01463     if (!(funcsA[0] = Function::parse(&obj1))) {
01464       obj1.free();
01465       goto err1;
01466     }
01467   }
01468   obj1.free();
01469 
01470   extend0A = extend1A = gFalse;
01471   if (dict->lookup("Extend", &obj1)->isArray() &&
01472       obj1.arrayGetLength() == 2) {
01473     extend0A = obj1.arrayGet(0, &obj2)->getBool();
01474     obj2.free();
01475     extend1A = obj1.arrayGet(1, &obj2)->getBool();
01476     obj2.free();
01477   }
01478   obj1.free();
01479 
01480   return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
01481                  funcsA, nFuncsA, extend0A, extend1A);
01482 
01483  err1:
01484   return NULL;
01485 }
01486 
01487 void GfxAxialShading::getColor(double t, GfxColor *color) {
01488   int i;
01489 
01490   for (i = 0; i < nFuncs; ++i) {
01491     funcs[i]->transform(&t, &color->c[i]);
01492   }
01493 }
01494 
01495 //------------------------------------------------------------------------
01496 // GfxRadialShading
01497 //------------------------------------------------------------------------
01498 
01499 GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
01500                    double x1A, double y1A, double r1A,
01501                    double t0A, double t1A,
01502                    Function **funcsA, int nFuncsA,
01503                    GBool extend0A, GBool extend1A) {
01504   int i;
01505 
01506   x0 = x0A;
01507   y0 = y0A;
01508   r0 = r0A;
01509   x1 = x1A;
01510   y1 = y1A;
01511   r1 = r1A;
01512   t0 = t0A;
01513   t1 = t1A;
01514   nFuncs = nFuncsA;
01515   for (i = 0; i < nFuncs; ++i) {
01516     funcs[i] = funcsA[i];
01517   }
01518   extend0 = extend0A;
01519   extend1 = extend1A;
01520 }
01521 
01522 GfxRadialShading::~GfxRadialShading() {
01523   int i;
01524 
01525   for (i = 0; i < nFuncs; ++i) {
01526     delete funcs[i];
01527   }
01528 }
01529 
01530 GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
01531   double x0A, y0A, r0A, x1A, y1A, r1A;
01532   double t0A, t1A;
01533   Function *funcsA[gfxColorMaxComps];
01534   int nFuncsA;
01535   GBool extend0A, extend1A;
01536   Object obj1, obj2;
01537   int i;
01538 
01539   x0A = y0A = r0A = x1A = y1A = r1A = 0;
01540   if (dict->lookup("Coords", &obj1)->isArray() &&
01541       obj1.arrayGetLength() == 6) {
01542     x0A = obj1.arrayGet(0, &obj2)->getNum();
01543     obj2.free();
01544     y0A = obj1.arrayGet(1, &obj2)->getNum();
01545     obj2.free();
01546     r0A = obj1.arrayGet(2, &obj2)->getNum();
01547     obj2.free();
01548     x1A = obj1.arrayGet(3, &obj2)->getNum();
01549     obj2.free();
01550     y1A = obj1.arrayGet(4, &obj2)->getNum();
01551     obj2.free();
01552     r1A = obj1.arrayGet(5, &obj2)->getNum();
01553     obj2.free();
01554   } else {
01555     error(-1, "Missing or invalid Coords in shading dictionary");
01556     goto err1;
01557   }
01558   obj1.free();
01559 
01560   t0A = 0;
01561   t1A = 1;
01562   if (dict->lookup("Domain", &obj1)->isArray() &&
01563       obj1.arrayGetLength() == 2) {
01564     t0A = obj1.arrayGet(0, &obj2)->getNum();
01565     obj2.free();
01566     t1A = obj1.arrayGet(1, &obj2)->getNum();
01567     obj2.free();
01568   }
01569   obj1.free();
01570 
01571   dict->lookup("Function", &obj1);
01572   if (obj1.isArray()) {
01573     nFuncsA = obj1.arrayGetLength();
01574     for (i = 0; i < nFuncsA; ++i) {
01575       obj1.arrayGet(i, &obj2);
01576       if (!(funcsA[i] = Function::parse(&obj2))) {
01577     obj1.free();
01578     obj2.free();
01579     goto err1;
01580       }
01581       obj2.free();
01582     }
01583   } else {
01584     nFuncsA = 1;
01585     if (!(funcsA[0] = Function::parse(&obj1))) {
01586       obj1.free();
01587       goto err1;
01588     }
01589   }
01590   obj1.free();
01591 
01592   extend0A = extend1A = gFalse;
01593   if (dict->lookup("Extend", &obj1)->isArray() &&
01594       obj1.arrayGetLength() == 2) {
01595     extend0A = obj1.arrayGet(0, &obj2)->getBool();
01596     obj2.free();
01597     extend1A = obj1.arrayGet(1, &obj2)->getBool();
01598     obj2.free();
01599   }
01600   obj1.free();
01601 
01602   return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
01603                   funcsA, nFuncsA, extend0A, extend1A);
01604 
01605  err1:
01606   return NULL;
01607 }
01608 
01609 void GfxRadialShading::getColor(double t, GfxColor *color) {
01610   int i;
01611 
01612   for (i = 0; i < nFuncs; ++i) {
01613     funcs[i]->transform(&t, &color->c[i]);
01614   }
01615 }
01616 
01617 //------------------------------------------------------------------------
01618 // GfxImageColorMap
01619 //------------------------------------------------------------------------
01620 
01621 GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
01622                    GfxColorSpace *colorSpaceA) {
01623   GfxIndexedColorSpace *indexedCS;
01624   GfxSeparationColorSpace *sepCS;
01625   int maxPixel, indexHigh;
01626   const Guchar *lookup2;
01627   const Function *sepFunc;
01628   Object obj;
01629   double x[gfxColorMaxComps];
01630   double y[gfxColorMaxComps];
01631   int i, j, k;
01632 
01633   ok = gTrue;
01634 
01635   // bits per component and color space
01636   bits = bitsA;
01637   maxPixel = (1 << bits) - 1;
01638   colorSpace = colorSpaceA;
01639 
01640   // get decode map
01641   if (decode->isNull()) {
01642     nComps = colorSpace->getNComps();
01643     colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
01644   } else if (decode->isArray()) {
01645     nComps = decode->arrayGetLength() / 2;
01646     if (nComps != colorSpace->getNComps()) {
01647       goto err1;
01648     }
01649     for (i = 0; i < nComps; ++i) {
01650       decode->arrayGet(2*i, &obj);
01651       if (!obj.isNum()) {
01652     goto err2;
01653       }
01654       decodeLow[i] = obj.getNum();
01655       obj.free();
01656       decode->arrayGet(2*i+1, &obj);
01657       if (!obj.isNum()) {
01658     goto err2;
01659       }
01660       decodeRange[i] = obj.getNum() - decodeLow[i];
01661       obj.free();
01662     }
01663   } else {
01664     goto err1;
01665   }
01666 
01667   // Construct a lookup table -- this stores pre-computed decoded
01668   // values for each component, i.e., the result of applying the
01669   // decode mapping to each possible image pixel component value.
01670   //
01671   // Optimization: for Indexed and Separation color spaces (which have
01672   // only one component), we store color values in the lookup table
01673   // rather than component values.
01674   colorSpace2 = NULL;
01675   nComps2 = 0;
01676   if (colorSpace->getMode() == csIndexed) {
01677     // Note that indexHigh may not be the same as maxPixel --
01678     // Distiller will remove unused palette entries, resulting in
01679     // indexHigh < maxPixel.
01680     indexedCS = (GfxIndexedColorSpace *)colorSpace;
01681     colorSpace2 = indexedCS->getBase();
01682     indexHigh = indexedCS->getIndexHigh();
01683     nComps2 = colorSpace2->getNComps();
01684     lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double));
01685     lookup2 = indexedCS->getLookup();
01686     colorSpace2->getDefaultRanges(x, y, indexHigh);
01687     for (i = 0; i <= indexHigh; ++i) {
01688       j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
01689       for (k = 0; k < nComps2; ++k) {
01690     lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k];
01691       }
01692     }
01693   } else if (colorSpace->getMode() == csSeparation) {
01694     sepCS = (GfxSeparationColorSpace *)colorSpace;
01695     colorSpace2 = sepCS->getAlt();
01696     nComps2 = colorSpace2->getNComps();
01697     lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double));
01698     sepFunc = sepCS->getFunc();
01699     for (i = 0; i <= maxPixel; ++i) {
01700       x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
01701       sepFunc->transform(x, y);
01702       for (k = 0; k < nComps2; ++k) {
01703     lookup[i*nComps2 + k] = y[k];
01704       }
01705     }
01706   } else {
01707     lookup = (double *)gmalloc((maxPixel + 1) * nComps * sizeof(double));
01708     for (i = 0; i <= maxPixel; ++i) {
01709       for (k = 0; k < nComps; ++k) {
01710     lookup[i*nComps + k] = decodeLow[k] +
01711                              (i * decodeRange[k]) / maxPixel;
01712       }
01713     }
01714   }
01715 
01716   return;
01717 
01718  err2:
01719   obj.free();
01720  err1:
01721   ok = gFalse;
01722 }
01723 
01724 GfxImageColorMap::~GfxImageColorMap() {
01725   delete colorSpace;
01726   gfree(lookup);
01727 }
01728 
01729 void GfxImageColorMap::getGray(Guchar *x, double *gray) {
01730   GfxColor color;
01731   double *p;
01732   int i;
01733 
01734   if (colorSpace2) {
01735     p = &lookup[x[0] * nComps2];
01736     for (i = 0; i < nComps2; ++i) {
01737       color.c[i] = *p++;
01738     }
01739     colorSpace2->getGray(&color, gray);
01740   } else {
01741     for (i = 0; i < nComps; ++i) {
01742       color.c[i] = lookup[x[i] * nComps + i];
01743     }
01744     colorSpace->getGray(&color, gray);
01745   }
01746 }
01747 
01748 void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
01749   GfxColor color;
01750   double *p;
01751   int i;
01752 
01753   if (colorSpace2) {
01754     p = &lookup[x[0] * nComps2];
01755     for (i = 0; i < nComps2; ++i) {
01756       color.c[i] = *p++;
01757     }
01758     colorSpace2->getRGB(&color, rgb);
01759   } else {
01760     for (i = 0; i < nComps; ++i) {
01761       color.c[i] = lookup[x[i] * nComps + i];
01762     }
01763     colorSpace->getRGB(&color, rgb);
01764   }
01765 }
01766 
01767 void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
01768   GfxColor color;
01769   double *p;
01770   int i;
01771 
01772   if (colorSpace2) {
01773     p = &lookup[x[0] * nComps2];
01774     for (i = 0; i < nComps2; ++i) {
01775       color.c[i] = *p++;
01776     }
01777     colorSpace2->getCMYK(&color, cmyk);
01778   } else {
01779     for (i = 0; i < nComps; ++i) {
01780       color.c[i] = lookup[x[i] * nComps + i];
01781     }
01782     colorSpace->getCMYK(&color, cmyk);
01783   }
01784 }
01785 
01786 //------------------------------------------------------------------------
01787 // GfxSubpath and GfxPath
01788 //------------------------------------------------------------------------
01789 
01790 GfxSubpath::GfxSubpath(double x1, double y1) {
01791   size = 16;
01792   x = (double *)gmalloc(size * sizeof(double));
01793   y = (double *)gmalloc(size * sizeof(double));
01794   curve = (GBool *)gmalloc(size * sizeof(GBool));
01795   n = 1;
01796   x[0] = x1;
01797   y[0] = y1;
01798   curve[0] = gFalse;
01799   closed = gFalse;
01800 }
01801 
01802 GfxSubpath::~GfxSubpath() {
01803   gfree(x);
01804   gfree(y);
01805   gfree(curve);
01806 }
01807 
01808 // Used for copy().
01809 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
01810   size = subpath->size;
01811   n = subpath->n;
01812   x = (double *)gmalloc(size * sizeof(double));
01813   y = (double *)gmalloc(size * sizeof(double));
01814   curve = (GBool *)gmalloc(size * sizeof(GBool));
01815   memcpy(x, subpath->x, n * sizeof(double));
01816   memcpy(y, subpath->y, n * sizeof(double));
01817   memcpy(curve, subpath->curve, n * sizeof(GBool));
01818   closed = subpath->closed;
01819 }
01820 
01821 void GfxSubpath::lineTo(double x1, double y1) {
01822   if (n >= size) {
01823     size += 16;
01824     x = (double *)grealloc(x, size * sizeof(double));
01825     y = (double *)grealloc(y, size * sizeof(double));
01826     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
01827   }
01828   x[n] = x1;
01829   y[n] = y1;
01830   curve[n] = gFalse;
01831   ++n;
01832 }
01833 
01834 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
01835              double x3, double y3) {
01836   if (n+3 > size) {
01837     size += 16;
01838     x = (double *)grealloc(x, size * sizeof(double));
01839     y = (double *)grealloc(y, size * sizeof(double));
01840     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
01841   }
01842   x[n] = x1;
01843   y[n] = y1;
01844   x[n+1] = x2;
01845   y[n+1] = y2;
01846   x[n+2] = x3;
01847   y[n+2] = y3;
01848   curve[n] = curve[n+1] = gTrue;
01849   curve[n+2] = gFalse;
01850   n += 3;
01851 }
01852 
01853 void GfxSubpath::close() {
01854   if (x[n-1] != x[0] || y[n-1] != y[0]) {
01855     lineTo(x[0], y[0]);
01856   }
01857   closed = gTrue;
01858 }
01859 
01860 GfxPath::GfxPath() {
01861   justMoved = gFalse;
01862   size = 16;
01863   n = 0;
01864   firstX = firstY = 0;
01865   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
01866 }
01867 
01868 GfxPath::~GfxPath() {
01869   int i;
01870 
01871   for (i = 0; i < n; ++i)
01872     delete subpaths[i];
01873   gfree(subpaths);
01874 }
01875 
01876 // Used for copy().
01877 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
01878          GfxSubpath **subpaths1, int n1, int size1) {
01879   int i;
01880 
01881   justMoved = justMoved1;
01882   firstX = firstX1;
01883   firstY = firstY1;
01884   size = size1;
01885   n = n1;
01886   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
01887   for (i = 0; i < n; ++i)
01888     subpaths[i] = subpaths1[i]->copy();
01889 }
01890 
01891 void GfxPath::moveTo(double x, double y) {
01892   justMoved = gTrue;
01893   firstX = x;
01894   firstY = y;
01895 }
01896 
01897 void GfxPath::lineTo(double x, double y) {
01898   if (justMoved) {
01899     if (n >= size) {
01900       size += 16;
01901       subpaths = (GfxSubpath **)
01902                grealloc(subpaths, size * sizeof(GfxSubpath *));
01903     }
01904     subpaths[n] = new GfxSubpath(firstX, firstY);
01905     ++n;
01906     justMoved = gFalse;
01907   }
01908   subpaths[n-1]->lineTo(x, y);
01909 }
01910 
01911 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
01912          double x3, double y3) {
01913   if (justMoved) {
01914     if (n >= size) {
01915       size += 16;
01916       subpaths = (GfxSubpath **)
01917                grealloc(subpaths, size * sizeof(GfxSubpath *));
01918     }
01919     subpaths[n] = new GfxSubpath(firstX, firstY);
01920     ++n;
01921     justMoved = gFalse;
01922   }
01923   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
01924 }
01925 
01926 void GfxPath::close() {
01927   // this is necessary to handle the pathological case of
01928   // moveto/closepath/clip, which defines an empty clipping region
01929   if (justMoved) {
01930     if (n >= size) {
01931       size += 16;
01932       subpaths = (GfxSubpath **)
01933                grealloc(subpaths, size * sizeof(GfxSubpath *));
01934     }
01935     subpaths[n] = new GfxSubpath(firstX, firstY);
01936     ++n;
01937     justMoved = gFalse;
01938   }
01939   subpaths[n-1]->close();
01940 }
01941 
01942 //------------------------------------------------------------------------
01943 // GfxState
01944 //------------------------------------------------------------------------
01945 
01946 GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
01947            GBool upsideDown) {
01948   double k;
01949 
01950   px1 = pageBox->x1;
01951   py1 = pageBox->y1;
01952   px2 = pageBox->x2;
01953   py2 = pageBox->y2;
01954   k = dpi / 72.0;
01955   if (rotate == 90) {
01956     ctm[0] = 0;
01957     ctm[1] = upsideDown ? k : -k;
01958     ctm[2] = k;
01959     ctm[3] = 0;
01960     ctm[4] = -k * py1;
01961     ctm[5] = k * (upsideDown ? -px1 : px2);
01962     pageWidth = k * (py2 - py1);
01963     pageHeight = k * (px2 - px1);
01964   } else if (rotate == 180) {
01965     ctm[0] = -k;
01966     ctm[1] = 0;
01967     ctm[2] = 0;
01968     ctm[3] = upsideDown ? k : -k;
01969     ctm[4] = k * px2;
01970     ctm[5] = k * (upsideDown ? -py1 : py2);
01971     pageWidth = k * (px2 - px1);
01972     pageHeight = k * (py2 - py1);
01973   } else if (rotate == 270) {
01974     ctm[0] = 0;
01975     ctm[1] = upsideDown ? -k : k;
01976     ctm[2] = -k;
01977     ctm[3] = 0;
01978     ctm[4] = k * py2;
01979     ctm[5] = k * (upsideDown ? px2 : -px1);
01980     pageWidth = k * (py2 - py1);
01981     pageHeight = k * (px2 - px1);
01982   } else {
01983     ctm[0] = k;
01984     ctm[1] = 0;
01985     ctm[2] = 0;
01986     ctm[3] = upsideDown ? -k : k;
01987     ctm[4] = -k * px1;
01988     ctm[5] = k * (upsideDown ? py2 : -py1);
01989     pageWidth = k * (px2 - px1);
01990     pageHeight = k * (py2 - py1);
01991   }
01992 
01993   fillColorSpace = new GfxDeviceGrayColorSpace();
01994   strokeColorSpace = new GfxDeviceGrayColorSpace();
01995   fillColor.c[0] = 0;
01996   strokeColor.c[0] = 0;
01997   fillPattern = NULL;
01998   strokePattern = NULL;
01999   fillOpacity = 1;
02000   strokeOpacity = 1;
02001 
02002   lineWidth = 1;
02003   lineDash = NULL;
02004   lineDashLength = 0;
02005   lineDashStart = 0;
02006   flatness = 0;
02007   lineJoin = 0;
02008   lineCap = 0;
02009   miterLimit = 10;
02010 
02011   font = NULL;
02012   fontSize = 0;
02013   textMat[0] = 1; textMat[1] = 0;
02014   textMat[2] = 0; textMat[3] = 1;
02015   textMat[4] = 0; textMat[5] = 0;
02016   charSpace = 0;
02017   wordSpace = 0;
02018   horizScaling = 1;
02019   leading = 0;
02020   rise = 0;
02021   render = 0;
02022 
02023   path = new GfxPath();
02024   curX = curY = 0;
02025   lineX = lineY = 0;
02026 
02027   clipXMin = 0;
02028   clipYMin = 0;
02029   clipXMax = pageWidth;
02030   clipYMax = pageHeight;
02031 
02032   saved = NULL;
02033 }
02034 
02035 GfxState::~GfxState() {
02036   if (fillColorSpace) {
02037     delete fillColorSpace;
02038   }
02039   if (strokeColorSpace) {
02040     delete strokeColorSpace;
02041   }
02042   if (fillPattern) {
02043     delete fillPattern;
02044   }
02045   if (strokePattern) {
02046     delete strokePattern;
02047   }
02048   gfree(lineDash);
02049   if (path) {
02050     // this gets set to NULL by restore()
02051     delete path;
02052   }
02053   if (saved) {
02054     delete saved;
02055   }
02056 }
02057 
02058 // Used for copy();
02059 GfxState::GfxState(const GfxState *state) {
02060   memcpy(this, state, sizeof(GfxState));
02061   if (fillColorSpace) {
02062     fillColorSpace = state->fillColorSpace->copy();
02063   }
02064   if (strokeColorSpace) {
02065     strokeColorSpace = state->strokeColorSpace->copy();
02066   }
02067   if (fillPattern) {
02068     fillPattern = state->fillPattern->copy();
02069   }
02070   if (strokePattern) {
02071     strokePattern = state->strokePattern->copy();
02072   }
02073   if (lineDashLength > 0) {
02074     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
02075     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
02076   }
02077   saved = NULL;
02078 }
02079 
02080 void GfxState::getUserClipBBox(double *xMin, double *yMin,
02081                    double *xMax, double *yMax) const {
02082   double ictm[6];
02083   double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
02084 
02085   // invert the CTM
02086   det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
02087   ictm[0] = ctm[3] * det;
02088   ictm[1] = -ctm[1] * det;
02089   ictm[2] = -ctm[2] * det;
02090   ictm[3] = ctm[0] * det;
02091   ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
02092   ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
02093 
02094   // transform all four corners of the clip bbox; find the min and max
02095   // x and y values
02096   xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
02097   yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
02098   tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
02099   ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
02100   if (tx < xMin1) {
02101     xMin1 = tx;
02102   } else if (tx > xMax1) {
02103     xMax1 = tx;
02104   }
02105   if (ty < yMin1) {
02106     yMin1 = ty;
02107   } else if (ty > yMax1) {
02108     yMax1 = ty;
02109   }
02110   tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
02111   ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
02112   if (tx < xMin1) {
02113     xMin1 = tx;
02114   } else if (tx > xMax1) {
02115     xMax1 = tx;
02116   }
02117   if (ty < yMin1) {
02118     yMin1 = ty;
02119   } else if (ty > yMax1) {
02120     yMax1 = ty;
02121   }
02122   tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
02123   ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
02124   if (tx < xMin1) {
02125     xMin1 = tx;
02126   } else if (tx > xMax1) {
02127     xMax1 = tx;
02128   }
02129   if (ty < yMin1) {
02130     yMin1 = ty;
02131   } else if (ty > yMax1) {
02132     yMax1 = ty;
02133   }
02134 
02135   *xMin = xMin1;
02136   *yMin = yMin1;
02137   *xMax = xMax1;
02138   *yMax = yMax1;
02139 }
02140 
02141 double GfxState::transformWidth(double w) {
02142   double x, y;
02143 
02144   x = ctm[0] + ctm[2];
02145   y = ctm[1] + ctm[3];
02146   return w * sqrt(0.5 * (x * x + y * y));
02147 }
02148 
02149 double GfxState::getTransformedFontSize() {
02150   double x1, y1, x2, y2;
02151 
02152   x1 = textMat[2] * fontSize;
02153   y1 = textMat[3] * fontSize;
02154   x2 = ctm[0] * x1 + ctm[2] * y1;
02155   y2 = ctm[1] * x1 + ctm[3] * y1;
02156   return sqrt(x2 * x2 + y2 * y2);
02157 }
02158 
02159 void GfxState::getFontTransMat(double *m11, double *m12,
02160                    double *m21, double *m22) {
02161   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
02162   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
02163   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
02164   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
02165 }
02166 
02167 void GfxState::setCTM(double a, double b, double c,
02168               double d, double e, double f) {
02169   int i;
02170 
02171   ctm[0] = a;
02172   ctm[1] = b;
02173   ctm[2] = c;
02174   ctm[3] = d;
02175   ctm[4] = e;
02176   ctm[5] = f;
02177 
02178   // avoid FP exceptions on badly messed up PDF files
02179   for (i = 0; i < 6; ++i) {
02180     if (ctm[i] > 1e10) {
02181       ctm[i] = 1e10;
02182     } else if (ctm[i] < -1e10) {
02183       ctm[i] = -1e10;
02184     }
02185   }
02186 }
02187 
02188 void GfxState::concatCTM(double a, double b, double c,
02189              double d, double e, double f) {
02190   double a1 = ctm[0];
02191   double b1 = ctm[1];
02192   double c1 = ctm[2];
02193   double d1 = ctm[3];
02194   int i;
02195 
02196   ctm[0] = a * a1 + b * c1;
02197   ctm[1] = a * b1 + b * d1;
02198   ctm[2] = c * a1 + d * c1;
02199   ctm[3] = c * b1 + d * d1;
02200   ctm[4] = e * a1 + f * c1 + ctm[4];
02201   ctm[5] = e * b1 + f * d1 + ctm[5];
02202 
02203   // avoid FP exceptions on badly messed up PDF files
02204   for (i = 0; i < 6; ++i) {
02205     if (ctm[i] > 1e10) {
02206       ctm[i] = 1e10;
02207     } else if (ctm[i] < -1e10) {
02208       ctm[i] = -1e10;
02209     }
02210   }
02211 }
02212 
02213 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
02214   if (fillColorSpace) {
02215     delete fillColorSpace;
02216   }
02217   fillColorSpace = colorSpace;
02218 }
02219 
02220 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
02221   if (strokeColorSpace) {
02222     delete strokeColorSpace;
02223   }
02224   strokeColorSpace = colorSpace;
02225 }
02226 
02227 void GfxState::setFillPattern(GfxPattern *pattern) {
02228   if (fillPattern) {
02229     delete fillPattern;
02230   }
02231   fillPattern = pattern;
02232 }
02233 
02234 void GfxState::setStrokePattern(GfxPattern *pattern) {
02235   if (strokePattern) {
02236     delete strokePattern;
02237   }
02238   strokePattern = pattern;
02239 }
02240 
02241 void GfxState::setLineDash(double *dash, int length, double start) {
02242   if (lineDash)
02243     gfree(lineDash);
02244   lineDash = dash;
02245   lineDashLength = length;
02246   lineDashStart = start;
02247 }
02248 
02249 void GfxState::clearPath() {
02250   delete path;
02251   path = new GfxPath();
02252 }
02253 
02254 void GfxState::clip() {
02255   double xMin, yMin, xMax, yMax, x, y;
02256   GfxSubpath *subpath;
02257   int i, j;
02258 
02259   xMin = xMax = yMin = yMax = 0; // make gcc happy
02260   for (i = 0; i < path->getNumSubpaths(); ++i) {
02261     subpath = path->getSubpath(i);
02262     for (j = 0; j < subpath->getNumPoints(); ++j) {
02263       transform(subpath->getX(j), subpath->getY(j), &x, &y);
02264       if (i == 0 && j == 0) {
02265     xMin = xMax = x;
02266     yMin = yMax = y;
02267       } else {
02268     if (x < xMin) {
02269       xMin = x;
02270     } else if (x > xMax) {
02271       xMax = x;
02272     }
02273     if (y < yMin) {
02274       yMin = y;
02275     } else if (y > yMax) {
02276       yMax = y;
02277     }
02278       }
02279     }
02280   }
02281   if (xMin > clipXMin) {
02282     clipXMin = xMin;
02283   }
02284   if (yMin > clipYMin) {
02285     clipYMin = yMin;
02286   }
02287   if (xMax < clipXMax) {
02288     clipXMax = xMax;
02289   }
02290   if (yMax < clipYMax) {
02291     clipYMax = yMax;
02292   }
02293 }
02294 
02295 void GfxState::textShift(double tx, double ty) {
02296   double dx, dy;
02297 
02298   textTransformDelta(tx, ty, &dx, &dy);
02299   curX += dx;
02300   curY += dy;
02301 }
02302 
02303 void GfxState::shift(double dx, double dy) {
02304   curX += dx;
02305   curY += dy;
02306 }
02307 
02308 GfxState *GfxState::save() {
02309   GfxState *newState;
02310 
02311   newState = copy();
02312   newState->saved = this;
02313   return newState;
02314 }
02315 
02316 GfxState *GfxState::restore() {
02317   GfxState *oldState;
02318 
02319   if (saved) {
02320     oldState = saved;
02321 
02322     // these attributes aren't saved/restored by the q/Q operators
02323     oldState->path = path;
02324     oldState->curX = curX;
02325     oldState->curY = curY;
02326     oldState->lineX = lineX;
02327     oldState->lineY = lineY;
02328 
02329     path = NULL;
02330     saved = NULL;
02331     delete this;
02332 
02333   } else {
02334     oldState = this;
02335   }
02336 
02337   return oldState;
02338 }
KDE Home | KDE Accessibility Home | Description of Access Keys