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
#ifdef PARSER_HAS_2_ARGS
155
parser = new Parser(xref, new Lexer(xref, obj));
157
parser = new Parser(xref, new Lexer(xref, obj), gTrue);
167
Object args[maxArgs];
170
// scan a sequence of objects
172
parser->getObj(&obj);
173
while (!obj.isEOF()) {
175
// got a command - execute it
178
execOp(&obj, args, numArgs);
181
for (i = 0; i < numArgs; ++i)
184
} else if (numArgs < maxArgs) {
185
args[numArgs++] = obj;
187
// too many arguments - something is wrong
189
p2pError(getPos(), const_cast<char *>("Too many args in content stream"));
193
// grab the next object
194
parser->getObj(&obj);
198
// args at end with no command
200
p2pError(getPos(), const_cast<char *>("Leftover args in content stream"));
201
for (i = 0; i < numArgs; ++i)
206
void P2PGfx::outputOp(const char *name, Object args[], int numArgs)
210
for (i = 0;i < numArgs;i++) {
211
P2POutput::outputObject(&args[i],str,xref);
214
str->printf(" %s ",name);
217
void P2PGfx::execOp(Object *cmd, Object args[], int numArgs) {
224
name = cmd->getCmd();
225
if (!(op = findOp(name))) {
226
outputOp(name,args,numArgs);
232
if (op->numArgs >= 0) {
233
if (numArgs < op->numArgs) {
234
p2pError(getPos(), const_cast<char *>("Too few (%d) args to '%s' operator"),
238
if (numArgs > op->numArgs) {
239
argPtr += numArgs - op->numArgs;
240
numArgs = op->numArgs;
243
if (numArgs > -op->numArgs) {
244
p2pError(getPos(), const_cast<char *>("Too many (%d) args to '%s' operator"),
249
for (i = 0; i < numArgs; ++i) {
250
if (!checkArg(&argPtr[i], op->tchk[i])) {
252
const_cast<char *>("Arg #%d to '%s' operator is wrong type (%s)"),
253
i, name, argPtr[i].getTypeName());
259
(this->*op->func)(argPtr, numArgs);
262
P2PGfx::P2POperator *P2PGfx::findOp(char *name) {
263
int a, b, m, cmp = 1;
267
// invariant: opTab[a] < name < opTab[b]
270
cmp = strcmp(opTab[m].name, name);
283
GBool P2PGfx::checkArg(Object *arg, TchkType type) {
285
case tchkBool: return arg->isBool();
286
case tchkInt: return arg->isInt();
287
case tchkNum: return arg->isNum();
288
case tchkString: return arg->isString();
289
case tchkName: return arg->isName();
290
case tchkArray: return arg->isArray();
291
case tchkProps: return arg->isDict() || arg->isName();
292
case tchkSCN: return arg->isNum() || arg->isName();
293
case tchkNone: return gFalse;
298
int P2PGfx::getPos() {
299
return parser ? parser->getPos() : -1;
302
void P2PGfx::opSetStrokeColorSpace(Object args[], int numArgs)
304
if (mappingTable != 0) {
305
P2POutput::outputObject(&args[0],str,xref,
306
mappingTable->tables[P2PResources::ColorSpace]);
308
P2POutput::outputObject(&args[0],str,xref);
313
void P2PGfx::opXObject(Object args[], int numArgs)
315
if (mappingTable != 0) {
316
P2POutput::outputObject(&args[0],str,xref,
317
mappingTable->tables[P2PResources::XObject]);
319
P2POutput::outputObject(&args[0],str,xref);
324
void P2PGfx::opSetStrokeColorN(Object args[], int numArgs)
328
for (i = 0;i < numArgs-1;i++) {
329
P2POutput::outputObject(&args[i],str,xref);
332
if (mappingTable != 0 && args[i].isName()) {
333
P2POutput::outputObject(&args[i],str,xref,
334
mappingTable->tables[P2PResources::Pattern]);
337
P2POutput::outputObject(&args[i],str,xref);
340
if (args[i].isName() && resources != 0) {
344
char *name = args[i].getName();
345
if (mappingTable != 0
346
&& mappingTable->tables[P2PResources::Pattern] != 0) {
347
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
348
name = obj.getName();
350
resources->refPattern(name,mat);
356
void P2PGfx::opSetFont(Object args[], int numArgs)
358
if (mappingTable != 0) {
359
P2POutput::outputObject(&args[0],str,xref,
360
mappingTable->tables[P2PResources::Font]);
362
P2POutput::outputObject(&args[0],str,xref);
364
if (fontResource != 0) {
365
if (mappingTable != 0) {
366
Dict *map = mappingTable->tables[P2PResources::Font];
369
#ifdef HAVE_UGOOSTRING_H
370
UGooString nameStr(args[0].getName());
372
map->lookupNF(nameStr,&obj);
374
map->lookupNF(args[0].getName(),&obj);
377
state.setFont(fontResource->lookup(obj.getName()));
382
state.setFont(fontResource->lookup(args[0].getName()));
386
P2POutput::outputObject(&args[1],str,xref);
390
void P2PGfx::opSetFillColorSpace(Object args[], int numArgs)
392
if (mappingTable != 0) {
393
P2POutput::outputObject(&args[0],str,xref,
394
mappingTable->tables[P2PResources::ColorSpace]);
396
P2POutput::outputObject(&args[0],str,xref);
401
void P2PGfx::opSetExtGState(Object args[], int numArgs)
403
if (mappingTable != 0) {
404
P2POutput::outputObject(&args[0],str,xref,
405
mappingTable->tables[P2PResources::ExtGState]);
406
if (fontResource != 0) {
407
Dict *map = mappingTable->tables[P2PResources::ExtGState];
410
#ifdef HAVE_UGOOSTRING_H
411
UGooString nameStr(args[0].getName());
413
map->lookupNF(nameStr,&obj);
415
map->lookupNF(args[0].getName(),&obj);
418
state.setFont(fontResource->lookupExtGState(obj.getName()));
424
P2POutput::outputObject(&args[0],str,xref);
425
if (fontResource != 0) {
426
if (args[0].isName()) {
427
state.setFont(fontResource->lookupExtGState(args[0].getName()));
434
void P2PGfx::opSetFillColorN(Object args[], int numArgs)
438
for (i = 0;i < numArgs-1;i++) {
439
P2POutput::outputObject(&args[i],str,xref);
442
if (mappingTable != 0 && args[i].isName()) {
443
P2POutput::outputObject(&args[i],str,xref,
444
mappingTable->tables[P2PResources::Pattern]);
447
P2POutput::outputObject(&args[i],str,xref);
450
if (args[i].isName() && resources != 0) {
454
char *name = args[i].getName();
455
if (mappingTable != 0
456
&& mappingTable->tables[P2PResources::Pattern] != 0) {
457
mappingTable->tables[P2PResources::Pattern]->lookup(name,&obj);
458
name = obj.getName();
460
resources->refPattern(name,mat);
466
void P2PGfx::opShFill(Object args[], int numArgs)
468
if (mappingTable != 0) {
469
P2POutput::outputObject(&args[0],str,xref,
470
mappingTable->tables[P2PResources::Shading]);
472
P2POutput::outputObject(&args[0],str,xref);
477
void P2PGfx::opMoveSetShowText(Object args[], int numArgs)
481
if ((f = state.getFont()) != 0) f->showText(args[2].getString());
482
outputOp("\"",args,numArgs);
485
void P2PGfx::opMoveShowText(Object args[], int numArgs)
489
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
490
outputOp("'",args,numArgs);
493
void P2PGfx::opShowSpaceText(Object args[], int numArgs)
497
if ((f = state.getFont()) != 0) {
501
a = args[0].getArray();
503
for (i = 0;i < n;i++) {
507
if (obj.isString()) {
508
f->showText(obj.getString());
513
outputOp("TJ",args,numArgs);
516
void P2PGfx::opShowText(Object args[], int numArgs)
520
if ((f = state.getFont()) != 0) f->showText(args[0].getString());
521
outputOp("Tj",args,numArgs);
524
void P2PGfx::opSave(Object args[], int numArgs)
530
void P2PGfx::opRestore(Object args[], int numArgs)
536
void P2PGfx::opBeginImage(Object args[], int numArgs)
545
/* handle dictionary */
547
parser->getObj(&obj);
548
while (!obj.isCmd(const_cast<char *>("ID")) && !obj.isEOF()) {
551
p2pError(getPos(), const_cast<char *>("Inline image dictionary key must be a name object"));
552
P2POutput::outputObject(&obj,str,xref);
556
key = copyString(obj.getName());
557
if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
558
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
559
/* when Filter or DecodeParms, not ouput because image is decoded. */
560
P2POutput::outputObject(&obj,str,xref);
564
parser->getObj(&obj);
565
if (obj.isEOF() || obj.isError()) {
569
if (mappingTable != 0 &&
570
(strcmp(key,"ColorSpace") == 0 || strcmp(key,"CS") == 0)) {
572
/* resource mapping is needed */
573
P2POutput::outputObject(&obj,str,xref,
574
mappingTable->tables[P2PResources::ColorSpace]);
575
} else if (strcmp("Filter",key) != 0 && strcmp("F",key) != 0
576
&& strcmp("DecodeParms",key) != 0 && strcmp("DP",key) != 0) {
577
/* when Filter or DecodeParms, not ouput because image is decoded. */
578
P2POutput::outputObject(&obj,str,xref);
580
dict.dictAdd(key,&obj);
582
parser->getObj(&obj);
586
p2pError(getPos(), const_cast<char *>("End of file in inline image"));
589
} else if (obj.isError()) {
590
p2pError(getPos(), const_cast<char *>("Error in inline image"));
598
P2POutput::outputObject(&obj,str,xref);
602
/* make image stream */
603
imageStr = new EmbedStream(parser->getStream(), &dict, gFalse,0);
604
imageStr = imageStr->addFilters(&dict);
607
c1 = imageStr->getBaseStream()->getChar();
608
c2 = imageStr->getBaseStream()->getChar();
609
while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
611
c2 = imageStr->getBaseStream()->getChar();
618
void P2PGfx::doImage(Stream *istr)
626
GfxColorSpace *colorSpace = NULL;
631
// get info from the stream
635
dict = istr->getDict();
638
dict->lookup(const_cast<char *>("Width"), &obj1);
641
dict->lookup(const_cast<char *>("W"), &obj1);
645
width = obj1.getInt();
647
dict->lookup(const_cast<char *>("Height"), &obj1);
650
dict->lookup(const_cast<char *>("H"), &obj1);
654
height = obj1.getInt();
658
dict->lookup(const_cast<char *>("ImageMask"), &obj1);
661
dict->lookup(const_cast<char *>("IM"), &obj1);
665
mask = obj1.getBool();
666
else if (!obj1.isNull())
672
dict->lookup(const_cast<char *>("BitsPerComponent"), &obj1);
675
dict->lookup(const_cast<char *>("BPC"), &obj1);
678
bits = obj1.getInt();
692
dict->lookup(const_cast<char *>("ColorSpace"), &obj1);
695
dict->lookup(const_cast<char *>("CS"), &obj1);
697
if (obj1.isName() && orgCSResource != 0) {
698
orgCSResource->lookup(obj1.getName(), &obj2);
699
if (!obj2.isNull()) {
706
if (!obj1.isNull()) {
708
colorSpace = GfxColorSpace::parse(&obj1);
710
colorSpace = GfxColorSpace::parse(&obj1, NULL);
717
nComponents = colorSpace->getNComps();
721
/* number of bytes per line */
722
bytes = (bits*nComponents*width+7)/8;
724
/* then, out image body */
725
lineBuf = new Guchar[bytes];
726
for (i = 0;i < height;i++) {
727
for (j = 0;j < bytes;j++) {
728
lineBuf[j] = istr->getChar();
730
str->write(lineBuf,bytes);
740
p2pError(getPos(), const_cast<char *>("Bad image parameters"));