3
developped by BBR Inc. 2006-2007
5
This file is based on Gfx.cc
6
Gfx.cc copyright notice is follows
7
and is licensed under GPL.
9
//========================================================================
13
// Copyright 1996-2003 Glyph & Cog, LLC
15
//========================================================================
20
#ifdef USE_GCC_PRAGMAS
21
#pragma implementation
30
#include "goo/GooTimer.h"
31
#include "goo/GooHash.h"
32
#include "GlobalParams.h"
33
#include "CharTypes.h"
42
#include "OutputDev.h"
46
#include "ProfileData.h"
47
#include "UGooString.h"
49
#include "P2POutputStream.h"
50
#include "P2POutput.h"
51
#include "P2PResources.h"
53
//------------------------------------------------------------------------
55
//------------------------------------------------------------------------
57
#ifdef WIN32 // this works around a bug in the VC7 compiler
58
# pragma optimize("",off)
61
P2PGfx::P2POperator P2PGfx::opTab[] = {
62
{"\"", 3, {tchkNum, tchkNum, tchkString},
63
&P2PGfx::opMoveSetShowText},
64
{"'", 1, {tchkString},
65
&P2PGfx::opMoveShowText},
67
&P2PGfx::opBeginImage},
69
&P2PGfx::opSetStrokeColorSpace},
74
{"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
76
&P2PGfx::opSetStrokeColorN},
77
{"TJ", 1, {tchkArray},
78
&P2PGfx::opShowSpaceText},
79
{"Tf", 2, {tchkName, tchkNum},
81
{"Tj", 1, {tchkString},
84
&P2PGfx::opSetFillColorSpace},
86
&P2PGfx::opSetExtGState},
89
{"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
91
&P2PGfx::opSetFillColorN},
96
#ifdef WIN32 // this works around a bug in the VC7 compiler
97
# pragma optimize("",on)
100
#define numOps (sizeof(opTab) / sizeof(P2POperator))
102
//------------------------------------------------------------------------
104
//------------------------------------------------------------------------
106
P2PGfx::P2PGfx(XRef *xrefA, P2POutputStream *strA,
107
P2PFontResource *fontResourceA, P2PResources *resourcesA)
111
fontResource = fontResourceA;
112
resources = resourcesA;
118
void P2PGfx::outputContents(Object *obj, P2PResourceMap *mappingTableA,
119
Dict *orgResourceA, P2PMatrix *matA)
124
mappingTable = mappingTableA;
127
if (orgResourceA != 0) {
128
orgResourceA->lookup(const_cast<char *>("ColorSpace"),&obj2);
130
orgCSResource = obj2.getDict();
131
orgCSResource->incRef();
135
if (obj->isArray()) {
136
for (i = 0; i < obj->arrayGetLength(); ++i) {
137
obj->arrayGet(i, &obj2);
138
if (!obj2.isStream()) {
139
error(-1, const_cast<char *>("Weird page contents"));
145
} else if (!obj->isStream()) {
146
error(-1, const_cast<char *>("Weird page contents"));
149
#ifdef PARSER_HAS_2_ARGS
150
parser = new Parser(xref, new Lexer(xref, obj));
152
parser = new Parser(xref, new Lexer(xref, obj), gTrue);
162
Object args[maxArgs];
165
// scan a sequence of objects
167
parser->getObj(&obj);
168
while (!obj.isEOF()) {
170
// got a command - execute it
173
execOp(&obj, args, numArgs);
176
for (i = 0; i < numArgs; ++i)
179
} else if (numArgs < maxArgs) {
180
args[numArgs++] = obj;
182
// too many arguments - something is wrong
184
error(getPos(), const_cast<char *>("Too many args in content stream"));
188
// grab the next object
189
parser->getObj(&obj);
193
// args at end with no command
195
error(getPos(), const_cast<char *>("Leftover args in content stream"));
196
for (i = 0; i < numArgs; ++i)
201
void P2PGfx::outputOp(const char *name, Object args[], int numArgs)
205
for (i = 0;i < numArgs;i++) {
206
P2POutput::outputObject(&args[i],str,xref);
209
str->printf(" %s ",name);
212
void P2PGfx::execOp(Object *cmd, Object args[], int numArgs) {
219
name = cmd->getCmd();
220
if (!(op = findOp(name))) {
221
outputOp(name,args,numArgs);
227
if (op->numArgs >= 0) {
228
if (numArgs < op->numArgs) {
229
error(getPos(), const_cast<char *>("Too few (%d) args to '%s' operator"),
233
if (numArgs > op->numArgs) {
234
argPtr += numArgs - op->numArgs;
235
numArgs = op->numArgs;
238
if (numArgs > -op->numArgs) {
239
error(getPos(), const_cast<char *>("Too many (%d) args to '%s' operator"),
244
for (i = 0; i < numArgs; ++i) {
245
if (!checkArg(&argPtr[i], op->tchk[i])) {
247
const_cast<char *>("Arg #%d to '%s' operator is wrong type (%s)"),
248
i, name, argPtr[i].getTypeName());
254
(this->*op->func)(argPtr, numArgs);
257
P2PGfx::P2POperator *P2PGfx::findOp(char *name) {
258
int a, b, m, cmp = 1;
262
// invariant: opTab[a] < name < opTab[b]
265
cmp = strcmp(opTab[m].name, name);
278
GBool P2PGfx::checkArg(Object *arg, TchkType type) {
280
case tchkBool: return arg->isBool();
281
case tchkInt: return arg->isInt();
282
case tchkNum: return arg->isNum();
283
case tchkString: return arg->isString();
284
case tchkName: return arg->isName();
285
case tchkArray: return arg->isArray();
286
case tchkProps: return arg->isDict() || arg->isName();
287
case tchkSCN: return arg->isNum() || arg->isName();
288
case tchkNone: return gFalse;
293
int P2PGfx::getPos() {
294
return parser ? parser->getPos() : -1;
297
void P2PGfx::opSetStrokeColorSpace(Object args[], int numArgs)
299
if (mappingTable != 0) {
300
P2POutput::outputObject(&args[0],str,xref,
301
mappingTable->tables[P2PResources::ColorSpace]);
303
P2POutput::outputObject(&args[0],str,xref);
308
void P2PGfx::opXObject(Object args[], int numArgs)
310
if (mappingTable != 0) {
311
P2POutput::outputObject(&args[0],str,xref,
312
mappingTable->tables[P2PResources::XObject]);
314
P2POutput::outputObject(&args[0],str,xref);
319
void P2PGfx::opSetStrokeColorN(Object args[], int numArgs)
323
for (i = 0;i < numArgs-1;i++) {
324
P2POutput::outputObject(&args[i],str,xref);
327
if (mappingTable != 0 && args[i].isName()) {
328
P2POutput::outputObject(&args[i],str,xref,
329
mappingTable->tables[P2PResources::Pattern]);
332
P2POutput::outputObject(&args[i],str,xref);
335
if (args[i].isName() && resources != 0) {
339
char *name = args[i].getName();
340
if (mappingTable != 0
341
&& mappingTable->tables[P2PResources::Pattern] != 0) {
342
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
343
name = obj.getName();
345
resources->refPattern(name,mat);
351
void P2PGfx::opSetFont(Object args[], int numArgs)
353
if (mappingTable != 0) {
354
P2POutput::outputObject(&args[0],str,xref,
355
mappingTable->tables[P2PResources::Font]);
357
P2POutput::outputObject(&args[0],str,xref);
359
if (fontResource != 0) {
360
if (mappingTable != 0) {
361
Dict *map = mappingTable->tables[P2PResources::Font];
364
#ifdef HAVE_UGOOSTRING_H
365
UGooString nameStr(args[0].getName());
367
map->lookupNF(nameStr,&obj);
369
map->lookupNF(args[0].getName(),&obj);
372
state.setFont(fontResource->lookup(obj.getName()));
377
state.setFont(fontResource->lookup(args[0].getName()));
381
P2POutput::outputObject(&args[1],str,xref);
385
void P2PGfx::opSetFillColorSpace(Object args[], int numArgs)
387
if (mappingTable != 0) {
388
P2POutput::outputObject(&args[0],str,xref,
389
mappingTable->tables[P2PResources::ColorSpace]);
391
P2POutput::outputObject(&args[0],str,xref);
396
void P2PGfx::opSetExtGState(Object args[], int numArgs)
398
if (mappingTable != 0) {
399
P2POutput::outputObject(&args[0],str,xref,
400
mappingTable->tables[P2PResources::ExtGState]);
401
if (fontResource != 0) {
402
Dict *map = mappingTable->tables[P2PResources::ExtGState];
405
#ifdef HAVE_UGOOSTRING_H
406
UGooString nameStr(args[0].getName());
408
map->lookupNF(nameStr,&obj);
410
map->lookupNF(args[0].getName(),&obj);
413
state.setFont(fontResource->lookupExtGState(obj.getName()));
419
P2POutput::outputObject(&args[0],str,xref);
420
if (fontResource != 0) {
421
if (args[0].isName()) {
422
state.setFont(fontResource->lookupExtGState(args[0].getName()));
429
void P2PGfx::opSetFillColorN(Object args[], int numArgs)
433
for (i = 0;i < numArgs-1;i++) {
434
P2POutput::outputObject(&args[i],str,xref);
437
if (mappingTable != 0 && args[i].isName()) {
438
P2POutput::outputObject(&args[i],str,xref,
439
mappingTable->tables[P2PResources::Pattern]);
442
P2POutput::outputObject(&args[i],str,xref);
445
if (args[i].isName() && resources != 0) {
449
char *name = args[i].getName();
450
if (mappingTable != 0
451
&& mappingTable->tables[P2PResources::Pattern] != 0) {
452
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
453
name = obj.getName();
455
resources->refPattern(name,mat);
461
void P2PGfx::opShFill(Object args[], int numArgs)
463
if (mappingTable != 0) {
464
P2POutput::outputObject(&args[0],str,xref,
465
mappingTable->tables[P2PResources::Shading]);
467
P2POutput::outputObject(&args[0],str,xref);
472
void P2PGfx::opMoveSetShowText(Object args[], int numArgs)
476
if ((f = state.getFont()) != 0) f->showText(args[2].getString());
477
outputOp("\"",args,numArgs);
480
void P2PGfx::opMoveShowText(Object args[], int numArgs)
484
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
485
outputOp("'",args,numArgs);
488
void P2PGfx::opShowSpaceText(Object args[], int numArgs)
492
if ((f = state.getFont()) != 0) {
496
a = args[0].getArray();
498
for (i = 0;i < n;i++) {
502
if (obj.isString()) {
503
f->showText(obj.getString());
508
outputOp("TJ",args,numArgs);
511
void P2PGfx::opShowText(Object args[], int numArgs)
515
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
516
outputOp("Tj",args,numArgs);
519
void P2PGfx::opSave(Object args[], int numArgs)
525
void P2PGfx::opRestore(Object args[], int numArgs)
531
void P2PGfx::opBeginImage(Object args[], int numArgs)
540
/* handle dictionary */
542
parser->getObj(&obj);
543
while (!obj.isCmd(const_cast<char *>("ID")) && !obj.isEOF()) {
546
error(getPos(), const_cast<char *>("Inline image dictionary key must be a name object"));
547
P2POutput::outputObject(&obj,str,xref);
551
key = copyString(obj.getName());
552
if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
553
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
554
/* when Filter or DecodeParms, not ouput because image is decoded. */
555
P2POutput::outputObject(&obj,str,xref);
559
parser->getObj(&obj);
560
if (obj.isEOF() || obj.isError()) {
564
if (mappingTable != 0 &&
565
(strcmp(key,"ColorSpace") == 0 || strcmp(key,"CS") == 0)) {
567
/* resource mapping is needed */
568
P2POutput::outputObject(&obj,str,xref,
569
mappingTable->tables[P2PResources::ColorSpace]);
570
} else if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
571
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
572
/* when Filter or DecodeParms, not ouput because image is decoded. */
573
P2POutput::outputObject(&obj,str,xref);
575
dict.dictAdd(key,&obj);
577
parser->getObj(&obj);
581
error(getPos(), const_cast<char *>("End of file in inline image"));
584
} else if (obj.isError()) {
585
error(getPos(), const_cast<char *>("Error in inline image"));
593
P2POutput::outputObject(&obj,str,xref);
597
/* make image stream */
598
imageStr = new EmbedStream(parser->getStream(), &dict, gFalse,0);
599
imageStr = imageStr->addFilters(&dict);
602
c1 = imageStr->getBaseStream()->getChar();
603
c2 = imageStr->getBaseStream()->getChar();
604
while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
606
c2 = imageStr->getBaseStream()->getChar();
613
void P2PGfx::doImage(Stream *istr)
621
GfxColorSpace *colorSpace = NULL;
626
// get info from the stream
630
dict = istr->getDict();
633
dict->lookup(const_cast<char *>("Width"), &obj1);
636
dict->lookup(const_cast<char *>("W"), &obj1);
640
width = obj1.getInt();
642
dict->lookup(const_cast<char *>("Height"), &obj1);
645
dict->lookup(const_cast<char *>("H"), &obj1);
649
height = obj1.getInt();
653
dict->lookup(const_cast<char *>("ImageMask"), &obj1);
656
dict->lookup(const_cast<char *>("IM"), &obj1);
660
mask = obj1.getBool();
661
else if (!obj1.isNull())
667
dict->lookup(const_cast<char *>("BitsPerComponent"), &obj1);
670
dict->lookup(const_cast<char *>("BPC"), &obj1);
673
bits = obj1.getInt();
687
dict->lookup(const_cast<char *>("ColorSpace"), &obj1);
690
dict->lookup(const_cast<char *>("CS"), &obj1);
692
if (obj1.isName() && orgCSResource != 0) {
693
orgCSResource->lookup(obj1.getName(), &obj2);
694
if (!obj2.isNull()) {
701
if (!obj1.isNull()) {
702
colorSpace = GfxColorSpace::parse(&obj1);
708
nComponents = colorSpace->getNComps();
712
/* number of bytes per line */
713
bytes = (bits*nComponents*width+7)/8;
715
/* then, out image body */
716
lineBuf = new Guchar[bytes];
717
for (i = 0;i < height;i++) {
718
for (j = 0;j < bytes;j++) {
719
lineBuf[j] = istr->getChar();
721
str->write(lineBuf,bytes);
731
error(getPos(), const_cast<char *>("Bad image parameters"));