3
* PDF parsing using libpoppler
5
* Derived from poppler's Gfx.cc
7
* Copyright 1996-2003 Glyph & Cog, LLC
17
#ifdef USE_GCC_PRAGMAS
18
#pragma implementation
31
#include "svg-builder.h"
33
#include "pdf-parser.h"
34
#include "unit-constants.h"
37
#include "goo/GooTimer.h"
38
#include "goo/GooHash.h"
39
#include "GlobalParams.h"
40
#include "CharTypes.h"
49
#include "OutputDev.h"
54
// the MSVC math.h doesn't define this
56
#define M_PI 3.14159265358979323846
59
//------------------------------------------------------------------------
61
//------------------------------------------------------------------------
63
// Default max delta allowed in any color component for a shading fill.
64
#define defaultShadingColorDelta (dblToCol( 1 / 2.0 ))
66
// Default max recursive depth for a shading fill.
67
#define defaultShadingMaxDepth 6
69
// Max number of operators kept in the history list.
70
#define maxOperatorHistoryDepth 16
72
//------------------------------------------------------------------------
74
//------------------------------------------------------------------------
76
#ifdef WIN32 // this works around a bug in the VC7 compiler
77
# pragma optimize("",off)
80
PdfOperator PdfParser::opTab[] = {
81
{"\"", 3, {tchkNum, tchkNum, tchkString},
82
&PdfParser::opMoveSetShowText},
83
{"'", 1, {tchkString},
84
&PdfParser::opMoveShowText},
86
&PdfParser::opFillStroke},
88
&PdfParser::opEOFillStroke},
89
{"BDC", 2, {tchkName, tchkProps},
90
&PdfParser::opBeginMarkedContent},
92
&PdfParser::opBeginImage},
93
{"BMC", 1, {tchkName},
94
&PdfParser::opBeginMarkedContent},
96
&PdfParser::opBeginText},
98
&PdfParser::opBeginIgnoreUndef},
100
&PdfParser::opSetStrokeColorSpace},
101
{"DP", 2, {tchkName, tchkProps},
102
&PdfParser::opMarkPoint},
103
{"Do", 1, {tchkName},
104
&PdfParser::opXObject},
105
{"EI", 0, {tchkNone},
106
&PdfParser::opEndImage},
107
{"EMC", 0, {tchkNone},
108
&PdfParser::opEndMarkedContent},
109
{"ET", 0, {tchkNone},
110
&PdfParser::opEndText},
111
{"EX", 0, {tchkNone},
112
&PdfParser::opEndIgnoreUndef},
116
&PdfParser::opSetStrokeGray},
117
{"ID", 0, {tchkNone},
118
&PdfParser::opImageData},
120
&PdfParser::opSetLineCap},
121
{"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
122
&PdfParser::opSetStrokeCMYKColor},
124
&PdfParser::opSetMiterLimit},
125
{"MP", 1, {tchkName},
126
&PdfParser::opMarkPoint},
128
&PdfParser::opRestore},
129
{"RG", 3, {tchkNum, tchkNum, tchkNum},
130
&PdfParser::opSetStrokeRGBColor},
132
&PdfParser::opStroke},
133
{"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
134
&PdfParser::opSetStrokeColor},
135
{"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
136
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
137
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
138
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
139
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
140
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
141
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
142
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
144
&PdfParser::opSetStrokeColorN},
145
{"T*", 0, {tchkNone},
146
&PdfParser::opTextNextLine},
147
{"TD", 2, {tchkNum, tchkNum},
148
&PdfParser::opTextMoveSet},
149
{"TJ", 1, {tchkArray},
150
&PdfParser::opShowSpaceText},
152
&PdfParser::opSetTextLeading},
154
&PdfParser::opSetCharSpacing},
155
{"Td", 2, {tchkNum, tchkNum},
156
&PdfParser::opTextMove},
157
{"Tf", 2, {tchkName, tchkNum},
158
&PdfParser::opSetFont},
159
{"Tj", 1, {tchkString},
160
&PdfParser::opShowText},
161
{"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
163
&PdfParser::opSetTextMatrix},
165
&PdfParser::opSetTextRender},
167
&PdfParser::opSetTextRise},
169
&PdfParser::opSetWordSpacing},
171
&PdfParser::opSetHorizScaling},
174
{"W*", 0, {tchkNone},
175
&PdfParser::opEOClip},
177
&PdfParser::opCloseFillStroke},
178
{"b*", 0, {tchkNone},
179
&PdfParser::opCloseEOFillStroke},
180
{"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
182
&PdfParser::opCurveTo},
183
{"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
185
&PdfParser::opConcat},
186
{"cs", 1, {tchkName},
187
&PdfParser::opSetFillColorSpace},
188
{"d", 2, {tchkArray, tchkNum},
189
&PdfParser::opSetDash},
190
{"d0", 2, {tchkNum, tchkNum},
191
&PdfParser::opSetCharWidth},
192
{"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
194
&PdfParser::opSetCacheDevice},
197
{"f*", 0, {tchkNone},
198
&PdfParser::opEOFill},
200
&PdfParser::opSetFillGray},
201
{"gs", 1, {tchkName},
202
&PdfParser::opSetExtGState},
204
&PdfParser::opClosePath},
206
&PdfParser::opSetFlat},
208
&PdfParser::opSetLineJoin},
209
{"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
210
&PdfParser::opSetFillCMYKColor},
211
{"l", 2, {tchkNum, tchkNum},
212
&PdfParser::opLineTo},
213
{"m", 2, {tchkNum, tchkNum},
214
&PdfParser::opMoveTo},
216
&PdfParser::opEndPath},
219
{"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
220
&PdfParser::opRectangle},
221
{"rg", 3, {tchkNum, tchkNum, tchkNum},
222
&PdfParser::opSetFillRGBColor},
223
{"ri", 1, {tchkName},
224
&PdfParser::opSetRenderingIntent},
226
&PdfParser::opCloseStroke},
227
{"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
228
&PdfParser::opSetFillColor},
229
{"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
230
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
231
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
232
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
233
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
234
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
235
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
236
tchkSCN, tchkSCN, tchkSCN, tchkSCN,
238
&PdfParser::opSetFillColorN},
239
{"sh", 1, {tchkName},
240
&PdfParser::opShFill},
241
{"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
242
&PdfParser::opCurveTo1},
244
&PdfParser::opSetLineWidth},
245
{"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
246
&PdfParser::opCurveTo2}
249
#ifdef WIN32 // this works around a bug in the VC7 compiler
250
# pragma optimize("",on)
253
#define numOps (sizeof(opTab) / sizeof(PdfOperator))
255
//------------------------------------------------------------------------
257
//------------------------------------------------------------------------
259
PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
260
int pageNum, int rotate, Dict *resDict,
261
PDFRectangle *box, PDFRectangle *cropBox) {
267
printCommands = false;
269
// start the resource stack
270
res = new GfxResources(xref, resDict, NULL);
273
state = new GfxState(72.0, 72.0, box, rotate, gTrue);
274
clipHistory = new ClipHistoryEntry();
275
setDefaultApproximationPrecision();
276
fontChanged = gFalse;
279
operatorHistory = NULL;
281
builder->setDocumentSize(state->getPageWidth()*PX_PER_PT,
282
state->getPageHeight()*PX_PER_PT);
284
double *ctm = state->getCTM();
286
for (i = 0; i < 6; ++i) {
287
baseMatrix[i] = ctm[i];
288
scaledCTM[i] = PX_PER_PT * ctm[i];
291
builder->setTransform((double*)&scaledCTM);
297
printf("cropBox: %f %f %f %f\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
298
// do not clip if it's not needed
299
if (cropBox->x1 != 0.0 || cropBox->y1 != 0.0 ||
300
cropBox->x2 != state->getPageWidth() || cropBox->y2 != state->getPageHeight()) {
302
state->moveTo(cropBox->x1, cropBox->y1);
303
state->lineTo(cropBox->x2, cropBox->y1);
304
state->lineTo(cropBox->x2, cropBox->y2);
305
state->lineTo(cropBox->x1, cropBox->y2);
308
clipHistory->setClip(state->getPath(), clipNormal);
309
builder->setClipPath(state);
313
pushOperator("startPage");
316
PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
317
Dict *resDict, PDFRectangle *box) {
323
printCommands = false;
325
// start the resource stack
326
res = new GfxResources(xref, resDict, NULL);
329
operatorHistory = NULL;
331
state = new GfxState(72, 72, box, 0, gFalse);
332
clipHistory = new ClipHistoryEntry();
333
setDefaultApproximationPrecision();
335
fontChanged = gFalse;
338
for (i = 0; i < 6; ++i) {
339
baseMatrix[i] = state->getCTM()[i];
344
PdfParser::~PdfParser() {
345
while (state->hasSaves()) {
362
void PdfParser::parse(Object *obj, GBool topLevel) {
366
if (obj->isArray()) {
367
for (i = 0; i < obj->arrayGetLength(); ++i) {
368
obj->arrayGet(i, &obj2);
369
if (!obj2.isStream()) {
370
#ifdef POPPLER_NEW_ERRORAPI
371
error(errInternal, -1, "Weird page contents");
373
error(-1, const_cast<char*>("Weird page contents"));
380
} else if (!obj->isStream()) {
381
#ifdef POPPLER_NEW_ERRORAPI
382
error(errInternal, -1, "Weird page contents");
384
error(-1, const_cast<char*>("Weird page contents"));
388
parser = new Parser(xref, new Lexer(xref, obj), gFalse);
394
void PdfParser::go(GBool topLevel) {
396
Object args[maxArgs];
399
// scan a sequence of objects
401
parser->getObj(&obj);
402
while (!obj.isEOF()) {
404
// got a command - execute it
408
for (i = 0; i < numArgs; ++i) {
410
args[i].print(stdout);
417
execOp(&obj, args, numArgs);
420
for (i = 0; i < numArgs; ++i)
424
// got an argument - save it
425
} else if (numArgs < maxArgs) {
426
args[numArgs++] = obj;
428
// too many arguments - something is wrong
430
#ifdef POPPLER_NEW_ERRORAPI
431
error(errSyntaxError, getPos(), "Too many args in content stream");
433
error(getPos(), const_cast<char*>("Too many args in content stream"));
436
printf("throwing away arg: ");
444
// grab the next object
445
parser->getObj(&obj);
449
// args at end with no command
451
#ifdef POPPLER_NEW_ERRORAPI
452
error(errSyntaxError, getPos(), "Leftover args in content stream");
454
error(getPos(), const_cast<char*>("Leftover args in content stream"));
457
printf("%d leftovers:", numArgs);
458
for (i = 0; i < numArgs; ++i) {
460
args[i].print(stdout);
465
for (i = 0; i < numArgs; ++i)
470
void PdfParser::pushOperator(const char *name) {
471
OpHistoryEntry *newEntry = new OpHistoryEntry;
472
newEntry->name = name;
473
newEntry->state = NULL;
474
newEntry->depth = (operatorHistory != NULL ? (operatorHistory->depth+1) : 0);
475
newEntry->next = operatorHistory;
476
operatorHistory = newEntry;
478
// Truncate list if needed
479
if (operatorHistory->depth > maxOperatorHistoryDepth) {
480
OpHistoryEntry *curr = operatorHistory;
481
OpHistoryEntry *prev = NULL;
482
while (curr && curr->next != NULL) {
488
if (curr->state != NULL)
496
const char *PdfParser::getPreviousOperator(unsigned int look_back) {
497
OpHistoryEntry *prev = NULL;
498
if (operatorHistory != NULL && look_back > 0) {
499
prev = operatorHistory->next;
500
while (--look_back > 0 && prev != NULL) {
511
void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
518
name = cmd->getCmd();
519
if (!(op = findOp(name))) {
520
if (ignoreUndef == 0)
521
#ifdef POPPLER_NEW_ERRORAPI
522
error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
524
error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
531
if (op->numArgs >= 0) {
532
if (numArgs < op->numArgs) {
533
#ifdef POPPLER_NEW_ERRORAPI
534
error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:d}' operator", numArgs, name);
536
error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
540
if (numArgs > op->numArgs) {
542
#ifdef POPPLER_NEW_ERRORAPI
543
error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
545
error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
548
argPtr += numArgs - op->numArgs;
549
numArgs = op->numArgs;
552
if (numArgs > -op->numArgs) {
553
#ifdef POPPLER_NEW_ERRORAPI
554
error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
556
error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
562
for (i = 0; i < numArgs; ++i) {
563
if (!checkArg(&argPtr[i], op->tchk[i])) {
564
#ifdef POPPLER_NEW_ERRORAPI
565
error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
567
error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
569
i, name, argPtr[i].getTypeName());
575
pushOperator((char*)&op->name);
578
(this->*op->func)(argPtr, numArgs);
581
PdfOperator *PdfParser::findOp(char *name) {
586
// invariant: opTab[a] < name < opTab[b]
589
cmp = strcmp(opTab[m].name, name);
602
GBool PdfParser::checkArg(Object *arg, TchkType type) {
604
case tchkBool: return arg->isBool();
605
case tchkInt: return arg->isInt();
606
case tchkNum: return arg->isNum();
607
case tchkString: return arg->isString();
608
case tchkName: return arg->isName();
609
case tchkArray: return arg->isArray();
610
case tchkProps: return arg->isDict() || arg->isName();
611
case tchkSCN: return arg->isNum() || arg->isName();
612
case tchkNone: return gFalse;
617
int PdfParser::getPos() {
618
return parser ? parser->getPos() : -1;
621
//------------------------------------------------------------------------
622
// graphics state operators
623
//------------------------------------------------------------------------
625
void PdfParser::opSave(Object args[], int numArgs) {
629
void PdfParser::opRestore(Object args[], int numArgs) {
633
void PdfParser::opConcat(Object args[], int numArgs) {
634
state->concatCTM(args[0].getNum(), args[1].getNum(),
635
args[2].getNum(), args[3].getNum(),
636
args[4].getNum(), args[5].getNum());
637
const char *prevOp = getPreviousOperator();
638
double a0 = args[0].getNum();
639
double a1 = args[1].getNum();
640
double a2 = args[2].getNum();
641
double a3 = args[3].getNum();
642
double a4 = args[4].getNum();
643
double a5 = args[5].getNum();
644
if (!strcmp(prevOp, "q")) {
645
builder->setTransform(a0, a1, a2, a3, a4, a5);
646
} else if (!strcmp(prevOp, "cm") || !strcmp(prevOp, "startPage")) {
647
// multiply it with the previous transform
648
double otherMatrix[6];
649
if (!builder->getTransform(otherMatrix)) { // invalid transform
650
// construct identity matrix
651
otherMatrix[0] = otherMatrix[3] = 1.0;
652
otherMatrix[1] = otherMatrix[2] = otherMatrix[4] = otherMatrix[5] = 0.0;
654
double c0 = a0*otherMatrix[0] + a1*otherMatrix[2];
655
double c1 = a0*otherMatrix[1] + a1*otherMatrix[3];
656
double c2 = a2*otherMatrix[0] + a3*otherMatrix[2];
657
double c3 = a2*otherMatrix[1] + a3*otherMatrix[3];
658
double c4 = a4*otherMatrix[0] + a5*otherMatrix[2] + otherMatrix[4];
659
double c5 = a4*otherMatrix[1] + a5*otherMatrix[3] + otherMatrix[5];
660
builder->setTransform(c0, c1, c2, c3, c4, c5);
662
builder->pushGroup();
663
builder->setTransform(a0, a1, a2, a3, a4, a5);
668
void PdfParser::opSetDash(Object args[], int numArgs) {
675
a = args[0].getArray();
676
length = a->getLength();
680
dash = (double *)gmallocn(length, sizeof(double));
681
for (i = 0; i < length; ++i) {
682
dash[i] = a->get(i, &obj)->getNum();
686
state->setLineDash(dash, length, args[1].getNum());
687
builder->updateStyle(state);
690
void PdfParser::opSetFlat(Object args[], int numArgs) {
691
state->setFlatness((int)args[0].getNum());
694
void PdfParser::opSetLineJoin(Object args[], int numArgs) {
695
state->setLineJoin(args[0].getInt());
696
builder->updateStyle(state);
699
void PdfParser::opSetLineCap(Object args[], int numArgs) {
700
state->setLineCap(args[0].getInt());
701
builder->updateStyle(state);
704
void PdfParser::opSetMiterLimit(Object args[], int numArgs) {
705
state->setMiterLimit(args[0].getNum());
706
builder->updateStyle(state);
709
void PdfParser::opSetLineWidth(Object args[], int numArgs) {
710
state->setLineWidth(args[0].getNum());
711
builder->updateStyle(state);
714
void PdfParser::opSetExtGState(Object args[], int numArgs) {
715
Object obj1, obj2, obj3, obj4, obj5;
719
GfxColor backdropColor;
720
GBool haveBackdropColor;
721
GfxColorSpace *blendingColorSpace;
722
GBool alpha, isolated, knockout;
725
if (!res->lookupGState(args[0].getName(), &obj1)) {
728
if (!obj1.isDict()) {
729
#ifdef POPPLER_NEW_ERRORAPI
730
error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type"), args[0].getName();
732
error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
738
printf(" gfx state dict: ");
743
// transparency support: blend mode, fill/stroke opacity
744
if (!obj1.dictLookup(const_cast<char*>("BM"), &obj2)->isNull()) {
745
if (state->parseBlendMode(&obj2, &mode)) {
746
state->setBlendMode(mode);
748
#ifdef POPPLER_NEW_ERRORAPI
749
error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
751
error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
756
if (obj1.dictLookup(const_cast<char*>("ca"), &obj2)->isNum()) {
757
state->setFillOpacity(obj2.getNum());
760
if (obj1.dictLookup(const_cast<char*>("CA"), &obj2)->isNum()) {
761
state->setStrokeOpacity(obj2.getNum());
765
// fill/stroke overprint
766
if ((haveFillOP = (obj1.dictLookup(const_cast<char*>("op"), &obj2)->isBool()))) {
767
state->setFillOverprint(obj2.getBool());
770
if (obj1.dictLookup(const_cast<char*>("OP"), &obj2)->isBool()) {
771
state->setStrokeOverprint(obj2.getBool());
773
state->setFillOverprint(obj2.getBool());
779
if (obj1.dictLookup(const_cast<char*>("SA"), &obj2)->isBool()) {
780
state->setStrokeAdjust(obj2.getBool());
785
if (obj1.dictLookup(const_cast<char*>("TR2"), &obj2)->isNull()) {
787
obj1.dictLookup(const_cast<char*>("TR"), &obj2);
789
if (obj2.isName(const_cast<char*>("Default")) ||
790
obj2.isName(const_cast<char*>("Identity"))) {
791
funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
792
state->setTransfer(funcs);
793
} else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
794
for (i = 0; i < 4; ++i) {
795
obj2.arrayGet(i, &obj3);
796
funcs[i] = Function::parse(&obj3);
803
state->setTransfer(funcs);
805
} else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
806
if ((funcs[0] = Function::parse(&obj2))) {
807
funcs[1] = funcs[2] = funcs[3] = NULL;
808
state->setTransfer(funcs);
810
} else if (!obj2.isNull()) {
811
#ifdef POPPLER_NEW_ERRORAPI
812
error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
814
error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
820
if (!obj1.dictLookup(const_cast<char*>("SMask"), &obj2)->isNull()) {
821
if (obj2.isName(const_cast<char*>("None"))) {
822
builder->clearSoftMask(state);
823
} else if (obj2.isDict()) {
824
if (obj2.dictLookup(const_cast<char*>("S"), &obj3)->isName(const_cast<char*>("Alpha"))) {
826
} else { // "Luminosity"
831
if (!obj2.dictLookup(const_cast<char*>("TR"), &obj3)->isNull()) {
832
funcs[0] = Function::parse(&obj3);
833
if (funcs[0]->getInputSize() != 1 ||
834
funcs[0]->getOutputSize() != 1) {
835
#ifdef POPPLER_NEW_ERRORAPI
836
error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState");
838
error(getPos(), const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
845
if ((haveBackdropColor = obj2.dictLookup(const_cast<char*>("BC"), &obj3)->isArray())) {
846
for (i = 0; i < gfxColorMaxComps; ++i) {
847
backdropColor.c[i] = 0;
849
for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
850
obj3.arrayGet(i, &obj4);
852
backdropColor.c[i] = dblToCol(obj4.getNum());
858
if (obj2.dictLookup(const_cast<char*>("G"), &obj3)->isStream()) {
859
if (obj3.streamGetDict()->lookup(const_cast<char*>("Group"), &obj4)->isDict()) {
860
blendingColorSpace = NULL;
861
isolated = knockout = gFalse;
862
if (!obj4.dictLookup(const_cast<char*>("CS"), &obj5)->isNull()) {
863
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
864
blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
866
blendingColorSpace = GfxColorSpace::parse(&obj5);
870
if (obj4.dictLookup(const_cast<char*>("I"), &obj5)->isBool()) {
871
isolated = obj5.getBool();
874
if (obj4.dictLookup(const_cast<char*>("K"), &obj5)->isBool()) {
875
knockout = obj5.getBool();
878
if (!haveBackdropColor) {
879
if (blendingColorSpace) {
880
blendingColorSpace->getDefaultColor(&backdropColor);
882
//~ need to get the parent or default color space (?)
883
for (i = 0; i < gfxColorMaxComps; ++i) {
884
backdropColor.c[i] = 0;
888
doSoftMask(&obj3, alpha, blendingColorSpace,
889
isolated, knockout, funcs[0], &backdropColor);
894
#ifdef POPPLER_NEW_ERRORAPI
895
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
897
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
902
#ifdef POPPLER_NEW_ERRORAPI
903
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
905
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
909
} else if (!obj2.isNull()) {
910
#ifdef POPPLER_NEW_ERRORAPI
911
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
913
error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
922
void PdfParser::doSoftMask(Object *str, GBool alpha,
923
GfxColorSpace *blendingColorSpace,
924
GBool isolated, GBool knockout,
925
Function *transferFunc, GfxColor *backdropColor) {
926
Dict *dict, *resDict;
927
double m[6], bbox[4];
931
// check for excessive recursion
932
if (formDepth > 20) {
937
dict = str->streamGetDict();
940
dict->lookup(const_cast<char*>("FormType"), &obj1);
941
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
942
#ifdef POPPLER_NEW_ERRORAPI
943
error(errSyntaxError, getPos(), "Unknown form type");
945
error(getPos(), const_cast<char*>("Unknown form type"));
951
dict->lookup(const_cast<char*>("BBox"), &obj1);
952
if (!obj1.isArray()) {
954
#ifdef POPPLER_NEW_ERRORAPI
955
error(errSyntaxError, getPos(), "Bad form bounding box");
957
error(getPos(), const_cast<char*>("Bad form bounding box"));
961
for (i = 0; i < 4; ++i) {
962
obj1.arrayGet(i, &obj2);
963
bbox[i] = obj2.getNum();
969
dict->lookup(const_cast<char*>("Matrix"), &obj1);
970
if (obj1.isArray()) {
971
for (i = 0; i < 6; ++i) {
972
obj1.arrayGet(i, &obj2);
973
m[i] = obj2.getNum();
984
dict->lookup(const_cast<char*>("Resources"), &obj1);
985
resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
989
doForm1(str, resDict, m, bbox, gTrue, gTrue,
990
blendingColorSpace, isolated, knockout,
991
alpha, transferFunc, backdropColor);
994
if (blendingColorSpace) {
995
delete blendingColorSpace;
1000
void PdfParser::opSetRenderingIntent(Object args[], int numArgs) {
1003
//------------------------------------------------------------------------
1005
//------------------------------------------------------------------------
1007
void PdfParser::opSetFillGray(Object args[], int numArgs) {
1010
state->setFillPattern(NULL);
1011
state->setFillColorSpace(new GfxDeviceGrayColorSpace());
1012
color.c[0] = dblToCol(args[0].getNum());
1013
state->setFillColor(&color);
1014
builder->updateStyle(state);
1017
void PdfParser::opSetStrokeGray(Object args[], int numArgs) {
1020
state->setStrokePattern(NULL);
1021
state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
1022
color.c[0] = dblToCol(args[0].getNum());
1023
state->setStrokeColor(&color);
1024
builder->updateStyle(state);
1027
void PdfParser::opSetFillCMYKColor(Object args[], int numArgs) {
1031
state->setFillPattern(NULL);
1032
state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
1033
for (i = 0; i < 4; ++i) {
1034
color.c[i] = dblToCol(args[i].getNum());
1036
state->setFillColor(&color);
1037
builder->updateStyle(state);
1040
void PdfParser::opSetStrokeCMYKColor(Object args[], int numArgs) {
1044
state->setStrokePattern(NULL);
1045
state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
1046
for (i = 0; i < 4; ++i) {
1047
color.c[i] = dblToCol(args[i].getNum());
1049
state->setStrokeColor(&color);
1050
builder->updateStyle(state);
1053
void PdfParser::opSetFillRGBColor(Object args[], int numArgs) {
1057
state->setFillPattern(NULL);
1058
state->setFillColorSpace(new GfxDeviceRGBColorSpace());
1059
for (i = 0; i < 3; ++i) {
1060
color.c[i] = dblToCol(args[i].getNum());
1062
state->setFillColor(&color);
1063
builder->updateStyle(state);
1066
void PdfParser::opSetStrokeRGBColor(Object args[], int numArgs) {
1070
state->setStrokePattern(NULL);
1071
state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
1072
for (i = 0; i < 3; ++i) {
1073
color.c[i] = dblToCol(args[i].getNum());
1075
state->setStrokeColor(&color);
1076
builder->updateStyle(state);
1079
void PdfParser::opSetFillColorSpace(Object args[], int numArgs) {
1081
GfxColorSpace *colorSpace;
1084
state->setFillPattern(NULL);
1085
res->lookupColorSpace(args[0].getName(), &obj);
1086
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1088
colorSpace = GfxColorSpace::parse(&args[0], NULL);
1090
colorSpace = GfxColorSpace::parse(&obj, NULL);
1094
colorSpace = GfxColorSpace::parse(&args[0]);
1096
colorSpace = GfxColorSpace::parse(&obj);
1101
state->setFillColorSpace(colorSpace);
1102
colorSpace->getDefaultColor(&color);
1103
state->setFillColor(&color);
1104
builder->updateStyle(state);
1106
#ifdef POPPLER_NEW_ERRORAPI
1107
error(errSyntaxError, getPos(), "Bad color space (fill)");
1109
error(getPos(), const_cast<char*>("Bad color space (fill)"));
1114
void PdfParser::opSetStrokeColorSpace(Object args[], int numArgs) {
1116
GfxColorSpace *colorSpace;
1119
state->setStrokePattern(NULL);
1120
res->lookupColorSpace(args[0].getName(), &obj);
1121
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1123
colorSpace = GfxColorSpace::parse(&args[0], NULL);
1125
colorSpace = GfxColorSpace::parse(&obj, NULL);
1129
colorSpace = GfxColorSpace::parse(&args[0]);
1131
colorSpace = GfxColorSpace::parse(&obj);
1136
state->setStrokeColorSpace(colorSpace);
1137
colorSpace->getDefaultColor(&color);
1138
state->setStrokeColor(&color);
1139
builder->updateStyle(state);
1141
#ifdef POPPLER_NEW_ERRORAPI
1142
error(errSyntaxError, getPos(), "Bad color space (stroke)");
1144
error(getPos(), const_cast<char*>("Bad color space (stroke)"));
1149
void PdfParser::opSetFillColor(Object args[], int numArgs) {
1153
if (numArgs != state->getFillColorSpace()->getNComps()) {
1154
#ifdef POPPLER_NEW_ERRORAPI
1155
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
1157
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
1161
state->setFillPattern(NULL);
1162
for (i = 0; i < numArgs; ++i) {
1163
color.c[i] = dblToCol(args[i].getNum());
1165
state->setFillColor(&color);
1166
builder->updateStyle(state);
1169
void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
1173
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1174
#ifdef POPPLER_NEW_ERRORAPI
1175
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
1177
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
1181
state->setStrokePattern(NULL);
1182
for (i = 0; i < numArgs; ++i) {
1183
color.c[i] = dblToCol(args[i].getNum());
1185
state->setStrokeColor(&color);
1186
builder->updateStyle(state);
1189
void PdfParser::opSetFillColorN(Object args[], int numArgs) {
1191
GfxPattern *pattern;
1194
if (state->getFillColorSpace()->getMode() == csPattern) {
1196
if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
1197
numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
1198
->getUnder()->getNComps()) {
1199
#ifdef POPPLER_NEW_ERRORAPI
1200
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
1202
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
1206
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1207
if (args[i].isNum()) {
1208
color.c[i] = dblToCol(args[i].getNum());
1211
state->setFillColor(&color);
1212
builder->updateStyle(state);
1214
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1215
if (args[numArgs-1].isName() &&
1216
(pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
1217
state->setFillPattern(pattern);
1218
builder->updateStyle(state);
1221
if (args[numArgs-1].isName() &&
1222
(pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1223
state->setFillPattern(pattern);
1224
builder->updateStyle(state);
1229
if (numArgs != state->getFillColorSpace()->getNComps()) {
1230
#ifdef POPPLER_NEW_ERRORAPI
1231
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
1233
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
1237
state->setFillPattern(NULL);
1238
for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1239
if (args[i].isNum()) {
1240
color.c[i] = dblToCol(args[i].getNum());
1243
state->setFillColor(&color);
1244
builder->updateStyle(state);
1248
void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
1250
GfxPattern *pattern;
1253
if (state->getStrokeColorSpace()->getMode() == csPattern) {
1255
if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
1257
numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
1258
->getUnder()->getNComps()) {
1259
#ifdef POPPLER_NEW_ERRORAPI
1260
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
1262
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
1266
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
1267
if (args[i].isNum()) {
1268
color.c[i] = dblToCol(args[i].getNum());
1271
state->setStrokeColor(&color);
1272
builder->updateStyle(state);
1274
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1275
if (args[numArgs-1].isName() &&
1276
(pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
1277
state->setStrokePattern(pattern);
1278
builder->updateStyle(state);
1281
if (args[numArgs-1].isName() &&
1282
(pattern = res->lookupPattern(args[numArgs-1].getName()))) {
1283
state->setStrokePattern(pattern);
1284
builder->updateStyle(state);
1289
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
1290
#ifdef POPPLER_NEW_ERRORAPI
1291
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
1293
error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
1297
state->setStrokePattern(NULL);
1298
for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
1299
if (args[i].isNum()) {
1300
color.c[i] = dblToCol(args[i].getNum());
1303
state->setStrokeColor(&color);
1304
builder->updateStyle(state);
1308
//------------------------------------------------------------------------
1309
// path segment operators
1310
//------------------------------------------------------------------------
1312
void PdfParser::opMoveTo(Object args[], int numArgs) {
1313
state->moveTo(args[0].getNum(), args[1].getNum());
1316
void PdfParser::opLineTo(Object args[], int numArgs) {
1317
if (!state->isCurPt()) {
1318
#ifdef POPPLER_NEW_ERRORAPI
1319
error(errSyntaxError, getPos(), "No current point in lineto");
1321
error(getPos(), const_cast<char*>("No current point in lineto"));
1325
state->lineTo(args[0].getNum(), args[1].getNum());
1328
void PdfParser::opCurveTo(Object args[], int numArgs) {
1329
double x1, y1, x2, y2, x3, y3;
1331
if (!state->isCurPt()) {
1332
#ifdef POPPLER_NEW_ERRORAPI
1333
error(errSyntaxError, getPos(), "No current point in curveto");
1335
error(getPos(), const_cast<char*>("No current point in curveto"));
1339
x1 = args[0].getNum();
1340
y1 = args[1].getNum();
1341
x2 = args[2].getNum();
1342
y2 = args[3].getNum();
1343
x3 = args[4].getNum();
1344
y3 = args[5].getNum();
1345
state->curveTo(x1, y1, x2, y2, x3, y3);
1348
void PdfParser::opCurveTo1(Object args[], int numArgs) {
1349
double x1, y1, x2, y2, x3, y3;
1351
if (!state->isCurPt()) {
1352
#ifdef POPPLER_NEW_ERRORAPI
1353
error(errSyntaxError, getPos(), "No current point in curveto1");
1355
error(getPos(), const_cast<char*>("No current point in curveto1"));
1359
x1 = state->getCurX();
1360
y1 = state->getCurY();
1361
x2 = args[0].getNum();
1362
y2 = args[1].getNum();
1363
x3 = args[2].getNum();
1364
y3 = args[3].getNum();
1365
state->curveTo(x1, y1, x2, y2, x3, y3);
1368
void PdfParser::opCurveTo2(Object args[], int numArgs) {
1369
double x1, y1, x2, y2, x3, y3;
1371
if (!state->isCurPt()) {
1372
#ifdef POPPLER_NEW_ERRORAPI
1373
error(errSyntaxError, getPos(), "No current point in curveto2");
1375
error(getPos(), const_cast<char*>("No current point in curveto2"));
1379
x1 = args[0].getNum();
1380
y1 = args[1].getNum();
1381
x2 = args[2].getNum();
1382
y2 = args[3].getNum();
1385
state->curveTo(x1, y1, x2, y2, x3, y3);
1388
void PdfParser::opRectangle(Object args[], int numArgs) {
1391
x = args[0].getNum();
1392
y = args[1].getNum();
1393
w = args[2].getNum();
1394
h = args[3].getNum();
1395
state->moveTo(x, y);
1396
state->lineTo(x + w, y);
1397
state->lineTo(x + w, y + h);
1398
state->lineTo(x, y + h);
1402
void PdfParser::opClosePath(Object args[], int numArgs) {
1403
if (!state->isCurPt()) {
1404
#ifdef POPPLER_NEW_ERRORAPI
1405
error(errSyntaxError, getPos(), "No current point in closepath");
1407
error(getPos(), const_cast<char*>("No current point in closepath"));
1414
//------------------------------------------------------------------------
1415
// path painting operators
1416
//------------------------------------------------------------------------
1418
void PdfParser::opEndPath(Object args[], int numArgs) {
1422
void PdfParser::opStroke(Object args[], int numArgs) {
1423
if (!state->isCurPt()) {
1424
//error(getPos(), const_cast<char*>("No path in stroke"));
1427
if (state->isPath()) {
1428
if (state->getStrokeColorSpace()->getMode() == csPattern &&
1429
!builder->isPatternTypeSupported(state->getStrokePattern())) {
1430
doPatternStrokeFallback();
1432
builder->addPath(state, false, true);
1438
void PdfParser::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
1439
if (!state->isCurPt()) {
1440
//error(getPos(), const_cast<char*>("No path in closepath/stroke"));
1444
if (state->isPath()) {
1445
if (state->getStrokeColorSpace()->getMode() == csPattern &&
1446
!builder->isPatternTypeSupported(state->getStrokePattern())) {
1447
doPatternStrokeFallback();
1449
builder->addPath(state, false, true);
1455
void PdfParser::opFill(Object args[], int numArgs) {
1456
if (!state->isCurPt()) {
1457
//error(getPos(), const_cast<char*>("No path in fill"));
1460
if (state->isPath()) {
1461
if (state->getFillColorSpace()->getMode() == csPattern &&
1462
!builder->isPatternTypeSupported(state->getFillPattern())) {
1463
doPatternFillFallback(gFalse);
1465
builder->addPath(state, true, false);
1471
void PdfParser::opEOFill(Object args[], int numArgs) {
1472
if (!state->isCurPt()) {
1473
//error(getPos(), const_cast<char*>("No path in eofill"));
1476
if (state->isPath()) {
1477
if (state->getFillColorSpace()->getMode() == csPattern &&
1478
!builder->isPatternTypeSupported(state->getFillPattern())) {
1479
doPatternFillFallback(gTrue);
1481
builder->addPath(state, true, false, true);
1487
void PdfParser::opFillStroke(Object args[], int numArgs) {
1488
if (!state->isCurPt()) {
1489
//error(getPos(), const_cast<char*>("No path in fill/stroke"));
1492
if (state->isPath()) {
1493
doFillAndStroke(gFalse);
1495
builder->addPath(state, true, true);
1500
void PdfParser::opCloseFillStroke(Object args[], int numArgs) {
1501
if (!state->isCurPt()) {
1502
//error(getPos(), const_cast<char*>("No path in closepath/fill/stroke"));
1505
if (state->isPath()) {
1507
doFillAndStroke(gFalse);
1512
void PdfParser::opEOFillStroke(Object args[], int numArgs) {
1513
if (!state->isCurPt()) {
1514
//error(getPos(), const_cast<char*>("No path in eofill/stroke"));
1517
if (state->isPath()) {
1518
doFillAndStroke(gTrue);
1523
void PdfParser::opCloseEOFillStroke(Object args[], int numArgs) {
1524
if (!state->isCurPt()) {
1525
//error(getPos(), const_cast<char*>("No path in closepath/eofill/stroke"));
1528
if (state->isPath()) {
1530
doFillAndStroke(gTrue);
1535
void PdfParser::doFillAndStroke(GBool eoFill) {
1536
GBool fillOk = gTrue, strokeOk = gTrue;
1537
if (state->getFillColorSpace()->getMode() == csPattern &&
1538
!builder->isPatternTypeSupported(state->getFillPattern())) {
1541
if (state->getStrokeColorSpace()->getMode() == csPattern &&
1542
!builder->isPatternTypeSupported(state->getStrokePattern())) {
1545
if (fillOk && strokeOk) {
1546
builder->addPath(state, true, true, eoFill);
1548
doPatternFillFallback(eoFill);
1549
doPatternStrokeFallback();
1553
void PdfParser::doPatternFillFallback(GBool eoFill) {
1554
GfxPattern *pattern;
1556
if (!(pattern = state->getFillPattern())) {
1559
switch (pattern->getType()) {
1563
doShadingPatternFillFallback((GfxShadingPattern *)pattern, gFalse, eoFill);
1566
#ifdef POPPLER_NEW_ERRORAPI
1567
error(errUnimplemented, getPos(), "Unimplemented pattern type (%d) in fill",
1569
error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
1571
pattern->getType());
1576
void PdfParser::doPatternStrokeFallback() {
1577
GfxPattern *pattern;
1579
if (!(pattern = state->getStrokePattern())) {
1582
switch (pattern->getType()) {
1586
doShadingPatternFillFallback((GfxShadingPattern *)pattern, gTrue, gFalse);
1589
#ifdef POPPLER_NEW_ERRORAPI
1590
error(errUnimplemented, getPos(), "Unimplemented pattern type ({0:d}) in stroke",
1592
error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
1594
pattern->getType());
1599
void PdfParser::doShadingPatternFillFallback(GfxShadingPattern *sPat,
1600
GBool stroke, GBool eoFill) {
1601
GfxShading *shading;
1603
double *ctm, *btm, *ptm;
1604
double m[6], ictm[6], m1[6];
1605
double xMin, yMin, xMax, yMax;
1608
shading = sPat->getShading();
1610
// save current graphics state
1611
savedPath = state->getPath()->copy();
1615
if (0 ){//shading->getHasBBox()) {
1616
shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1617
state->moveTo(xMin, yMin);
1618
state->lineTo(xMax, yMin);
1619
state->lineTo(xMax, yMax);
1620
state->lineTo(xMin, yMax);
1623
//builder->clip(state);
1624
state->setPath(savedPath->copy());
1627
// clip to current path
1629
state->clipToStrokePath();
1630
//out->clipToStrokePath(state);
1634
builder->setClipPath(state, true);
1636
builder->setClipPath(state);
1640
// set the color space
1641
state->setFillColorSpace(shading->getColorSpace()->copy());
1643
// background color fill
1644
if (shading->getHasBackground()) {
1645
state->setFillColor(shading->getBackground());
1646
builder->addPath(state, true, false);
1650
// construct a (pattern space) -> (current space) transform matrix
1651
ctm = state->getCTM();
1653
ptm = sPat->getMatrix();
1654
// iCTM = invert CTM
1655
det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1656
ictm[0] = ctm[3] * det;
1657
ictm[1] = -ctm[1] * det;
1658
ictm[2] = -ctm[2] * det;
1659
ictm[3] = ctm[0] * det;
1660
ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1661
ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1662
// m1 = PTM * BTM = PTM * base transform matrix
1663
m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
1664
m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
1665
m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
1666
m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
1667
m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
1668
m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
1669
// m = m1 * iCTM = (PTM * BTM) * (iCTM)
1670
m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
1671
m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
1672
m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
1673
m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
1674
m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1675
m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1677
// set the new matrix
1678
state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
1679
builder->setTransform(m[0], m[1], m[2], m[3], m[4], m[5]);
1681
// do shading type-specific operations
1682
switch (shading->getType()) {
1684
doFunctionShFill((GfxFunctionShading *)shading);
1688
// no need to implement these
1692
doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1696
doPatchMeshShFill((GfxPatchMeshShading *)shading);
1700
// restore graphics state
1702
state->setPath(savedPath);
1705
void PdfParser::opShFill(Object args[], int numArgs) {
1706
GfxShading *shading;
1707
GfxPath *savedPath = NULL;
1708
double xMin, yMin, xMax, yMax;
1709
double gradientTransform[6];
1710
double *matrix = NULL;
1711
GBool savedState = gFalse;
1713
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
1714
if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
1718
if (!(shading = res->lookupShading(args[0].getName()))) {
1723
// save current graphics state
1724
if (shading->getType() != 2 && shading->getType() != 3) {
1725
savedPath = state->getPath()->copy();
1728
} else { // get gradient transform if possible
1729
// check proper operator sequence
1730
// first there should be one W(*) and then one 'cm' somewhere before 'sh'
1731
GBool seenClip, seenConcat;
1732
seenClip = (clipHistory->getClipPath() != NULL);
1733
seenConcat = gFalse;
1735
while (i <= maxOperatorHistoryDepth) {
1736
const char *opName = getPreviousOperator(i);
1737
if (!strcmp(opName, "cm")) {
1738
if (seenConcat) { // more than one 'cm'
1747
if (seenConcat && seenClip) {
1748
if (builder->getTransform(gradientTransform)) {
1749
matrix = (double*)&gradientTransform;
1750
builder->setTransform(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); // remove transform
1756
if (shading->getHasBBox()) {
1757
shading->getBBox(&xMin, &yMin, &xMax, &yMax);
1758
state->moveTo(xMin, yMin);
1759
state->lineTo(xMax, yMin);
1760
state->lineTo(xMax, yMax);
1761
state->lineTo(xMin, yMax);
1765
builder->setClipPath(state);
1767
builder->clip(state);
1771
// set the color space
1773
state->setFillColorSpace(shading->getColorSpace()->copy());
1775
// do shading type-specific operations
1776
switch (shading->getType()) {
1778
doFunctionShFill((GfxFunctionShading *)shading);
1782
if (clipHistory->getClipPath()) {
1783
builder->addShadedFill(shading, matrix, clipHistory->getClipPath(),
1784
clipHistory->getClipType() == clipEO ? true : false);
1789
doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
1793
doPatchMeshShFill((GfxPatchMeshShading *)shading);
1797
// restore graphics state
1800
state->setPath(savedPath);
1806
void PdfParser::doFunctionShFill(GfxFunctionShading *shading) {
1807
double x0, y0, x1, y1;
1810
shading->getDomain(&x0, &y0, &x1, &y1);
1811
shading->getColor(x0, y0, &colors[0]);
1812
shading->getColor(x0, y1, &colors[1]);
1813
shading->getColor(x1, y0, &colors[2]);
1814
shading->getColor(x1, y1, &colors[3]);
1815
doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
1818
void PdfParser::doFunctionShFill1(GfxFunctionShading *shading,
1819
double x0, double y0,
1820
double x1, double y1,
1821
GfxColor *colors, int depth) {
1823
GfxColor color0M, color1M, colorM0, colorM1, colorMM;
1824
GfxColor colors2[4];
1825
double functionColorDelta = colorDeltas[pdfFunctionShading-1];
1830
nComps = shading->getColorSpace()->getNComps();
1831
matrix = shading->getMatrix();
1833
// compare the four corner colors
1834
for (i = 0; i < 4; ++i) {
1835
for (j = 0; j < nComps; ++j) {
1836
if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
1845
// center of the rectangle
1846
xM = 0.5 * (x0 + x1);
1847
yM = 0.5 * (y0 + y1);
1849
// the four corner colors are close (or we hit the recursive limit)
1850
// -- fill the rectangle; but require at least one subdivision
1851
// (depth==0) to avoid problems when the four outer corners of the
1852
// shaded region are the same color
1853
if ((i == 4 && depth > 0) || depth == maxDepths[pdfFunctionShading-1]) {
1855
// use the center color
1856
shading->getColor(xM, yM, &fillColor);
1857
state->setFillColor(&fillColor);
1859
// fill the rectangle
1860
state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
1861
x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
1862
state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
1863
x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
1864
state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
1865
x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
1866
state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
1867
x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
1869
builder->addPath(state, true, false);
1872
// the four corner colors are not close enough -- subdivide the
1876
// colors[0] colorM0 colors[2]
1877
// (x0,y0) (xM,y0) (x1,y0)
1878
// +----------+----------+
1881
// color0M | colorMM | color1M
1882
// (x0,yM) +----------+----------+ (x1,yM)
1886
// +----------+----------+
1887
// colors[1] colorM1 colors[3]
1888
// (x0,y1) (xM,y1) (x1,y1)
1890
shading->getColor(x0, yM, &color0M);
1891
shading->getColor(x1, yM, &color1M);
1892
shading->getColor(xM, y0, &colorM0);
1893
shading->getColor(xM, y1, &colorM1);
1894
shading->getColor(xM, yM, &colorMM);
1896
// upper-left sub-rectangle
1897
colors2[0] = colors[0];
1898
colors2[1] = color0M;
1899
colors2[2] = colorM0;
1900
colors2[3] = colorMM;
1901
doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
1903
// lower-left sub-rectangle
1904
colors2[0] = color0M;
1905
colors2[1] = colors[1];
1906
colors2[2] = colorMM;
1907
colors2[3] = colorM1;
1908
doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
1910
// upper-right sub-rectangle
1911
colors2[0] = colorM0;
1912
colors2[1] = colorMM;
1913
colors2[2] = colors[2];
1914
colors2[3] = color1M;
1915
doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
1917
// lower-right sub-rectangle
1918
colors2[0] = colorMM;
1919
colors2[1] = colorM1;
1920
colors2[2] = color1M;
1921
colors2[3] = colors[3];
1922
doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
1926
void PdfParser::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
1927
double x0, y0, x1, y1, x2, y2;
1928
GfxColor color0, color1, color2;
1931
for (i = 0; i < shading->getNTriangles(); ++i) {
1932
shading->getTriangle(i, &x0, &y0, &color0,
1935
gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
1936
shading->getColorSpace()->getNComps(), 0);
1940
void PdfParser::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
1941
double x1, double y1, GfxColor *color1,
1942
double x2, double y2, GfxColor *color2,
1943
int nComps, int depth) {
1944
double x01, y01, x12, y12, x20, y20;
1945
double gouraudColorDelta = colorDeltas[pdfGouraudTriangleShading-1];
1946
GfxColor color01, color12, color20;
1949
for (i = 0; i < nComps; ++i) {
1950
if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
1951
abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
1955
if (i == nComps || depth == maxDepths[pdfGouraudTriangleShading-1]) {
1956
state->setFillColor(color0);
1957
state->moveTo(x0, y0);
1958
state->lineTo(x1, y1);
1959
state->lineTo(x2, y2);
1961
builder->addPath(state, true, false);
1964
x01 = 0.5 * (x0 + x1);
1965
y01 = 0.5 * (y0 + y1);
1966
x12 = 0.5 * (x1 + x2);
1967
y12 = 0.5 * (y1 + y2);
1968
x20 = 0.5 * (x2 + x0);
1969
y20 = 0.5 * (y2 + y0);
1970
//~ if the shading has a Function, this should interpolate on the
1971
//~ function parameter, not on the color components
1972
for (i = 0; i < nComps; ++i) {
1973
color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
1974
color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
1975
color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
1977
gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
1978
x20, y20, &color20, nComps, depth + 1);
1979
gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
1980
x12, y12, &color12, nComps, depth + 1);
1981
gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
1982
x20, y20, &color20, nComps, depth + 1);
1983
gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
1984
x2, y2, color2, nComps, depth + 1);
1988
void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) {
1991
if (shading->getNPatches() > 128) {
1993
} else if (shading->getNPatches() > 64) {
1995
} else if (shading->getNPatches() > 16) {
2000
for (i = 0; i < shading->getNPatches(); ++i) {
2001
fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
2006
void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
2007
GfxPatch patch00, patch01, patch10, patch11;
2008
#ifdef POPPLER_NEW_GFXPATCH
2011
double xx[4][8], yy[4][8];
2013
double patchColorDelta = colorDeltas[pdfPatchMeshShading-1];
2016
for (i = 0; i < nComps; ++i) {
2017
if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
2018
> patchColorDelta ||
2019
abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
2020
> patchColorDelta ||
2021
abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
2022
> patchColorDelta ||
2023
abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
2024
> patchColorDelta) {
2027
#ifdef POPPLER_NEW_GFXPATCH
2028
color.c[i] = GfxColorComp(patch->color[0][0].c[i]);
2031
if (i == nComps || depth == maxDepths[pdfPatchMeshShading-1]) {
2032
#ifdef POPPLER_NEW_GFXPATCH
2033
state->setFillColor(&color);
2035
state->setFillColor(&patch->color[0][0]);
2037
state->moveTo(patch->x[0][0], patch->y[0][0]);
2038
state->curveTo(patch->x[0][1], patch->y[0][1],
2039
patch->x[0][2], patch->y[0][2],
2040
patch->x[0][3], patch->y[0][3]);
2041
state->curveTo(patch->x[1][3], patch->y[1][3],
2042
patch->x[2][3], patch->y[2][3],
2043
patch->x[3][3], patch->y[3][3]);
2044
state->curveTo(patch->x[3][2], patch->y[3][2],
2045
patch->x[3][1], patch->y[3][1],
2046
patch->x[3][0], patch->y[3][0]);
2047
state->curveTo(patch->x[2][0], patch->y[2][0],
2048
patch->x[1][0], patch->y[1][0],
2049
patch->x[0][0], patch->y[0][0]);
2051
builder->addPath(state, true, false);
2054
for (i = 0; i < 4; ++i) {
2055
xx[i][0] = patch->x[i][0];
2056
yy[i][0] = patch->y[i][0];
2057
xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
2058
yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
2059
xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
2060
yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
2061
xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
2062
yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
2063
xx[i][2] = 0.5 * (xx[i][1] + xxm);
2064
yy[i][2] = 0.5 * (yy[i][1] + yym);
2065
xx[i][5] = 0.5 * (xxm + xx[i][6]);
2066
yy[i][5] = 0.5 * (yym + yy[i][6]);
2067
xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
2068
yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
2069
xx[i][7] = patch->x[i][3];
2070
yy[i][7] = patch->y[i][3];
2072
for (i = 0; i < 4; ++i) {
2073
patch00.x[0][i] = xx[0][i];
2074
patch00.y[0][i] = yy[0][i];
2075
patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
2076
patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
2077
xxm = 0.5 * (xx[1][i] + xx[2][i]);
2078
yym = 0.5 * (yy[1][i] + yy[2][i]);
2079
patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
2080
patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
2081
patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
2082
patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
2083
patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
2084
patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
2085
patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
2086
patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
2087
patch10.x[0][i] = patch00.x[3][i];
2088
patch10.y[0][i] = patch00.y[3][i];
2089
patch10.x[3][i] = xx[3][i];
2090
patch10.y[3][i] = yy[3][i];
2092
for (i = 4; i < 8; ++i) {
2093
patch01.x[0][i-4] = xx[0][i];
2094
patch01.y[0][i-4] = yy[0][i];
2095
patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
2096
patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
2097
xxm = 0.5 * (xx[1][i] + xx[2][i]);
2098
yym = 0.5 * (yy[1][i] + yy[2][i]);
2099
patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
2100
patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
2101
patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
2102
patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
2103
patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
2104
patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
2105
patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
2106
patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
2107
patch11.x[0][i-4] = patch01.x[3][i-4];
2108
patch11.y[0][i-4] = patch01.y[3][i-4];
2109
patch11.x[3][i-4] = xx[3][i];
2110
patch11.y[3][i-4] = yy[3][i];
2112
//~ if the shading has a Function, this should interpolate on the
2113
//~ function parameter, not on the color components
2114
for (i = 0; i < nComps; ++i) {
2115
patch00.color[0][0].c[i] = patch->color[0][0].c[i];
2116
patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
2117
patch->color[0][1].c[i]) / 2;
2118
patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
2119
patch01.color[0][1].c[i] = patch->color[0][1].c[i];
2120
patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
2121
patch->color[1][1].c[i]) / 2;
2122
patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
2123
patch11.color[1][1].c[i] = patch->color[1][1].c[i];
2124
patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
2125
patch->color[1][0].c[i]) / 2;
2126
patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
2127
patch10.color[1][0].c[i] = patch->color[1][0].c[i];
2128
patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
2129
patch->color[0][0].c[i]) / 2;
2130
patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
2131
patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
2132
patch01.color[1][1].c[i]) / 2;
2133
patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
2134
patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
2135
patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
2137
fillPatch(&patch00, nComps, depth + 1);
2138
fillPatch(&patch10, nComps, depth + 1);
2139
fillPatch(&patch01, nComps, depth + 1);
2140
fillPatch(&patch11, nComps, depth + 1);
2144
void PdfParser::doEndPath() {
2145
if (state->isCurPt() && clip != clipNone) {
2147
if (clip == clipNormal) {
2148
clipHistory->setClip(state->getPath(), clipNormal);
2149
builder->clip(state);
2151
clipHistory->setClip(state->getPath(), clipEO);
2152
builder->clip(state, true);
2159
//------------------------------------------------------------------------
2160
// path clipping operators
2161
//------------------------------------------------------------------------
2163
void PdfParser::opClip(Object args[], int numArgs) {
2167
void PdfParser::opEOClip(Object args[], int numArgs) {
2171
//------------------------------------------------------------------------
2172
// text object operators
2173
//------------------------------------------------------------------------
2175
void PdfParser::opBeginText(Object args[], int numArgs) {
2176
state->setTextMat(1, 0, 0, 1, 0, 0);
2177
state->textMoveTo(0, 0);
2178
builder->updateTextPosition(0.0, 0.0);
2179
fontChanged = gTrue;
2180
builder->beginTextObject(state);
2183
void PdfParser::opEndText(Object args[], int numArgs) {
2184
builder->endTextObject(state);
2187
//------------------------------------------------------------------------
2188
// text state operators
2189
//------------------------------------------------------------------------
2191
void PdfParser::opSetCharSpacing(Object args[], int numArgs) {
2192
state->setCharSpace(args[0].getNum());
2195
void PdfParser::opSetFont(Object args[], int numArgs) {
2198
if (!(font = res->lookupFont(args[0].getName()))) {
2199
// unsetting the font (drawing no text) is better than using the
2200
// previous one and drawing random glyphs from it
2201
state->setFont(NULL, args[1].getNum());
2202
fontChanged = gTrue;
2205
if (printCommands) {
2206
printf(" font: tag=%s name='%s' %g\n",
2207
font->getTag()->getCString(),
2208
font->getName() ? font->getName()->getCString() : "???",
2214
state->setFont(font, args[1].getNum());
2215
fontChanged = gTrue;
2218
void PdfParser::opSetTextLeading(Object args[], int numArgs) {
2219
state->setLeading(args[0].getNum());
2222
void PdfParser::opSetTextRender(Object args[], int numArgs) {
2223
state->setRender(args[0].getInt());
2224
builder->updateStyle(state);
2227
void PdfParser::opSetTextRise(Object args[], int numArgs) {
2228
state->setRise(args[0].getNum());
2231
void PdfParser::opSetWordSpacing(Object args[], int numArgs) {
2232
state->setWordSpace(args[0].getNum());
2235
void PdfParser::opSetHorizScaling(Object args[], int numArgs) {
2236
state->setHorizScaling(args[0].getNum());
2237
builder->updateTextMatrix(state);
2238
fontChanged = gTrue;
2241
//------------------------------------------------------------------------
2242
// text positioning operators
2243
//------------------------------------------------------------------------
2245
void PdfParser::opTextMove(Object args[], int numArgs) {
2248
tx = state->getLineX() + args[0].getNum();
2249
ty = state->getLineY() + args[1].getNum();
2250
state->textMoveTo(tx, ty);
2251
builder->updateTextPosition(tx, ty);
2254
void PdfParser::opTextMoveSet(Object args[], int numArgs) {
2257
tx = state->getLineX() + args[0].getNum();
2258
ty = args[1].getNum();
2259
state->setLeading(-ty);
2260
ty += state->getLineY();
2261
state->textMoveTo(tx, ty);
2262
builder->updateTextPosition(tx, ty);
2265
void PdfParser::opSetTextMatrix(Object args[], int numArgs) {
2266
state->setTextMat(args[0].getNum(), args[1].getNum(),
2267
args[2].getNum(), args[3].getNum(),
2268
args[4].getNum(), args[5].getNum());
2269
state->textMoveTo(0, 0);
2270
builder->updateTextMatrix(state);
2271
builder->updateTextPosition(0.0, 0.0);
2272
fontChanged = gTrue;
2275
void PdfParser::opTextNextLine(Object args[], int numArgs) {
2278
tx = state->getLineX();
2279
ty = state->getLineY() - state->getLeading();
2280
state->textMoveTo(tx, ty);
2281
builder->updateTextPosition(tx, ty);
2284
//------------------------------------------------------------------------
2285
// text string operators
2286
//------------------------------------------------------------------------
2288
void PdfParser::opShowText(Object args[], int numArgs) {
2289
if (!state->getFont()) {
2290
#ifdef POPPLER_NEW_ERRORAPI
2291
error(errSyntaxError, getPos(), "No font in show");
2293
error(getPos(), const_cast<char*>("No font in show"));
2298
builder->updateFont(state);
2299
fontChanged = gFalse;
2301
doShowText(args[0].getString());
2304
void PdfParser::opMoveShowText(Object args[], int numArgs) {
2307
if (!state->getFont()) {
2308
#ifdef POPPLER_NEW_ERRORAPI
2309
error(errSyntaxError, getPos(), "No font in move/show");
2311
error(getPos(), const_cast<char*>("No font in move/show"));
2316
builder->updateFont(state);
2317
fontChanged = gFalse;
2319
tx = state->getLineX();
2320
ty = state->getLineY() - state->getLeading();
2321
state->textMoveTo(tx, ty);
2322
builder->updateTextPosition(tx, ty);
2323
doShowText(args[0].getString());
2326
void PdfParser::opMoveSetShowText(Object args[], int numArgs) {
2329
if (!state->getFont()) {
2330
#ifdef POPPLER_NEW_ERRORAPI
2331
error(errSyntaxError, getPos(), "No font in move/set/show");
2333
error(getPos(), const_cast<char*>("No font in move/set/show"));
2338
builder->updateFont(state);
2339
fontChanged = gFalse;
2341
state->setWordSpace(args[0].getNum());
2342
state->setCharSpace(args[1].getNum());
2343
tx = state->getLineX();
2344
ty = state->getLineY() - state->getLeading();
2345
state->textMoveTo(tx, ty);
2346
builder->updateTextPosition(tx, ty);
2347
doShowText(args[2].getString());
2350
void PdfParser::opShowSpaceText(Object args[], int numArgs) {
2356
if (!state->getFont()) {
2357
#ifdef POPPLER_NEW_ERRORAPI
2358
error(errSyntaxError, getPos(), "No font in show/space");
2360
error(getPos(), const_cast<char*>("No font in show/space"));
2365
builder->updateFont(state);
2366
fontChanged = gFalse;
2368
wMode = state->getFont()->getWMode();
2369
a = args[0].getArray();
2370
for (i = 0; i < a->getLength(); ++i) {
2373
// this uses the absolute value of the font size to match
2374
// Acrobat's behavior
2376
state->textShift(0, -obj.getNum() * 0.001 *
2377
fabs(state->getFontSize()));
2379
state->textShift(-obj.getNum() * 0.001 *
2380
fabs(state->getFontSize()), 0);
2382
builder->updateTextShift(state, obj.getNum());
2383
} else if (obj.isString()) {
2384
doShowText(obj.getString());
2386
#ifdef POPPLER_NEW_ERRORAPI
2387
error(errSyntaxError, getPos(), "Element of show/space array must be number or string");
2389
error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
2399
* The `POPPLER_NEW_GFXFONT' stuff is for the change to GfxFont's getNextChar() call.
2400
* Thanks to tsdgeos for the fix.
2401
* Miklos, does this look ok?
2404
void PdfParser::doShowText(GooString *s) {
2407
double riseX, riseY;
2409
#ifdef POPPLER_NEW_GFXFONT
2414
double x, y, dx, dy, curX, curY, tdx, tdy, lineX, lineY;
2415
double originX, originY, tOriginX, tOriginY;
2416
double oldCTM[6], newCTM[6];
2422
int len, n, uLen, i;
2424
font = state->getFont();
2425
wMode = font->getWMode();
2427
builder->beginString(state, s);
2429
// handle a Type 3 char
2430
if (font->getType() == fontType3 && 0) {//out->interpretType3Chars()) {
2431
mat = state->getCTM();
2432
for (i = 0; i < 6; ++i) {
2435
mat = state->getTextMat();
2436
newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
2437
newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
2438
newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
2439
newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
2440
mat = font->getFontMatrix();
2441
newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
2442
newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
2443
newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
2444
newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
2445
newCTM[0] *= state->getFontSize();
2446
newCTM[1] *= state->getFontSize();
2447
newCTM[2] *= state->getFontSize();
2448
newCTM[3] *= state->getFontSize();
2449
newCTM[0] *= state->getHorizScaling();
2450
newCTM[2] *= state->getHorizScaling();
2451
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
2452
curX = state->getCurX();
2453
curY = state->getCurY();
2454
lineX = state->getLineX();
2455
lineY = state->getLineY();
2457
p = s->getCString();
2458
len = s->getLength();
2460
n = font->getNextChar(p, len, &code,
2461
#ifdef POPPLER_NEW_GFXFONT
2462
&u, &uLen, /* TODO: This looks like a memory leak for u. */
2464
u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2466
&dx, &dy, &originX, &originY);
2467
dx = dx * state->getFontSize() + state->getCharSpace();
2468
if (n == 1 && *p == ' ') {
2469
dx += state->getWordSpace();
2471
dx *= state->getHorizScaling();
2472
dy *= state->getFontSize();
2473
state->textTransformDelta(dx, dy, &tdx, &tdy);
2474
state->transform(curX + riseX, curY + riseY, &x, &y);
2476
state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
2477
//~ the CTM concat values here are wrong (but never used)
2478
//out->updateCTM(state, 1, 0, 0, 1, 0, 0);
2479
if (0){ /*!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
2481
((Gfx8BitFont *)font)->getCharProc(code, &charProc);
2482
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
2483
pushResources(resDict);
2485
if (charProc.isStream()) {
2486
//parse(&charProc, gFalse); // TODO: parse into SVG font
2488
#ifdef POPPLER_NEW_ERRORAPI
2489
error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
2491
error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
2494
//out->endType3Char(state);
2501
// GfxState::restore() does *not* restore the current position,
2502
// so we deal with it here using (curX, curY) and (lineX, lineY)
2505
state->moveTo(curX, curY);
2506
state->textSetPos(lineX, lineY);
2513
state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
2514
p = s->getCString();
2515
len = s->getLength();
2517
n = font->getNextChar(p, len, &code,
2518
#ifdef POPPLER_NEW_GFXFONT
2519
&u, &uLen, /* TODO: This looks like a memory leak for u. */
2521
u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
2523
&dx, &dy, &originX, &originY);
2526
dx *= state->getFontSize();
2527
dy = dy * state->getFontSize() + state->getCharSpace();
2528
if (n == 1 && *p == ' ') {
2529
dy += state->getWordSpace();
2532
dx = dx * state->getFontSize() + state->getCharSpace();
2533
if (n == 1 && *p == ' ') {
2534
dx += state->getWordSpace();
2536
dx *= state->getHorizScaling();
2537
dy *= state->getFontSize();
2539
state->textTransformDelta(dx, dy, &tdx, &tdy);
2540
originX *= state->getFontSize();
2541
originY *= state->getFontSize();
2542
state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
2543
builder->addChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
2544
dx, dy, tOriginX, tOriginY, code, n, u, uLen);
2545
state->shift(tdx, tdy);
2551
builder->endString(state);
2555
//------------------------------------------------------------------------
2556
// XObject operators
2557
//------------------------------------------------------------------------
2559
void PdfParser::opXObject(Object args[], int numArgs) {
2561
Object obj1, obj2, obj3, refObj;
2563
name = args[0].getName();
2564
if (!res->lookupXObject(name, &obj1)) {
2567
if (!obj1.isStream()) {
2568
#ifdef POPPLER_NEW_ERRORAPI
2569
error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
2571
error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
2576
obj1.streamGetDict()->lookup(const_cast<char*>("Subtype"), &obj2);
2577
if (obj2.isName(const_cast<char*>("Image"))) {
2578
res->lookupXObjectNF(name, &refObj);
2579
doImage(&refObj, obj1.getStream(), gFalse);
2581
} else if (obj2.isName(const_cast<char*>("Form"))) {
2583
} else if (obj2.isName(const_cast<char*>("PS"))) {
2584
obj1.streamGetDict()->lookup(const_cast<char*>("Level1"), &obj3);
2585
/* out->psXObject(obj1.getStream(),
2586
obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
2587
} else if (obj2.isName()) {
2588
#ifdef POPPLER_NEW_ERRORAPI
2589
error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
2591
error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
2594
#ifdef POPPLER_NEW_ERRORAPI
2595
error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
2597
error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
2604
void PdfParser::doImage(Object *ref, Stream *str, GBool inlineImg) {
2605
Dict *dict, *maskDict;
2608
StreamColorSpaceMode csMode;
2611
GfxColorSpace *colorSpace, *maskColorSpace;
2612
GfxImageColorMap *colorMap, *maskColorMap;
2613
Object maskObj, smaskObj;
2614
GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
2615
int maskColors[2*gfxColorMaxComps];
2616
int maskWidth, maskHeight;
2622
// get info from the stream
2624
csMode = streamCSNone;
2625
str->getImageParams(&bits, &csMode);
2628
dict = str->getDict();
2631
dict->lookup(const_cast<char*>("Width"), &obj1);
2632
if (obj1.isNull()) {
2634
dict->lookup(const_cast<char*>("W"), &obj1);
2637
width = obj1.getInt();
2638
else if (obj1.isReal())
2639
width = (int)obj1.getReal();
2643
dict->lookup(const_cast<char*>("Height"), &obj1);
2644
if (obj1.isNull()) {
2646
dict->lookup(const_cast<char*>("H"), &obj1);
2649
height = obj1.getInt();
2650
else if (obj1.isReal())
2651
height = (int)obj1.getReal();
2657
dict->lookup(const_cast<char*>("ImageMask"), &obj1);
2658
if (obj1.isNull()) {
2660
dict->lookup(const_cast<char*>("IM"), &obj1);
2664
mask = obj1.getBool();
2665
else if (!obj1.isNull())
2671
dict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
2672
if (obj1.isNull()) {
2674
dict->lookup(const_cast<char*>("BPC"), &obj1);
2677
bits = obj1.getInt();
2689
// check for inverted mask
2693
dict->lookup(const_cast<char*>("Decode"), &obj1);
2694
if (obj1.isNull()) {
2696
dict->lookup(const_cast<char*>("D"), &obj1);
2698
if (obj1.isArray()) {
2699
obj1.arrayGet(0, &obj2);
2700
if (obj2.isInt() && obj2.getInt() == 1)
2703
} else if (!obj1.isNull()) {
2709
builder->addImageMask(state, str, width, height, invert);
2713
// get color space and color map
2714
dict->lookup(const_cast<char*>("ColorSpace"), &obj1);
2715
if (obj1.isNull()) {
2717
dict->lookup(const_cast<char*>("CS"), &obj1);
2719
if (obj1.isName()) {
2720
res->lookupColorSpace(obj1.getName(), &obj2);
2721
if (!obj2.isNull()) {
2728
if (!obj1.isNull()) {
2729
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
2730
colorSpace = GfxColorSpace::parse(&obj1, NULL);
2732
colorSpace = GfxColorSpace::parse(&obj1);
2734
} else if (csMode == streamCSDeviceGray) {
2735
colorSpace = new GfxDeviceGrayColorSpace();
2736
} else if (csMode == streamCSDeviceRGB) {
2737
colorSpace = new GfxDeviceRGBColorSpace();
2738
} else if (csMode == streamCSDeviceCMYK) {
2739
colorSpace = new GfxDeviceCMYKColorSpace();
2747
dict->lookup(const_cast<char*>("Decode"), &obj1);
2748
if (obj1.isNull()) {
2750
dict->lookup(const_cast<char*>("D"), &obj1);
2752
colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
2754
if (!colorMap->isOk()) {
2760
haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
2761
maskStr = NULL; // make gcc happy
2762
maskWidth = maskHeight = 0; // make gcc happy
2763
maskInvert = gFalse; // make gcc happy
2764
maskColorMap = NULL; // make gcc happy
2765
dict->lookup(const_cast<char*>("Mask"), &maskObj);
2766
dict->lookup(const_cast<char*>("SMask"), &smaskObj);
2767
if (smaskObj.isStream()) {
2772
maskStr = smaskObj.getStream();
2773
maskDict = smaskObj.streamGetDict();
2774
maskDict->lookup(const_cast<char*>("Width"), &obj1);
2775
if (obj1.isNull()) {
2777
maskDict->lookup(const_cast<char*>("W"), &obj1);
2779
if (!obj1.isInt()) {
2782
maskWidth = obj1.getInt();
2784
maskDict->lookup(const_cast<char*>("Height"), &obj1);
2785
if (obj1.isNull()) {
2787
maskDict->lookup(const_cast<char*>("H"), &obj1);
2789
if (!obj1.isInt()) {
2792
maskHeight = obj1.getInt();
2794
maskDict->lookup(const_cast<char*>("BitsPerComponent"), &obj1);
2795
if (obj1.isNull()) {
2797
maskDict->lookup(const_cast<char*>("BPC"), &obj1);
2799
if (!obj1.isInt()) {
2802
maskBits = obj1.getInt();
2804
maskDict->lookup(const_cast<char*>("ColorSpace"), &obj1);
2805
if (obj1.isNull()) {
2807
maskDict->lookup(const_cast<char*>("CS"), &obj1);
2809
if (obj1.isName()) {
2810
res->lookupColorSpace(obj1.getName(), &obj2);
2811
if (!obj2.isNull()) {
2818
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
2819
maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
2821
maskColorSpace = GfxColorSpace::parse(&obj1);
2824
if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
2827
maskDict->lookup(const_cast<char*>("Decode"), &obj1);
2828
if (obj1.isNull()) {
2830
maskDict->lookup(const_cast<char*>("D"), &obj1);
2832
maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
2834
if (!maskColorMap->isOk()) {
2835
delete maskColorMap;
2838
//~ handle the Matte entry
2839
haveSoftMask = gTrue;
2840
} else if (maskObj.isArray()) {
2843
i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
2845
maskObj.arrayGet(i, &obj1);
2846
maskColors[i] = obj1.getInt();
2849
haveColorKeyMask = gTrue;
2850
} else if (maskObj.isStream()) {
2855
maskStr = maskObj.getStream();
2856
maskDict = maskObj.streamGetDict();
2857
maskDict->lookup(const_cast<char*>("Width"), &obj1);
2858
if (obj1.isNull()) {
2860
maskDict->lookup(const_cast<char*>("W"), &obj1);
2862
if (!obj1.isInt()) {
2865
maskWidth = obj1.getInt();
2867
maskDict->lookup(const_cast<char*>("Height"), &obj1);
2868
if (obj1.isNull()) {
2870
maskDict->lookup(const_cast<char*>("H"), &obj1);
2872
if (!obj1.isInt()) {
2875
maskHeight = obj1.getInt();
2877
maskDict->lookup(const_cast<char*>("ImageMask"), &obj1);
2878
if (obj1.isNull()) {
2880
maskDict->lookup(const_cast<char*>("IM"), &obj1);
2882
if (!obj1.isBool() || !obj1.getBool()) {
2886
maskInvert = gFalse;
2887
maskDict->lookup(const_cast<char*>("Decode"), &obj1);
2888
if (obj1.isNull()) {
2890
maskDict->lookup(const_cast<char*>("D"), &obj1);
2892
if (obj1.isArray()) {
2893
obj1.arrayGet(0, &obj2);
2894
if (obj2.isInt() && obj2.getInt() == 1) {
2898
} else if (!obj1.isNull()) {
2902
haveExplicitMask = gTrue;
2907
builder->addSoftMaskedImage(state, str, width, height, colorMap,
2908
maskStr, maskWidth, maskHeight, maskColorMap);
2909
delete maskColorMap;
2910
} else if (haveExplicitMask) {
2911
builder->addMaskedImage(state, str, width, height, colorMap,
2912
maskStr, maskWidth, maskHeight, maskInvert);
2914
builder->addImage(state, str, width, height, colorMap,
2915
haveColorKeyMask ? maskColors : (int *)NULL);
2928
#ifdef POPPLER_NEW_ERRORAPI
2929
error(errSyntaxError, getPos(), "Bad image parameters");
2931
error(getPos(), const_cast<char*>("Bad image parameters"));
2935
void PdfParser::doForm(Object *str) {
2937
GBool transpGroup, isolated, knockout;
2938
GfxColorSpace *blendingColorSpace;
2939
Object matrixObj, bboxObj;
2940
double m[6], bbox[4];
2943
Object obj1, obj2, obj3;
2946
// check for excessive recursion
2947
if (formDepth > 20) {
2952
dict = str->streamGetDict();
2955
dict->lookup(const_cast<char*>("FormType"), &obj1);
2956
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
2957
#ifdef POPPLER_NEW_ERRORAPI
2958
error(errSyntaxError, getPos(), "Unknown form type");
2960
error(getPos(), const_cast<char*>("Unknown form type"));
2966
dict->lookup(const_cast<char*>("BBox"), &bboxObj);
2967
if (!bboxObj.isArray()) {
2969
#ifdef POPPLER_NEW_ERRORAPI
2970
error(errSyntaxError, getPos(), "Bad form bounding box");
2972
error(getPos(), const_cast<char*>("Bad form bounding box"));
2976
for (i = 0; i < 4; ++i) {
2977
bboxObj.arrayGet(i, &obj1);
2978
bbox[i] = obj1.getNum();
2984
dict->lookup(const_cast<char*>("Matrix"), &matrixObj);
2985
if (matrixObj.isArray()) {
2986
for (i = 0; i < 6; ++i) {
2987
matrixObj.arrayGet(i, &obj1);
2988
m[i] = obj1.getNum();
2999
dict->lookup(const_cast<char*>("Resources"), &resObj);
3000
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
3002
// check for a transparency group
3003
transpGroup = isolated = knockout = gFalse;
3004
blendingColorSpace = NULL;
3005
if (dict->lookup(const_cast<char*>("Group"), &obj1)->isDict()) {
3006
if (obj1.dictLookup(const_cast<char*>("S"), &obj2)->isName(const_cast<char*>("Transparency"))) {
3007
transpGroup = gTrue;
3008
if (!obj1.dictLookup(const_cast<char*>("CS"), &obj3)->isNull()) {
3009
#if defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
3010
blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
3012
blendingColorSpace = GfxColorSpace::parse(&obj3);
3016
if (obj1.dictLookup(const_cast<char*>("I"), &obj3)->isBool()) {
3017
isolated = obj3.getBool();
3020
if (obj1.dictLookup(const_cast<char*>("K"), &obj3)->isBool()) {
3021
knockout = obj3.getBool();
3031
doForm1(str, resDict, m, bbox,
3032
transpGroup, gFalse, blendingColorSpace, isolated, knockout);
3035
if (blendingColorSpace) {
3036
delete blendingColorSpace;
3041
void PdfParser::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
3042
GBool transpGroup, GBool softMask,
3043
GfxColorSpace *blendingColorSpace,
3044
GBool isolated, GBool knockout,
3045
GBool alpha, Function *transferFunc,
3046
GfxColor *backdropColor) {
3048
double oldBaseMatrix[6];
3051
// push new resources on stack
3052
pushResources(resDict);
3054
// save current graphics state
3057
// kill any pre-existing path
3060
if (softMask || transpGroup) {
3061
builder->clearSoftMask(state);
3062
builder->pushTransparencyGroup(state, bbox, blendingColorSpace,
3063
isolated, knockout, softMask);
3066
// save current parser
3069
// set form transformation matrix
3070
state->concatCTM(matrix[0], matrix[1], matrix[2],
3071
matrix[3], matrix[4], matrix[5]);
3072
builder->setTransform(matrix[0], matrix[1], matrix[2],
3073
matrix[3], matrix[4], matrix[5]);
3075
// set form bounding box
3076
state->moveTo(bbox[0], bbox[1]);
3077
state->lineTo(bbox[2], bbox[1]);
3078
state->lineTo(bbox[2], bbox[3]);
3079
state->lineTo(bbox[0], bbox[3]);
3082
clipHistory->setClip(state->getPath());
3083
builder->clip(state);
3086
if (softMask || transpGroup) {
3087
if (state->getBlendMode() != gfxBlendNormal) {
3088
state->setBlendMode(gfxBlendNormal);
3090
if (state->getFillOpacity() != 1) {
3091
builder->setGroupOpacity(state->getFillOpacity());
3092
state->setFillOpacity(1);
3094
if (state->getStrokeOpacity() != 1) {
3095
state->setStrokeOpacity(1);
3099
// set new base matrix
3100
for (i = 0; i < 6; ++i) {
3101
oldBaseMatrix[i] = baseMatrix[i];
3102
baseMatrix[i] = state->getCTM()[i];
3108
// restore base matrix
3109
for (i = 0; i < 6; ++i) {
3110
baseMatrix[i] = oldBaseMatrix[i];
3116
if (softMask || transpGroup) {
3117
builder->popTransparencyGroup(state);
3120
// restore graphics state
3123
// pop resource stack
3127
builder->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
3128
} else if (transpGroup) {
3129
builder->paintTransparencyGroup(state, bbox);
3135
//------------------------------------------------------------------------
3136
// in-line image operators
3137
//------------------------------------------------------------------------
3139
void PdfParser::opBeginImage(Object args[], int numArgs) {
3143
// build dict/stream
3144
str = buildImageStream();
3146
// display the image
3148
doImage(NULL, str, gTrue);
3151
c1 = str->getUndecodedStream()->getChar();
3152
c2 = str->getUndecodedStream()->getChar();
3153
while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
3155
c2 = str->getUndecodedStream()->getChar();
3161
Stream *PdfParser::buildImageStream() {
3168
dict.initDict(xref);
3169
parser->getObj(&obj);
3170
while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
3171
if (!obj.isName()) {
3172
#ifdef POPPLER_NEW_ERRORAPI
3173
error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
3175
error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
3179
key = copyString(obj.getName());
3181
parser->getObj(&obj);
3182
if (obj.isEOF() || obj.isError()) {
3186
dict.dictAdd(key, &obj);
3188
parser->getObj(&obj);
3191
#ifdef POPPLER_NEW_ERRORAPI
3192
error(errSyntaxError, getPos(), "End of file in inline image");
3194
error(getPos(), const_cast<char*>("End of file in inline image"));
3203
str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
3204
str = str->addFilters(&dict);
3209
void PdfParser::opImageData(Object args[], int numArgs) {
3210
#ifdef POPPLER_NEW_ERRORAPI
3211
error(errInternal, getPos(), "Internal: got 'ID' operator");
3213
error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
3217
void PdfParser::opEndImage(Object args[], int numArgs) {
3218
#ifdef POPPLER_NEW_ERRORAPI
3219
error(errInternal, getPos(), "Internal: got 'EI' operator");
3221
error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
3225
//------------------------------------------------------------------------
3226
// type 3 font operators
3227
//------------------------------------------------------------------------
3229
void PdfParser::opSetCharWidth(Object args[], int numArgs) {
3232
void PdfParser::opSetCacheDevice(Object args[], int numArgs) {
3235
//------------------------------------------------------------------------
3236
// compatibility operators
3237
//------------------------------------------------------------------------
3239
void PdfParser::opBeginIgnoreUndef(Object args[], int numArgs) {
3243
void PdfParser::opEndIgnoreUndef(Object args[], int numArgs) {
3244
if (ignoreUndef > 0)
3248
//------------------------------------------------------------------------
3249
// marked content operators
3250
//------------------------------------------------------------------------
3252
void PdfParser::opBeginMarkedContent(Object args[], int numArgs) {
3253
if (printCommands) {
3254
printf(" marked content: %s ", args[0].getName());
3256
args[2].print(stdout);
3262
//out->beginMarkedContent(args[0].getName(),args[1].getDict());
3264
//out->beginMarkedContent(args[0].getName());
3268
void PdfParser::opEndMarkedContent(Object args[], int numArgs) {
3269
//out->endMarkedContent();
3272
void PdfParser::opMarkPoint(Object args[], int numArgs) {
3273
if (printCommands) {
3274
printf(" mark point: %s ", args[0].getName());
3276
args[2].print(stdout);
3282
//out->markPoint(args[0].getName(),args[1].getDict());
3284
//out->markPoint(args[0].getName());
3289
//------------------------------------------------------------------------
3291
//------------------------------------------------------------------------
3293
void PdfParser::saveState() {
3294
builder->saveState();
3295
state = state->save();
3296
clipHistory = clipHistory->save();
3299
void PdfParser::restoreState() {
3300
clipHistory = clipHistory->restore();
3301
state = state->restore();
3302
builder->restoreState();
3305
void PdfParser::pushResources(Dict *resDict) {
3306
res = new GfxResources(xref, resDict, res);
3309
void PdfParser::popResources() {
3310
GfxResources *resPtr;
3312
resPtr = res->getNext();
3317
void PdfParser::setDefaultApproximationPrecision() {
3320
for (i = 1; i <= pdfNumShadingTypes; ++i) {
3321
setApproximationPrecision(i, defaultShadingColorDelta, defaultShadingMaxDepth);
3325
void PdfParser::setApproximationPrecision(int shadingType, double colorDelta,
3328
if (shadingType > pdfNumShadingTypes || shadingType < 1) {
3331
colorDeltas[shadingType-1] = dblToCol(colorDelta);
3332
maxDepths[shadingType-1] = maxDepth;
3335
//------------------------------------------------------------------------
3337
//------------------------------------------------------------------------
3339
ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) {
3341
clipPath = clipPathA->copy();
3345
clipType = clipTypeA;
3349
ClipHistoryEntry::~ClipHistoryEntry() {
3355
void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) {
3356
// Free previous clip path
3361
clipPath = clipPathA->copy();
3362
clipType = clipTypeA;
3368
ClipHistoryEntry *ClipHistoryEntry::save() {
3369
ClipHistoryEntry *newEntry = new ClipHistoryEntry(this);
3370
newEntry->saved = this;
3375
ClipHistoryEntry *ClipHistoryEntry::restore() {
3376
ClipHistoryEntry *oldEntry;
3389
ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) {
3390
if (other->clipPath) {
3391
this->clipPath = other->clipPath->copy();
3392
this->clipType = other->clipType;
3394
this->clipPath = NULL;
3399
#endif /* HAVE_POPPLER */