Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GfxState.cc

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

Generated on Sat Nov 5 16:18:15 2005 for OPIE by  doxygen 1.4.2