00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014
00015 #include <stdio.h>
00016 #include <stddef.h>
00017 #include <string.h>
00018 #include <math.h>
00019 #include "gmem.h"
00020 #include "GlobalParams.h"
00021 #include "CharTypes.h"
00022 #include "Object.h"
00023 #include "Array.h"
00024 #include "Dict.h"
00025 #include "Stream.h"
00026 #include "Lexer.h"
00027 #include "Parser.h"
00028 #include "GfxFont.h"
00029 #include "GfxState.h"
00030 #include "OutputDev.h"
00031 #include "Page.h"
00032 #include "Error.h"
00033 #include "Gfx.h"
00034
00035
00036 #ifndef M_PI
00037 #define M_PI 3.14159265358979323846
00038 #endif
00039
00040
00041
00042
00043
00044
00045 #define axialMaxSplits 256
00046
00047
00048 #define axialColorDelta (1 / 256.0)
00049
00050
00051 #define radialMaxSplits 256
00052
00053
00054 #define radialColorDelta (1 / 256.0)
00055
00056
00057
00058
00059
00060 Operator Gfx::opTab[] = {
00061 {"\"", 3, {tchkNum, tchkNum, tchkString},
00062 &Gfx::opMoveSetShowText},
00063 {"'", 1, {tchkString},
00064 &Gfx::opMoveShowText},
00065 {"B", 0, {tchkNone},
00066 &Gfx::opFillStroke},
00067 {"B*", 0, {tchkNone},
00068 &Gfx::opEOFillStroke},
00069 {"BDC", 2, {tchkName, tchkProps},
00070 &Gfx::opBeginMarkedContent},
00071 {"BI", 0, {tchkNone},
00072 &Gfx::opBeginImage},
00073 {"BMC", 1, {tchkName},
00074 &Gfx::opBeginMarkedContent},
00075 {"BT", 0, {tchkNone},
00076 &Gfx::opBeginText},
00077 {"BX", 0, {tchkNone},
00078 &Gfx::opBeginIgnoreUndef},
00079 {"CS", 1, {tchkName},
00080 &Gfx::opSetStrokeColorSpace},
00081 {"DP", 2, {tchkName, tchkProps},
00082 &Gfx::opMarkPoint},
00083 {"Do", 1, {tchkName},
00084 &Gfx::opXObject},
00085 {"EI", 0, {tchkNone},
00086 &Gfx::opEndImage},
00087 {"EMC", 0, {tchkNone},
00088 &Gfx::opEndMarkedContent},
00089 {"ET", 0, {tchkNone},
00090 &Gfx::opEndText},
00091 {"EX", 0, {tchkNone},
00092 &Gfx::opEndIgnoreUndef},
00093 {"F", 0, {tchkNone},
00094 &Gfx::opFill},
00095 {"G", 1, {tchkNum},
00096 &Gfx::opSetStrokeGray},
00097 {"ID", 0, {tchkNone},
00098 &Gfx::opImageData},
00099 {"J", 1, {tchkInt},
00100 &Gfx::opSetLineCap},
00101 {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
00102 &Gfx::opSetStrokeCMYKColor},
00103 {"M", 1, {tchkNum},
00104 &Gfx::opSetMiterLimit},
00105 {"MP", 1, {tchkName},
00106 &Gfx::opMarkPoint},
00107 {"Q", 0, {tchkNone},
00108 &Gfx::opRestore},
00109 {"RG", 3, {tchkNum, tchkNum, tchkNum},
00110 &Gfx::opSetStrokeRGBColor},
00111 {"S", 0, {tchkNone},
00112 &Gfx::opStroke},
00113 {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
00114 &Gfx::opSetStrokeColor},
00115 {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
00116 tchkSCN},
00117 &Gfx::opSetStrokeColorN},
00118 {"T*", 0, {tchkNone},
00119 &Gfx::opTextNextLine},
00120 {"TD", 2, {tchkNum, tchkNum},
00121 &Gfx::opTextMoveSet},
00122 {"TJ", 1, {tchkArray},
00123 &Gfx::opShowSpaceText},
00124 {"TL", 1, {tchkNum},
00125 &Gfx::opSetTextLeading},
00126 {"Tc", 1, {tchkNum},
00127 &Gfx::opSetCharSpacing},
00128 {"Td", 2, {tchkNum, tchkNum},
00129 &Gfx::opTextMove},
00130 {"Tf", 2, {tchkName, tchkNum},
00131 &Gfx::opSetFont},
00132 {"Tj", 1, {tchkString},
00133 &Gfx::opShowText},
00134 {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
00135 tchkNum, tchkNum},
00136 &Gfx::opSetTextMatrix},
00137 {"Tr", 1, {tchkInt},
00138 &Gfx::opSetTextRender},
00139 {"Ts", 1, {tchkNum},
00140 &Gfx::opSetTextRise},
00141 {"Tw", 1, {tchkNum},
00142 &Gfx::opSetWordSpacing},
00143 {"Tz", 1, {tchkNum},
00144 &Gfx::opSetHorizScaling},
00145 {"W", 0, {tchkNone},
00146 &Gfx::opClip},
00147 {"W*", 0, {tchkNone},
00148 &Gfx::opEOClip},
00149 {"b", 0, {tchkNone},
00150 &Gfx::opCloseFillStroke},
00151 {"b*", 0, {tchkNone},
00152 &Gfx::opCloseEOFillStroke},
00153 {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
00154 tchkNum, tchkNum},
00155 &Gfx::opCurveTo},
00156 {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
00157 tchkNum, tchkNum},
00158 &Gfx::opConcat},
00159 {"cs", 1, {tchkName},
00160 &Gfx::opSetFillColorSpace},
00161 {"d", 2, {tchkArray, tchkNum},
00162 &Gfx::opSetDash},
00163 {"d0", 2, {tchkNum, tchkNum},
00164 &Gfx::opSetCharWidth},
00165 {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
00166 tchkNum, tchkNum},
00167 &Gfx::opSetCacheDevice},
00168 {"f", 0, {tchkNone},
00169 &Gfx::opFill},
00170 {"f*", 0, {tchkNone},
00171 &Gfx::opEOFill},
00172 {"g", 1, {tchkNum},
00173 &Gfx::opSetFillGray},
00174 {"gs", 1, {tchkName},
00175 &Gfx::opSetExtGState},
00176 {"h", 0, {tchkNone},
00177 &Gfx::opClosePath},
00178 {"i", 1, {tchkNum},
00179 &Gfx::opSetFlat},
00180 {"j", 1, {tchkInt},
00181 &Gfx::opSetLineJoin},
00182 {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
00183 &Gfx::opSetFillCMYKColor},
00184 {"l", 2, {tchkNum, tchkNum},
00185 &Gfx::opLineTo},
00186 {"m", 2, {tchkNum, tchkNum},
00187 &Gfx::opMoveTo},
00188 {"n", 0, {tchkNone},
00189 &Gfx::opEndPath},
00190 {"q", 0, {tchkNone},
00191 &Gfx::opSave},
00192 {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
00193 &Gfx::opRectangle},
00194 {"rg", 3, {tchkNum, tchkNum, tchkNum},
00195 &Gfx::opSetFillRGBColor},
00196 {"ri", 1, {tchkName},
00197 &Gfx::opSetRenderingIntent},
00198 {"s", 0, {tchkNone},
00199 &Gfx::opCloseStroke},
00200 {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
00201 &Gfx::opSetFillColor},
00202 {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
00203 tchkSCN},
00204 &Gfx::opSetFillColorN},
00205 {"sh", 1, {tchkName},
00206 &Gfx::opShFill},
00207 {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
00208 &Gfx::opCurveTo1},
00209 {"w", 1, {tchkNum},
00210 &Gfx::opSetLineWidth},
00211 {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
00212 &Gfx::opCurveTo2},
00213 };
00214
00215 #define numOps (sizeof(opTab) / sizeof(Operator))
00216
00217
00218
00219
00220
00221 GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
00222 Object obj1;
00223
00224 if (resDict) {
00225
00226
00227 fonts = NULL;
00228 resDict->lookup("Font", &obj1);
00229 if (obj1.isDict()) {
00230 fonts = new GfxFontDict(xref, obj1.getDict());
00231 }
00232 obj1.free();
00233
00234
00235 resDict->lookup("XObject", &xObjDict);
00236
00237
00238 resDict->lookup("ColorSpace", &colorSpaceDict);
00239
00240
00241 resDict->lookup("Pattern", &patternDict);
00242
00243
00244 resDict->lookup("Shading", &shadingDict);
00245
00246
00247 resDict->lookup("ExtGState", &gStateDict);
00248
00249 } else {
00250 fonts = NULL;
00251 xObjDict.initNull();
00252 colorSpaceDict.initNull();
00253 patternDict.initNull();
00254 gStateDict.initNull();
00255 }
00256
00257 next = nextA;
00258 }
00259
00260 GfxResources::~GfxResources() {
00261 if (fonts) {
00262 delete fonts;
00263 }
00264 xObjDict.free();
00265 colorSpaceDict.free();
00266 patternDict.free();
00267 shadingDict.free();
00268 gStateDict.free();
00269 }
00270
00271 GfxFont *GfxResources::lookupFont(char *name) {
00272 GfxFont *font;
00273 GfxResources *resPtr;
00274
00275 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00276 if (resPtr->fonts) {
00277 if ((font = resPtr->fonts->lookup(name)))
00278 return font;
00279 }
00280 }
00281 error(-1, "Unknown font tag '%s'", name);
00282 return NULL;
00283 }
00284
00285 GBool GfxResources::lookupXObject(char *name, Object *obj) {
00286 GfxResources *resPtr;
00287
00288 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00289 if (resPtr->xObjDict.isDict()) {
00290 if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
00291 return gTrue;
00292 obj->free();
00293 }
00294 }
00295 error(-1, "XObject '%s' is unknown", name);
00296 return gFalse;
00297 }
00298
00299 GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
00300 GfxResources *resPtr;
00301
00302 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00303 if (resPtr->xObjDict.isDict()) {
00304 if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
00305 return gTrue;
00306 obj->free();
00307 }
00308 }
00309 error(-1, "XObject '%s' is unknown", name);
00310 return gFalse;
00311 }
00312
00313 void GfxResources::lookupColorSpace(char *name, Object *obj) {
00314 GfxResources *resPtr;
00315
00316 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00317 if (resPtr->colorSpaceDict.isDict()) {
00318 if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
00319 return;
00320 }
00321 obj->free();
00322 }
00323 }
00324 obj->initNull();
00325 }
00326
00327 GfxPattern *GfxResources::lookupPattern(char *name) {
00328 GfxResources *resPtr;
00329 GfxPattern *pattern;
00330 Object obj;
00331
00332 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00333 if (resPtr->patternDict.isDict()) {
00334 if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
00335 pattern = GfxPattern::parse(&obj);
00336 obj.free();
00337 return pattern;
00338 }
00339 obj.free();
00340 }
00341 }
00342 error(-1, "Unknown pattern '%s'", name);
00343 return NULL;
00344 }
00345
00346 GfxShading *GfxResources::lookupShading(char *name) {
00347 GfxResources *resPtr;
00348 GfxShading *shading;
00349 Object obj;
00350
00351 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00352 if (resPtr->shadingDict.isDict()) {
00353 if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
00354 shading = GfxShading::parse(&obj);
00355 obj.free();
00356 return shading;
00357 }
00358 obj.free();
00359 }
00360 }
00361 error(-1, "Unknown shading '%s'", name);
00362 return NULL;
00363 }
00364
00365 GBool GfxResources::lookupGState(char *name, Object *obj) {
00366 GfxResources *resPtr;
00367
00368 for (resPtr = this; resPtr; resPtr = resPtr->next) {
00369 if (resPtr->gStateDict.isDict()) {
00370 if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) {
00371 return gTrue;
00372 }
00373 obj->free();
00374 }
00375 }
00376 error(-1, "ExtGState '%s' is unknown", name);
00377 return gFalse;
00378 }
00379
00380
00381
00382
00383
00384 Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
00385 PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
00386 GBool (*abortCheckCbkA)(void *data),
00387 void *abortCheckCbkDataA) {
00388 int i;
00389
00390 xref = xrefA;
00391 subPage = gFalse;
00392 printCommands = globalParams->getPrintCommands();
00393
00394
00395 res = new GfxResources(xref, resDict, NULL);
00396
00397
00398 out = outA;
00399 state = new GfxState(dpi, box, rotate, out->upsideDown());
00400 fontChanged = gFalse;
00401 clip = clipNone;
00402 ignoreUndef = 0;
00403 out->startPage(pageNum, state);
00404 out->setDefaultCTM(state->getCTM());
00405 out->updateAll(state);
00406 for (i = 0; i < 6; ++i) {
00407 baseMatrix[i] = state->getCTM()[i];
00408 }
00409 abortCheckCbk = abortCheckCbkA;
00410 abortCheckCbkData = abortCheckCbkDataA;
00411
00412
00413 if (crop) {
00414 state->moveTo(cropBox->x1, cropBox->y1);
00415 state->lineTo(cropBox->x2, cropBox->y1);
00416 state->lineTo(cropBox->x2, cropBox->y2);
00417 state->lineTo(cropBox->x1, cropBox->y2);
00418 state->closePath();
00419 state->clip();
00420 out->clip(state);
00421 state->clearPath();
00422 }
00423 }
00424
00425 Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
00426 PDFRectangle *box, GBool crop, PDFRectangle *cropBox,
00427 GBool (*abortCheckCbkA)(void *data),
00428 void *abortCheckCbkDataA) {
00429 int i;
00430
00431 xref = xrefA;
00432 subPage = gTrue;
00433 printCommands = globalParams->getPrintCommands();
00434
00435
00436 res = new GfxResources(xref, resDict, NULL);
00437
00438
00439 out = outA;
00440 state = new GfxState(72, box, 0, gFalse);
00441 fontChanged = gFalse;
00442 clip = clipNone;
00443 ignoreUndef = 0;
00444 for (i = 0; i < 6; ++i) {
00445 baseMatrix[i] = state->getCTM()[i];
00446 }
00447 abortCheckCbk = abortCheckCbkA;
00448 abortCheckCbkData = abortCheckCbkDataA;
00449
00450
00451 if (crop) {
00452 state->moveTo(cropBox->x1, cropBox->y1);
00453 state->lineTo(cropBox->x2, cropBox->y1);
00454 state->lineTo(cropBox->x2, cropBox->y2);
00455 state->lineTo(cropBox->x1, cropBox->y2);
00456 state->closePath();
00457 state->clip();
00458 out->clip(state);
00459 state->clearPath();
00460 }
00461 }
00462
00463 Gfx::~Gfx() {
00464 while (state->hasSaves()) {
00465 state = state->restore();
00466 out->restoreState(state);
00467 }
00468 if (!subPage) {
00469 out->endPage();
00470 }
00471 while (res) {
00472 popResources();
00473 }
00474 if (state) {
00475 delete state;
00476 }
00477 }
00478
00479 void Gfx::display(Object *obj, GBool topLevel) {
00480 Object obj2;
00481 int i;
00482
00483 if (obj->isArray()) {
00484 for (i = 0; i < obj->arrayGetLength(); ++i) {
00485 obj->arrayGet(i, &obj2);
00486 if (!obj2.isStream()) {
00487 error(-1, "Weird page contents");
00488 obj2.free();
00489 return;
00490 }
00491 obj2.free();
00492 }
00493 } else if (!obj->isStream()) {
00494 error(-1, "Weird page contents");
00495 return;
00496 }
00497 parser = new Parser(xref, new Lexer(xref, obj));
00498 go(topLevel);
00499 delete parser;
00500 parser = NULL;
00501 }
00502
00503 void Gfx::go(GBool topLevel) {
00504 Object obj;
00505 Object args[maxArgs];
00506 int numArgs, i;
00507 int lastAbortCheck;
00508
00509
00510 updateLevel = lastAbortCheck = 0;
00511 numArgs = 0;
00512 parser->getObj(&obj);
00513 while (!obj.isEOF()) {
00514
00515
00516 if (obj.isCmd()) {
00517 if (printCommands) {
00518 obj.print(stdout);
00519 for (i = 0; i < numArgs; ++i) {
00520 printf(" ");
00521 args[i].print(stdout);
00522 }
00523 printf("\n");
00524 fflush(stdout);
00525 }
00526 execOp(&obj, args, numArgs);
00527 obj.free();
00528 for (i = 0; i < numArgs; ++i)
00529 args[i].free();
00530 numArgs = 0;
00531
00532
00533 if (++updateLevel >= 20000) {
00534 out->dump();
00535 updateLevel = 0;
00536 }
00537
00538
00539 if (abortCheckCbk) {
00540 if (updateLevel - lastAbortCheck > 10) {
00541 if ((*abortCheckCbk)(abortCheckCbkData)) {
00542 break;
00543 }
00544 lastAbortCheck = updateLevel;
00545 }
00546 }
00547
00548
00549 } else if (numArgs < maxArgs) {
00550 args[numArgs++] = obj;
00551
00552
00553 } else {
00554 error(getPos(), "Too many args in content stream");
00555 if (printCommands) {
00556 printf("throwing away arg: ");
00557 obj.print(stdout);
00558 printf("\n");
00559 fflush(stdout);
00560 }
00561 obj.free();
00562 }
00563
00564
00565 parser->getObj(&obj);
00566 }
00567 obj.free();
00568
00569
00570 if (numArgs > 0) {
00571 error(getPos(), "Leftover args in content stream");
00572 if (printCommands) {
00573 printf("%d leftovers:", numArgs);
00574 for (i = 0; i < numArgs; ++i) {
00575 printf(" ");
00576 args[i].print(stdout);
00577 }
00578 printf("\n");
00579 fflush(stdout);
00580 }
00581 for (i = 0; i < numArgs; ++i)
00582 args[i].free();
00583 }
00584
00585
00586 if (topLevel && updateLevel > 0) {
00587 out->dump();
00588 }
00589 }
00590
00591 void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
00592 Operator *op;
00593 const char *name;
00594 int i;
00595
00596
00597 name = cmd->getCmd();
00598 if (!(op = findOp(name))) {
00599 if (ignoreUndef == 0)
00600 error(getPos(), "Unknown operator '%s'", name);
00601 return;
00602 }
00603
00604
00605 if (op->numArgs >= 0) {
00606 if (numArgs != op->numArgs) {
00607 error(getPos(), "Wrong number (%d) of args to '%s' operator",
00608 numArgs, name);
00609 return;
00610 }
00611 } else {
00612 if (numArgs > -op->numArgs) {
00613 error(getPos(), "Too many (%d) args to '%s' operator",
00614 numArgs, name);
00615 return;
00616 }
00617 }
00618 for (i = 0; i < numArgs; ++i) {
00619 if (!checkArg(&args[i], op->tchk[i])) {
00620 error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
00621 i, name, args[i].getTypeName());
00622 return;
00623 }
00624 }
00625
00626
00627 (this->*op->func)(args, numArgs);
00628 }
00629
00630 Operator *Gfx::findOp(const char *name) {
00631 int a, b, m, cmp;
00632
00633 a = -1;
00634 b = numOps;
00635
00636 while (b - a > 1) {
00637 m = (a + b) / 2;
00638 cmp = strcmp(opTab[m].name, name);
00639 if (cmp < 0)
00640 a = m;
00641 else if (cmp > 0)
00642 b = m;
00643 else
00644 a = b = m;
00645 }
00646 if (cmp != 0)
00647 return NULL;
00648 return &opTab[a];
00649 }
00650
00651 GBool Gfx::checkArg(Object *arg, TchkType type) {
00652 switch (type) {
00653 case tchkBool: return arg->isBool();
00654 case tchkInt: return arg->isInt();
00655 case tchkNum: return arg->isNum();
00656 case tchkString: return arg->isString();
00657 case tchkName: return arg->isName();
00658 case tchkArray: return arg->isArray();
00659 case tchkProps: return arg->isDict() || arg->isName();
00660 case tchkSCN: return arg->isNum() || arg->isName();
00661 case tchkNone: return gFalse;
00662 }
00663 return gFalse;
00664 }
00665
00666 int Gfx::getPos() {
00667 return parser ? parser->getPos() : -1;
00668 }
00669
00670
00671
00672
00673
00674 void Gfx::opSave(Object [], int ) {
00675 out->saveState(state);
00676 state = state->save();
00677 }
00678
00679 void Gfx::opRestore(Object [], int ) {
00680 state = state->restore();
00681 out->restoreState(state);
00682 }
00683
00684 void Gfx::opConcat(Object args[], int ) {
00685 state->concatCTM(args[0].getNum(), args[1].getNum(),
00686 args[2].getNum(), args[3].getNum(),
00687 args[4].getNum(), args[5].getNum());
00688 out->updateCTM(state, args[0].getNum(), args[1].getNum(),
00689 args[2].getNum(), args[3].getNum(),
00690 args[4].getNum(), args[5].getNum());
00691 fontChanged = gTrue;
00692 }
00693
00694 void Gfx::opSetDash(Object args[], int ) {
00695 Array *a;
00696 int length;
00697 Object obj;
00698 double *dash;
00699 int i;
00700
00701 a = args[0].getArray();
00702 length = a->getLength();
00703 if (length == 0) {
00704 dash = NULL;
00705 } else {
00706 dash = (double *)gmalloc(length * sizeof(double));
00707 for (i = 0; i < length; ++i) {
00708 dash[i] = a->get(i, &obj)->getNum();
00709 obj.free();
00710 }
00711 }
00712 state->setLineDash(dash, length, args[1].getNum());
00713 out->updateLineDash(state);
00714 }
00715
00716 void Gfx::opSetFlat(Object args[], int ) {
00717 state->setFlatness((int)args[0].getNum());
00718 out->updateFlatness(state);
00719 }
00720
00721 void Gfx::opSetLineJoin(Object args[], int ) {
00722 state->setLineJoin(args[0].getInt());
00723 out->updateLineJoin(state);
00724 }
00725
00726 void Gfx::opSetLineCap(Object args[], int ) {
00727 state->setLineCap(args[0].getInt());
00728 out->updateLineCap(state);
00729 }
00730
00731 void Gfx::opSetMiterLimit(Object args[], int ) {
00732 state->setMiterLimit(args[0].getNum());
00733 out->updateMiterLimit(state);
00734 }
00735
00736 void Gfx::opSetLineWidth(Object args[], int ) {
00737 state->setLineWidth(args[0].getNum());
00738 out->updateLineWidth(state);
00739 }
00740
00741 void Gfx::opSetExtGState(Object args[], int ) {
00742 Object obj1, obj2;
00743
00744 if (!res->lookupGState(args[0].getName(), &obj1)) {
00745 return;
00746 }
00747 if (!obj1.isDict()) {
00748 error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
00749 obj1.free();
00750 return;
00751 }
00752 if (obj1.dictLookup("ca", &obj2)->isNum()) {
00753 state->setFillOpacity(obj2.getNum());
00754 out->updateFillOpacity(state);
00755 }
00756 obj2.free();
00757 if (obj1.dictLookup("CA", &obj2)->isNum()) {
00758 state->setStrokeOpacity(obj2.getNum());
00759 out->updateStrokeOpacity(state);
00760 }
00761 obj2.free();
00762 obj1.free();
00763 }
00764
00765 void Gfx::opSetRenderingIntent(Object [], int ) {
00766 }
00767
00768
00769
00770
00771
00772 void Gfx::opSetFillGray(Object args[], int ) {
00773 GfxColor color;
00774
00775 state->setFillPattern(NULL);
00776 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
00777 color.c[0] = args[0].getNum();
00778 state->setFillColor(&color);
00779 out->updateFillColor(state);
00780 }
00781
00782 void Gfx::opSetStrokeGray(Object args[], int ) {
00783 GfxColor color;
00784
00785 state->setStrokePattern(NULL);
00786 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
00787 color.c[0] = args[0].getNum();
00788 state->setStrokeColor(&color);
00789 out->updateStrokeColor(state);
00790 }
00791
00792 void Gfx::opSetFillCMYKColor(Object args[], int ) {
00793 GfxColor color;
00794 int i;
00795
00796 state->setFillPattern(NULL);
00797 state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
00798 for (i = 0; i < 4; ++i) {
00799 color.c[i] = args[i].getNum();
00800 }
00801 state->setFillColor(&color);
00802 out->updateFillColor(state);
00803 }
00804
00805 void Gfx::opSetStrokeCMYKColor(Object args[], int ) {
00806 GfxColor color;
00807 int i;
00808
00809 state->setStrokePattern(NULL);
00810 state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
00811 for (i = 0; i < 4; ++i) {
00812 color.c[i] = args[i].getNum();
00813 }
00814 state->setStrokeColor(&color);
00815 out->updateStrokeColor(state);
00816 }
00817
00818 void Gfx::opSetFillRGBColor(Object args[], int ) {
00819 GfxColor color;
00820 int i;
00821
00822 state->setFillPattern(NULL);
00823 state->setFillColorSpace(new GfxDeviceRGBColorSpace());
00824 for (i = 0; i < 3; ++i) {
00825 color.c[i] = args[i].getNum();
00826 }
00827 state->setFillColor(&color);
00828 out->updateFillColor(state);
00829 }
00830
00831 void Gfx::opSetStrokeRGBColor(Object args[], int ) {
00832 GfxColor color;
00833 int i;
00834
00835 state->setStrokePattern(NULL);
00836 state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
00837 for (i = 0; i < 3; ++i) {
00838 color.c[i] = args[i].getNum();
00839 }
00840 state->setStrokeColor(&color);
00841 out->updateStrokeColor(state);
00842 }
00843
00844 void Gfx::opSetFillColorSpace(Object args[], int ) {
00845 Object obj;
00846 GfxColorSpace *colorSpace;
00847 GfxColor color;
00848 int i;
00849
00850 state->setFillPattern(NULL);
00851 res->lookupColorSpace(args[0].getName(), &obj);
00852 if (obj.isNull()) {
00853 colorSpace = GfxColorSpace::parse(&args[0]);
00854 } else {
00855 colorSpace = GfxColorSpace::parse(&obj);
00856 }
00857 obj.free();
00858 if (colorSpace) {
00859 state->setFillColorSpace(colorSpace);
00860 } else {
00861 error(getPos(), "Bad color space (fill)");
00862 }
00863 for (i = 0; i < gfxColorMaxComps; ++i) {
00864 color.c[i] = 0;
00865 }
00866 state->setFillColor(&color);
00867 out->updateFillColor(state);
00868 }
00869
00870 void Gfx::opSetStrokeColorSpace(Object args[], int ) {
00871 Object obj;
00872 GfxColorSpace *colorSpace;
00873 GfxColor color;
00874 int i;
00875
00876 state->setStrokePattern(NULL);
00877 res->lookupColorSpace(args[0].getName(), &obj);
00878 if (obj.isNull()) {
00879 colorSpace = GfxColorSpace::parse(&args[0]);
00880 } else {
00881 colorSpace = GfxColorSpace::parse(&obj);
00882 }
00883 obj.free();
00884 if (colorSpace) {
00885 state->setStrokeColorSpace(colorSpace);
00886 } else {
00887 error(getPos(), "Bad color space (stroke)");
00888 }
00889 for (i = 0; i < gfxColorMaxComps; ++i) {
00890 color.c[i] = 0;
00891 }
00892 state->setStrokeColor(&color);
00893 out->updateStrokeColor(state);
00894 }
00895
00896 void Gfx::opSetFillColor(Object args[], int numArgs) {
00897 GfxColor color;
00898 int i;
00899
00900 state->setFillPattern(NULL);
00901 for (i = 0; i < numArgs; ++i) {
00902 color.c[i] = args[i].getNum();
00903 }
00904 state->setFillColor(&color);
00905 out->updateFillColor(state);
00906 }
00907
00908 void Gfx::opSetStrokeColor(Object args[], int numArgs) {
00909 GfxColor color;
00910 int i;
00911
00912 state->setStrokePattern(NULL);
00913 for (i = 0; i < numArgs; ++i) {
00914 color.c[i] = args[i].getNum();
00915 }
00916 state->setStrokeColor(&color);
00917 out->updateStrokeColor(state);
00918 }
00919
00920 void Gfx::opSetFillColorN(Object args[], int numArgs) {
00921 GfxColor color;
00922 GfxPattern *pattern;
00923 int i;
00924
00925 if (state->getFillColorSpace()->getMode() == csPattern) {
00926 if (numArgs > 1) {
00927 for (i = 0; i < numArgs && i < 4; ++i) {
00928 if (args[i].isNum()) {
00929 color.c[i] = args[i].getNum();
00930 }
00931 }
00932 state->setFillColor(&color);
00933 out->updateFillColor(state);
00934 }
00935 if (args[numArgs-1].isName() &&
00936 (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
00937 state->setFillPattern(pattern);
00938 }
00939
00940 } else {
00941 state->setFillPattern(NULL);
00942 for (i = 0; i < numArgs && i < 4; ++i) {
00943 if (args[i].isNum()) {
00944 color.c[i] = args[i].getNum();
00945 }
00946 }
00947 state->setFillColor(&color);
00948 out->updateFillColor(state);
00949 }
00950 }
00951
00952 void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
00953 GfxColor color;
00954 GfxPattern *pattern;
00955 int i;
00956
00957 if (state->getStrokeColorSpace()->getMode() == csPattern) {
00958 if (numArgs > 1) {
00959 for (i = 0; i < numArgs && i < 4; ++i) {
00960 if (args[i].isNum()) {
00961 color.c[i] = args[i].getNum();
00962 }
00963 }
00964 state->setStrokeColor(&color);
00965 out->updateStrokeColor(state);
00966 }
00967 if (args[numArgs-1].isName() &&
00968 (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
00969 state->setStrokePattern(pattern);
00970 }
00971
00972 } else {
00973 state->setStrokePattern(NULL);
00974 for (i = 0; i < numArgs && i < 4; ++i) {
00975 if (args[i].isNum()) {
00976 color.c[i] = args[i].getNum();
00977 }
00978 }
00979 state->setStrokeColor(&color);
00980 out->updateStrokeColor(state);
00981 }
00982 }
00983
00984
00985
00986
00987
00988 void Gfx::opMoveTo(Object args[], int ) {
00989 state->moveTo(args[0].getNum(), args[1].getNum());
00990 }
00991
00992 void Gfx::opLineTo(Object args[], int ) {
00993 if (!state->isCurPt()) {
00994 error(getPos(), "No current point in lineto");
00995 return;
00996 }
00997 state->lineTo(args[0].getNum(), args[1].getNum());
00998 }
00999
01000 void Gfx::opCurveTo(Object args[], int ) {
01001 double x1, y1, x2, y2, x3, y3;
01002
01003 if (!state->isCurPt()) {
01004 error(getPos(), "No current point in curveto");
01005 return;
01006 }
01007 x1 = args[0].getNum();
01008 y1 = args[1].getNum();
01009 x2 = args[2].getNum();
01010 y2 = args[3].getNum();
01011 x3 = args[4].getNum();
01012 y3 = args[5].getNum();
01013 state->curveTo(x1, y1, x2, y2, x3, y3);
01014 }
01015
01016 void Gfx::opCurveTo1(Object args[], int ) {
01017 double x1, y1, x2, y2, x3, y3;
01018
01019 if (!state->isCurPt()) {
01020 error(getPos(), "No current point in curveto1");
01021 return;
01022 }
01023 x1 = state->getCurX();
01024 y1 = state->getCurY();
01025 x2 = args[0].getNum();
01026 y2 = args[1].getNum();
01027 x3 = args[2].getNum();
01028 y3 = args[3].getNum();
01029 state->curveTo(x1, y1, x2, y2, x3, y3);
01030 }
01031
01032 void Gfx::opCurveTo2(Object args[], int ) {
01033 double x1, y1, x2, y2, x3, y3;
01034
01035 if (!state->isCurPt()) {
01036 error(getPos(), "No current point in curveto2");
01037 return;
01038 }
01039 x1 = args[0].getNum();
01040 y1 = args[1].getNum();
01041 x2 = args[2].getNum();
01042 y2 = args[3].getNum();
01043 x3 = x2;
01044 y3 = y2;
01045 state->curveTo(x1, y1, x2, y2, x3, y3);
01046 }
01047
01048 void Gfx::opRectangle(Object args[], int ) {
01049 double x, y, w, h;
01050
01051 x = args[0].getNum();
01052 y = args[1].getNum();
01053 w = args[2].getNum();
01054 h = args[3].getNum();
01055 state->moveTo(x, y);
01056 state->lineTo(x + w, y);
01057 state->lineTo(x + w, y + h);
01058 state->lineTo(x, y + h);
01059 state->closePath();
01060 }
01061
01062 void Gfx::opClosePath(Object [], int ) {
01063 if (!state->isCurPt()) {
01064 error(getPos(), "No current point in closepath");
01065 return;
01066 }
01067 state->closePath();
01068 }
01069
01070
01071
01072
01073
01074 void Gfx::opEndPath(Object [], int ) {
01075 doEndPath();
01076 }
01077
01078 void Gfx::opStroke(Object [], int ) {
01079 if (!state->isCurPt()) {
01080
01081 return;
01082 }
01083 if (state->isPath())
01084 out->stroke(state);
01085 doEndPath();
01086 }
01087
01088 void Gfx::opCloseStroke(Object [], int ) {
01089 if (!state->isCurPt()) {
01090
01091 return;
01092 }
01093 if (state->isPath()) {
01094 state->closePath();
01095 out->stroke(state);
01096 }
01097 doEndPath();
01098 }
01099
01100 void Gfx::opFill(Object [], int ) {
01101 if (!state->isCurPt()) {
01102
01103 return;
01104 }
01105 if (state->isPath()) {
01106 if (state->getFillColorSpace()->getMode() == csPattern) {
01107 doPatternFill(gFalse);
01108 } else {
01109 out->fill(state);
01110 }
01111 }
01112 doEndPath();
01113 }
01114
01115 void Gfx::opEOFill(Object [], int ) {
01116 if (!state->isCurPt()) {
01117
01118 return;
01119 }
01120 if (state->isPath()) {
01121 if (state->getFillColorSpace()->getMode() == csPattern) {
01122 doPatternFill(gTrue);
01123 } else {
01124 out->eoFill(state);
01125 }
01126 }
01127 doEndPath();
01128 }
01129
01130 void Gfx::opFillStroke(Object [], int ) {
01131 if (!state->isCurPt()) {
01132
01133 return;
01134 }
01135 if (state->isPath()) {
01136 if (state->getFillColorSpace()->getMode() == csPattern) {
01137 doPatternFill(gFalse);
01138 } else {
01139 out->fill(state);
01140 }
01141 out->stroke(state);
01142 }
01143 doEndPath();
01144 }
01145
01146 void Gfx::opCloseFillStroke(Object [], int ) {
01147 if (!state->isCurPt()) {
01148
01149 return;
01150 }
01151 if (state->isPath()) {
01152 state->closePath();
01153 if (state->getFillColorSpace()->getMode() == csPattern) {
01154 doPatternFill(gFalse);
01155 } else {
01156 out->fill(state);
01157 }
01158 out->stroke(state);
01159 }
01160 doEndPath();
01161 }
01162
01163 void Gfx::opEOFillStroke(Object [], int ) {
01164 if (!state->isCurPt()) {
01165
01166 return;
01167 }
01168 if (state->isPath()) {
01169 if (state->getFillColorSpace()->getMode() == csPattern) {
01170 doPatternFill(gTrue);
01171 } else {
01172 out->eoFill(state);
01173 }
01174 out->stroke(state);
01175 }
01176 doEndPath();
01177 }
01178
01179 void Gfx::opCloseEOFillStroke(Object [], int ) {
01180 if (!state->isCurPt()) {
01181
01182 return;
01183 }
01184 if (state->isPath()) {
01185 state->closePath();
01186 if (state->getFillColorSpace()->getMode() == csPattern) {
01187 doPatternFill(gTrue);
01188 } else {
01189 out->eoFill(state);
01190 }
01191 out->stroke(state);
01192 }
01193 doEndPath();
01194 }
01195
01196 void Gfx::doPatternFill(GBool eoFill) {
01197 GfxPatternColorSpace *patCS;
01198 GfxPattern *pattern;
01199 GfxTilingPattern *tPat;
01200 const GfxColorSpace *cs;
01201 double xMin, yMin, xMax, yMax, x, y, x1, y1;
01202 double cxMin, cyMin, cxMax, cyMax;
01203 int xi0, yi0, xi1, yi1, xi, yi;
01204 const double *ctm;
01205 double *btm, *ptm;
01206 double m[6], ictm[6], m1[6], imb[6];
01207 double det;
01208 double xstep, ystep;
01209 int i;
01210
01211
01212
01213
01214 if (!out->needNonText()) {
01215 return;
01216 }
01217
01218
01219 patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
01220
01221
01222 if (!(pattern = state->getFillPattern())) {
01223 return;
01224 }
01225 if (pattern->getType() != 1) {
01226 return;
01227 }
01228 tPat = (GfxTilingPattern *)pattern;
01229
01230
01231 ctm = state->getCTM();
01232 btm = baseMatrix;
01233 ptm = tPat->getMatrix();
01234
01235 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
01236 ictm[0] = ctm[3] * det;
01237 ictm[1] = -ctm[1] * det;
01238 ictm[2] = -ctm[2] * det;
01239 ictm[3] = ctm[0] * det;
01240 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
01241 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
01242
01243 m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
01244 m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
01245 m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
01246 m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
01247 m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
01248 m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
01249
01250 m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
01251 m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
01252 m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
01253 m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
01254 m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
01255 m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
01256
01257
01258 det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
01259 imb[0] = m1[3] * det;
01260 imb[1] = -m1[1] * det;
01261 imb[2] = -m1[2] * det;
01262 imb[3] = m1[0] * det;
01263 imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
01264 imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
01265
01266
01267 out->saveState(state);
01268 state = state->save();
01269
01270
01271 if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
01272 state->setFillColorSpace(cs->copy());
01273 } else {
01274 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
01275 }
01276 state->setFillPattern(NULL);
01277 out->updateFillColor(state);
01278
01279
01280 state->clip();
01281 if (eoFill) {
01282 out->eoClip(state);
01283 } else {
01284 out->clip(state);
01285 }
01286 state->clearPath();
01287
01288
01289 state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
01290 xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
01291 yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
01292 x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
01293 y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
01294 if (x1 < xMin) {
01295 xMin = x1;
01296 } else if (x1 > xMax) {
01297 xMax = x1;
01298 }
01299 if (y1 < yMin) {
01300 yMin = y1;
01301 } else if (y1 > yMax) {
01302 yMax = y1;
01303 }
01304 x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
01305 y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
01306 if (x1 < xMin) {
01307 xMin = x1;
01308 } else if (x1 > xMax) {
01309 xMax = x1;
01310 }
01311 if (y1 < yMin) {
01312 yMin = y1;
01313 } else if (y1 > yMax) {
01314 yMax = y1;
01315 }
01316 x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
01317 y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
01318 if (x1 < xMin) {
01319 xMin = x1;
01320 } else if (x1 > xMax) {
01321 xMax = x1;
01322 }
01323 if (y1 < yMin) {
01324 yMin = y1;
01325 } else if (y1 > yMax) {
01326 yMax = y1;
01327 }
01328
01329
01330
01331
01332 xstep = fabs(tPat->getXStep());
01333 ystep = fabs(tPat->getYStep());
01334 xi0 = (int)floor(xMin / xstep);
01335 xi1 = (int)ceil(xMax / xstep);
01336 yi0 = (int)floor(yMin / ystep);
01337 yi1 = (int)ceil(yMax / ystep);
01338 for (i = 0; i < 4; ++i) {
01339 m1[i] = m[i];
01340 }
01341 for (yi = yi0; yi < yi1; ++yi) {
01342 for (xi = xi0; xi < xi1; ++xi) {
01343 x = xi * xstep;
01344 y = yi * ystep;
01345 m1[4] = x * m[0] + y * m[2] + m[4];
01346 m1[5] = x * m[1] + y * m[3] + m[5];
01347 doForm1(tPat->getContentStream(), tPat->getResDict(),
01348 m1, tPat->getBBox());
01349 }
01350 }
01351
01352
01353 state = state->restore();
01354 out->restoreState(state);
01355 }
01356
01357 void Gfx::opShFill(Object args[], int ) {
01358 GfxShading *shading;
01359 double xMin, yMin, xMax, yMax;
01360
01361 if (!(shading = res->lookupShading(args[0].getName()))) {
01362 return;
01363 }
01364
01365
01366 out->saveState(state);
01367 state = state->save();
01368
01369
01370 if (shading->getHasBBox()) {
01371 shading->getBBox(&xMin, &yMin, &xMax, &yMax);
01372 state->moveTo(xMin, yMin);
01373 state->lineTo(xMax, yMin);
01374 state->lineTo(xMax, yMax);
01375 state->lineTo(xMin, yMax);
01376 state->closePath();
01377 state->clip();
01378 out->clip(state);
01379 state->clearPath();
01380 }
01381
01382
01383 state->setFillColorSpace(shading->getColorSpace()->copy());
01384
01385
01386 switch (shading->getType()) {
01387 case 2:
01388 doAxialShFill((GfxAxialShading *)shading);
01389 break;
01390 case 3:
01391 doRadialShFill((GfxRadialShading *)shading);
01392 break;
01393 }
01394
01395
01396 state = state->restore();
01397 out->restoreState(state);
01398
01399 delete shading;
01400 }
01401
01402 void Gfx::doAxialShFill(GfxAxialShading *shading) {
01403 double xMin, yMin, xMax, yMax;
01404 double x0, y0, x1, y1;
01405 double dx, dy, mul;
01406 double tMin, tMax, t, tx, ty;
01407 double s[4], sMin, sMax, tmp;
01408 double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
01409 double t0, t1, tt;
01410 double ta[axialMaxSplits + 1];
01411 int next[axialMaxSplits + 1];
01412 GfxColor color0, color1;
01413 int nComps;
01414 int i, j, k, kk;
01415
01416
01417 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
01418
01419
01420
01421 shading->getCoords(&x0, &y0, &x1, &y1);
01422 dx = x1 - x0;
01423 dy = y1 - y0;
01424 mul = 1 / (dx * dx + dy * dy);
01425 tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
01426 t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
01427 if (t < tMin) {
01428 tMin = t;
01429 } else if (t > tMax) {
01430 tMax = t;
01431 }
01432 t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
01433 if (t < tMin) {
01434 tMin = t;
01435 } else if (t > tMax) {
01436 tMax = t;
01437 }
01438 t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
01439 if (t < tMin) {
01440 tMin = t;
01441 } else if (t > tMax) {
01442 tMax = t;
01443 }
01444 if (tMin < 0 && !shading->getExtend0()) {
01445 tMin = 0;
01446 }
01447 if (tMax > 1 && !shading->getExtend1()) {
01448 tMax = 1;
01449 }
01450
01451
01452 t0 = shading->getDomain0();
01453 t1 = shading->getDomain1();
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 nComps = shading->getColorSpace()->getNComps();
01486 ta[0] = tMin;
01487 ta[axialMaxSplits] = tMax;
01488 next[0] = axialMaxSplits;
01489
01490
01491 if (tMin < 0) {
01492 tt = t0;
01493 } else if (tMin > 1) {
01494 tt = t1;
01495 } else {
01496 tt = t0 + (t1 - t0) * tMin;
01497 }
01498 shading->getColor(tt, &color0);
01499
01500
01501
01502
01503 tx = x0 + tMin * dx;
01504 ty = y0 + tMin * dy;
01505 if (dx == 0 && dy == 0) {
01506 sMin = sMax = 0;
01507 } if (dx == 0) {
01508 sMin = (xMin - tx) / -dy;
01509 sMax = (xMax - tx) / -dy;
01510 if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
01511 } else if (dy == 0) {
01512 sMin = (yMin - ty) / dx;
01513 sMax = (yMax - ty) / dx;
01514 if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
01515 } else {
01516 s[0] = (yMin - ty) / dx;
01517 s[1] = (yMax - ty) / dx;
01518 s[2] = (xMin - tx) / -dy;
01519 s[3] = (xMax - tx) / -dy;
01520 for (j = 0; j < 3; ++j) {
01521 kk = j;
01522 for (k = j + 1; k < 4; ++k) {
01523 if (s[k] < s[kk]) {
01524 kk = k;
01525 }
01526 }
01527 tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
01528 }
01529 sMin = s[1];
01530 sMax = s[2];
01531 }
01532 ux0 = tx - sMin * dy;
01533 uy0 = ty + sMin * dx;
01534 vx0 = tx - sMax * dy;
01535 vy0 = ty + sMax * dx;
01536
01537 i = 0;
01538 while (i < axialMaxSplits) {
01539
01540
01541
01542 j = next[i];
01543 while (j > i + 1) {
01544 if (ta[j] < 0) {
01545 tt = t0;
01546 } else if (ta[j] > 1) {
01547 tt = t1;
01548 } else {
01549 tt = t0 + (t1 - t0) * ta[j];
01550 }
01551 shading->getColor(tt, &color1);
01552 for (k = 0; k < nComps; ++k) {
01553 if (fabs(color1.c[k] - color0.c[k]) > axialColorDelta) {
01554 break;
01555 }
01556 }
01557 if (k == nComps) {
01558 break;
01559 }
01560 k = (i + j) / 2;
01561 ta[k] = 0.5 * (ta[i] + ta[j]);
01562 next[i] = k;
01563 next[k] = j;
01564 j = k;
01565 }
01566
01567
01568 for (k = 0; k < nComps; ++k) {
01569 color0.c[k] = 0.5 * (color0.c[k] + color1.c[k]);
01570 }
01571
01572
01573
01574
01575 tx = x0 + ta[j] * dx;
01576 ty = y0 + ta[j] * dy;
01577 if (dx == 0 && dy == 0) {
01578 sMin = sMax = 0;
01579 } if (dx == 0) {
01580 sMin = (xMin - tx) / -dy;
01581 sMax = (xMax - tx) / -dy;
01582 if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
01583 } else if (dy == 0) {
01584 sMin = (yMin - ty) / dx;
01585 sMax = (yMax - ty) / dx;
01586 if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
01587 } else {
01588 s[0] = (yMin - ty) / dx;
01589 s[1] = (yMax - ty) / dx;
01590 s[2] = (xMin - tx) / -dy;
01591 s[3] = (xMax - tx) / -dy;
01592 for (j = 0; j < 3; ++j) {
01593 kk = j;
01594 for (k = j + 1; k < 4; ++k) {
01595 if (s[k] < s[kk]) {
01596 kk = k;
01597 }
01598 }
01599 tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
01600 }
01601 sMin = s[1];
01602 sMax = s[2];
01603 }
01604 ux1 = tx - sMin * dy;
01605 uy1 = ty + sMin * dx;
01606 vx1 = tx - sMax * dy;
01607 vy1 = ty + sMax * dx;
01608
01609
01610 state->setFillColor(&color0);
01611 out->updateFillColor(state);
01612
01613
01614 state->moveTo(ux0, uy0);
01615 state->lineTo(vx0, vy0);
01616 state->lineTo(vx1, vy1);
01617 state->lineTo(ux1, uy1);
01618 state->closePath();
01619 out->fill(state);
01620 state->clearPath();
01621
01622
01623 ux0 = ux1;
01624 uy0 = uy1;
01625 vx0 = vx1;
01626 vy0 = vy1;
01627 color0 = color1;
01628 i = next[i];
01629 }
01630 }
01631
01632 void Gfx::doRadialShFill(GfxRadialShading *shading) {
01633 double sMin, sMax, xMin, yMin, xMax, yMax;
01634 double x0, y0, r0, x1, y1, r1, t0, t1;
01635 int nComps;
01636 GfxColor colorA, colorB;
01637 double xa, ya, xb, yb, ra, rb;
01638 double ta, tb, sa, sb;
01639 int ia, ib, k, n;
01640 const double *ctm;
01641 double angle, t;
01642
01643
01644 shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
01645 t0 = shading->getDomain0();
01646 t1 = shading->getDomain1();
01647 nComps = shading->getColorSpace()->getNComps();
01648
01649
01650 sMin = 0;
01651 sMax = 1;
01652 if (shading->getExtend0()) {
01653 if (r0 < r1) {
01654
01655 sMin = -r0 / (r1 - r0);
01656 } else {
01657
01658
01659
01660
01661
01662 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
01663 sMin = (sqrt((xMax - xMin) * (xMax - xMin) +
01664 (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
01665 if (sMin > 0) {
01666 sMin = 0;
01667 } else if (sMin < -20) {
01668
01669 sMin = -20;
01670 }
01671 }
01672 }
01673 if (shading->getExtend1()) {
01674 if (r1 < r0) {
01675
01676 sMax = -r0 / (r1 - r0);
01677 } else if (r1 > r0) {
01678
01679 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
01680 sMax = (sqrt((xMax - xMin) * (xMax - xMin) +
01681 (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
01682 if (sMax < 1) {
01683 sMin = 1;
01684 } else if (sMax > 20) {
01685
01686 sMax = 20;
01687 }
01688 }
01689 }
01690
01691
01692
01693
01694
01695 ctm = state->getCTM();
01696 t = fabs(ctm[0]);
01697 if (fabs(ctm[1]) > t) {
01698 t = fabs(ctm[1]);
01699 }
01700 if (fabs(ctm[2]) > t) {
01701 t = fabs(ctm[2]);
01702 }
01703 if (fabs(ctm[3]) > t) {
01704 t = fabs(ctm[3]);
01705 }
01706 if (r0 > r1) {
01707 t *= r0;
01708 } else {
01709 t *= r1;
01710 }
01711 if (t < 1) {
01712 n = 3;
01713 } else {
01714 n = (int)(M_PI / acos(1 - 0.1 / t));
01715 if (n < 3) {
01716 n = 3;
01717 } else if (n > 200) {
01718 n = 200;
01719 }
01720 }
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 ia = 0;
01735 sa = sMin;
01736 ta = t0 + sa * (t1 - t0);
01737 xa = x0 + sa * (x1 - x0);
01738 ya = y0 + sa * (y1 - y0);
01739 ra = r0 + sa * (r1 - r0);
01740 if (ta < t0) {
01741 shading->getColor(t0, &colorA);
01742 } else if (ta > t1) {
01743 shading->getColor(t1, &colorA);
01744 } else {
01745 shading->getColor(ta, &colorA);
01746 }
01747
01748 while (ia < radialMaxSplits) {
01749
01750
01751
01752
01753
01754 ib = radialMaxSplits;
01755 sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
01756 tb = t0 + sb * (t1 - t0);
01757 if (tb < t0) {
01758 shading->getColor(t0, &colorB);
01759 } else if (tb > t1) {
01760 shading->getColor(t1, &colorB);
01761 } else {
01762 shading->getColor(tb, &colorB);
01763 }
01764 while (ib - ia > 1) {
01765 for (k = 0; k < nComps; ++k) {
01766 if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
01767 break;
01768 }
01769 }
01770 if (k == nComps) {
01771 break;
01772 }
01773 ib = (ia + ib) / 2;
01774 sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
01775 tb = t0 + sb * (t1 - t0);
01776 if (tb < t0) {
01777 shading->getColor(t0, &colorB);
01778 } else if (tb > t1) {
01779 shading->getColor(t1, &colorB);
01780 } else {
01781 shading->getColor(tb, &colorB);
01782 }
01783 }
01784
01785
01786 xb = x0 + sb * (x1 - x0);
01787 yb = y0 + sb * (y1 - y0);
01788 rb = r0 + sb * (r1 - r0);
01789
01790
01791 for (k = 0; k < nComps; ++k) {
01792 colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]);
01793 }
01794 state->setFillColor(&colorA);
01795 out->updateFillColor(state);
01796
01797
01798 state->moveTo(xa + ra, ya);
01799 for (k = 1; k < n; ++k) {
01800 angle = ((double)k / (double)n) * 2 * M_PI;
01801 state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
01802 }
01803 state->closePath();
01804
01805
01806 state->moveTo(xb + rb, yb);
01807 for (k = 1; k < n; ++k) {
01808 angle = ((double)k / (double)n) * 2 * M_PI;
01809 state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
01810 }
01811 state->closePath();
01812
01813
01814 out->eoFill(state);
01815 state->clearPath();
01816
01817
01818 ia = ib;
01819 sa = sb;
01820 ta = tb;
01821 xa = xb;
01822 ya = yb;
01823 ra = rb;
01824 colorA = colorB;
01825 }
01826 }
01827
01828 void Gfx::doEndPath() {
01829 if (state->isPath() && clip != clipNone) {
01830 state->clip();
01831 if (clip == clipNormal) {
01832 out->clip(state);
01833 } else {
01834 out->eoClip(state);
01835 }
01836 }
01837 clip = clipNone;
01838 state->clearPath();
01839 }
01840
01841
01842
01843
01844
01845 void Gfx::opClip(Object [], int ) {
01846 clip = clipNormal;
01847 }
01848
01849 void Gfx::opEOClip(Object [], int ) {
01850 clip = clipEO;
01851 }
01852
01853
01854
01855
01856
01857 void Gfx::opBeginText(Object [], int ) {
01858 state->setTextMat(1, 0, 0, 1, 0, 0);
01859 state->textMoveTo(0, 0);
01860 out->updateTextMat(state);
01861 out->updateTextPos(state);
01862 fontChanged = gTrue;
01863 }
01864
01865 void Gfx::opEndText(Object [], int ) {
01866 }
01867
01868
01869
01870
01871
01872 void Gfx::opSetCharSpacing(Object args[], int ) {
01873 state->setCharSpace(args[0].getNum());
01874 out->updateCharSpace(state);
01875 }
01876
01877 void Gfx::opSetFont(Object args[], int ) {
01878 GfxFont *font;
01879
01880 if (!(font = res->lookupFont(args[0].getName()))) {
01881 return;
01882 }
01883 if (printCommands) {
01884 printf(" font: tag=%s name='%s' %g\n",
01885 font->getTag()->getCString(),
01886 font->getName() ? font->getName()->getCString() : "???",
01887 args[1].getNum());
01888 fflush(stdout);
01889 }
01890 state->setFont(font, args[1].getNum());
01891 fontChanged = gTrue;
01892 }
01893
01894 void Gfx::opSetTextLeading(Object args[], int ) {
01895 state->setLeading(args[0].getNum());
01896 }
01897
01898 void Gfx::opSetTextRender(Object args[], int ) {
01899 state->setRender(args[0].getInt());
01900 out->updateRender(state);
01901 }
01902
01903 void Gfx::opSetTextRise(Object args[], int ) {
01904 state->setRise(args[0].getNum());
01905 out->updateRise(state);
01906 }
01907
01908 void Gfx::opSetWordSpacing(Object args[], int ) {
01909 state->setWordSpace(args[0].getNum());
01910 out->updateWordSpace(state);
01911 }
01912
01913 void Gfx::opSetHorizScaling(Object args[], int ) {
01914 state->setHorizScaling(args[0].getNum());
01915 out->updateHorizScaling(state);
01916 fontChanged = gTrue;
01917 }
01918
01919
01920
01921
01922
01923 void Gfx::opTextMove(Object args[], int ) {
01924 double tx, ty;
01925
01926 tx = state->getLineX() + args[0].getNum();
01927 ty = state->getLineY() + args[1].getNum();
01928 state->textMoveTo(tx, ty);
01929 out->updateTextPos(state);
01930 }
01931
01932 void Gfx::opTextMoveSet(Object args[], int ) {
01933 double tx, ty;
01934
01935 tx = state->getLineX() + args[0].getNum();
01936 ty = args[1].getNum();
01937 state->setLeading(-ty);
01938 ty += state->getLineY();
01939 state->textMoveTo(tx, ty);
01940 out->updateTextPos(state);
01941 }
01942
01943 void Gfx::opSetTextMatrix(Object args[], int ) {
01944 state->setTextMat(args[0].getNum(), args[1].getNum(),
01945 args[2].getNum(), args[3].getNum(),
01946 args[4].getNum(), args[5].getNum());
01947 state->textMoveTo(0, 0);
01948 out->updateTextMat(state);
01949 out->updateTextPos(state);
01950 fontChanged = gTrue;
01951 }
01952
01953 void Gfx::opTextNextLine(Object [], int ) {
01954 double tx, ty;
01955
01956 tx = state->getLineX();
01957 ty = state->getLineY() - state->getLeading();
01958 state->textMoveTo(tx, ty);
01959 out->updateTextPos(state);
01960 }
01961
01962
01963
01964
01965
01966 void Gfx::opShowText(Object args[], int ) {
01967 if (!state->getFont()) {
01968 error(getPos(), "No font in show");
01969 return;
01970 }
01971 doShowText(args[0].getString());
01972 }
01973
01974 void Gfx::opMoveShowText(Object args[], int ) {
01975 double tx, ty;
01976
01977 if (!state->getFont()) {
01978 error(getPos(), "No font in move/show");
01979 return;
01980 }
01981 tx = state->getLineX();
01982 ty = state->getLineY() - state->getLeading();
01983 state->textMoveTo(tx, ty);
01984 out->updateTextPos(state);
01985 doShowText(args[0].getString());
01986 }
01987
01988 void Gfx::opMoveSetShowText(Object args[], int ) {
01989 double tx, ty;
01990
01991 if (!state->getFont()) {
01992 error(getPos(), "No font in move/set/show");
01993 return;
01994 }
01995 state->setWordSpace(args[0].getNum());
01996 state->setCharSpace(args[1].getNum());
01997 tx = state->getLineX();
01998 ty = state->getLineY() - state->getLeading();
01999 state->textMoveTo(tx, ty);
02000 out->updateWordSpace(state);
02001 out->updateCharSpace(state);
02002 out->updateTextPos(state);
02003 doShowText(args[2].getString());
02004 }
02005
02006 void Gfx::opShowSpaceText(Object args[], int ) {
02007 Array *a;
02008 Object obj;
02009 int wMode;
02010 int i;
02011
02012 if (!state->getFont()) {
02013 error(getPos(), "No font in show/space");
02014 return;
02015 }
02016 wMode = state->getFont()->getWMode();
02017 a = args[0].getArray();
02018 for (i = 0; i < a->getLength(); ++i) {
02019 a->get(i, &obj);
02020 if (obj.isNum()) {
02021 if (wMode) {
02022 state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize());
02023 } else {
02024 state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0);
02025 }
02026 out->updateTextShift(state, obj.getNum());
02027 } else if (obj.isString()) {
02028 doShowText(obj.getString());
02029 } else {
02030 error(getPos(), "Element of show/space array must be number or string");
02031 }
02032 obj.free();
02033 }
02034 }
02035
02036 void Gfx::doShowText(GString *s) {
02037 GfxFont *font;
02038 int wMode;
02039 double riseX, riseY;
02040 CharCode code;
02041 Unicode u[8];
02042 double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy;
02043 double originX, originY, tOriginX, tOriginY;
02044 double oldCTM[6], newCTM[6];
02045 const double *mat;
02046 Object charProc;
02047 Dict *resDict;
02048 Parser *oldParser;
02049 char *p;
02050 int len, n, uLen, nChars, nSpaces, i;
02051
02052 if (fontChanged) {
02053 out->updateFont(state);
02054 fontChanged = gFalse;
02055 }
02056 font = state->getFont();
02057 wMode = font->getWMode();
02058
02059 if (out->useDrawChar()) {
02060 out->beginString(state, s);
02061 }
02062
02063
02064 if (font->getType() == fontType3 && out->interpretType3Chars()) {
02065 mat = state->getCTM();
02066 for (i = 0; i < 6; ++i) {
02067 oldCTM[i] = mat[i];
02068 }
02069 mat = state->getTextMat();
02070 newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
02071 newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
02072 newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
02073 newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
02074 mat = font->getFontMatrix();
02075 newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
02076 newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
02077 newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
02078 newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
02079 newCTM[0] *= state->getFontSize();
02080 newCTM[3] *= state->getFontSize();
02081 newCTM[0] *= state->getHorizScaling();
02082 newCTM[2] *= state->getHorizScaling();
02083 state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
02084 curX = state->getCurX();
02085 curY = state->getCurY();
02086 oldParser = parser;
02087 p = s->getCString();
02088 len = s->getLength();
02089 while (len > 0) {
02090 n = font->getNextChar(p, len, &code,
02091 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
02092 &dx, &dy, &originX, &originY);
02093 dx = dx * state->getFontSize() + state->getCharSpace();
02094 if (n == 1 && *p == ' ') {
02095 dx += state->getWordSpace();
02096 }
02097 dx *= state->getHorizScaling();
02098 dy *= state->getFontSize();
02099 state->textTransformDelta(dx, dy, &tdx, &tdy);
02100 state->transform(curX + riseX, curY + riseY, &x, &y);
02101 out->saveState(state);
02102 state = state->save();
02103 state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
02104
02105 if (!out->beginType3Char(state, code, u, uLen)) {
02106 ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
02107 if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
02108 pushResources(resDict);
02109 }
02110 if (charProc.isStream()) {
02111 display(&charProc, gFalse);
02112 } else {
02113 error(getPos(), "Missing or bad Type3 CharProc entry");
02114 }
02115 out->endType3Char(state);
02116 if (resDict) {
02117 popResources();
02118 }
02119 charProc.free();
02120 }
02121 state = state->restore();
02122 out->restoreState(state);
02123
02124
02125 curX += tdx;
02126 curY += tdy;
02127 state->moveTo(curX, curY);
02128 p += n;
02129 len -= n;
02130 }
02131 parser = oldParser;
02132
02133 } else if (out->useDrawChar()) {
02134 state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
02135 p = s->getCString();
02136 len = s->getLength();
02137 while (len > 0) {
02138 n = font->getNextChar(p, len, &code,
02139 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
02140 &dx, &dy, &originX, &originY);
02141 if (wMode) {
02142 dx *= state->getFontSize();
02143 dy = dy * state->getFontSize() + state->getCharSpace();
02144 if (n == 1 && *p == ' ') {
02145 dy += state->getWordSpace();
02146 }
02147 } else {
02148 dx = dx * state->getFontSize() + state->getCharSpace();
02149 if (n == 1 && *p == ' ') {
02150 dx += state->getWordSpace();
02151 }
02152 dx *= state->getHorizScaling();
02153 dy *= state->getFontSize();
02154 }
02155 state->textTransformDelta(dx, dy, &tdx, &tdy);
02156 originX *= state->getFontSize();
02157 originY *= state->getFontSize();
02158 state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
02159 out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
02160 tdx, tdy, tOriginX, tOriginY, code, u, uLen);
02161 state->shift(tdx, tdy);
02162 p += n;
02163 len -= n;
02164 }
02165
02166 } else {
02167 dx = dy = 0;
02168 p = s->getCString();
02169 len = s->getLength();
02170 nChars = nSpaces = 0;
02171 while (len > 0) {
02172 n = font->getNextChar(p, len, &code,
02173 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
02174 &dx2, &dy2, &originX, &originY);
02175 dx += dx2;
02176 dy += dy2;
02177 if (n == 1 && *p == ' ') {
02178 ++nSpaces;
02179 }
02180 ++nChars;
02181 p += n;
02182 len -= n;
02183 }
02184 if (wMode) {
02185 dx *= state->getFontSize();
02186 dy = dy * state->getFontSize()
02187 + nChars * state->getCharSpace()
02188 + nSpaces * state->getWordSpace();
02189 } else {
02190 dx = dx * state->getFontSize()
02191 + nChars * state->getCharSpace()
02192 + nSpaces * state->getWordSpace();
02193 dx *= state->getHorizScaling();
02194 dy *= state->getFontSize();
02195 }
02196 state->textTransformDelta(dx, dy, &tdx, &tdy);
02197 out->drawString(state, s);
02198 state->shift(tdx, tdy);
02199 }
02200
02201 if (out->useDrawChar()) {
02202 out->endString(state);
02203 }
02204
02205 updateLevel += 10 * s->getLength();
02206 }
02207
02208
02209
02210
02211
02212 void Gfx::opXObject(Object args[], int ) {
02213 Object obj1, obj2, obj3, refObj;
02214 #ifdef OPI_SUPPORT
02215 Object opiDict;
02216 #endif
02217
02218 if (!res->lookupXObject(args[0].getName(), &obj1)) {
02219 return;
02220 }
02221 if (!obj1.isStream()) {
02222 error(getPos(), "XObject '%s' is wrong type", args[0].getName());
02223 obj1.free();
02224 return;
02225 }
02226 #ifdef OPI_SUPPORT
02227 obj1.streamGetDict()->lookup("OPI", &opiDict);
02228 if (opiDict.isDict()) {
02229 out->opiBegin(state, opiDict.getDict());
02230 }
02231 #endif
02232 obj1.streamGetDict()->lookup("Subtype", &obj2);
02233 if (obj2.isName("Image")) {
02234 res->lookupXObjectNF(args[0].getName(), &refObj);
02235 doImage(&refObj, obj1.getStream(), gFalse);
02236 refObj.free();
02237 } else if (obj2.isName("Form")) {
02238 doForm(&obj1);
02239 } else if (obj2.isName("PS")) {
02240 obj1.streamGetDict()->lookup("Level1", &obj3);
02241 out->psXObject(obj1.getStream(),
02242 obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
02243 } else if (obj2.isName()) {
02244 error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
02245 } else {
02246 error(getPos(), "XObject subtype is missing or wrong type");
02247 }
02248 obj2.free();
02249 #ifdef OPI_SUPPORT
02250 if (opiDict.isDict()) {
02251 out->opiEnd(state, opiDict.getDict());
02252 }
02253 opiDict.free();
02254 #endif
02255 obj1.free();
02256 }
02257
02258 void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
02259 Dict *dict;
02260 int width, height;
02261 int bits;
02262 GBool mask;
02263 GBool invert;
02264 GfxColorSpace *colorSpace;
02265 GfxImageColorMap *colorMap;
02266 Object maskObj;
02267 GBool haveMask;
02268 int maskColors[2*gfxColorMaxComps];
02269 Object obj1, obj2;
02270 int i;
02271
02272
02273 dict = str->getDict();
02274
02275
02276 dict->lookup("Width", &obj1);
02277 if (obj1.isNull()) {
02278 obj1.free();
02279 dict->lookup("W", &obj1);
02280 }
02281 if (!obj1.isInt())
02282 goto err2;
02283 width = obj1.getInt();
02284 obj1.free();
02285 dict->lookup("Height", &obj1);
02286 if (obj1.isNull()) {
02287 obj1.free();
02288 dict->lookup("H", &obj1);
02289 }
02290 if (!obj1.isInt())
02291 goto err2;
02292 height = obj1.getInt();
02293 obj1.free();
02294
02295
02296 dict->lookup("ImageMask", &obj1);
02297 if (obj1.isNull()) {
02298 obj1.free();
02299 dict->lookup("IM", &obj1);
02300 }
02301 mask = gFalse;
02302 if (obj1.isBool())
02303 mask = obj1.getBool();
02304 else if (!obj1.isNull())
02305 goto err2;
02306 obj1.free();
02307
02308
02309 dict->lookup("BitsPerComponent", &obj1);
02310 if (obj1.isNull()) {
02311 obj1.free();
02312 dict->lookup("BPC", &obj1);
02313 }
02314 if (!obj1.isInt())
02315 goto err2;
02316 bits = obj1.getInt();
02317 obj1.free();
02318
02319
02320 if (mask) {
02321
02322
02323 if (bits != 1)
02324 goto err1;
02325 invert = gFalse;
02326 dict->lookup("Decode", &obj1);
02327 if (obj1.isNull()) {
02328 obj1.free();
02329 dict->lookup("D", &obj1);
02330 }
02331 if (obj1.isArray()) {
02332 obj1.arrayGet(0, &obj2);
02333 if (obj2.isInt() && obj2.getInt() == 1)
02334 invert = gTrue;
02335 obj2.free();
02336 } else if (!obj1.isNull()) {
02337 goto err2;
02338 }
02339 obj1.free();
02340
02341
02342 out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
02343
02344 } else {
02345
02346
02347 dict->lookup("ColorSpace", &obj1);
02348 if (obj1.isNull()) {
02349 obj1.free();
02350 dict->lookup("CS", &obj1);
02351 }
02352 if (obj1.isName()) {
02353 res->lookupColorSpace(obj1.getName(), &obj2);
02354 if (!obj2.isNull()) {
02355 obj1.free();
02356 obj1 = obj2;
02357 } else {
02358 obj2.free();
02359 }
02360 }
02361 colorSpace = GfxColorSpace::parse(&obj1);
02362 obj1.free();
02363 if (!colorSpace) {
02364 goto err1;
02365 }
02366 dict->lookup("Decode", &obj1);
02367 if (obj1.isNull()) {
02368 obj1.free();
02369 dict->lookup("D", &obj1);
02370 }
02371 colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
02372 obj1.free();
02373 if (!colorMap->isOk()) {
02374 delete colorMap;
02375 goto err1;
02376 }
02377
02378
02379 haveMask = gFalse;
02380 dict->lookup("Mask", &maskObj);
02381 if (maskObj.isArray()) {
02382 for (i = 0;
02383 i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
02384 ++i) {
02385 maskObj.arrayGet(i, &obj1);
02386 maskColors[i] = obj1.getInt();
02387 obj1.free();
02388 }
02389 haveMask = gTrue;
02390 }
02391
02392
02393 out->drawImage(state, ref, str, width, height, colorMap,
02394 haveMask ? maskColors : (int *)NULL, inlineImg);
02395 delete colorMap;
02396
02397 maskObj.free();
02398 }
02399
02400 if ((i = width * height) > 1000) {
02401 i = 1000;
02402 }
02403 updateLevel += i;
02404
02405 return;
02406
02407 err2:
02408 obj1.free();
02409 err1:
02410 error(getPos(), "Bad image parameters");
02411 }
02412
02413 void Gfx::doForm(Object *str) {
02414 Dict *dict;
02415 Object matrixObj, bboxObj;
02416 double m[6], bbox[6];
02417 Object resObj;
02418 Dict *resDict;
02419 Object obj1;
02420 int i;
02421
02422
02423 dict = str->streamGetDict();
02424
02425
02426 dict->lookup("FormType", &obj1);
02427 if (!(obj1.isInt() && obj1.getInt() == 1)) {
02428 error(getPos(), "Unknown form type");
02429 }
02430 obj1.free();
02431
02432
02433 dict->lookup("BBox", &bboxObj);
02434 if (!bboxObj.isArray()) {
02435 matrixObj.free();
02436 bboxObj.free();
02437 error(getPos(), "Bad form bounding box");
02438 return;
02439 }
02440 for (i = 0; i < 4; ++i) {
02441 bboxObj.arrayGet(i, &obj1);
02442 bbox[i] = obj1.getNum();
02443 obj1.free();
02444 }
02445 bboxObj.free();
02446
02447
02448 dict->lookup("Matrix", &matrixObj);
02449 if (matrixObj.isArray()) {
02450 for (i = 0; i < 6; ++i) {
02451 matrixObj.arrayGet(i, &obj1);
02452 m[i] = obj1.getNum();
02453 obj1.free();
02454 }
02455 } else {
02456 m[0] = 1; m[1] = 0;
02457 m[2] = 0; m[3] = 1;
02458 m[4] = 0; m[5] = 0;
02459 }
02460 matrixObj.free();
02461
02462
02463 dict->lookup("Resources", &resObj);
02464 resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
02465
02466
02467 doForm1(str, resDict, m, bbox);
02468
02469 resObj.free();
02470 }
02471
02472 void Gfx::doAnnot(Object *str, double xMin, double yMin,
02473 double xMax, double yMax) {
02474 Dict *dict, *resDict;
02475 Object matrixObj, bboxObj, resObj;
02476 Object obj1;
02477 double m[6], bbox[6], ictm[6];
02478 const double *ctm;
02479 double formX0, formY0, formX1, formY1;
02480 double annotX0, annotY0, annotX1, annotY1;
02481 double det, x, y, sx, sy;
02482 int i;
02483
02484
02485 dict = str->streamGetDict();
02486
02487
02488 dict->lookup("BBox", &bboxObj);
02489 if (!bboxObj.isArray()) {
02490 bboxObj.free();
02491 error(getPos(), "Bad form bounding box");
02492 return;
02493 }
02494 for (i = 0; i < 4; ++i) {
02495 bboxObj.arrayGet(i, &obj1);
02496 bbox[i] = obj1.getNum();
02497 obj1.free();
02498 }
02499 bboxObj.free();
02500
02501
02502 dict->lookup("Matrix", &matrixObj);
02503 if (matrixObj.isArray()) {
02504 for (i = 0; i < 6; ++i) {
02505 matrixObj.arrayGet(i, &obj1);
02506 m[i] = obj1.getNum();
02507 obj1.free();
02508 }
02509 } else {
02510 m[0] = 1; m[1] = 0;
02511 m[2] = 0; m[3] = 1;
02512 m[4] = 0; m[5] = 0;
02513 }
02514 matrixObj.free();
02515
02516
02517 formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
02518 formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
02519 formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
02520 formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
02521
02522
02523
02524 ctm = state->getCTM();
02525 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
02526 ictm[0] = ctm[3] * det;
02527 ictm[1] = -ctm[1] * det;
02528 ictm[2] = -ctm[2] * det;
02529 ictm[3] = ctm[0] * det;
02530 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
02531 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
02532 x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
02533 y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
02534 annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
02535 annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
02536 x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
02537 y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
02538 annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
02539 annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
02540
02541
02542 if (formX0 > formX1) {
02543 x = formX0; formX0 = formX1; formX1 = x;
02544 }
02545 if (formY0 > formY1) {
02546 y = formY0; formY0 = formY1; formY1 = y;
02547 }
02548 if (annotX0 > annotX1) {
02549 x = annotX0; annotX0 = annotX1; annotX1 = x;
02550 }
02551 if (annotY0 > annotY1) {
02552 y = annotY0; annotY0 = annotY1; annotY1 = y;
02553 }
02554
02555
02556 if (formX1 == formX0) {
02557
02558 sx = 1;
02559 } else {
02560 sx = (annotX1 - annotX0) / (formX1 - formX0);
02561 }
02562 if (formY1 == formY0) {
02563
02564 sy = 1;
02565 } else {
02566 sy = (annotY1 - annotY0) / (formY1 - formY0);
02567 }
02568 m[0] *= sx;
02569 m[2] *= sx;
02570 m[4] = (m[4] - formX0) * sx + annotX0;
02571 m[1] *= sy;
02572 m[3] *= sy;
02573 m[5] = (m[5] - formY0) * sy + annotY0;
02574
02575
02576 dict->lookup("Resources", &resObj);
02577 resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
02578
02579
02580 doForm1(str, resDict, m, bbox);
02581
02582 resObj.free();
02583 bboxObj.free();
02584 }
02585
02586 void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
02587 Parser *oldParser;
02588 double oldBaseMatrix[6];
02589 int i;
02590
02591
02592 pushResources(resDict);
02593
02594
02595 out->saveState(state);
02596 state = state->save();
02597
02598
02599 oldParser = parser;
02600
02601
02602 state->concatCTM(matrix[0], matrix[1], matrix[2],
02603 matrix[3], matrix[4], matrix[5]);
02604 out->updateCTM(state, matrix[0], matrix[1], matrix[2],
02605 matrix[3], matrix[4], matrix[5]);
02606
02607
02608 for (i = 0; i < 6; ++i) {
02609 oldBaseMatrix[i] = baseMatrix[i];
02610 baseMatrix[i] = state->getCTM()[i];
02611 }
02612
02613
02614 state->moveTo(bbox[0], bbox[1]);
02615 state->lineTo(bbox[2], bbox[1]);
02616 state->lineTo(bbox[2], bbox[3]);
02617 state->lineTo(bbox[0], bbox[3]);
02618 state->closePath();
02619 state->clip();
02620 out->clip(state);
02621 state->clearPath();
02622
02623
02624 display(str, gFalse);
02625
02626
02627 for (i = 0; i < 6; ++i) {
02628 baseMatrix[i] = oldBaseMatrix[i];
02629 }
02630
02631
02632 parser = oldParser;
02633
02634
02635 state = state->restore();
02636 out->restoreState(state);
02637
02638
02639 popResources();
02640
02641 return;
02642 }
02643
02644 void Gfx::pushResources(Dict *resDict) {
02645 res = new GfxResources(xref, resDict, res);
02646 }
02647
02648 void Gfx::popResources() {
02649 GfxResources *resPtr;
02650
02651 resPtr = res->getNext();
02652 delete res;
02653 res = resPtr;
02654 }
02655
02656
02657
02658
02659
02660 void Gfx::opBeginImage(Object [], int ) {
02661 Stream *str;
02662 int c1, c2;
02663
02664
02665 str = buildImageStream();
02666
02667
02668 if (str) {
02669 doImage(NULL, str, gTrue);
02670
02671
02672 c1 = str->getBaseStream()->getChar();
02673 c2 = str->getBaseStream()->getChar();
02674 while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
02675 c1 = c2;
02676 c2 = str->getBaseStream()->getChar();
02677 }
02678 delete str;
02679 }
02680 }
02681
02682 Stream *Gfx::buildImageStream() {
02683 Object dict;
02684 Object obj;
02685 char *key;
02686 Stream *str;
02687
02688
02689 dict.initDict(xref);
02690 parser->getObj(&obj);
02691 while (!obj.isCmd("ID") && !obj.isEOF()) {
02692 if (!obj.isName()) {
02693 error(getPos(), "Inline image dictionary key must be a name object");
02694 obj.free();
02695 } else {
02696 key = copyString(obj.getName());
02697 obj.free();
02698 parser->getObj(&obj);
02699 if (obj.isEOF() || obj.isError()) {
02700 gfree(key);
02701 break;
02702 }
02703 dict.dictAdd(key, &obj);
02704 }
02705 parser->getObj(&obj);
02706 }
02707 if (obj.isEOF()) {
02708 error(getPos(), "End of file in inline image");
02709 obj.free();
02710 dict.free();
02711 return NULL;
02712 }
02713 obj.free();
02714
02715
02716 str = new EmbedStream(parser->getStream(), &dict);
02717 str = str->addFilters(&dict);
02718
02719 return str;
02720 }
02721
02722 void Gfx::opImageData(Object [], int ) {
02723 error(getPos(), "Internal: got 'ID' operator");
02724 }
02725
02726 void Gfx::opEndImage(Object [], int ) {
02727 error(getPos(), "Internal: got 'EI' operator");
02728 }
02729
02730
02731
02732
02733
02734 void Gfx::opSetCharWidth(Object args[], int ) {
02735 out->type3D0(state, args[0].getNum(), args[1].getNum());
02736 }
02737
02738 void Gfx::opSetCacheDevice(Object args[], int ) {
02739 out->type3D1(state, args[0].getNum(), args[1].getNum(),
02740 args[2].getNum(), args[3].getNum(),
02741 args[4].getNum(), args[5].getNum());
02742 }
02743
02744
02745
02746
02747
02748 void Gfx::opBeginIgnoreUndef(Object [], int ) {
02749 ++ignoreUndef;
02750 }
02751
02752 void Gfx::opEndIgnoreUndef(Object [], int ) {
02753 if (ignoreUndef > 0)
02754 --ignoreUndef;
02755 }
02756
02757
02758
02759
02760
02761 void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
02762 if (printCommands) {
02763 printf(" marked content: %s ", args[0].getName());
02764 if (numArgs == 2)
02765 args[2].print(stdout);
02766 printf("\n");
02767 fflush(stdout);
02768 }
02769 }
02770
02771 void Gfx::opEndMarkedContent(Object [], int ) {
02772 }
02773
02774 void Gfx::opMarkPoint(Object args[], int numArgs) {
02775 if (printCommands) {
02776 printf(" mark point: %s ", args[0].getName());
02777 if (numArgs == 2)
02778 args[2].print(stdout);
02779 printf("\n");
02780 fflush(stdout);
02781 }
02782 }