home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- //
- // Gfx.cc
- //
- // Copyright 1996 Derek B. Noonburg
- //
- //========================================================================
-
- #ifdef __GNUC__
- #pragma implementation
- #endif
-
- #include <stdio.h>
- #include <stddef.h>
- #include <string.h>
- #include "gmem.h"
- #include "Object.h"
- #include "Array.h"
- #include "Dict.h"
- #include "Stream.h"
- #include "Lexer.h"
- #include "Parser.h"
- #include "GfxFont.h"
- #include "GfxState.h"
- #include "OutputDev.h"
- #include "Params.h"
- #include "Error.h"
- #include "Gfx.h"
-
- //------------------------------------------------------------------------
- // Operator table
- //------------------------------------------------------------------------
-
- Operator Gfx::opTab[] = {
- {"\"", 3, {tchkNum, tchkNum, tchkString},
- &Gfx::opMoveSetShowText},
- {"'", 1, {tchkString},
- &Gfx::opMoveShowText},
- {"B", 0, {tchkNone},
- &Gfx::opFillStroke},
- {"B*", 0, {tchkNone},
- &Gfx::opEOFillStroke},
- {"BDC", 2, {tchkName, tchkProps},
- &Gfx::opBeginMarkedContent},
- {"BI", 0, {tchkNone},
- &Gfx::opBeginImage},
- {"BMC", 1, {tchkName},
- &Gfx::opBeginMarkedContent},
- {"BT", 0, {tchkNone},
- &Gfx::opBeginText},
- {"BX", 0, {tchkNone},
- &Gfx::opBeginIgnoreUndef},
- {"CS", 1, {tchkName},
- &Gfx::opSetStrokeColorSpace},
- {"DP", 2, {tchkName, tchkProps},
- &Gfx::opMarkPoint},
- {"Do", 1, {tchkName},
- &Gfx::opXObject},
- {"EI", 0, {tchkNone},
- &Gfx::opEndImage},
- {"EMC", 0, {tchkNone},
- &Gfx::opEndMarkedContent},
- {"ET", 0, {tchkNone},
- &Gfx::opEndText},
- {"EX", 0, {tchkNone},
- &Gfx::opEndIgnoreUndef},
- {"F", 0, {tchkNone},
- &Gfx::opFill},
- {"G", 1, {tchkNum},
- &Gfx::opSetStrokeGray},
- {"ID", 0, {tchkNone},
- &Gfx::opImageData},
- {"J", 1, {tchkInt},
- &Gfx::opSetLineCap},
- {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opSetStrokeCMYKColor},
- {"M", 1, {tchkNum},
- &Gfx::opSetMiterLimit},
- {"MP", 1, {tchkName},
- &Gfx::opMarkPoint},
- {"Q", 0, {tchkNone},
- &Gfx::opRestore},
- {"RG", 3, {tchkNum, tchkNum, tchkNum},
- &Gfx::opSetStrokeRGBColor},
- {"S", 0, {tchkNone},
- &Gfx::opStroke},
- {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opSetStrokeColor},
- {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
- tchkSCN},
- &Gfx::opSetStrokeColorN},
- {"T*", 0, {tchkNone},
- &Gfx::opTextNextLine},
- {"TD", 2, {tchkNum, tchkNum},
- &Gfx::opTextMoveSet},
- {"TJ", 1, {tchkArray},
- &Gfx::opShowSpaceText},
- {"TL", 1, {tchkNum},
- &Gfx::opSetTextLeading},
- {"Tc", 1, {tchkNum},
- &Gfx::opSetCharSpacing},
- {"Td", 2, {tchkNum, tchkNum},
- &Gfx::opTextMove},
- {"Tf", 2, {tchkName, tchkNum},
- &Gfx::opSetFont},
- {"Tj", 1, {tchkString},
- &Gfx::opShowText},
- {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
- tchkNum, tchkNum},
- &Gfx::opSetTextMatrix},
- {"Tr", 1, {tchkInt},
- &Gfx::opSetTextRender},
- {"Ts", 1, {tchkNum},
- &Gfx::opSetTextRise},
- {"Tw", 1, {tchkNum},
- &Gfx::opSetWordSpacing},
- {"Tz", 1, {tchkNum},
- &Gfx::opSetHorizScaling},
- {"W", 0, {tchkNone},
- &Gfx::opClip},
- {"W*", 0, {tchkNone},
- &Gfx::opEOClip},
- {"b", 0, {tchkNone},
- &Gfx::opCloseFillStroke},
- {"b*", 0, {tchkNone},
- &Gfx::opCloseEOFillStroke},
- {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
- tchkNum, tchkNum},
- &Gfx::opCurveTo},
- {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
- tchkNum, tchkNum},
- &Gfx::opConcat},
- {"cs", 1, {tchkName},
- &Gfx::opSetFillColorSpace},
- {"d", 2, {tchkArray, tchkNum},
- &Gfx::opSetDash},
- {"d0", 2, {tchkNum, tchkNum},
- &Gfx::opSetCharWidth},
- {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
- tchkNum, tchkNum},
- &Gfx::opSetCacheDevice},
- {"f", 0, {tchkNone},
- &Gfx::opFill},
- {"f*", 0, {tchkNone},
- &Gfx::opEOFill},
- {"g", 1, {tchkNum},
- &Gfx::opSetFillGray},
- {"gs", 1, {tchkName},
- &Gfx::opSetExtGState},
- {"h", 0, {tchkNone},
- &Gfx::opClosePath},
- {"i", 1, {tchkNum},
- &Gfx::opSetFlat},
- {"j", 1, {tchkInt},
- &Gfx::opSetLineJoin},
- {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opSetFillCMYKColor},
- {"l", 2, {tchkNum, tchkNum},
- &Gfx::opLineTo},
- {"m", 2, {tchkNum, tchkNum},
- &Gfx::opMoveTo},
- {"n", 0, {tchkNone},
- &Gfx::opEndPath},
- {"q", 0, {tchkNone},
- &Gfx::opSave},
- {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opRectangle},
- {"rg", 3, {tchkNum, tchkNum, tchkNum},
- &Gfx::opSetFillRGBColor},
- {"s", 0, {tchkNone},
- &Gfx::opCloseStroke},
- {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opSetFillColor},
- {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
- tchkSCN},
- &Gfx::opSetFillColorN},
- {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opCurveTo1},
- {"w", 1, {tchkNum},
- &Gfx::opSetLineWidth},
- {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
- &Gfx::opCurveTo2},
- };
-
- #define numOps (sizeof(opTab) / sizeof(Operator))
-
- //------------------------------------------------------------------------
- // Gfx
- //------------------------------------------------------------------------
-
- Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
- int dpi, double x1, double y1, double x2, double y2, GBool crop,
- double cropX1, double cropY1, double cropX2, double cropY2,
- int rotate) {
- Object obj1;
-
- // start the resource stack
- res = new GfxResources(NULL);
-
- // build font dictionary
- res->fonts = NULL;
- if (resDict) {
- resDict->lookup("Font", &obj1);
- if (obj1.isDict())
- res->fonts = new GfxFontDict(obj1.getDict());
- obj1.free();
- }
-
- // get XObject dictionary
- if (resDict)
- resDict->lookup("XObject", &res->xObjDict);
- else
- res->xObjDict.initNull();
-
- // get colorspace dictionary
- if (resDict)
- resDict->lookup("ColorSpace", &res->colorSpaceDict);
- else
- res->colorSpaceDict.initNull();
-
- // initialize
- out = out1;
- state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
- fontChanged = gFalse;
- clip = clipNone;
- ignoreUndef = 0;
- out->startPage(pageNum, state);
- out->setDefaultCTM(state->getCTM());
- out->updateAll(state);
-
- // set crop box
- if (crop) {
- state->moveTo(cropX1, cropY1);
- state->lineTo(cropX2, cropY1);
- state->lineTo(cropX2, cropY2);
- state->lineTo(cropX1, cropY2);
- state->closePath();
- out->clip(state);
- state->clearPath();
- }
- }
-
- Gfx::~Gfx() {
- GfxResources *resPtr;
-
- while (state->hasSaves()) {
- state = state->restore();
- out->restoreState(state);
- }
- out->endPage();
- while (res) {
- resPtr = res->next;
- delete res;
- res = resPtr;
- }
- if (state)
- delete state;
- }
-
- GfxResources::~GfxResources() {
- if (fonts)
- delete fonts;
- xObjDict.free();
- colorSpaceDict.free();
- }
-
- void Gfx::display(Object *obj) {
- Object obj2;
- int i;
-
- if (obj->isArray()) {
- for (i = 0; i < obj->arrayGetLength(); ++i) {
- obj->arrayGet(i, &obj2);
- if (!obj2.isStream()) {
- error(-1, "Weird page contents");
- obj2.free();
- return;
- }
- obj2.free();
- }
- } else if (!obj->isStream()) {
- error(-1, "Weird page contents");
- return;
- }
- parser = new Parser(new Lexer(obj));
- go();
- }
-
- void Gfx::go() {
- Object obj;
- Object args[maxArgs];
- int numCmds, numArgs;
- int i;
-
- // scan a sequence of objects
- numCmds = 0;
- numArgs = 0;
- parser->getObj(&obj);
- while (!obj.isEOF()) {
-
- // got a command - execute it
- if (obj.isCmd()) {
- if (printCommands) {
- obj.print(stdout);
- for (i = 0; i < numArgs; ++i) {
- printf(" ");
- args[i].print(stdout);
- }
- printf("\n");
- }
- execOp(&obj, args, numArgs);
- obj.free();
- for (i = 0; i < numArgs; ++i)
- args[i].free();
- numArgs = 0;
-
- // periodically update display
- if (++numCmds == 200) {
- out->dump();
- numCmds = 0;
- }
-
- // got an argument - save it
- } else if (numArgs < maxArgs) {
- args[numArgs++] = obj;
-
- // too many arguments - something is wrong
- } else {
- error(getPos(), "Too many args in content stream");
- if (printCommands) {
- printf("throwing away arg: ");
- obj.print(stdout);
- printf("\n");
- }
- obj.free();
- }
-
- // grab the next object
- parser->getObj(&obj);
- }
- obj.free();
-
- // args at end with no command
- if (numArgs > 0) {
- error(getPos(), "Leftover args in content stream");
- if (printCommands) {
- printf("%d leftovers:", numArgs);
- for (i = 0; i < numArgs; ++i) {
- printf(" ");
- args[i].print(stdout);
- }
- printf("\n");
- }
- for (i = 0; i < numArgs; ++i)
- args[i].free();
- }
-
- // update display
- if (numCmds > 0)
- out->dump();
-
- // clean up
- if (parser)
- delete parser;
- if (printCommands)
- fflush(stdout);
- }
-
- void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
- Operator *op;
- char *name;
- int i;
-
- // find operator
- name = cmd->getName();
- if (!(op = findOp(name))) {
- if (ignoreUndef == 0)
- error(getPos(), "Unknown operator '%s'", name);
- return;
- }
-
- // type check args
- if (op->numArgs >= 0) {
- if (numArgs != op->numArgs) {
- error(getPos(), "Wrong number (%d) of args to '%s' operator",
- numArgs, name);
- return;
- }
- } else {
- if (numArgs > -op->numArgs) {
- error(getPos(), "Too many (%d) args to '%s' operator",
- numArgs, name);
- return;
- }
- }
- for (i = 0; i < numArgs; ++i) {
- if (!checkArg(&args[i], op->tchk[i])) {
- error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
- i, name, args[i].getTypeName());
- return;
- }
- }
-
- // do it
- (this->*op->func)(args, numArgs);
- }
-
- Operator *Gfx::findOp(char *name) {
- int a, b, m, cmp;
-
- a = -1;
- b = numOps;
- // invariant: opTab[a] < name < opTab[b]
- while (b - a > 1) {
- m = (a + b) / 2;
- cmp = strcmp(opTab[m].name, name);
- if (cmp < 0)
- a = m;
- else if (cmp > 0)
- b = m;
- else
- a = b = m;
- }
- if (cmp != 0)
- return NULL;
- return &opTab[a];
- }
-
- GBool Gfx::checkArg(Object *arg, TchkType type) {
- switch (type) {
- case tchkBool: return arg->isBool();
- case tchkInt: return arg->isInt();
- case tchkNum: return arg->isNum();
- case tchkString: return arg->isString();
- case tchkName: return arg->isName();
- case tchkArray: return arg->isArray();
- case tchkProps: return arg->isDict() || arg->isName();
- case tchkSCN: return arg->isNum() || arg->isName();
- case tchkNone: return gFalse;
- }
- return gFalse;
- }
-
- int Gfx::getPos() {
- return parser->getPos();
- }
-
- GfxFont *Gfx::lookupFont(char *name) {
- GfxFont *font;
- GfxResources *resPtr;
-
- for (resPtr = res; resPtr; resPtr = resPtr->next) {
- if (resPtr->fonts) {
- if ((font = resPtr->fonts->lookup(name)))
- return font;
- }
- }
- error(getPos(), "unknown font tag '%s'", name);
- return NULL;
- }
-
- GBool Gfx::lookupXObject(char *name, Object *obj) {
- GfxResources *resPtr;
-
- for (resPtr = res; resPtr; resPtr = resPtr->next) {
- if (resPtr->xObjDict.isDict()) {
- if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
- return gTrue;
- obj->free();
- }
- }
- error(getPos(), "XObject '%s' is unknown", name);
- return gFalse;
- }
-
- void Gfx::lookupColorSpace(char *name, Object *obj) {
- GfxResources *resPtr;
-
- for (resPtr = res; resPtr; resPtr = resPtr->next) {
- if (resPtr->colorSpaceDict.isDict()) {
- if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull())
- return;
- obj->free();
- }
- }
- obj->initNull();
- }
-
- //------------------------------------------------------------------------
- // graphics state operators
- //------------------------------------------------------------------------
-
- void Gfx::opSave(Object args[], int numArgs) {
- out->saveState(state);
- state = state->save();
- }
-
- void Gfx::opRestore(Object args[], int numArgs) {
- state = state->restore();
- out->restoreState(state);
- }
-
- void Gfx::opConcat(Object args[], int numArgs) {
- state->concatCTM(args[0].getNum(), args[1].getNum(),
- args[2].getNum(), args[3].getNum(),
- args[4].getNum(), args[5].getNum());
- out->updateCTM(state, args[0].getNum(), args[1].getNum(),
- args[2].getNum(), args[3].getNum(),
- args[4].getNum(), args[5].getNum());
- fontChanged = gTrue;
- }
-
- void Gfx::opSetDash(Object args[], int numArgs) {
- Array *a;
- int length;
- Object obj;
- double *dash;
- int i;
-
- a = args[0].getArray();
- length = a->getLength();
- if (length == 0) {
- dash = NULL;
- } else {
- dash = (double *)gmalloc(length * sizeof(double));
- for (i = 0; i < length; ++i) {
- dash[i] = a->get(i, &obj)->getNum();
- obj.free();
- }
- }
- state->setLineDash(dash, length, args[1].getNum());
- out->updateLineDash(state);
- }
-
- void Gfx::opSetFlat(Object args[], int numArgs) {
- state->setFlatness((int)args[0].getNum());
- out->updateFlatness(state);
- }
-
- void Gfx::opSetLineJoin(Object args[], int numArgs) {
- state->setLineJoin(args[0].getInt());
- out->updateLineJoin(state);
- }
-
- void Gfx::opSetLineCap(Object args[], int numArgs) {
- state->setLineCap(args[0].getInt());
- out->updateLineCap(state);
- }
-
- void Gfx::opSetMiterLimit(Object args[], int numArgs) {
- state->setMiterLimit(args[0].getNum());
- out->updateMiterLimit(state);
- }
-
- void Gfx::opSetLineWidth(Object args[], int numArgs) {
- state->setLineWidth(args[0].getNum());
- out->updateLineWidth(state);
- }
-
- void Gfx::opSetExtGState(Object args[], int numArgs) {
- }
-
- //------------------------------------------------------------------------
- // color operators
- //------------------------------------------------------------------------
-
- void Gfx::opSetFillGray(Object args[], int numArgs) {
- state->setFillColorSpace(new GfxColorSpace(colorGray));
- state->setFillGray(args[0].getNum());
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeGray(Object args[], int numArgs) {
- state->setStrokeColorSpace(new GfxColorSpace(colorGray));
- state->setStrokeGray(args[0].getNum());
- out->updateStrokeColor(state);
- }
-
- void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
- state->setFillColorSpace(new GfxColorSpace(colorCMYK));
- state->setFillCMYK(args[0].getNum(), args[1].getNum(),
- args[2].getNum(), args[3].getNum());
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
- state->setStrokeColorSpace(new GfxColorSpace(colorCMYK));
- state->setStrokeCMYK(args[0].getNum(), args[1].getNum(),
- args[2].getNum(), args[3].getNum());
- out->updateStrokeColor(state);
- }
-
- void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
- state->setFillColorSpace(new GfxColorSpace(colorRGB));
- state->setFillRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
- state->setStrokeColorSpace(new GfxColorSpace(colorRGB));
- state->setStrokeRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
- out->updateStrokeColor(state);
- }
-
- void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
- Object obj;
- GfxColorSpace *colorSpace;
- double x[4];
-
- lookupColorSpace(args[0].getName(), &obj);
- if (obj.isNull())
- colorSpace = new GfxColorSpace(&args[0]);
- else
- colorSpace = new GfxColorSpace(&obj);
- obj.free();
- if (colorSpace->isOk()) {
- state->setFillColorSpace(colorSpace);
- } else {
- delete colorSpace;
- error(getPos(), "Bad colorspace");
- }
- x[0] = x[1] = x[2] = x[3] = 0;
- state->setFillColor(x);
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
- Object obj;
- GfxColorSpace *colorSpace;
- double x[4];
-
- lookupColorSpace(args[0].getName(), &obj);
- if (obj.isNull())
- colorSpace = new GfxColorSpace(&args[0]);
- else
- colorSpace = new GfxColorSpace(&obj);
- obj.free();
- if (colorSpace->isOk()) {
- state->setStrokeColorSpace(colorSpace);
- } else {
- delete colorSpace;
- error(getPos(), "Bad colorspace");
- }
- x[0] = x[1] = x[2] = x[3] = 0;
- state->setStrokeColor(x);
- out->updateStrokeColor(state);
- }
-
- void Gfx::opSetFillColor(Object args[], int numArgs) {
- double x[4];
- int i;
-
- x[0] = x[1] = x[2] = x[3] = 0;
- for (i = 0; i < numArgs; ++i)
- x[i] = args[i].getNum();
- state->setFillColor(x);
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeColor(Object args[], int numArgs) {
- double x[4];
- int i;
-
- x[0] = x[1] = x[2] = x[3] = 0;
- for (i = 0; i < numArgs; ++i)
- x[i] = args[i].getNum();
- state->setStrokeColor(x);
- out->updateStrokeColor(state);
- }
-
- void Gfx::opSetFillColorN(Object args[], int numArgs) {
- double x[4];
- int i;
-
- x[0] = x[1] = x[2] = x[3] = 0;
- for (i = 0; i < numArgs && i < 4; ++i) {
- if (args[i].isNum())
- x[i] = args[i].getNum();
- else
- break;
- }
- state->setFillColor(x);
- out->updateFillColor(state);
- }
-
- void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
- double x[4];
- int i;
-
- x[0] = x[1] = x[2] = x[3] = 0;
- for (i = 0; i < numArgs && i < 4; ++i) {
- if (args[i].isNum())
- x[i] = args[i].getNum();
- else
- break;
- }
- state->setStrokeColor(x);
- out->updateStrokeColor(state);
- }
-
- //------------------------------------------------------------------------
- // path segment operators
- //------------------------------------------------------------------------
-
- void Gfx::opMoveTo(Object args[], int numArgs) {
- state->moveTo(args[0].getNum(), args[1].getNum());
- }
-
- void Gfx::opLineTo(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- error(getPos(), "No current point in lineto");
- return;
- }
- state->lineTo(args[0].getNum(), args[1].getNum());
- }
-
- void Gfx::opCurveTo(Object args[], int numArgs) {
- double x1, y1, x2, y2, x3, y3;
-
- if (!state->isCurPt()) {
- error(getPos(), "No current point in curveto");
- return;
- }
- x1 = args[0].getNum();
- y1 = args[1].getNum();
- x2 = args[2].getNum();
- y2 = args[3].getNum();
- x3 = args[4].getNum();
- y3 = args[5].getNum();
- state->curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- void Gfx::opCurveTo1(Object args[], int numArgs) {
- double x1, y1, x2, y2, x3, y3;
-
- if (!state->isCurPt()) {
- error(getPos(), "No current point in curveto1");
- return;
- }
- x1 = state->getCurX();
- y1 = state->getCurY();
- x2 = args[0].getNum();
- y2 = args[1].getNum();
- x3 = args[2].getNum();
- y3 = args[3].getNum();
- state->curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- void Gfx::opCurveTo2(Object args[], int numArgs) {
- double x1, y1, x2, y2, x3, y3;
-
- if (!state->isCurPt()) {
- error(getPos(), "No current point in curveto2");
- return;
- }
- x1 = args[0].getNum();
- y1 = args[1].getNum();
- x2 = args[2].getNum();
- y2 = args[3].getNum();
- x3 = x2;
- y3 = y2;
- state->curveTo(x1, y1, x2, y2, x3, y3);
- }
-
- void Gfx::opRectangle(Object args[], int numArgs) {
- double x, y, w, h;
-
- x = args[0].getNum();
- y = args[1].getNum();
- w = args[2].getNum();
- h = args[3].getNum();
- state->moveTo(x, y);
- state->lineTo(x + w, y);
- state->lineTo(x + w, y + h);
- state->lineTo(x, y + h);
- state->closePath();
- }
-
- void Gfx::opClosePath(Object args[], int numArgs) {
- if (!state->isPath()) {
- error(getPos(), "No current point in closepath");
- return;
- }
- state->closePath();
- }
-
- //------------------------------------------------------------------------
- // path painting operators
- //------------------------------------------------------------------------
-
- void Gfx::opEndPath(Object args[], int numArgs) {
- doEndPath();
- }
-
- void Gfx::opStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in stroke");
- return;
- }
- if (state->isPath())
- out->stroke(state);
- doEndPath();
- }
-
- void Gfx::opCloseStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in closepath/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
- out->stroke(state);
- }
- doEndPath();
- }
-
- void Gfx::opFill(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in fill");
- return;
- }
- if (state->isPath())
- out->fill(state);
- doEndPath();
- }
-
- void Gfx::opEOFill(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in eofill");
- return;
- }
- if (state->isPath())
- out->eoFill(state);
- doEndPath();
- }
-
- void Gfx::opFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in fill/stroke");
- return;
- }
- if (state->isPath()) {
- out->fill(state);
- out->stroke(state);
- }
- doEndPath();
- }
-
- void Gfx::opCloseFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in closepath/fill/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
- out->fill(state);
- out->stroke(state);
- }
- doEndPath();
- }
-
- void Gfx::opEOFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in eofill/stroke");
- return;
- }
- if (state->isPath()) {
- out->eoFill(state);
- out->stroke(state);
- }
- doEndPath();
- }
-
- void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
- if (!state->isCurPt()) {
- //error(getPos(), "No path in closepath/eofill/stroke");
- return;
- }
- if (state->isPath()) {
- state->closePath();
- out->eoFill(state);
- out->stroke(state);
- }
- doEndPath();
- }
-
- void Gfx::doEndPath() {
- if (state->isPath()) {
- if (clip == clipNormal)
- out->clip(state);
- else if (clip == clipEO)
- out->eoClip(state);
- }
- clip = clipNone;
- state->clearPath();
- }
-
- //------------------------------------------------------------------------
- // path clipping operators
- //------------------------------------------------------------------------
-
- void Gfx::opClip(Object args[], int numArgs) {
- clip = clipNormal;
- }
-
- void Gfx::opEOClip(Object args[], int numArgs) {
- clip = clipEO;
- }
-
- //------------------------------------------------------------------------
- // text object operators
- //------------------------------------------------------------------------
-
- void Gfx::opBeginText(Object args[], int numArgs) {
- state->setTextMat(1, 0, 0, 1, 0, 0);
- state->textMoveTo(0, 0);
- out->updateTextMat(state);
- out->updateTextPos(state);
- fontChanged = gTrue;
- }
-
- void Gfx::opEndText(Object args[], int numArgs) {
- }
-
- //------------------------------------------------------------------------
- // text state operators
- //------------------------------------------------------------------------
-
- void Gfx::opSetCharSpacing(Object args[], int numArgs) {
- state->setCharSpace(args[0].getNum());
- out->updateCharSpace(state);
- }
-
- void Gfx::opSetFont(Object args[], int numArgs) {
- GfxFont *font;
-
- if (!(font = lookupFont(args[0].getName())))
- return;
- if (printCommands) {
- printf(" font: '%s' %g\n",
- font->getName() ? font->getName()->getCString() : "???",
- args[1].getNum());
- }
- state->setFont(font, args[1].getNum());
- fontChanged = gTrue;
- }
-
- void Gfx::opSetTextLeading(Object args[], int numArgs) {
- state->setLeading(args[0].getNum());
- }
-
- void Gfx::opSetTextRender(Object args[], int numArgs) {
- state->setRender(args[0].getInt());
- out->updateRender(state);
- }
-
- void Gfx::opSetTextRise(Object args[], int numArgs) {
- state->setRise(args[0].getNum());
- out->updateRise(state);
- }
-
- void Gfx::opSetWordSpacing(Object args[], int numArgs) {
- state->setWordSpace(args[0].getNum());
- out->updateWordSpace(state);
- }
-
- void Gfx::opSetHorizScaling(Object args[], int numArgs) {
- state->setHorizScaling(args[0].getNum());
- out->updateHorizScaling(state);
- }
-
- //------------------------------------------------------------------------
- // text positioning operators
- //------------------------------------------------------------------------
-
- void Gfx::opTextMove(Object args[], int numArgs) {
- double tx, ty;
-
- tx = state->getLineX() + args[0].getNum();
- ty = state->getLineY() + args[1].getNum();
- state->textMoveTo(tx, ty);
- out->updateTextPos(state);
- }
-
- void Gfx::opTextMoveSet(Object args[], int numArgs) {
- double tx, ty;
-
- tx = state->getLineX() + args[0].getNum();
- ty = args[1].getNum();
- state->setLeading(-ty);
- ty += state->getLineY();
- state->textMoveTo(tx, ty);
- out->updateTextPos(state);
- }
-
- void Gfx::opSetTextMatrix(Object args[], int numArgs) {
- state->setTextMat(args[0].getNum(), args[1].getNum(),
- args[2].getNum(), args[3].getNum(),
- args[4].getNum(), args[5].getNum());
- state->textMoveTo(0, 0);
- out->updateTextMat(state);
- out->updateTextPos(state);
- fontChanged = gTrue;
- }
-
- void Gfx::opTextNextLine(Object args[], int numArgs) {
- double tx, ty;
-
- tx = state->getLineX();
- ty = state->getLineY() - state->getLeading();
- state->textMoveTo(tx, ty);
- out->updateTextPos(state);
- }
-
- //------------------------------------------------------------------------
- // text string operators
- //------------------------------------------------------------------------
-
- void Gfx::opShowText(Object args[], int numArgs) {
- if (!state->getFont()) {
- error(getPos(), "No font in show");
- return;
- }
- doShowText(args[0].getString());
- }
-
- void Gfx::opMoveShowText(Object args[], int numArgs) {
- double tx, ty;
-
- if (!state->getFont()) {
- error(getPos(), "No font in move/show");
- return;
- }
- tx = state->getLineX();
- ty = state->getLineY() - state->getLeading();
- state->textMoveTo(tx, ty);
- out->updateTextPos(state);
- doShowText(args[0].getString());
- }
-
- void Gfx::opMoveSetShowText(Object args[], int numArgs) {
- double tx, ty;
-
- if (!state->getFont()) {
- error(getPos(), "No font in move/set/show");
- return;
- }
- state->setWordSpace(args[0].getNum());
- state->setCharSpace(args[1].getNum());
- tx = state->getLineX();
- ty = state->getLineY() - state->getLeading();
- state->textMoveTo(tx, ty);
- out->updateWordSpace(state);
- out->updateCharSpace(state);
- out->updateTextPos(state);
- doShowText(args[2].getString());
- }
-
- void Gfx::opShowSpaceText(Object args[], int numArgs) {
- Array *a;
- Object obj;
- int i;
-
- if (!state->getFont()) {
- error(getPos(), "No font in show/space");
- return;
- }
- a = args[0].getArray();
- for (i = 0; i < a->getLength(); ++i) {
- a->get(i, &obj);
- if (obj.isNum()) {
- state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
- out->updateTextShift(state, obj.getNum());
- } else if (obj.isString()) {
- doShowText(obj.getString());
- } else {
- error(getPos(), "Element of show/space array must be number or string");
- }
- obj.free();
- }
- }
-
- void Gfx::doShowText(GString *s) {
- GfxFont *font;
- GfxFontEncoding16 *enc;
- Guchar *p;
- Guchar c8;
- int c16;
- GString *s16;
- int m, n;
- double dx, dy, width, w, h;
-
- if (fontChanged) {
- out->updateFont(state);
- fontChanged = gFalse;
- }
- font = state->getFont();
-
- //----- 16-bit font
- if (font->is16Bit()) {
- enc = font->getEncoding16();
- if (out->useDrawChar()) {
- out->beginString(state, s);
- s16 = NULL;
- } else {
- s16 = new GString(" ");
- }
- state->textTransformDelta(0, state->getRise(), &dx, &dy);
- p = (Guchar *)s->getCString();
- n = s->getLength();
- while (n > 0) {
- m = getNextChar16(enc, p, &c16);
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth16(c16) +
- state->getCharSpace();
- if (c16 == ' ')
- width += state->getWordSpace();
- state->textTransformDelta(width, 0, &w, &h);
- if (out->useDrawChar()) {
- out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy,
- w, h, c16);
- } else {
- s16->setChar(0, (char)(c16 >> 8));
- s16->setChar(1, (char)c16);
- out->drawString16(state, s16);
- }
- state->textShift(width);
- n -= m;
- p += m;
- }
- if (out->useDrawChar())
- out->endString(state);
- else
- delete s16;
-
- //----- 8-bit font
- } else {
- if (out->useDrawChar()) {
- out->beginString(state, s);
- state->textTransformDelta(0, state->getRise(), &dx, &dy);
- for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- c8 = *p;
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(c8) +
- state->getCharSpace();
- if (c8 == ' ')
- width += state->getWordSpace();
- state->textTransformDelta(width, 0, &w, &h);
- out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
- w, h, c8);
- state->textShift(width);
- }
- out->endString(state);
- } else {
- out->drawString(state, s);
- width = state->getFontSize() * state->getHorizScaling() *
- font->getWidth(s) +
- s->getLength() * state->getCharSpace();
- for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- if (*p == ' ')
- width += state->getWordSpace();
- }
- state->textShift(width);
- }
- }
- }
-
- int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) {
- int n;
- int code;
- int a, b, m;
-
- n = enc->codeLen[*p];
- if (n == 1) {
- *c16 = enc->map1[*p];
- } else {
- code = (p[0] << 8) + p[1];
- a = 0;
- b = enc->map2Len;
- // invariant: map2[2*a] <= code < map2[2*b]
- while (b - a > 1) {
- m = (a + b) / 2;
- if (enc->map2[2*m] <= code)
- a = m;
- else if (enc->map2[2*m] > code)
- b = m;
- else
- break;
- }
- *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]);
- }
- return n;
- }
-
- //------------------------------------------------------------------------
- // XObject operators
- //------------------------------------------------------------------------
-
- void Gfx::opXObject(Object args[], int numArgs) {
- Object obj1, obj2;
-
- if (!lookupXObject(args[0].getName(), &obj1))
- return;
- if (!obj1.isStream("XObject")) {
- error(getPos(), "XObject '%s' is wrong type", args[0].getName());
- obj1.free();
- return;
- }
- obj1.streamGetDict()->lookup("Subtype", &obj2);
- if (obj2.isName("Image"))
- doImage(obj1.getStream(), gFalse);
- else if (obj2.isName("Form"))
- doForm(&obj1);
- else if (obj2.isName())
- error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
- else
- error(getPos(), "XObject subtype is missing or wrong type");
- obj2.free();
- obj1.free();
- }
-
- void Gfx::doImage(Stream *str, GBool inlineImg) {
- Dict *dict;
- Object obj1, obj2;
- int width, height;
- int bits;
- GBool mask;
- GfxColorSpace *colorSpace;
- GfxImageColorMap *colorMap;
- GBool invert;
-
- // get stream dict
- dict = str->getDict();
-
- // get size
- dict->lookup("Width", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("W", &obj1);
- }
- if (!obj1.isInt())
- goto err2;
- width = obj1.getInt();
- obj1.free();
- dict->lookup("Height", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("H", &obj1);
- }
- if (!obj1.isInt())
- goto err2;
- height = obj1.getInt();
- obj1.free();
-
- // image or mask?
- dict->lookup("ImageMask", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("IM", &obj1);
- }
- mask = gFalse;
- if (obj1.isBool())
- mask = obj1.getBool();
- else if (!obj1.isNull())
- goto err2;
- obj1.free();
-
- // bit depth
- dict->lookup("BitsPerComponent", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("BPC", &obj1);
- }
- if (!obj1.isInt())
- goto err2;
- bits = obj1.getInt();
- obj1.free();
-
- // display a mask
- if (mask) {
-
- // check for inverted mask
- if (bits != 1)
- goto err1;
- invert = gFalse;
- dict->lookup("Decode", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("D", &obj1);
- }
- if (obj1.isArray()) {
- obj1.arrayGet(0, &obj2);
- if (obj2.isInt() && obj2.getInt() == 1)
- invert = gTrue;
- obj2.free();
- } else if (!obj1.isNull()) {
- goto err2;
- }
- obj1.free();
-
- // draw it
- out->drawImageMask(state, str, width, height, invert, inlineImg);
-
- } else {
-
- // get color space and color map
- dict->lookup("ColorSpace", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("CS", &obj1);
- }
- if (obj1.isName()) {
- lookupColorSpace(obj1.getName(), &obj2);
- if (!obj2.isNull()) {
- obj1.free();
- obj1 = obj2;
- } else {
- obj2.free();
- }
- }
- colorSpace = new GfxColorSpace(&obj1);
- obj1.free();
- if (!colorSpace->isOk()) {
- delete colorSpace;
- goto err1;
- }
- dict->lookup("Decode", &obj1);
- if (obj1.isNull()) {
- obj1.free();
- dict->lookup("D", &obj1);
- }
- colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
- obj1.free();
- if (!colorMap->isOk()) {
- delete colorSpace;
- goto err1;
- }
-
- // draw it
- out->drawImage(state, str, width, height, colorMap, inlineImg);
- delete colorMap;
- }
-
- return;
-
- err2:
- obj1.free();
- err1:
- error(getPos(), "Bad image parameters");
- }
-
- void Gfx::doForm(Object *str) {
- Parser *oldParser;
- GfxResources *resPtr;
- Dict *dict;
- Dict *resDict;
- Object matrixObj, bboxObj;
- double m[6];
- Object obj1, obj2;
- int i;
-
- // get stream dict
- dict = str->streamGetDict();
-
- // check form type
- dict->lookup("FormType", &obj1);
- if (!(obj1.isInt() && obj1.getInt() == 1)) {
- obj1.free();
- error(getPos(), "Unknown form type");
- return;
- }
- obj1.free();
-
- // get matrix and bounding box
- dict->lookup("Matrix", &matrixObj);
- if (!matrixObj.isArray()) {
- matrixObj.free();
- error(getPos(), "Bad form matrix");
- return;
- }
- dict->lookup("BBox", &bboxObj);
- if (!bboxObj.isArray()) {
- matrixObj.free();
- bboxObj.free();
- error(getPos(), "Bad form bounding box");
- return;
- }
-
- // push new resources on stack
- dict->lookup("Resources", &obj1);
- if (obj1.isDict()) {
- resDict = obj1.getDict();
- res = new GfxResources(res);
- res->fonts = NULL;
- resDict->lookup("Font", &obj2);
- if (obj2.isDict())
- res->fonts = new GfxFontDict(obj2.getDict());
- obj2.free();
- resDict->lookup("XObject", &res->xObjDict);
- resDict->lookup("ColorSpace", &res->colorSpaceDict);
- obj1.free();
- }
-
- // save current graphics state
- out->saveState(state);
- state = state->save();
-
- // save current parser
- oldParser = parser;
-
- // set form transformation matrix
- for (i = 0; i < 6; ++i) {
- matrixObj.arrayGet(i, &obj1);
- m[i] = obj1.getNum();
- obj1.free();
- }
- state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
- out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
-
- // set form bounding box
- for (i = 0; i < 4; ++i) {
- bboxObj.arrayGet(i, &obj1);
- m[i] = obj1.getNum();
- obj1.free();
- }
- state->moveTo(m[0], m[1]);
- state->lineTo(m[0]+m[2], m[1]);
- state->lineTo(m[0]+m[2], m[1]+m[3]);
- state->lineTo(m[0], m[1]+m[3]);
- state->closePath();
- out->clip(state);
- state->clearPath();
-
- // draw the form
- display(str);
-
- // free matrix and bounding box
- matrixObj.free();
- bboxObj.free();
-
- // restore parser
- parser = oldParser;
-
- // restore graphics state
- state = state->restore();
- out->restoreState(state);
-
- // pop resource stack
- resPtr = res->next;
- delete res;
- res = resPtr;
-
- return;
- }
-
- //------------------------------------------------------------------------
- // in-line image operators
- //------------------------------------------------------------------------
-
- void Gfx::opBeginImage(Object args[], int numArgs) {
- Stream *str;
- int c1, c2;
-
- // build dict/stream
- str = buildImageStream();
-
- // display the image
- if (str) {
- doImage(str, gTrue);
-
- // skip 'EI' tag
- c1 = str->getBaseStream()->getChar();
- c2 = str->getBaseStream()->getChar();
- while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
- c1 = c2;
- c2 = str->getBaseStream()->getChar();
- }
- delete str;
- }
- }
-
- Stream *Gfx::buildImageStream() {
- Object dict;
- Object obj;
- char *key;
- Stream *str;
-
- // build dictionary
- dict.initDict();
- parser->getObj(&obj);
- while (!obj.isCmd("ID") && !obj.isEOF()) {
- if (!obj.isName()) {
- error(getPos(), "Inline image dictionary key must be a name object");
- obj.free();
- parser->getObj(&obj);
- } else {
- key = copyString(obj.getName());
- obj.free();
- parser->getObj(&obj);
- if (obj.isEOF() || obj.isError())
- break;
- dict.dictAdd(key, &obj);
- }
- parser->getObj(&obj);
- }
- if (obj.isEOF())
- error(getPos(), "End of file in inline image");
- obj.free();
-
- // make stream
- str = new SubStream(parser->getStream(), &dict);
- str = str->addFilters(&dict);
-
- return str;
- }
-
- void Gfx::opImageData(Object args[], int numArgs) {
- error(getPos(), "Internal: got 'ID' operator");
- }
-
- void Gfx::opEndImage(Object args[], int numArgs) {
- error(getPos(), "Internal: got 'EI' operator");
- }
-
- //------------------------------------------------------------------------
- // type 3 font operators
- //------------------------------------------------------------------------
-
- void Gfx::opSetCharWidth(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd0' operator in content stream");
- }
-
- void Gfx::opSetCacheDevice(Object args[], int numArgs) {
- error(getPos(), "Encountered 'd1' operator in content stream");
- }
-
- //------------------------------------------------------------------------
- // compatibility operators
- //------------------------------------------------------------------------
-
- void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
- ++ignoreUndef;
- }
-
- void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
- if (ignoreUndef > 0)
- --ignoreUndef;
- }
-
- //------------------------------------------------------------------------
- // marked content operators
- //------------------------------------------------------------------------
-
- void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
- if (printCommands) {
- printf(" marked content: %s ", args[0].getName());
- if (numArgs == 2)
- args[2].print(stdout);
- printf("\n");
- }
- }
-
- void Gfx::opEndMarkedContent(Object args[], int numArgs) {
- }
-
- void Gfx::opMarkPoint(Object args[], int numArgs) {
- if (printCommands) {
- printf(" mark point: %s ", args[0].getName());
- if (numArgs == 2)
- args[2].print(stdout);
- printf("\n");
- }
- }
-