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;
114
/* make dummy GfxState for initializing color space */
116
GfxState state(72,72,&box,0,gFalse);
123
void P2PGfx::outputContents(Object *obj, P2PResourceMap *mappingTableA,
124
Dict *orgResourceA, P2PMatrix *matA)
129
mappingTable = mappingTableA;
132
if (orgResourceA != 0) {
133
orgResourceA->lookup(const_cast<char *>("ColorSpace"),&obj2);
135
orgCSResource = obj2.getDict();
136
orgCSResource->incRef();
140
if (obj->isArray()) {
141
for (i = 0; i < obj->arrayGetLength(); ++i) {
142
obj->arrayGet(i, &obj2);
143
if (!obj2.isStream()) {
144
p2pError(-1, const_cast<char *>("Weird page contents"));
150
} else if (!obj->isStream()) {
151
p2pError(-1, const_cast<char *>("Weird page contents"));
154
parser = new Parser(xref, new Lexer(xref, obj), gTrue);
163
Object args[maxArgs];
166
// scan a sequence of objects
168
parser->getObj(&obj);
169
while (!obj.isEOF()) {
171
// got a command - execute it
174
execOp(&obj, args, numArgs);
177
for (i = 0; i < numArgs; ++i)
180
} else if (numArgs < maxArgs) {
181
args[numArgs++] = obj;
183
// too many arguments - something is wrong
185
p2pError(getPos(), const_cast<char *>("Too many args in content stream"));
189
// grab the next object
190
parser->getObj(&obj);
194
// args at end with no command
196
p2pError(getPos(), const_cast<char *>("Leftover args in content stream"));
197
for (i = 0; i < numArgs; ++i)
202
void P2PGfx::outputOp(const char *name, Object args[], int numArgs)
206
for (i = 0;i < numArgs;i++) {
207
P2POutput::outputObject(&args[i],str,xref);
210
str->printf(" %s ",name);
213
void P2PGfx::execOp(Object *cmd, Object args[], int numArgs) {
220
name = cmd->getCmd();
221
if (!(op = findOp(name))) {
222
outputOp(name,args,numArgs);
228
if (op->numArgs >= 0) {
229
if (numArgs < op->numArgs) {
230
p2pError(getPos(), const_cast<char *>("Too few (%d) args to '%s' operator"),
234
if (numArgs > op->numArgs) {
235
argPtr += numArgs - op->numArgs;
236
numArgs = op->numArgs;
239
if (numArgs > -op->numArgs) {
240
p2pError(getPos(), const_cast<char *>("Too many (%d) args to '%s' operator"),
245
for (i = 0; i < numArgs; ++i) {
246
if (!checkArg(&argPtr[i], op->tchk[i])) {
248
const_cast<char *>("Arg #%d to '%s' operator is wrong type (%s)"),
249
i, name, argPtr[i].getTypeName());
255
(this->*op->func)(argPtr, numArgs);
258
P2PGfx::P2POperator *P2PGfx::findOp(char *name) {
259
int a, b, m, cmp = 1;
263
// invariant: opTab[a] < name < opTab[b]
266
cmp = strcmp(opTab[m].name, name);
279
GBool P2PGfx::checkArg(Object *arg, TchkType type) {
281
case tchkBool: return arg->isBool();
282
case tchkInt: return arg->isInt();
283
case tchkNum: return arg->isNum();
284
case tchkString: return arg->isString();
285
case tchkName: return arg->isName();
286
case tchkArray: return arg->isArray();
287
case tchkProps: return arg->isDict() || arg->isName();
288
case tchkSCN: return arg->isNum() || arg->isName();
289
case tchkNone: return gFalse;
294
int P2PGfx::getPos() {
295
return parser ? parser->getPos() : -1;
298
void P2PGfx::opSetStrokeColorSpace(Object args[], int numArgs)
300
if (mappingTable != 0) {
301
P2POutput::outputObject(&args[0],str,xref,
302
mappingTable->tables[P2PResources::ColorSpace]);
304
P2POutput::outputObject(&args[0],str,xref);
309
void P2PGfx::opXObject(Object args[], int numArgs)
311
if (mappingTable != 0) {
312
P2POutput::outputObject(&args[0],str,xref,
313
mappingTable->tables[P2PResources::XObject]);
315
P2POutput::outputObject(&args[0],str,xref);
320
void P2PGfx::opSetStrokeColorN(Object args[], int numArgs)
324
for (i = 0;i < numArgs-1;i++) {
325
P2POutput::outputObject(&args[i],str,xref);
328
if (mappingTable != 0 && args[i].isName()) {
329
P2POutput::outputObject(&args[i],str,xref,
330
mappingTable->tables[P2PResources::Pattern]);
333
P2POutput::outputObject(&args[i],str,xref);
336
if (args[i].isName() && resources != 0) {
340
char *name = args[i].getName();
341
if (mappingTable != 0
342
&& mappingTable->tables[P2PResources::Pattern] != 0) {
343
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
344
name = obj.getName();
346
resources->refPattern(name,mat);
352
void P2PGfx::opSetFont(Object args[], int numArgs)
354
if (mappingTable != 0) {
355
P2POutput::outputObject(&args[0],str,xref,
356
mappingTable->tables[P2PResources::Font]);
358
P2POutput::outputObject(&args[0],str,xref);
360
if (fontResource != 0) {
361
if (mappingTable != 0) {
362
Dict *map = mappingTable->tables[P2PResources::Font];
365
#ifdef HAVE_UGOOSTRING_H
366
UGooString nameStr(args[0].getName());
368
map->lookupNF(nameStr,&obj);
370
map->lookupNF(args[0].getName(),&obj);
373
state.setFont(fontResource->lookup(obj.getName()));
378
state.setFont(fontResource->lookup(args[0].getName()));
382
P2POutput::outputObject(&args[1],str,xref);
386
void P2PGfx::opSetFillColorSpace(Object args[], int numArgs)
388
if (mappingTable != 0) {
389
P2POutput::outputObject(&args[0],str,xref,
390
mappingTable->tables[P2PResources::ColorSpace]);
392
P2POutput::outputObject(&args[0],str,xref);
397
void P2PGfx::opSetExtGState(Object args[], int numArgs)
399
if (mappingTable != 0) {
400
P2POutput::outputObject(&args[0],str,xref,
401
mappingTable->tables[P2PResources::ExtGState]);
402
if (fontResource != 0) {
403
Dict *map = mappingTable->tables[P2PResources::ExtGState];
406
#ifdef HAVE_UGOOSTRING_H
407
UGooString nameStr(args[0].getName());
409
map->lookupNF(nameStr,&obj);
411
map->lookupNF(args[0].getName(),&obj);
414
state.setFont(fontResource->lookupExtGState(obj.getName()));
420
P2POutput::outputObject(&args[0],str,xref);
421
if (fontResource != 0) {
422
if (args[0].isName()) {
423
state.setFont(fontResource->lookupExtGState(args[0].getName()));
430
void P2PGfx::opSetFillColorN(Object args[], int numArgs)
434
for (i = 0;i < numArgs-1;i++) {
435
P2POutput::outputObject(&args[i],str,xref);
438
if (mappingTable != 0 && args[i].isName()) {
439
P2POutput::outputObject(&args[i],str,xref,
440
mappingTable->tables[P2PResources::Pattern]);
443
P2POutput::outputObject(&args[i],str,xref);
446
if (args[i].isName() && resources != 0) {
450
char *name = args[i].getName();
451
if (mappingTable != 0
452
&& mappingTable->tables[P2PResources::Pattern] != 0) {
453
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
454
name = obj.getName();
456
resources->refPattern(name,mat);
462
void P2PGfx::opShFill(Object args[], int numArgs)
464
if (mappingTable != 0) {
465
P2POutput::outputObject(&args[0],str,xref,
466
mappingTable->tables[P2PResources::Shading]);
468
P2POutput::outputObject(&args[0],str,xref);
473
void P2PGfx::opMoveSetShowText(Object args[], int numArgs)
477
if ((f = state.getFont()) != 0) f->showText(args[2].getString());
478
outputOp("\"",args,numArgs);
481
void P2PGfx::opMoveShowText(Object args[], int numArgs)
485
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
486
outputOp("'",args,numArgs);
489
void P2PGfx::opShowSpaceText(Object args[], int numArgs)
493
if ((f = state.getFont()) != 0) {
497
a = args[0].getArray();
499
for (i = 0;i < n;i++) {
503
if (obj.isString()) {
504
f->showText(obj.getString());
509
outputOp("TJ",args,numArgs);
512
void P2PGfx::opShowText(Object args[], int numArgs)
516
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
517
outputOp("Tj",args,numArgs);
520
void P2PGfx::opSave(Object args[], int numArgs)
526
void P2PGfx::opRestore(Object args[], int numArgs)
532
void P2PGfx::opBeginImage(Object args[], int numArgs)
541
/* handle dictionary */
543
parser->getObj(&obj);
544
while (!obj.isCmd(const_cast<char *>("ID")) && !obj.isEOF()) {
547
p2pError(getPos(), const_cast<char *>("Inline image dictionary key must be a name object"));
548
P2POutput::outputObject(&obj,str,xref);
552
key = copyString(obj.getName());
553
if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
554
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
555
/* when Filter or DecodeParms, not ouput because image is decoded. */
556
P2POutput::outputObject(&obj,str,xref);
560
parser->getObj(&obj);
561
if (obj.isEOF() || obj.isError()) {
565
if (mappingTable != 0 &&
566
(strcmp(key,"ColorSpace") == 0 || strcmp(key,"CS") == 0)) {
568
/* resource mapping is needed */
569
P2POutput::outputObject(&obj,str,xref,
570
mappingTable->tables[P2PResources::ColorSpace]);
571
} else if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
572
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
573
/* when Filter or DecodeParms, not ouput because image is decoded. */
574
P2POutput::outputObject(&obj,str,xref);
576
dict.dictAdd(key,&obj);
578
parser->getObj(&obj);
582
p2pError(getPos(), const_cast<char *>("End of file in inline image"));
585
} else if (obj.isError()) {
586
p2pError(getPos(), const_cast<char *>("Error in inline image"));
594
P2POutput::outputObject(&obj,str,xref);
598
/* make image stream */
599
imageStr = new EmbedStream(parser->getStream(), &dict, gFalse,0);
600
imageStr = imageStr->addFilters(&dict);
603
c1 = imageStr->getBaseStream()->getChar();
604
c2 = imageStr->getBaseStream()->getChar();
605
while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
607
c2 = imageStr->getBaseStream()->getChar();
614
void P2PGfx::doImage(Stream *istr)
622
GfxColorSpace *colorSpace = NULL;
627
// get info from the stream
631
dict = istr->getDict();
634
dict->lookup(const_cast<char *>("Width"), &obj1);
637
dict->lookup(const_cast<char *>("W"), &obj1);
641
width = obj1.getInt();
643
dict->lookup(const_cast<char *>("Height"), &obj1);
646
dict->lookup(const_cast<char *>("H"), &obj1);
650
height = obj1.getInt();
654
dict->lookup(const_cast<char *>("ImageMask"), &obj1);
657
dict->lookup(const_cast<char *>("IM"), &obj1);
661
mask = obj1.getBool();
662
else if (!obj1.isNull())
668
dict->lookup(const_cast<char *>("BitsPerComponent"), &obj1);
671
dict->lookup(const_cast<char *>("BPC"), &obj1);
674
bits = obj1.getInt();
688
dict->lookup(const_cast<char *>("ColorSpace"), &obj1);
691
dict->lookup(const_cast<char *>("CS"), &obj1);
693
if (obj1.isName() && orgCSResource != 0) {
694
orgCSResource->lookup(obj1.getName(), &obj2);
695
if (!obj2.isNull()) {
702
if (!obj1.isNull()) {
704
colorSpace = GfxColorSpace::parse(&obj1);
706
colorSpace = GfxColorSpace::parse(&obj1, NULL);
713
nComponents = colorSpace->getNComps();
717
/* number of bytes per line */
718
bytes = (bits*nComponents*width+7)/8;
720
/* then, out image body */
721
lineBuf = new Guchar[bytes];
722
for (i = 0;i < height;i++) {
723
for (j = 0;j < bytes;j++) {
724
lineBuf[j] = istr->getChar();
726
str->write(lineBuf,bytes);
736
p2pError(getPos(), const_cast<char *>("Bad image parameters"));