}
}
++n;
- map = (Gushort *)gmalloc(n * sizeof(Gushort));
+ map = (Gushort *)gmallocn(n, sizeof(Gushort));
memset(map, 0, n * sizeof(Gushort));
for (i = 0; i < nGlyphs; ++i) {
map[charset[i]] = i;
(*outputFunc)(outputStream,
"0 1 255 {1 index exch /.notdef put} for\n", 40);
enc = newEncoding ? newEncoding : encoding;
- if(!enc) {
- fprintf(stderr, "convertToType1: Warning: No Encoding\n");
- }
for (i = 0; i < 256; ++i) {
- if (enc && enc[i]) {
+ if (enc[i]) {
sprintf(buf, "dup %d /%s put\n", i, enc[i]);
(*outputFunc)(outputStream, buf, strlen(buf));
}
nCIDs = charset[i] + 1;
}
}
- cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ cidMap = (int *)gmallocn(nCIDs, sizeof(int));
for (i = 0; i < nCIDs; ++i) {
cidMap[i] = -1;
}
// build the charstrings
charStrings = new GString();
- charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
+ charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int));
for (i = 0; i < nCIDs; ++i) {
charStringOffsets[i] = charStrings->getLength();
if ((gid = cidMap[i]) >= 0) {
sprintf(buf, " /Supplement %d def\n", topDict.supplement);
(*outputFunc)(outputStream, buf, strlen(buf));
(*outputFunc)(outputStream, "end def\n", 8);
- sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
- topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2],
- topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]);
- (*outputFunc)(outputStream, buf, strlen(buf));
+ if (topDict.hasFontMatrix) {
+ sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ topDict.fontMatrix[0], topDict.fontMatrix[1],
+ topDict.fontMatrix[2], topDict.fontMatrix[3],
+ topDict.fontMatrix[4], topDict.fontMatrix[5]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ } else if (privateDicts[0].hasFontMatrix) {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ } else {
+ (*outputFunc)(outputStream,
+ "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
+ }
sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
topDict.fontBBox[0], topDict.fontBBox[1],
topDict.fontBBox[2], topDict.fontBBox[3]);
sprintf(buf, "dup %d 10 dict begin\n", i);
(*outputFunc)(outputStream, buf, strlen(buf));
(*outputFunc)(outputStream, "/FontType 1 def\n", 16);
- (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ if (privateDicts[i].hasFontMatrix) {
+ sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ privateDicts[i].fontMatrix[0],
+ privateDicts[i].fontMatrix[1],
+ privateDicts[i].fontMatrix[2],
+ privateDicts[i].fontMatrix[3],
+ privateDicts[i].fontMatrix[4],
+ privateDicts[i].fontMatrix[5]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ } else {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ }
sprintf(buf, "/PaintType %d def\n", topDict.paintType);
(*outputFunc)(outputStream, buf, strlen(buf));
(*outputFunc)(outputStream, "/Private 32 dict begin\n", 23);
nCIDs = charset[i] + 1;
}
}
- cidMap = (int *)gmalloc(nCIDs * sizeof(int));
+ cidMap = (int *)gmallocn(nCIDs, sizeof(int));
for (i = 0; i < nCIDs; ++i) {
cidMap[i] = -1;
}
sprintf(buf, "_%02x def\n", i >> 8);
(*outputFunc)(outputStream, buf, strlen(buf));
(*outputFunc)(outputStream, "/FontType 1 def\n", 16);
- sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
- topDict.fontMatrix[0], topDict.fontMatrix[1],
- topDict.fontMatrix[2], topDict.fontMatrix[3],
- topDict.fontMatrix[4], topDict.fontMatrix[5]);
- (*outputFunc)(outputStream, buf, strlen(buf));
+ if (privateDicts[fd].hasFontMatrix) {
+ sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ privateDicts[fd].fontMatrix[0],
+ privateDicts[fd].fontMatrix[1],
+ privateDicts[fd].fontMatrix[2],
+ privateDicts[fd].fontMatrix[3],
+ privateDicts[fd].fontMatrix[4],
+ privateDicts[fd].fontMatrix[5]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ } else if (topDict.hasFontMatrix) {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ } else {
+ (*outputFunc)(outputStream,
+ "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
+ }
sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
topDict.fontBBox[0], topDict.fontBBox[1],
topDict.fontBBox[2], topDict.fontBBox[3]);
(*outputFunc)(outputStream, psName, strlen(psName));
(*outputFunc)(outputStream, " def\n", 5);
(*outputFunc)(outputStream, "/FontType 0 def\n", 16);
- (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ if (topDict.hasFontMatrix) {
+ sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
+ topDict.fontMatrix[0], topDict.fontMatrix[1],
+ topDict.fontMatrix[2], topDict.fontMatrix[3],
+ topDict.fontMatrix[4], topDict.fontMatrix[5]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ } else {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ }
(*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
(*outputFunc)(outputStream, "/Encoding [\n", 12);
for (i = 0; i < nCIDs; i += 256) {
nOps = 0;
nHints = 0;
firstOp = gTrue;
+ openPath = gFalse;
}
pos = offset;
d = 0;
dFP = gFalse;
for (k = 0; k < nOps; k += 2) {
+ // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints
if (ops[k+1].num < 0) {
d += ops[k].num + ops[k+1].num;
dFP |= ops[k].isFP | ops[k+1].isFP;
d = 0;
dFP = gFalse;
for (k = 0; k < nOps; k += 2) {
+ // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints
if (ops[k+1].num < 0) {
d += ops[k].num + ops[k+1].num;
dFP |= ops[k].isFP | ops[k+1].isFP;
cvtGlyphWidth(nOps == 2, charBuf, pDict);
firstOp = gFalse;
}
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
if (nOps != 1) {
//~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
}
charBuf->append((char)5);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x0006: // hlineto
if (nOps < 1) {
charBuf->append((char)((k & 1) ? 7 : 6));
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x0007: // vlineto
if (nOps < 1) {
charBuf->append((char)((k & 1) ? 6 : 7));
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x0008: // rrcurveto
if (nOps < 6 || nOps % 6 != 0) {
charBuf->append((char)8);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x000a: // callsubr
if (nOps >= 1) {
cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict);
firstOp = gFalse;
}
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
if (nOps == 4) {
cvtNum(0, gFalse, charBuf);
cvtNum(ops[0].num, ops[0].isFP, charBuf);
cvtGlyphWidth(nOps == 3, charBuf, pDict);
firstOp = gFalse;
}
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
if (nOps != 2) {
//~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
}
cvtGlyphWidth(nOps == 2, charBuf, pDict);
firstOp = gFalse;
}
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
if (nOps != 1) {
//~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
}
cvtNum(ops[k+1].num, ops[k].isFP, charBuf);
charBuf->append((char)5);
nOps = 0;
+ openPath = gTrue;
break;
case 0x0019: // rlinecurve
if (nOps < 8 || (nOps - 6) % 2 != 0) {
cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf);
charBuf->append((char)8);
nOps = 0;
+ openPath = gTrue;
break;
case 0x001a: // vvcurveto
if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
charBuf->append((char)8);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x001b: // hhcurveto
if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
charBuf->append((char)8);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x001d: // callgsubr
if (nOps >= 1) {
charBuf->append((char)8);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x001f: // hvcurveto
if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
charBuf->append((char)8);
}
nOps = 0;
+ openPath = gTrue;
break;
case 0x0c00: // dotsection (should be Type 1 only?)
// ignored
cvtNum(0, gFalse, charBuf);
charBuf->append((char)8);
nOps = 0;
+ openPath = gTrue;
break;
case 0x0c23: // flex
if (nOps != 13) {
cvtNum(ops[11].num, ops[11].isFP, charBuf);
charBuf->append((char)8);
nOps = 0;
+ openPath = gTrue;
break;
case 0x0c24: // hflex1
if (nOps != 9) {
ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf);
charBuf->append((char)8);
nOps = 0;
+ openPath = gTrue;
break;
case 0x0c25: // flex1
if (nOps != 11) {
}
charBuf->append((char)8);
nOps = 0;
+ openPath = gTrue;
break;
default:
//~ error(-1, "Illegal Type 2 charstring op: %04x",
}
nFDs = fdIdx.len;
privateDicts = (Type1CPrivateDict *)
- gmalloc(nFDs * sizeof(Type1CPrivateDict));
+ gmallocn(nFDs, sizeof(Type1CPrivateDict));
for (i = 0; i < nFDs; ++i) {
getIndexVal(&fdIdx, i, &val, &parsedOk);
if (!parsedOk) {
topDict.fontMatrix[3] = 0.001;
topDict.fontMatrix[4] = 0;
topDict.fontMatrix[5] = 0;
+ topDict.hasFontMatrix = gFalse;
topDict.uniqueID = 0;
topDict.fontBBox[0] = 0;
topDict.fontBBox[1] = 0;
topDict.fontMatrix[2] = ops[2].num;
topDict.fontMatrix[3] = ops[3].num;
topDict.fontMatrix[4] = ops[4].num;
- topDict.fontMatrix[5] = ops[5].num; break;
+ topDict.fontMatrix[5] = ops[5].num;
+ topDict.hasFontMatrix = gTrue; break;
case 0x000d: topDict.uniqueID = (int)ops[0].num; break;
case 0x0005: topDict.fontBBox[0] = ops[0].num;
topDict.fontBBox[1] = ops[1].num;
}
// Read a CID font dict (FD) - this pulls out the private dict
-// pointer, and reads the private dict.
+// pointer, and reads the private dict. It also pulls the FontMatrix
+// (if any) out of the FD.
void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) {
int pos, pSize, pOffset;
+ double fontMatrix[6];
+ GBool hasFontMatrix;
+ hasFontMatrix = gFalse;
pSize = pOffset = 0;
pos = offset;
nOps = 0;
pSize = (int)ops[0].num;
pOffset = (int)ops[1].num;
break;
+ } else if (ops[nOps - 1].op == 0x0c07) {
+ fontMatrix[0] = ops[0].num;
+ fontMatrix[1] = ops[1].num;
+ fontMatrix[2] = ops[2].num;
+ fontMatrix[3] = ops[3].num;
+ fontMatrix[4] = ops[4].num;
+ fontMatrix[5] = ops[5].num;
+ hasFontMatrix = gTrue;
}
nOps = 0;
}
}
readPrivateDict(pOffset, pSize, pDict);
+ if (hasFontMatrix) {
+ pDict->fontMatrix[0] = fontMatrix[0];
+ pDict->fontMatrix[1] = fontMatrix[1];
+ pDict->fontMatrix[2] = fontMatrix[2];
+ pDict->fontMatrix[3] = fontMatrix[3];
+ pDict->fontMatrix[4] = fontMatrix[4];
+ pDict->fontMatrix[5] = fontMatrix[5];
+ pDict->hasFontMatrix = gTrue;
+ }
}
void FoFiType1C::readPrivateDict(int offset, int length,
Type1CPrivateDict *pDict) {
int pos;
+ pDict->hasFontMatrix = gFalse;
pDict->nBlueValues = 0;
pDict->nOtherBlues = 0;
pDict->nFamilyBlues = 0;
pDict->initialRandomSeed = 0;
pDict->subrsOffset = 0;
pDict->defaultWidthX = 0;
- pDict->defaultWidthXFP = 0;
+ pDict->defaultWidthXFP = gFalse;
pDict->nominalWidthX = 0;
- pDict->nominalWidthXFP = 0;
+ pDict->nominalWidthXFP = gFalse;
// no dictionary
if (offset == 0 || length == 0) {
break;
case 0x0014:
pDict->defaultWidthX = ops[0].num;
+ pDict->defaultWidthXFP = ops[0].isFP;
break;
case 0x0015:
pDict->nominalWidthX = ops[0].num;
+ pDict->nominalWidthXFP = ops[0].isFP;
break;
}
nOps = 0;
encoding = fofiType1ExpertEncoding;
} else {
- encoding = (char **)gmalloc(256 * sizeof(char *));
+ encoding = (char **)gmallocn(256, sizeof(char *));
for (i = 0; i < 256; ++i) {
encoding[i] = NULL;
}
} else if (topDict.charsetOffset == 2) {
charset = fofiType1CExpertSubsetCharset;
} else {
- charset = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
+ charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort));
for (i = 0; i < nGlyphs; ++i) {
charset[i] = 0;
}
idx->pos = pos;
idx->len = getU16BE(pos, ok);
if (idx->len == 0) {
- // empty indexes are legal
+ // empty indexes are legal and contain just the length field
idx->offSize = 0;
- idx->startPos = idx->endPos = 0;
+ idx->startPos = idx->endPos = pos + 2;
} else {
idx->offSize = getU8(pos + 2, ok);
if (idx->offSize < 1 || idx->offSize > 4) {
idx->offSize, ok);
pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize,
idx->offSize, ok);
- if (pos0 < idx->startPos || pos0 >= idx->endPos ||
+ if (pos0 < idx->startPos || pos0 > idx->endPos ||
pos1 <= idx->startPos || pos1 > idx->endPos ||
pos1 < pos0) {
*ok = gFalse;
} else {
sid -= 391;
getIndexVal(&stringIdx, sid, &val, ok);
- if (ok) {
+ if (*ok) {
if ((n = val.len) > 255) {
n = 255;
}
#pragma implementation
#endif
+#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#define functionMaxDepth 6
// Max delta allowed in any color component for a function shading fill.
-#define functionColorDelta (1 / 256.0)
+#define functionColorDelta (dblToCol(1 / 256.0))
// Max number of splits along the t axis for an axial shading fill.
#define axialMaxSplits 256
// Max delta allowed in any color component for an axial shading fill.
-#define axialColorDelta (1 / 256.0)
+#define axialColorDelta (dblToCol(1 / 256.0))
// Max number of splits along the t axis for a radial shading fill.
#define radialMaxSplits 256
// Max delta allowed in any color component for a radial shading fill.
-#define radialColorDelta (1 / 256.0)
+#define radialColorDelta (dblToCol(1 / 256.0))
+
+// Max recursive depth for a Gouraud triangle shading fill.
+#define gouraudMaxDepth 4
+
+// Max delta allowed in any color component for a Gouraud triangle
+// shading fill.
+#define gouraudColorDelta (dblToCol(1 / 256.0))
+
+// Max recursive depth for a patch mesh shading fill.
+#define patchMaxDepth 6
+
+// Max delta allowed in any color component for a patch mesh shading
+// fill.
+#define patchColorDelta (dblToCol(1 / 256.0))
//------------------------------------------------------------------------
// Operator table
//------------------------------------------------------------------------
Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
- double hDPI, double vDPI, PDFRectangle *box, GBool crop,
+ double hDPI, double vDPI, PDFRectangle *box,
PDFRectangle *cropBox, int rotate,
GBool (*abortCheckCbkA)(void *data),
void *abortCheckCbkDataA) {
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
- out->startPage(pageNum, state, cropBox->x1,cropBox->y1,cropBox->x2,cropBox->y2);
+ out->startPage(pageNum, state);
out->setDefaultCTM(state->getCTM());
out->updateAll(state);
for (i = 0; i < 6; ++i) {
abortCheckCbkData = abortCheckCbkDataA;
// set crop box
- /*if (crop) {
+ if (cropBox) {
state->moveTo(cropBox->x1, cropBox->y1);
state->lineTo(cropBox->x2, cropBox->y1);
state->lineTo(cropBox->x2, cropBox->y2);
state->clip();
out->clip(state);
state->clearPath();
- }*/
+ }
}
Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
- PDFRectangle *box, GBool crop, PDFRectangle *cropBox,
+ PDFRectangle *box, PDFRectangle *cropBox,
GBool (*abortCheckCbkA)(void *data),
void *abortCheckCbkDataA) {
int i;
abortCheckCbkData = abortCheckCbkDataA;
// set crop box
- if (crop) {
+ if (cropBox) {
state->moveTo(cropBox->x1, cropBox->y1);
state->lineTo(cropBox->x2, cropBox->y1);
state->lineTo(cropBox->x2, cropBox->y2);
if (length == 0) {
dash = NULL;
} else {
- dash = (double *)gmalloc(length * sizeof(double));
+ dash = (double *)gmallocn(length, sizeof(double));
for (i = 0; i < length; ++i) {
dash[i] = a->get(i, &obj)->getNum();
obj.free();
void Gfx::opSetExtGState(Object args[], int numArgs) {
Object obj1, obj2;
+ GfxBlendMode mode;
+ GBool haveFillOP;
if (!res->lookupGState(args[0].getName(), &obj1)) {
return;
obj1.free();
return;
}
+
+ // transparency support: blend mode, fill/stroke opacity
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+ if (state->parseBlendMode(&obj2, &mode)) {
+ state->setBlendMode(mode);
+ out->updateBlendMode(state);
+ } else {
+ error(getPos(), "Invalid blend mode in ExtGState");
+ }
+ }
+ obj2.free();
if (obj1.dictLookup("ca", &obj2)->isNum()) {
state->setFillOpacity(obj2.getNum());
out->updateFillOpacity(state);
out->updateStrokeOpacity(state);
}
obj2.free();
+
+ // fill/stroke overprint
+ if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("OP", &obj2)->isBool()) {
+ state->setStrokeOverprint(obj2.getBool());
+ out->updateStrokeOverprint(state);
+ if (!haveFillOP) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ }
+ obj2.free();
+
obj1.free();
}
state->setFillPattern(NULL);
state->setFillColorSpace(new GfxDeviceGrayColorSpace());
- color.c[0] = args[0].getNum();
+ out->updateFillColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
state->setFillColor(&color);
out->updateFillColor(state);
}
state->setStrokePattern(NULL);
state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
- color.c[0] = args[0].getNum();
+ out->updateStrokeColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
state->setStrokeColor(&color);
out->updateStrokeColor(state);
}
state->setFillPattern(NULL);
state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+ out->updateFillColorSpace(state);
for (i = 0; i < 4; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setFillColor(&color);
out->updateFillColor(state);
state->setStrokePattern(NULL);
state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
+ out->updateStrokeColorSpace(state);
for (i = 0; i < 4; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setStrokeColor(&color);
out->updateStrokeColor(state);
state->setFillPattern(NULL);
state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateFillColorSpace(state);
for (i = 0; i < 3; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setFillColor(&color);
out->updateFillColor(state);
state->setStrokePattern(NULL);
state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateStrokeColorSpace(state);
for (i = 0; i < 3; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setStrokeColor(&color);
out->updateStrokeColor(state);
obj.free();
if (colorSpace) {
state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
} else {
error(getPos(), "Bad color space (fill)");
}
obj.free();
if (colorSpace) {
state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
} else {
error(getPos(), "Bad color space (stroke)");
}
state->setFillPattern(NULL);
for (i = 0; i < numArgs; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setFillColor(&color);
out->updateFillColor(state);
state->setStrokePattern(NULL);
for (i = 0; i < numArgs; ++i) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
state->setStrokeColor(&color);
out->updateStrokeColor(state);
if (numArgs > 1) {
for (i = 0; i < numArgs && i < 4; ++i) {
if (args[i].isNum()) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
}
state->setFillColor(&color);
state->setFillPattern(NULL);
for (i = 0; i < numArgs && i < 4; ++i) {
if (args[i].isNum()) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
}
state->setFillColor(&color);
if (numArgs > 1) {
for (i = 0; i < numArgs && i < 4; ++i) {
if (args[i].isNum()) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
}
state->setStrokeColor(&color);
state->setStrokePattern(NULL);
for (i = 0; i < numArgs && i < 4; ++i) {
if (args[i].isNum()) {
- color.c[i] = args[i].getNum();
+ color.c[i] = dblToCol(args[i].getNum());
}
}
state->setStrokeColor(&color);
m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
- // construct a (base space) -> (pattern space) transform matrix
+ // construct a (device space) -> (pattern space) transform matrix
det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
imb[0] = m1[3] * det;
imb[1] = -m1[1] * det;
// Adobe's behavior
if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
state->setFillColorSpace(cs->copy());
+ out->updateFillColorSpace(state);
state->setStrokeColorSpace(cs->copy());
+ out->updateStrokeColorSpace(state);
state->setStrokeColor(state->getFillColor());
} else {
state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateFillColorSpace(state);
state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateStrokeColorSpace(state);
}
state->setFillPattern(NULL);
out->updateFillColor(state);
}
state->clearPath();
- // transform clip region bbox to pattern space
+ // get the clip region, check for empty
state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ if (cxMin > cxMax || cyMin > cyMax) {
+ goto err;
+ }
+
+ // transform clip region bbox to pattern space
xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
for (i = 0; i < 4; ++i) {
m1[i] = m[i];
}
- for (yi = yi0; yi < yi1; ++yi) {
- for (xi = xi0; xi < xi1; ++xi) {
- x = xi * xstep;
- y = yi * ystep;
- m1[4] = x * m[0] + y * m[2] + m[4];
- m1[5] = x * m[1] + y * m[3] + m[5];
- doForm1(tPat->getContentStream(), tPat->getResDict(),
- m1, tPat->getBBox());
+ if (out->useTilingPatternFill()) {
+ m1[4] = m[4];
+ m1[5] = m[5];
+ out->tilingPatternFill(state, tPat->getContentStream(),
+ tPat->getPaintType(), tPat->getResDict(),
+ m1, tPat->getBBox(),
+ xi0, yi0, xi1, yi1, xstep, ystep);
+ } else {
+ for (yi = yi0; yi < yi1; ++yi) {
+ for (xi = xi0; xi < xi1; ++xi) {
+ x = xi * xstep;
+ y = yi * ystep;
+ m1[4] = x * m[0] + y * m[2] + m[4];
+ m1[5] = x * m[1] + y * m[3] + m[5];
+ doForm1(tPat->getContentStream(), tPat->getResDict(),
+ m1, tPat->getBBox());
+ }
}
}
// restore graphics state
+ err:
restoreState();
state->setPath(savedPath);
}
state->closePath();
state->clip();
out->clip(state);
- state->clearPath();
+ state->setPath(savedPath->copy());
}
// clip to current path
} else {
out->clip(state);
}
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
+
+ // background color fill
+ if (shading->getHasBackground()) {
+ state->setFillColor(shading->getBackground());
+ out->updateFillColor(state);
+ out->fill(state);
+ }
state->clearPath();
// construct a (pattern space) -> (current space) transform matrix
state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
- // set the color space
- state->setFillColorSpace(shading->getColorSpace()->copy());
-
// do shading type-specific operations
switch (shading->getType()) {
case 1:
case 3:
doRadialShFill((GfxRadialShading *)shading);
break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
}
// restore graphics state
// set the color space
state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
// do shading type-specific operations
switch (shading->getType()) {
case 3:
doRadialShFill((GfxRadialShading *)shading);
break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
}
// restore graphics state
double x0, y0, x1, y1;
GfxColor colors[4];
- shading->getDomain(&x0, &y0, &x1, &y1);
- shading->getColor(x0, y0, &colors[0]);
- shading->getColor(x0, y1, &colors[1]);
- shading->getColor(x1, y0, &colors[2]);
- shading->getColor(x1, y1, &colors[3]);
- doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
+ if (out->useShadedFills()) {
+ out->functionShadedFill(state, shading);
+ } else {
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ shading->getColor(x0, y0, &colors[0]);
+ shading->getColor(x0, y1, &colors[1]);
+ shading->getColor(x1, y0, &colors[2]);
+ shading->getColor(x1, y1, &colors[3]);
+ doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
+ }
}
void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
// compare the four corner colors
for (i = 0; i < 4; ++i) {
for (j = 0; j < nComps; ++j) {
- if (fabs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
+ if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
break;
}
}
// center of the rectangle
xM = 0.5 * (x0 + x1);
yM = 0.5 * (y0 + y1);
-
- out->useGradients();
// the four corner colors are close (or we hit the recursive limit)
// -- fill the rectangle; but require at least one subdivision
double xMin, yMin, xMax, yMax;
double x0, y0, x1, y1;
double dx, dy, mul;
+ GBool dxZero, dyZero;
double tMin, tMax, t, tx, ty;
double s[4], sMin, sMax, tmp;
double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
int nComps;
int i, j, k, kk;
- // get the clip region bbox
- state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
-
- // compute min and max t values, based on the four corners of the
- // clip region bbox
- shading->getCoords(&x0, &y0, &x1, &y1);
- dx = x1 - x0;
- dy = y1 - y0;
- mul = 1 / (dx * dx + dy * dy);
- tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
- t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
- if (t < tMin) {
- tMin = t;
- } else if (t > tMax) {
- tMax = t;
- }
- t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
- if (t < tMin) {
- tMin = t;
- } else if (t > tMax) {
- tMax = t;
- }
- t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
- if (t < tMin) {
- tMin = t;
- } else if (t > tMax) {
- tMax = t;
- }
- if (tMin < 0 && !shading->getExtend0()) {
- tMin = 0;
- }
- if (tMax > 1 && !shading->getExtend1()) {
- tMax = 1;
- }
-
- // get the function domain
- t0 = shading->getDomain0();
- t1 = shading->getDomain1();
-
- // Traverse the t axis and do the shading.
- //
- // For each point (tx, ty) on the t axis, consider a line through
- // that point perpendicular to the t axis:
- //
- // x(s) = tx + s * -dy --> s = (x - tx) / -dy
- // y(s) = ty + s * dx --> s = (y - ty) / dx
- //
- // Then look at the intersection of this line with the bounding box
- // (xMin, yMin, xMax, yMax). In the general case, there are four
- // intersection points:
- //
- // s0 = (xMin - tx) / -dy
- // s1 = (xMax - tx) / -dy
- // s2 = (yMin - ty) / dx
- // s3 = (yMax - ty) / dx
- //
- // and we want the middle two s values.
- //
- // In the case where dx = 0, take s0 and s1; in the case where dy =
- // 0, take s2 and s3.
- //
- // Each filled polygon is bounded by two of these line segments
- // perpdendicular to the t axis.
- //
- // The t axis is bisected into smaller regions until the color
- // difference across a region is small enough, and then the region
- // is painted with a single color.
-
- // set up: require at least one split to avoid problems when the two
- // ends of the t axis have the same color
- nComps = shading->getColorSpace()->getNComps();
- ta[0] = tMin;
- next[0] = axialMaxSplits / 2;
- ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
- next[axialMaxSplits / 2] = axialMaxSplits;
- ta[axialMaxSplits] = tMax;
-
- // compute the color at t = tMin
- if (tMin < 0) {
- tt = t0;
- } else if (tMin > 1) {
- tt = t1;
- } else {
- tt = t0 + (t1 - t0) * tMin;
- }
- shading->getColor(tt, &color0);
-
- // compute the coordinates of the point on the t axis at t = tMin;
- // then compute the intersection of the perpendicular line with the
- // bounding box
- tx = x0 + tMin * dx;
- ty = y0 + tMin * dy;
- if (dx == 0 && dy == 0) {
- sMin = sMax = 0;
- } if (dx == 0) {
- sMin = (xMin - tx) / -dy;
- sMax = (xMax - tx) / -dy;
- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
- } else if (dy == 0) {
- sMin = (yMin - ty) / dx;
- sMax = (yMax - ty) / dx;
- if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ if (out->useShadedFills()) {
+
+ out->axialShadedFill(state, shading);
+
} else {
- s[0] = (yMin - ty) / dx;
- s[1] = (yMax - ty) / dx;
- s[2] = (xMin - tx) / -dy;
- s[3] = (xMax - tx) / -dy;
- for (j = 0; j < 3; ++j) {
- kk = j;
- for (k = j + 1; k < 4; ++k) {
- if (s[k] < s[kk]) {
- kk = k;
- }
- }
- tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
- }
- sMin = s[1];
- sMax = s[2];
- }
- ux0 = tx - sMin * dy;
- uy0 = ty + sMin * dx;
- vx0 = tx - sMax * dy;
- vy0 = ty + sMax * dx;
-
- i = 0;
- if(i < axialMaxSplits)
- out->useGradients();
-
- while (i < axialMaxSplits) {
-
- // bisect until color difference is small enough or we hit the
- // bisection limit
- j = next[i];
- while (j > i + 1) {
- if (ta[j] < 0) {
- tt = t0;
- } else if (ta[j] > 1) {
- tt = t1;
- } else {
- tt = t0 + (t1 - t0) * ta[j];
- }
- shading->getColor(tt, &color1);
- for (k = 0; k < nComps; ++k) {
- if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) {
- break;
- }
- }
- if (k == nComps) {
- break;
- }
- k = (i + j) / 2;
- ta[k] = 0.5 * (ta[i] + ta[j]);
- next[i] = k;
- next[k] = j;
- j = k;
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ dxZero = fabs(dx) < 0.001;
+ dyZero = fabs(dy) < 0.001;
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
}
- // use the average of the colors of the two sides of the region
- for (k = 0; k < nComps; ++k) {
- color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]);
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up: require at least one split to avoid problems when the two
+ // ends of the t axis have the same color
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ next[0] = axialMaxSplits / 2;
+ ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
+ next[axialMaxSplits / 2] = axialMaxSplits;
+ ta[axialMaxSplits] = tMax;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
}
+ shading->getColor(tt, &color0);
- // compute the coordinates of the point on the t axis; then
- // compute the intersection of the perpendicular line with the
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
// bounding box
- tx = x0 + ta[j] * dx;
- ty = y0 + ta[j] * dy;
- if (dx == 0 && dy == 0) {
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dxZero && dyZero) {
sMin = sMax = 0;
- } if (dx == 0) {
+ } if (dxZero) {
sMin = (xMin - tx) / -dy;
sMax = (xMax - tx) / -dy;
if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
- } else if (dy == 0) {
+ } else if (dyZero) {
sMin = (yMin - ty) / dx;
sMax = (yMax - ty) / dx;
if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
sMin = s[1];
sMax = s[2];
}
- ux1 = tx - sMin * dy;
- uy1 = ty + sMin * dx;
- vx1 = tx - sMax * dy;
- vy1 = ty + sMax * dx;
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ for (k = 0; k < nComps; ++k) {
+ if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
- // set the color
- state->setFillColor(&color0);
- out->updateFillColor(state);
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = (color0.c[k] + color1.c[k]) / 2;
+ }
- // fill the region
- state->moveTo(ux0, uy0);
- state->lineTo(vx0, vy0);
- state->lineTo(vx1, vy1);
- state->lineTo(ux1, uy1);
- state->closePath();
- out->fill(state);
- state->clearPath();
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dxZero && dyZero) {
+ sMin = sMax = 0;
+ } if (dxZero) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dyZero) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
- // set up for next region
- ux0 = ux1;
- uy0 = uy1;
- vx0 = vx1;
- vy0 = vy1;
- color0 = color1;
- i = next[i];
+ // set the color
+ state->setFillColor(&color0);
+ out->updateFillColor(state);
+
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
}
}
double ta, tb, sa, sb;
int ia, ib, k, n;
double *ctm;
- double angle, t;
+ double angle, t, d0, d1;
- // get the shading info
- shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
- t0 = shading->getDomain0();
- t1 = shading->getDomain1();
- nComps = shading->getColorSpace()->getNComps();
+ if (out->useShadedFills()) {
- // compute the (possibly extended) s range
- sMin = 0;
- sMax = 1;
- if (shading->getExtend0()) {
- if (r0 < r1) {
- // extend the smaller end
- sMin = -r0 / (r1 - r0);
- } else {
- // extend the larger end
- //~ this computes the diagonal of the bounding box -- we should
- //~ really compute the intersection of the moving/expanding
- //~ circles with each of the four corners and look for the max
- //~ radius
- state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
- sMin = (sqrt((xMax - xMin) * (xMax - xMin) +
- (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
- if (sMin > 0) {
- sMin = 0;
- } else if (sMin < -20) {
- // sanity check
- sMin = -20;
+ out->radialShadedFill(state, shading);
+
+ } else {
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ nComps = shading->getColorSpace()->getNComps();
+
+ // compute the (possibly extended) s range
+ sMin = 0;
+ sMax = 1;
+ if (shading->getExtend0()) {
+ if (r0 < r1) {
+ // extend the smaller end
+ sMin = -r0 / (r1 - r0);
+ } else {
+ // extend the larger end
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ d0 = (x0 - xMin) * (x0 - xMin);
+ d1 = (x0 - xMax) * (x0 - xMax);
+ sMin = d0 > d1 ? d0 : d1;
+ d0 = (y0 - yMin) * (y0 - yMin);
+ d1 = (y0 - yMax) * (y0 - yMax);
+ sMin += d0 > d1 ? d0 : d1;
+ sMin = (sqrt(sMin) - r0) / (r1 - r0);
+ if (sMin > 0) {
+ sMin = 0;
+ } else if (sMin < -20) {
+ // sanity check
+ sMin = -20;
+ }
}
}
- }
- if (shading->getExtend1()) {
- if (r1 < r0) {
- // extend the smaller end
- sMax = -r0 / (r1 - r0);
- } else if (r1 > r0) {
- // extend the larger end
- state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
- sMax = (sqrt((xMax - xMin) * (xMax - xMin) +
- (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
- if (sMax < 1) {
- sMin = 1;
- } else if (sMax > 20) {
- // sanity check
- sMax = 20;
+ if (shading->getExtend1()) {
+ if (r1 < r0) {
+ // extend the smaller end
+ sMax = -r0 / (r1 - r0);
+ } else if (r1 > r0) {
+ // extend the larger end
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ d0 = (x1 - xMin) * (x1 - xMin);
+ d1 = (x1 - xMax) * (x1 - xMax);
+ sMax = d0 > d1 ? d0 : d1;
+ d0 = (y1 - yMin) * (y1 - yMin);
+ d1 = (y1 - yMax) * (y1 - yMax);
+ sMax += d0 > d1 ? d0 : d1;
+ sMax = (sqrt(sMax) - r0) / (r1 - r0);
+ if (sMax < 1) {
+ sMax = 1;
+ } else if (sMax > 20) {
+ // sanity check
+ sMax = 20;
+ }
}
}
- }
- // compute the number of steps into which circles must be divided to
- // achieve a curve flatness of 0.1 pixel in device space for the
- // largest circle (note that "device space" is 72 dpi when generating
- // PostScript, hence the relatively small 0.1 pixel accuracy)
- ctm = state->getCTM();
- t = fabs(ctm[0]);
- if (fabs(ctm[1]) > t) {
- t = fabs(ctm[1]);
- }
- if (fabs(ctm[2]) > t) {
- t = fabs(ctm[2]);
- }
- if (fabs(ctm[3]) > t) {
- t = fabs(ctm[3]);
- }
- if (r0 > r1) {
- t *= r0;
- } else {
- t *= r1;
- }
- if (t < 1) {
- n = 3;
- } else {
- n = (int)(M_PI / acos(1 - 0.1 / t));
- if (n < 3) {
- n = 3;
- } else if (n > 200) {
- n = 200;
- }
- }
-
- // Traverse the t axis and do the shading.
- //
- // This generates and fills a series of rings. Each ring is defined
- // by two circles:
- // sa, ta, xa, ya, ra, colorA
- // sb, tb, xb, yb, rb, colorB
- //
- // The s/t axis is divided into radialMaxSplits parts; these parts
- // are combined as much as possible while respecting the
- // radialColorDelta parameter.
-
- // setup for the start circle
- ia = 0;
- sa = sMin;
- ta = t0 + sa * (t1 - t0);
- xa = x0 + sa * (x1 - x0);
- ya = y0 + sa * (y1 - y0);
- ra = r0 + sa * (r1 - r0);
- if (ta < t0) {
- shading->getColor(t0, &colorA);
- } else if (ta > t1) {
- shading->getColor(t1, &colorA);
- } else {
- shading->getColor(ta, &colorA);
- }
-
- if(ia < radialMaxSplits)
- out->useGradients();
-
- while (ia < radialMaxSplits) {
-
- // go as far along the t axis (toward t1) as we can, such that the
- // color difference is within the tolerance (radialColorDelta) --
- // this uses bisection (between the current value, t, and t1),
- // limited to radialMaxSplits points along the t axis; require at
- // least one split to avoid problems when the innermost and
- // outermost colors are the same
- ib = radialMaxSplits;
- sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
- tb = t0 + sb * (t1 - t0);
- if (tb < t0) {
- shading->getColor(t0, &colorB);
- } else if (tb > t1) {
- shading->getColor(t1, &colorB);
+ // compute the number of steps into which circles must be divided to
+ // achieve a curve flatness of 0.1 pixel in device space for the
+ // largest circle (note that "device space" is 72 dpi when generating
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
+ ctm = state->getCTM();
+ t = fabs(ctm[0]);
+ if (fabs(ctm[1]) > t) {
+ t = fabs(ctm[1]);
+ }
+ if (fabs(ctm[2]) > t) {
+ t = fabs(ctm[2]);
+ }
+ if (fabs(ctm[3]) > t) {
+ t = fabs(ctm[3]);
+ }
+ if (r0 > r1) {
+ t *= r0;
} else {
- shading->getColor(tb, &colorB);
+ t *= r1;
}
- while (ib - ia > 1) {
- for (k = 0; k < nComps; ++k) {
- if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
- break;
- }
- }
- if (k == nComps && ib < radialMaxSplits) {
- break;
+ if (t < 1) {
+ n = 3;
+ } else {
+ n = (int)(M_PI / acos(1 - 0.1 / t));
+ if (n < 3) {
+ n = 3;
+ } else if (n > 200) {
+ n = 200;
}
- ib = (ia + ib) / 2;
+ }
+
+ // Traverse the t axis and do the shading.
+ //
+ // This generates and fills a series of rings. Each ring is defined
+ // by two circles:
+ // sa, ta, xa, ya, ra, colorA
+ // sb, tb, xb, yb, rb, colorB
+ //
+ // The s/t axis is divided into radialMaxSplits parts; these parts
+ // are combined as much as possible while respecting the
+ // radialColorDelta parameter.
+
+ // setup for the start circle
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ if (ta < t0) {
+ shading->getColor(t0, &colorA);
+ } else if (ta > t1) {
+ shading->getColor(t1, &colorA);
+ } else {
+ shading->getColor(ta, &colorA);
+ }
+
+ while (ia < radialMaxSplits) {
+
+ // go as far along the t axis (toward t1) as we can, such that the
+ // color difference is within the tolerance (radialColorDelta) --
+ // this uses bisection (between the current value, t, and t1),
+ // limited to radialMaxSplits points along the t axis; require at
+ // least one split to avoid problems when the innermost and
+ // outermost colors are the same
+ ib = radialMaxSplits;
sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
tb = t0 + sb * (t1 - t0);
if (tb < t0) {
} else {
shading->getColor(tb, &colorB);
}
- }
+ while (ib - ia > 1) {
+ for (k = 0; k < nComps; ++k) {
+ if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps && ib < radialMaxSplits) {
+ break;
+ }
+ ib = (ia + ib) / 2;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ }
+
+ // compute center and radius of the circle
+ xb = x0 + sb * (x1 - x0);
+ yb = y0 + sb * (y1 - y0);
+ rb = r0 + sb * (r1 - r0);
+
+ // use the average of the colors at the two circles
+ for (k = 0; k < nComps; ++k) {
+ colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2;
+ }
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+
+ // construct path for first circle
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
- // compute center and radius of the circle
- xb = x0 + sb * (x1 - x0);
- yb = y0 + sb * (y1 - y0);
- rb = r0 + sb * (r1 - r0);
+ // construct and append path for second circle
+ state->moveTo(xb + rb, yb);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ state->closePath();
- // use the average of the colors at the two circles
- for (k = 0; k < nComps; ++k) {
- colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]);
+ // fill the ring
+ out->eoFill(state);
+ state->clearPath();
+
+ // step to the next value of t
+ ia = ib;
+ sa = sb;
+ ta = tb;
+ xa = xb;
+ ya = yb;
+ ra = rb;
+ colorA = colorB;
}
- state->setFillColor(&colorA);
- out->updateFillColor(state);
+ }
+}
+
+void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
+ double x0, y0, x1, y1, x2, y2;
+ GfxColor color0, color1, color2;
+ int i;
+
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
+ shading->getColorSpace()->getNComps(), 0);
+ }
+}
+
+void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth) {
+ double x01, y01, x12, y12, x20, y20;
+ GfxColor color01, color12, color20;
+ int i;
- // construct path for first circle
- state->moveTo(xa + ra, ya);
- for (k = 1; k < n; ++k) {
- angle = ((double)k / (double)n) * 2 * M_PI;
- state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ for (i = 0; i < nComps; ++i) {
+ if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
+ abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
+ break;
}
+ }
+ if (i == nComps || depth == gouraudMaxDepth) {
+ state->setFillColor(color0);
+ out->updateFillColor(state);
+ state->moveTo(x0, y0);
+ state->lineTo(x1, y1);
+ state->lineTo(x2, y2);
state->closePath();
+ out->fill(state);
+ state->clearPath();
+ } else {
+ x01 = 0.5 * (x0 + x1);
+ y01 = 0.5 * (y0 + y1);
+ x12 = 0.5 * (x1 + x2);
+ y12 = 0.5 * (y1 + y2);
+ x20 = 0.5 * (x2 + x0);
+ y20 = 0.5 * (y2 + y0);
+ //~ if the shading has a Function, this should interpolate on the
+ //~ function parameter, not on the color components
+ for (i = 0; i < nComps; ++i) {
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
+ color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
+ color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
+ }
+ gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
+ x20, y20, &color20, nComps, depth + 1);
+ gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
+ x12, y12, &color12, nComps, depth + 1);
+ gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
+ x20, y20, &color20, nComps, depth + 1);
+ gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
+ x2, y2, color2, nComps, depth + 1);
+ }
+}
+
+void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
+ int start, i;
+
+ if (shading->getNPatches() > 128) {
+ start = 3;
+ } else if (shading->getNPatches() > 64) {
+ start = 2;
+ } else if (shading->getNPatches() > 16) {
+ start = 1;
+ } else {
+ start = 0;
+ }
+ for (i = 0; i < shading->getNPatches(); ++i) {
+ fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
+ start);
+ }
+}
- // construct and append path for second circle
- state->moveTo(xb + rb, yb);
- for (k = 1; k < n; ++k) {
- angle = ((double)k / (double)n) * 2 * M_PI;
- state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
+ GfxPatch patch00, patch01, patch10, patch11;
+ double xx[4][8], yy[4][8];
+ double xxm, yym;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
+ > patchColorDelta ||
+ abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
+ > patchColorDelta ||
+ abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
+ > patchColorDelta ||
+ abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
+ > patchColorDelta) {
+ break;
}
+ }
+ if (i == nComps || depth == patchMaxDepth) {
+ state->setFillColor(&patch->color[0][0]);
+ out->updateFillColor(state);
+ state->moveTo(patch->x[0][0], patch->y[0][0]);
+ state->curveTo(patch->x[0][1], patch->y[0][1],
+ patch->x[0][2], patch->y[0][2],
+ patch->x[0][3], patch->y[0][3]);
+ state->curveTo(patch->x[1][3], patch->y[1][3],
+ patch->x[2][3], patch->y[2][3],
+ patch->x[3][3], patch->y[3][3]);
+ state->curveTo(patch->x[3][2], patch->y[3][2],
+ patch->x[3][1], patch->y[3][1],
+ patch->x[3][0], patch->y[3][0]);
+ state->curveTo(patch->x[2][0], patch->y[2][0],
+ patch->x[1][0], patch->y[1][0],
+ patch->x[0][0], patch->y[0][0]);
state->closePath();
-
- // fill the ring
- out->eoFill(state);
+ out->fill(state);
state->clearPath();
-
- // step to the next value of t
- ia = ib;
- sa = sb;
- ta = tb;
- xa = xb;
- ya = yb;
- ra = rb;
- colorA = colorB;
+ } else {
+ for (i = 0; i < 4; ++i) {
+ xx[i][0] = patch->x[i][0];
+ yy[i][0] = patch->y[i][0];
+ xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
+ yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
+ xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
+ yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
+ xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
+ yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
+ xx[i][2] = 0.5 * (xx[i][1] + xxm);
+ yy[i][2] = 0.5 * (yy[i][1] + yym);
+ xx[i][5] = 0.5 * (xxm + xx[i][6]);
+ yy[i][5] = 0.5 * (yym + yy[i][6]);
+ xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
+ yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
+ xx[i][7] = patch->x[i][3];
+ yy[i][7] = patch->y[i][3];
+ }
+ for (i = 0; i < 4; ++i) {
+ patch00.x[0][i] = xx[0][i];
+ patch00.y[0][i] = yy[0][i];
+ patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
+ patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
+ patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
+ patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
+ patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
+ patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
+ patch10.x[0][i] = patch00.x[3][i];
+ patch10.y[0][i] = patch00.y[3][i];
+ patch10.x[3][i] = xx[3][i];
+ patch10.y[3][i] = yy[3][i];
+ }
+ for (i = 4; i < 8; ++i) {
+ patch01.x[0][i-4] = xx[0][i];
+ patch01.y[0][i-4] = yy[0][i];
+ patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
+ patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
+ patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
+ patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
+ patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
+ patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
+ patch11.x[0][i-4] = patch01.x[3][i-4];
+ patch11.y[0][i-4] = patch01.y[3][i-4];
+ patch11.x[3][i-4] = xx[3][i];
+ patch11.y[3][i-4] = yy[3][i];
+ }
+ //~ if the shading has a Function, this should interpolate on the
+ //~ function parameter, not on the color components
+ for (i = 0; i < nComps; ++i) {
+ patch00.color[0][0].c[i] = patch->color[0][0].c[i];
+ patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
+ patch->color[0][1].c[i]) / 2;
+ patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
+ patch01.color[0][1].c[i] = patch->color[0][1].c[i];
+ patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
+ patch->color[1][1].c[i]) / 2;
+ patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
+ patch11.color[1][1].c[i] = patch->color[1][1].c[i];
+ patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
+ patch->color[1][0].c[i]) / 2;
+ patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
+ patch10.color[1][0].c[i] = patch->color[1][0].c[i];
+ patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
+ patch->color[0][0].c[i]) / 2;
+ patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
+ patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
+ patch01.color[1][1].c[i]) / 2;
+ patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
+ patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
+ patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
+ }
+ fillPatch(&patch00, nComps, depth + 1);
+ fillPatch(&patch10, nComps, depth + 1);
+ fillPatch(&patch01, nComps, depth + 1);
+ fillPatch(&patch11, nComps, depth + 1);
}
}
error(getPos(), "No font in show");
return;
}
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
doShowText(args[0].getString());
+ out->endStringOp(state);
}
void Gfx::opMoveShowText(Object args[], int numArgs) {
error(getPos(), "No font in move/show");
return;
}
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
tx = state->getLineX();
ty = state->getLineY() - state->getLeading();
state->textMoveTo(tx, ty);
out->updateTextPos(state);
+ out->beginStringOp(state);
doShowText(args[0].getString());
+ out->endStringOp(state);
}
void Gfx::opMoveSetShowText(Object args[], int numArgs) {
error(getPos(), "No font in move/set/show");
return;
}
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
state->setWordSpace(args[0].getNum());
state->setCharSpace(args[1].getNum());
tx = state->getLineX();
out->updateWordSpace(state);
out->updateCharSpace(state);
out->updateTextPos(state);
+ out->beginStringOp(state);
doShowText(args[2].getString());
+ out->endStringOp(state);
}
void Gfx::opShowSpaceText(Object args[], int numArgs) {
error(getPos(), "No font in show/space");
return;
}
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
wMode = state->getFont()->getWMode();
a = args[0].getArray();
for (i = 0; i < a->getLength(); ++i) {
a->get(i, &obj);
if (obj.isNum()) {
+ // this uses the absolute value of the font size to match
+ // Acrobat's behavior
if (wMode) {
- state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize());
+ state->textShift(0, -obj.getNum() * 0.001 *
+ fabs(state->getFontSize()));
} else {
- state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0);
+ state->textShift(-obj.getNum() * 0.001 *
+ fabs(state->getFontSize()), 0);
}
out->updateTextShift(state, obj.getNum());
} else if (obj.isString()) {
}
obj.free();
}
+ out->endStringOp(state);
}
void Gfx::doShowText(GString *s) {
char *p;
int len, n, uLen, nChars, nSpaces, i;
- if (fontChanged) {
- out->updateFont(state);
- fontChanged = gFalse;
- }
font = state->getFont();
wMode = font->getWMode();
originY *= state->getFontSize();
state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
- tdx, tdy, tOriginX, tOriginY, code, u, uLen);
+ tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
state->shift(tdx, tdy);
p += n;
len -= n;
#endif
obj1.streamGetDict()->lookup("Subtype", &obj2);
if (obj2.isName("Image")) {
- res->lookupXObjectNF(args[0].getName(), &refObj);
- doImage(&refObj, obj1.getStream(), gFalse);
- refObj.free();
+ if (out->needNonText()) {
+ res->lookupXObjectNF(args[0].getName(), &refObj);
+ doImage(&refObj, obj1.getStream(), gFalse);
+ refObj.free();
+ }
} else if (obj2.isName("Form")) {
doForm(&obj1);
} else if (obj2.isName("PS")) {
}
void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
- Dict *dict;
+ Dict *dict, *maskDict;
int width, height;
- int bits;
+ int bits, maskBits;
+ StreamColorSpaceMode csMode;
GBool mask;
GBool invert;
- GfxColorSpace *colorSpace;
- GfxImageColorMap *colorMap;
- Object maskObj;
- GBool haveMask;
+ GfxColorSpace *colorSpace, *maskColorSpace;
+ GfxImageColorMap *colorMap, *maskColorMap;
+ Object maskObj, smaskObj;
+ GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
int maskColors[2*gfxColorMaxComps];
+ int maskWidth, maskHeight;
+ GBool maskInvert;
+ Stream *maskStr;
Object obj1, obj2;
int i;
+ // get info from the stream
+ bits = 0;
+ csMode = streamCSNone;
+ str->getImageParams(&bits, &csMode);
+
// get stream dict
dict = str->getDict();
obj1.free();
// bit depth
- dict->lookup("BitsPerComponent", &obj1);
- if (obj1.isNull()) {
+ if (bits == 0) {
+ dict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("BPC", &obj1);
+ }
+ if (obj1.isInt()) {
+ bits = obj1.getInt();
+ } else if (mask) {
+ bits = 1;
+ } else {
+ goto err2;
+ }
obj1.free();
- dict->lookup("BPC", &obj1);
}
- if (obj1.isInt()) {
- bits = obj1.getInt();
- } else if (mask) {
- bits = 1;
- } else {
- goto err2;
- }
- obj1.free();
// display a mask
if (mask) {
obj2.free();
}
}
- colorSpace = GfxColorSpace::parse(&obj1);
+ if (!obj1.isNull()) {
+ colorSpace = GfxColorSpace::parse(&obj1);
+ } else if (csMode == streamCSDeviceGray) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ } else if (csMode == streamCSDeviceRGB) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ } else if (csMode == streamCSDeviceCMYK) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ } else {
+ colorSpace = NULL;
+ }
obj1.free();
if (!colorSpace) {
goto err1;
}
// get the mask
- haveMask = gFalse;
+ haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
+ maskStr = NULL; // make gcc happy
+ maskWidth = maskHeight = 0; // make gcc happy
+ maskInvert = gFalse; // make gcc happy
+ maskColorMap = NULL; // make gcc happy
dict->lookup("Mask", &maskObj);
- if (maskObj.isArray()) {
- for (i = 0; i < maskObj.arrayGetLength(); ++i) {
+ dict->lookup("SMask", &smaskObj);
+ if (smaskObj.isStream()) {
+ // soft mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = smaskObj.getStream();
+ maskDict = smaskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("BPC", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskBits = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("CS", &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ maskColorSpace = GfxColorSpace::parse(&obj1);
+ obj1.free();
+ if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
+ goto err1;
+ }
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
+ obj1.free();
+ if (!maskColorMap->isOk()) {
+ delete maskColorMap;
+ goto err1;
+ }
+ //~ handle the Matte entry
+ haveSoftMask = gTrue;
+ } else if (maskObj.isArray()) {
+ // color key mask
+ for (i = 0;
+ i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
+ ++i) {
maskObj.arrayGet(i, &obj1);
maskColors[i] = obj1.getInt();
obj1.free();
}
- haveMask = gTrue;
+ haveColorKeyMask = gTrue;
+ } else if (maskObj.isStream()) {
+ // explicit mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = maskObj.getStream();
+ maskDict = maskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("IM", &obj1);
+ }
+ if (!obj1.isBool() || !obj1.getBool()) {
+ goto err2;
+ }
+ obj1.free();
+ maskInvert = gFalse;
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1) {
+ maskInvert = gTrue;
+ }
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+ haveExplicitMask = gTrue;
}
// draw it
- out->drawImage(state, ref, str, width, height, colorMap,
- haveMask ? maskColors : (int *)NULL, inlineImg);
+ if (haveSoftMask) {
+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskColorMap);
+ delete maskColorMap;
+ } else if (haveExplicitMask) {
+ out->drawMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskInvert);
+ } else {
+ out->drawImage(state, ref, str, width, height, colorMap,
+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
+ }
delete colorMap;
maskObj.free();
+ smaskObj.free();
}
if ((i = width * height) > 1000) {
// check form type
dict->lookup("FormType", &obj1);
- if (!(obj1.isInt() && obj1.getInt() == 1)) {
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
error(getPos(), "Unknown form type");
}
obj1.free();