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, DeviceN, and Pattern colorspaces
49 colorSpace->copy(&csObj);
51 if (colorSpace->isArray()) {
52 colorSpace->arrayGet(0, &obj);
53 if (obj.isName("Separation") || obj.isName("DeviceN")) {
55 colorSpace->arrayGet(2, &csObj);
56 sepFunc = new Function(colorSpace->arrayGet(3, &obj2));
58 if (!sepFunc->isOk()) {
62 } else if (obj.isName("Pattern")) {
64 colorSpace->arrayGet(1, &csObj);
73 } else if (csObj.isArray()) {
74 csObj.arrayGet(0, &obj);
75 if (obj.isName("Indexed") || obj.isName("I")) {
77 setMode(csObj.arrayGet(1, &obj2));
90 // get lookup table for indexed colorspace
92 csObj.arrayGet(2, &obj);
95 indexHigh = obj.getInt();
97 lookup = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar));
98 csObj.arrayGet(3, &obj);
101 for (i = 0; i <= indexHigh; ++i) {
102 for (j = 0; j < numComps; ++j) {
103 if ((x = obj.streamGetChar()) == EOF)
105 lookup[i][j] = (Guchar)x;
108 } else if (obj.isString()) {
109 s = obj.getString()->getCString();
110 for (i = 0; i <= indexHigh; ++i)
111 for (j = 0; j < numComps; ++j)
112 lookup[i][j] = (Guchar)*s++;
129 GfxColorSpace::GfxColorSpace(GfxColorMode mode1) {
134 case colorGray: numComps = 1; break;
135 case colorCMYK: numComps = 4; break;
136 case colorRGB: numComps = 3; break;
142 GfxColorSpace::~GfxColorSpace() {
148 GfxColorSpace::GfxColorSpace(GfxColorSpace *colorSpace) {
151 if (colorSpace->sepFunc)
152 sepFunc = colorSpace->sepFunc->copy();
155 mode = colorSpace->mode;
156 indexed = colorSpace->indexed;
157 numComps = colorSpace->numComps;
158 indexHigh = colorSpace->indexHigh;
160 size = (indexHigh + 1) * 4 * sizeof(Guchar);
161 lookup = (Guchar (*)[4])gmalloc(size);
162 memcpy(lookup, colorSpace->lookup, size);
169 void GfxColorSpace::setMode(Object *colorSpace) {
172 if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) {
175 } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) {
178 } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) {
181 } else if (colorSpace->isArray()) {
182 colorSpace->arrayGet(0, &obj);
183 if (obj.isName("CalGray")) {
186 } else if (obj.isName("CalRGB")) {
189 } else if (obj.isName("CalCMYK")) {
201 void GfxColorSpace::getColor(double x[4], GfxColor *color) {
206 sepFunc->transform(x, y);
214 p = lookup[(int)(y[0] + 0.5)];
217 color->setGray(p[0] / 255.0);
220 color->setCMYK(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0, p[3] / 255.0);
223 color->setRGB(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0);
229 color->setGray(y[0]);
232 color->setCMYK(y[0], y[1], y[2], y[3]);
235 color->setRGB(y[0], y[1], y[2]);
241 //------------------------------------------------------------------------
243 //------------------------------------------------------------------------
245 Function::Function(Object *funcObj) {
248 int nSamples, sampleBits;
259 if (!funcObj->isStream()) {
260 error(-1, "Expected function dictionary");
263 str = funcObj->getStream();
264 dict = str->getDict();
267 if (!dict->lookup("FunctionType", &obj1)->isInt() ||
268 obj1.getInt() != 0) {
269 error(-1, "Unknown function type");
275 if (!dict->lookup("Domain", &obj1)->isArray()) {
276 error(-1, "Function is missing domain");
279 m = obj1.arrayGetLength() / 2;
281 error(-1, "Functions with more than 1 input are unsupported");
284 for (i = 0; i < m; ++i) {
285 obj1.arrayGet(2*i, &obj2);
287 error(-1, "Illegal value in function domain array");
290 domain[i][0] = obj2.getNum();
292 obj1.arrayGet(2*i+1, &obj2);
294 error(-1, "Illegal value in function domain array");
297 domain[i][1] = obj2.getNum();
303 if (!dict->lookup("Range", &obj1)->isArray()) {
304 error(-1, "Function is missing range");
307 n = obj1.arrayGetLength() / 2;
309 error(-1, "Functions with more than 4 outputs are unsupported");
312 for (i = 0; i < n; ++i) {
313 obj1.arrayGet(2*i, &obj2);
315 error(-1, "Illegal value in function range array");
318 range[i][0] = obj2.getNum();
320 obj1.arrayGet(2*i+1, &obj2);
322 error(-1, "Illegal value in function range array");
325 range[i][1] = obj2.getNum();
331 if (!dict->lookup("Size", &obj1)->isArray() ||
332 obj1.arrayGetLength() != m) {
333 error(-1, "Function has missing or invalid size array");
336 for (i = 0; i < m; ++i) {
337 obj1.arrayGet(i, &obj2);
339 error(-1, "Illegal value in function size array");
342 sampleSize[i] = obj2.getInt();
347 //----- BitsPerSample
348 if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
349 error(-1, "Function has missing or invalid BitsPerSample");
352 sampleBits = obj1.getInt();
353 sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
357 if (dict->lookup("Encode", &obj1)->isArray() &&
358 obj1.arrayGetLength() == 2*m) {
359 for (i = 0; i < m; ++i) {
360 obj1.arrayGet(2*i, &obj2);
362 error(-1, "Illegal value in function encode array");
365 encode[i][0] = obj2.getNum();
367 obj1.arrayGet(2*i+1, &obj2);
369 error(-1, "Illegal value in function encode array");
372 encode[i][1] = obj2.getNum();
376 for (i = 0; i < m; ++i) {
378 encode[i][1] = sampleSize[i] - 1;
384 if (dict->lookup("Decode", &obj1)->isArray() &&
385 obj1.arrayGetLength() == 2*n) {
386 for (i = 0; i < n; ++i) {
387 obj1.arrayGet(2*i, &obj2);
389 error(-1, "Illegal value in function decode array");
392 decode[i][0] = obj2.getNum();
394 obj1.arrayGet(2*i+1, &obj2);
396 error(-1, "Illegal value in function decode array");
399 decode[i][1] = obj2.getNum();
403 for (i = 0; i < n; ++i) {
404 decode[i][0] = range[i][0];
405 decode[i][1] = range[i][1];
412 for (i = 0; i < m; ++i)
413 nSamples *= sampleSize[i];
414 samples = (double *)gmalloc(nSamples * sizeof(double));
417 bitMask = (1 << sampleBits) - 1;
419 for (i = 0; i < nSamples; ++i) {
420 if (sampleBits == 8) {
422 } else if (sampleBits == 16) {
424 s = (s << 8) + str->getChar();
425 } else if (sampleBits == 32) {
427 s = (s << 8) + str->getChar();
428 s = (s << 8) + str->getChar();
429 s = (s << 8) + str->getChar();
431 while (bits < sampleBits) {
432 buf = (buf << 8) | (str->getChar() & 0xff);
435 s = (buf >> (bits - sampleBits)) & bitMask;
438 samples[i] = (double)s * sampleMul;
452 Function::Function(Function *func) {
457 memcpy(domain, func->domain, sizeof(domain));
458 memcpy(range, func->range, sizeof(range));
459 memcpy(sampleSize, func->sampleSize, sizeof(sampleSize));
460 memcpy(encode, func->encode, sizeof(encode));
461 memcpy(decode, func->decode, sizeof(decode));
464 for (i = 0; i < m; ++i)
465 nSamples *= sampleSize[i];
466 samples = (double *)gmalloc(nSamples * sizeof(double));
467 memcpy(samples, func->samples, nSamples * sizeof(double));
472 Function::~Function() {
477 void Function::transform(double *in, double *out) {
485 // map input values into sample array
486 for (i = 0; i < m; ++i) {
487 e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
488 (encode[i][1] - encode[i][0]) + encode[i][0];
491 else if (e[i] > sampleSize[i] - 1)
492 e[i] = sampleSize[i] - 1;
495 for (i = 0; i < n; ++i) {
497 // m-linear interpolation
498 // (only m=1 is currently supported)
499 e0 = (int)floor(e[0]);
500 e1 = (int)ceil(e[0]);
502 x0 = samples[e0 * n + i];
503 x1 = samples[e1 * n + i];
504 s = (1 - efrac) * x0 + efrac * x1;
506 // map output values to range
507 out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
508 if (out[i] < range[i][0])
509 out[i] = range[i][0];
510 else if (out[i] > range[i][1])
511 out[i] = range[i][1];
515 //------------------------------------------------------------------------
517 //------------------------------------------------------------------------
519 GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode,
520 GfxColorSpace *colorSpace1) {
529 // bits per component and colorspace
531 maxPixel = (1 << bits) - 1;
532 colorSpace = colorSpace1;
533 mode = colorSpace->getMode();
535 // work around a bug in Distiller (?)
536 if (colorSpace->isIndexed() && maxPixel > colorSpace->getIndexHigh()) {
537 maxPixel = colorSpace->getIndexHigh();
541 if (decode->isNull()) {
542 if (colorSpace->isIndexed()) {
546 decodeRange[0] = maxPixel;
549 numComps = colorSpace->getNumPixelComps();
550 for (i = 0; i < numComps; ++i) {
555 } else if (decode->isArray()) {
556 numComps = decode->arrayGetLength() / 2;
557 if (numComps != colorSpace->getNumPixelComps())
559 indexed = colorSpace->isIndexed();
560 for (i = 0; i < numComps; ++i) {
561 decode->arrayGet(2*i, &obj);
564 decodeLow[i] = obj.getNum();
566 decode->arrayGet(2*i+1, &obj);
569 decodeRange[i] = obj.getNum() - decodeLow[i];
576 // construct lookup table
577 lookup = (double (*)[4])gmalloc((maxPixel + 1) * 4 * sizeof(double));
579 for (i = 0; i <= maxPixel; ++i) {
581 colorSpace->getColor(x, &color);
582 lookup[i][0] = color.getR();
583 lookup[i][1] = color.getG();
584 lookup[i][2] = color.getB();
587 for (i = 0; i <= maxPixel; ++i)
588 for (j = 0; j < numComps; ++j)
589 lookup[i][j] = decodeLow[j] + (i * decodeRange[j]) / maxPixel;
600 GfxImageColorMap::~GfxImageColorMap() {
605 void GfxImageColorMap::getColor(Guchar x[4], GfxColor *color) {
610 color->setRGB(p[0], p[1], p[2]);
614 color->setGray(lookup[x[0]][0]);
617 color->setCMYK(lookup[x[0]][0], lookup[x[1]][1],
618 lookup[x[2]][2], lookup[x[3]][3]);
621 color->setRGB(lookup[x[0]][0], lookup[x[1]][1], lookup[x[2]][2]);
627 //------------------------------------------------------------------------
628 // GfxSubpath and GfxPath
629 //------------------------------------------------------------------------
631 GfxSubpath::GfxSubpath(double x1, double y1) {
633 x = (double *)gmalloc(size * sizeof(double));
634 y = (double *)gmalloc(size * sizeof(double));
635 curve = (GBool *)gmalloc(size * sizeof(GBool));
642 GfxSubpath::~GfxSubpath() {
649 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
650 size = subpath->size;
652 x = (double *)gmalloc(size * sizeof(double));
653 y = (double *)gmalloc(size * sizeof(double));
654 curve = (GBool *)gmalloc(size * sizeof(GBool));
655 memcpy(x, subpath->x, n * sizeof(double));
656 memcpy(y, subpath->y, n * sizeof(double));
657 memcpy(curve, subpath->curve, n * sizeof(GBool));
660 void GfxSubpath::lineTo(double x1, double y1) {
663 x = (double *)grealloc(x, size * sizeof(double));
664 y = (double *)grealloc(y, size * sizeof(double));
665 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
673 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
674 double x3, double y3) {
677 x = (double *)grealloc(x, size * sizeof(double));
678 y = (double *)grealloc(y, size * sizeof(double));
679 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
687 curve[n] = curve[n+1] = gTrue;
696 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
699 GfxPath::~GfxPath() {
702 for (i = 0; i < n; ++i)
708 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
709 GfxSubpath **subpaths1, int n1, int size1) {
712 justMoved = justMoved1;
717 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
718 for (i = 0; i < n; ++i)
719 subpaths[i] = subpaths1[i]->copy();
722 void GfxPath::moveTo(double x, double y) {
728 void GfxPath::lineTo(double x, double y) {
732 subpaths = (GfxSubpath **)
733 grealloc(subpaths, size * sizeof(GfxSubpath *));
735 subpaths[n] = new GfxSubpath(firstX, firstY);
739 subpaths[n-1]->lineTo(x, y);
742 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
743 double x3, double y3) {
747 subpaths = (GfxSubpath **)
748 grealloc(subpaths, size * sizeof(GfxSubpath *));
750 subpaths[n] = new GfxSubpath(firstX, firstY);
754 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
758 //------------------------------------------------------------------------
760 //------------------------------------------------------------------------
762 GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a,
763 int rotate, GBool upsideDown) {
770 k = (double)dpi / 72.0;
773 ctm[1] = upsideDown ? k : -k;
777 ctm[5] = k * (upsideDown ? -px1 : px2);
778 pageWidth = (int)(k * (py2 - py1));
779 pageHeight = (int)(k * (px2 - px1));
780 } else if (rotate == 180) {
784 ctm[3] = upsideDown ? k : -k;
786 ctm[5] = k * (upsideDown ? -py1 : py2);
787 pageWidth = (int)(k * (px2 - px1));
788 pageHeight = (int)(k * (py2 - py1));
789 } else if (rotate == 270) {
791 ctm[1] = upsideDown ? -k : k;
795 ctm[5] = k * (upsideDown ? px2 : -px1);
796 pageWidth = (int)(k * (py2 - py1));
797 pageHeight = (int)(k * (px2 - px1));
802 ctm[3] = upsideDown ? -k : k;
804 ctm[5] = k * (upsideDown ? py2 : -py1);
805 pageWidth = (int)(k * (px2 - px1));
806 pageHeight = (int)(k * (py2 - py1));
809 fillColorSpace = new GfxColorSpace(colorGray);
810 strokeColorSpace = new GfxColorSpace(colorGray);
811 fillColor.setGray(0);
812 strokeColor.setGray(0);
825 textMat[0] = 1; textMat[1] = 0;
826 textMat[2] = 0; textMat[3] = 1;
827 textMat[4] = 0; textMat[5] = 0;
835 path = new GfxPath();
842 GfxState::~GfxState() {
844 delete fillColorSpace;
845 if (strokeColorSpace)
846 delete strokeColorSpace;
854 GfxState::GfxState(GfxState *state) {
855 memcpy(this, state, sizeof(GfxState));
857 fillColorSpace = state->fillColorSpace->copy();
858 if (strokeColorSpace)
859 strokeColorSpace = state->strokeColorSpace->copy();
860 if (lineDashLength > 0) {
861 lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
862 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
864 path = state->path->copy();
868 double GfxState::transformWidth(double w) {
873 return w * sqrt(0.5 * (x * x + y * y));
876 double GfxState::getTransformedFontSize() {
877 double x1, y1, x2, y2;
879 x1 = textMat[2] * fontSize;
880 y1 = textMat[3] * fontSize;
881 x2 = ctm[0] * x1 + ctm[2] * y1;
882 y2 = ctm[1] * x1 + ctm[3] * y1;
883 return sqrt(x2 * x2 + y2 * y2);
886 void GfxState::getFontTransMat(double *m11, double *m12,
887 double *m21, double *m22) {
888 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
889 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
890 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
891 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
894 void GfxState::concatCTM(double a, double b, double c,
895 double d, double e, double f) {
901 ctm[0] = a * a1 + b * c1;
902 ctm[1] = a * b1 + b * d1;
903 ctm[2] = c * a1 + d * c1;
904 ctm[3] = c * b1 + d * d1;
905 ctm[4] = e * a1 + f * c1 + ctm[4];
906 ctm[5] = e * b1 + f * d1 + ctm[5];
909 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
911 delete fillColorSpace;
912 fillColorSpace = colorSpace;
915 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
916 if (strokeColorSpace)
917 delete strokeColorSpace;
918 strokeColorSpace = colorSpace;
921 void GfxState::setLineDash(double *dash, int length, double start) {
925 lineDashLength = length;
926 lineDashStart = start;
929 void GfxState::clearPath() {
931 path = new GfxPath();
934 void GfxState::textShift(double tx) {
937 textTransformDelta(tx, 0, &dx, &dy);
942 void GfxState::textShift(double tx, double ty) {
945 textTransformDelta(tx, ty, &dx, &dy);
950 GfxState *GfxState::save() {
954 newState->saved = this;
958 GfxState *GfxState::restore() {