1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
15 #include <string.h> // for memcpy()
21 //------------------------------------------------------------------------
23 //------------------------------------------------------------------------
25 void GfxColor::setCMYK(double c, double m, double y, double k) {
26 if ((r = 1 - (c + k)) < 0)
28 if ((g = 1 - (m + k)) < 0)
30 if ((b = 1 - (y + k)) < 0)
34 //------------------------------------------------------------------------
36 //------------------------------------------------------------------------
38 GfxColorSpace::GfxColorSpace(Object *colorSpace) {
48 // check for Separation colorspace
49 colorSpace->copy(&csObj);
51 if (colorSpace->isArray()) {
52 colorSpace->arrayGet(0, &obj);
53 if (obj.isName("Separation")) {
55 colorSpace->arrayGet(2, &csObj);
56 sepFunc = new Function(colorSpace->arrayGet(3, &obj2));
58 if (!sepFunc->isOk()) {
70 } else if (csObj.isArray()) {
71 csObj.arrayGet(0, &obj);
72 if (obj.isName("Indexed") || obj.isName("I")) {
74 setMode(csObj.arrayGet(1, &obj2));
86 // get lookup table for indexed colorspace
88 csObj.arrayGet(2, &obj);
91 indexHigh = obj.getInt();
93 lookup = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar));
94 csObj.arrayGet(3, &obj);
97 for (i = 0; i <= indexHigh; ++i) {
98 for (j = 0; j < numComps; ++j) {
99 if ((x = obj.streamGetChar()) == EOF)
101 lookup[i][j] = (Guchar)x;
104 } else if (obj.isString()) {
105 s = obj.getString()->getCString();
106 for (i = 0; i <= indexHigh; ++i)
107 for (j = 0; j < numComps; ++j)
108 lookup[i][j] = (Guchar)*s++;
125 GfxColorSpace::GfxColorSpace(GfxColorMode mode1) {
130 case colorGray: numComps = 1; break;
131 case colorCMYK: numComps = 4; break;
132 case colorRGB: numComps = 3; break;
138 GfxColorSpace::~GfxColorSpace() {
144 GfxColorSpace::GfxColorSpace(GfxColorSpace *colorSpace) {
147 if (colorSpace->sepFunc)
148 sepFunc = colorSpace->sepFunc->copy();
151 mode = colorSpace->mode;
152 indexed = colorSpace->indexed;
153 numComps = colorSpace->numComps;
154 indexHigh = colorSpace->indexHigh;
156 size = (indexHigh + 1) * 4 * sizeof(Guchar);
157 lookup = (Guchar (*)[4])gmalloc(size);
158 memcpy(lookup, colorSpace->lookup, size);
165 void GfxColorSpace::setMode(Object *colorSpace) {
168 if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) {
171 } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) {
174 } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) {
177 } else if (colorSpace->isArray()) {
178 colorSpace->arrayGet(0, &obj);
179 if (obj.isName("CalGray")) {
182 } else if (obj.isName("CalRGB")) {
185 } else if (obj.isName("CalCMYK")) {
197 void GfxColorSpace::getColor(double x[4], GfxColor *color) {
202 sepFunc->transform(x, y);
210 p = lookup[(int)(y[0] + 0.5)];
213 color->setGray(p[0] / 255.0);
216 color->setCMYK(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0, p[3] / 255.0);
219 color->setRGB(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0);
225 color->setGray(y[0]);
228 color->setCMYK(y[0], y[1], y[2], y[3]);
231 color->setRGB(y[0], y[1], y[2]);
237 //------------------------------------------------------------------------
239 //------------------------------------------------------------------------
241 Function::Function(Object *funcObj) {
244 int nSamples, sampleBits;
255 if (!funcObj->isStream()) {
256 error(-1, "Expected function dictionary");
259 str = funcObj->getStream();
260 dict = str->getDict();
263 if (!dict->lookup("FunctionType", &obj1)->isInt() ||
264 obj1.getInt() != 0) {
265 error(-1, "Unknown function type");
271 if (!dict->lookup("Domain", &obj1)->isArray()) {
272 error(-1, "Function is missing domain");
275 m = obj1.arrayGetLength() / 2;
277 error(-1, "Functions with more than 1 input are unsupported");
280 for (i = 0; i < m; ++i) {
281 obj1.arrayGet(2*i, &obj2);
283 error(-1, "Illegal value in function domain array");
286 domain[i][0] = obj2.getNum();
288 obj1.arrayGet(2*i+1, &obj2);
290 error(-1, "Illegal value in function domain array");
293 domain[i][1] = obj2.getNum();
299 if (!dict->lookup("Range", &obj1)->isArray()) {
300 error(-1, "Function is missing range");
303 n = obj1.arrayGetLength() / 2;
305 error(-1, "Functions with more than 4 outputs are unsupported");
308 for (i = 0; i < n; ++i) {
309 obj1.arrayGet(2*i, &obj2);
311 error(-1, "Illegal value in function range array");
314 range[i][0] = obj2.getNum();
316 obj1.arrayGet(2*i+1, &obj2);
318 error(-1, "Illegal value in function range array");
321 range[i][1] = obj2.getNum();
327 if (!dict->lookup("Size", &obj1)->isArray() ||
328 obj1.arrayGetLength() != m) {
329 error(-1, "Function has missing or invalid size array");
332 for (i = 0; i < m; ++i) {
333 obj1.arrayGet(i, &obj2);
335 error(-1, "Illegal value in function size array");
338 sampleSize[i] = obj2.getInt();
343 //----- BitsPerSample
344 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
345 error(-1, "Function has missing or invalid BitsPerSample");
348 sampleBits = obj1.getInt();
349 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
353 if (dict->lookup("Encode", &obj1)->isArray() &&
354 obj1.arrayGetLength() == 2*m) {
355 for (i = 0; i < m; ++i) {
356 obj1.arrayGet(2*i, &obj2);
358 error(-1, "Illegal value in function encode array");
361 encode[i][0] = obj2.getNum();
363 obj1.arrayGet(2*i+1, &obj2);
365 error(-1, "Illegal value in function encode array");
368 encode[i][1] = obj2.getNum();
372 for (i = 0; i < m; ++i) {
374 encode[i][1] = sampleSize[i] - 1;
380 if (dict->lookup("Decode", &obj1)->isArray() &&
381 obj1.arrayGetLength() == 2*n) {
382 for (i = 0; i < n; ++i) {
383 obj1.arrayGet(2*i, &obj2);
385 error(-1, "Illegal value in function decode array");
388 decode[i][0] = obj2.getNum();
390 obj1.arrayGet(2*i+1, &obj2);
392 error(-1, "Illegal value in function decode array");
395 decode[i][1] = obj2.getNum();
399 for (i = 0; i < n; ++i) {
400 decode[i][0] = range[i][0];
401 decode[i][1] = range[i][1];
408 for (i = 0; i < m; ++i)
409 nSamples *= sampleSize[i];
410 samples = (double *)gmalloc(nSamples * sizeof(double));
413 bitMask = (1 << sampleBits) - 1;
415 for (i = 0; i < nSamples; ++i) {
416 if (sampleBits == 8) {
418 } else if (sampleBits == 16) {
420 s = (s << 8) + str->getChar();
421 } else if (sampleBits == 32) {
423 s = (s << 8) + str->getChar();
424 s = (s << 8) + str->getChar();
425 s = (s << 8) + str->getChar();
427 while (bits < sampleBits) {
428 buf = (buf << 8) | (str->getChar() & 0xff);
431 s = (buf >> (bits - sampleBits)) & bitMask;
434 samples[i] = (double)s * sampleMul;
448 Function::Function(Function *func) {
453 memcpy(domain, func->domain, sizeof(domain));
454 memcpy(range, func->range, sizeof(range));
455 memcpy(sampleSize, func->sampleSize, sizeof(sampleSize));
456 memcpy(encode, func->encode, sizeof(encode));
457 memcpy(decode, func->decode, sizeof(decode));
460 for (i = 0; i < m; ++i)
461 nSamples *= sampleSize[i];
462 samples = (double *)gmalloc(nSamples * sizeof(double));
463 memcpy(samples, func->samples, nSamples * sizeof(double));
468 Function::~Function() {
473 void Function::transform(double *in, double *out) {
481 // map input values into sample array
482 for (i = 0; i < m; ++i) {
483 e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
484 (encode[i][1] - encode[i][0]) + encode[i][0];
487 else if (e[i] > sampleSize[i] - 1)
488 e[i] = sampleSize[i] - 1;
491 for (i = 0; i < n; ++i) {
493 // m-linear interpolation
494 // (only m=1 is currently supported)
495 e0 = (int)floor(e[0]);
496 e1 = (int)ceil(e[0]);
498 x0 = samples[e0 * n + i];
499 x1 = samples[e1 * n + i];
500 s = (1 - efrac) * x0 + efrac * x1;
502 // map output values to range
503 out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
504 if (out[i] < range[i][0])
505 out[i] = range[i][0];
506 else if (out[i] > range[i][1])
507 out[i] = range[i][1];
511 //------------------------------------------------------------------------
513 //------------------------------------------------------------------------
515 GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode,
516 GfxColorSpace *colorSpace1) {
525 // bits per component and colorspace
527 maxPixel = (1 << bits) - 1;
528 colorSpace = colorSpace1;
529 mode = colorSpace->getMode();
532 if (decode->isNull()) {
533 if (colorSpace->isIndexed()) {
537 decodeRange[0] = maxPixel;
540 numComps = colorSpace->getNumPixelComps();
541 for (i = 0; i < numComps; ++i) {
546 } else if (decode->isArray()) {
547 numComps = decode->arrayGetLength() / 2;
548 if (numComps != colorSpace->getNumPixelComps())
550 indexed = colorSpace->isIndexed();
551 for (i = 0; i < numComps; ++i) {
552 decode->arrayGet(2*i, &obj);
555 decodeLow[i] = obj.getNum();
557 decode->arrayGet(2*i+1, &obj);
560 decodeRange[i] = obj.getNum() - decodeLow[i];
567 // construct lookup table
568 lookup = (double (*)[4])gmalloc((maxPixel + 1) * 4 * sizeof(double));
570 for (i = 0; i <= maxPixel; ++i) {
572 colorSpace->getColor(x, &color);
573 lookup[i][0] = color.getR();
574 lookup[i][1] = color.getG();
575 lookup[i][2] = color.getB();
578 for (i = 0; i <= maxPixel; ++i)
579 for (j = 0; j < numComps; ++j)
580 lookup[i][j] = decodeLow[j] + (i * decodeRange[j]) / maxPixel;
591 GfxImageColorMap::~GfxImageColorMap() {
596 void GfxImageColorMap::getColor(Guchar x[4], GfxColor *color) {
601 color->setRGB(p[0], p[1], p[2]);
605 color->setGray(lookup[x[0]][0]);
608 color->setCMYK(lookup[x[0]][0], lookup[x[1]][1],
609 lookup[x[2]][2], lookup[x[3]][3]);
612 color->setRGB(lookup[x[0]][0], lookup[x[1]][1], lookup[x[2]][2]);
618 //------------------------------------------------------------------------
619 // GfxSubpath and GfxPath
620 //------------------------------------------------------------------------
622 GfxSubpath::GfxSubpath(double x1, double y1) {
624 x = (double *)gmalloc(size * sizeof(double));
625 y = (double *)gmalloc(size * sizeof(double));
626 curve = (GBool *)gmalloc(size * sizeof(GBool));
633 GfxSubpath::~GfxSubpath() {
640 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
641 size = subpath->size;
643 x = (double *)gmalloc(size * sizeof(double));
644 y = (double *)gmalloc(size * sizeof(double));
645 curve = (GBool *)gmalloc(size * sizeof(GBool));
646 memcpy(x, subpath->x, n * sizeof(double));
647 memcpy(y, subpath->y, n * sizeof(double));
648 memcpy(curve, subpath->curve, n * sizeof(GBool));
651 void GfxSubpath::lineTo(double x1, double y1) {
654 x = (double *)grealloc(x, size * sizeof(double));
655 y = (double *)grealloc(y, size * sizeof(double));
656 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
664 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
665 double x3, double y3) {
668 x = (double *)grealloc(x, size * sizeof(double));
669 y = (double *)grealloc(y, size * sizeof(double));
670 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
678 curve[n] = curve[n+1] = gTrue;
687 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
690 GfxPath::~GfxPath() {
693 for (i = 0; i < n; ++i)
699 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
700 GfxSubpath **subpaths1, int n1, int size1) {
703 justMoved = justMoved1;
708 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
709 for (i = 0; i < n; ++i)
710 subpaths[i] = subpaths1[i]->copy();
713 void GfxPath::moveTo(double x, double y) {
719 void GfxPath::lineTo(double x, double y) {
723 subpaths = (GfxSubpath **)
724 grealloc(subpaths, size * sizeof(GfxSubpath *));
726 subpaths[n] = new GfxSubpath(firstX, firstY);
730 subpaths[n-1]->lineTo(x, y);
733 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
734 double x3, double y3) {
738 subpaths = (GfxSubpath **)
739 grealloc(subpaths, size * sizeof(GfxSubpath *));
741 subpaths[n] = new GfxSubpath(firstX, firstY);
745 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
749 //------------------------------------------------------------------------
751 //------------------------------------------------------------------------
753 GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a,
754 int rotate, GBool upsideDown) {
761 k = (double)dpi / 72.0;
764 ctm[1] = upsideDown ? k : -k;
768 ctm[5] = k * (upsideDown ? -px1 : px2);
769 pageWidth = (int)(k * (py2 - py1));
770 pageHeight = (int)(k * (px2 - px1));
771 } else if (rotate == 180) {
775 ctm[3] = upsideDown ? k : -k;
777 ctm[5] = k * (upsideDown ? -py1 : py2);
778 pageWidth = (int)(k * (px2 - px1));
779 pageHeight = (int)(k * (py2 - py1));
780 } else if (rotate == 270) {
782 ctm[1] = upsideDown ? -k : k;
786 ctm[5] = k * (upsideDown ? px2 : -px1);
787 pageWidth = (int)(k * (py2 - py1));
788 pageHeight = (int)(k * (px2 - px1));
793 ctm[3] = upsideDown ? -k : k;
795 ctm[5] = k * (upsideDown ? py2 : -py1);
796 pageWidth = (int)(k * (px2 - px1));
797 pageHeight = (int)(k * (py2 - py1));
800 fillColorSpace = new GfxColorSpace(colorGray);
801 strokeColorSpace = new GfxColorSpace(colorGray);
802 fillColor.setGray(0);
803 strokeColor.setGray(0);
816 textMat[0] = 1; textMat[1] = 0;
817 textMat[2] = 0; textMat[3] = 1;
818 textMat[4] = 0; textMat[5] = 0;
826 path = new GfxPath();
833 GfxState::~GfxState() {
835 delete fillColorSpace;
836 if (strokeColorSpace)
837 delete strokeColorSpace;
845 GfxState::GfxState(GfxState *state) {
846 memcpy(this, state, sizeof(GfxState));
848 fillColorSpace = state->fillColorSpace->copy();
849 if (strokeColorSpace)
850 strokeColorSpace = state->strokeColorSpace->copy();
851 if (lineDashLength > 0) {
852 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
853 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
855 path = state->path->copy();
859 double GfxState::transformWidth(double w) {
864 return w * sqrt(0.5 * (x * x + y * y));
867 double GfxState::getTransformedFontSize() {
868 double x1, y1, x2, y2;
870 x1 = textMat[2] * fontSize;
871 y1 = textMat[3] * fontSize;
872 x2 = ctm[0] * x1 + ctm[2] * y1;
873 y2 = ctm[1] * x1 + ctm[3] * y1;
874 return sqrt(x2 * x2 + y2 * y2);
877 void GfxState::getFontTransMat(double *m11, double *m12,
878 double *m21, double *m22) {
879 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
880 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
881 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
882 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
885 void GfxState::concatCTM(double a, double b, double c,
886 double d, double e, double f) {
892 ctm[0] = a * a1 + b * c1;
893 ctm[1] = a * b1 + b * d1;
894 ctm[2] = c * a1 + d * c1;
895 ctm[3] = c * b1 + d * d1;
896 ctm[4] = e * a1 + f * c1 + ctm[4];
897 ctm[5] = e * b1 + f * d1 + ctm[5];
900 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
902 delete fillColorSpace;
903 fillColorSpace = colorSpace;
906 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
907 if (strokeColorSpace)
908 delete strokeColorSpace;
909 strokeColorSpace = colorSpace;
912 void GfxState::setLineDash(double *dash, int length, double start) {
916 lineDashLength = length;
917 lineDashStart = start;
920 void GfxState::clearPath() {
922 path = new GfxPath();
925 void GfxState::textShift(double tx) {
928 textTransformDelta(tx, 0, &dx, &dy);
933 GfxState *GfxState::save() {
937 newState->saved = this;
941 GfxState *GfxState::restore() {