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