~ubuntu-branches/ubuntu/jaunty/cups/jaunty

« back to all changes in this revision

Viewing changes to debian/local/filters/pdf-filters/pdftopdf/P2PGfx.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt, Till Kamppeter, Martin Pitt
  • Date: 2009-02-15 18:39:03 UTC
  • mfrom: (6.1.30 jaunty)
  • Revision ID: james.westby@ubuntu.com-20090215183903-i0nhvqyqj4vyn52a
Tags: 1.3.9-13
[ Till Kamppeter ]
* debian/local/filters/pdf-filters/filter/imagetopdf.c: Added support for
  the new "fit-to-page" option (new, more intuitive name for "fitplot").
* debian/filters/pstopdf: Only apply paper size if the "fitplot" or the
  "fit-to-page" option is set.
* debian/local/filters/cpdftocps: Only the last digit of the number of
  copies was used (LP: #309314).
* debian/local/filters/pdf-filters/pdftopdf/pdftopdf.cxx: Do not preceed the
  PDF output with a newline (LP: #303691). Only impose the page size from
  the PPD file to all pages if the "fitplot" or the "fit-to-page" option is 
  set. This prevented from automatic paper tray switching to the correct paper
  sizes when a multiple-page-size document is printed (partial fix for
  LP: #310575).
* debian/patches/pdftops-cups-1.4.dpatch: Updated from CUPS 1.4 SVN. Contains
  fixes for multiple-page-size document printing (partial fix for
  LP: #310575).
* debian/patches/pdftops-dont_fail_on_cancel.dpatch: Removed, should be
  fixed in the new upstream version of pdftops.

[ Martin Pitt ]
* debian/patches/pdftops-cups-1.4.dpatch: Add definition of
  HAVE_PDFTOPS and CUPS_PDFTOPS, so that the filter actually gets
  again built with pdftops support. (Fixes Till's change from above).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
  P2PGfx.cc
 
3
  developped by BBR Inc. 2006-2007
 
4
 
 
5
  This file is based on Gfx.cc
 
6
  Gfx.cc copyright notice is follows
 
7
  and is licensed under GPL.
 
8
*/
 
9
//========================================================================
 
10
//
 
11
// Gfx.cc
 
12
//
 
13
// Copyright 1996-2003 Glyph & Cog, LLC
 
14
//
 
15
//========================================================================
 
16
 
 
17
#include <config.h>
 
18
 
 
19
 
 
20
#ifdef USE_GCC_PRAGMAS
 
21
#pragma implementation
 
22
#endif
 
23
 
 
24
#include <stdlib.h>
 
25
#include <stdio.h>
 
26
#include <stddef.h>
 
27
#include <string.h>
 
28
#include <math.h>
 
29
#include "goo/gmem.h"
 
30
#include "goo/GooTimer.h"
 
31
#include "goo/GooHash.h"
 
32
#include "GlobalParams.h"
 
33
#include "CharTypes.h"
 
34
#include "Object.h"
 
35
#include "Array.h"
 
36
#include "Dict.h"
 
37
#include "Stream.h"
 
38
#include "Lexer.h"
 
39
#include "Parser.h"
 
40
#include "GfxFont.h"
 
41
#include "GfxState.h"
 
42
#include "OutputDev.h"
 
43
#include "Page.h"
 
44
#include "Error.h"
 
45
#include "Gfx.h"
 
46
#include "ProfileData.h"
 
47
#include "UGooString.h"
 
48
#include "P2PGfx.h"
 
49
#include "P2POutputStream.h"
 
50
#include "P2POutput.h"
 
51
#include "P2PResources.h"
 
52
 
 
53
//------------------------------------------------------------------------
 
54
// Operator table
 
55
//------------------------------------------------------------------------
 
56
 
 
57
#ifdef WIN32 // this works around a bug in the VC7 compiler
 
58
#  pragma optimize("",off)
 
59
#endif
 
60
 
 
61
P2PGfx::P2POperator P2PGfx::opTab[] = {
 
62
  {"\"",  3, {tchkNum,    tchkNum,    tchkString},
 
63
            &P2PGfx::opMoveSetShowText},
 
64
  {"'",   1, {tchkString},
 
65
            &P2PGfx::opMoveShowText},
 
66
  {"BI",  0, {tchkNone},
 
67
          &P2PGfx::opBeginImage},
 
68
  {"CS",  1, {tchkName},
 
69
          &P2PGfx::opSetStrokeColorSpace},
 
70
  {"Do",  1, {tchkName},
 
71
          &P2PGfx::opXObject},
 
72
  {"Q",   0, {tchkNone},
 
73
          &P2PGfx::opRestore},
 
74
  {"SCN", -5, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
 
75
               tchkSCN},
 
76
          &P2PGfx::opSetStrokeColorN},
 
77
  {"TJ",  1, {tchkArray},
 
78
            &P2PGfx::opShowSpaceText},
 
79
  {"Tf",  2, {tchkName,   tchkNum},
 
80
          &P2PGfx::opSetFont},
 
81
  {"Tj",  1, {tchkString},
 
82
            &P2PGfx::opShowText},
 
83
  {"cs",  1, {tchkName},
 
84
          &P2PGfx::opSetFillColorSpace},
 
85
  {"gs",  1, {tchkName},
 
86
          &P2PGfx::opSetExtGState},
 
87
  {"q",   0, {tchkNone},
 
88
            &P2PGfx::opSave},
 
89
  {"scn", -5, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
 
90
               tchkSCN},
 
91
          &P2PGfx::opSetFillColorN},
 
92
  {"sh",  1, {tchkName},
 
93
          &P2PGfx::opShFill},
 
94
};
 
95
 
 
96
#ifdef WIN32 // this works around a bug in the VC7 compiler
 
97
#  pragma optimize("",on)
 
98
#endif
 
99
 
 
100
#define numOps (sizeof(opTab) / sizeof(P2POperator))
 
101
 
 
102
//------------------------------------------------------------------------
 
103
// P2PGfx
 
104
//------------------------------------------------------------------------
 
105
 
 
106
P2PGfx::P2PGfx(XRef *xrefA, P2POutputStream *strA,
 
107
  P2PFontResource *fontResourceA, P2PResources *resourcesA)
 
108
{
 
109
  xref = xrefA;
 
110
  str = strA;
 
111
  fontResource = fontResourceA;
 
112
  resources = resourcesA;
 
113
}
 
114
 
 
115
P2PGfx::~P2PGfx() {
 
116
}
 
117
 
 
118
void P2PGfx::outputContents(Object *obj, P2PResourceMap *mappingTableA,
 
119
  Dict *orgResourceA, P2PMatrix *matA)
 
120
{
 
121
  Object obj2;
 
122
  int i;
 
123
 
 
124
  mappingTable = mappingTableA;
 
125
  mat = matA;
 
126
  orgCSResource = 0;
 
127
  if (orgResourceA != 0) {
 
128
    orgResourceA->lookup(const_cast<char *>("ColorSpace"),&obj2);
 
129
    if (obj2.isDict()) {
 
130
      orgCSResource = obj2.getDict();
 
131
      orgCSResource->incRef();
 
132
    }
 
133
  }
 
134
  obj2.free();
 
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"));
 
140
        obj2.free();
 
141
        return;
 
142
      }
 
143
      obj2.free();
 
144
    }
 
145
  } else if (!obj->isStream()) {
 
146
    error(-1, const_cast<char *>("Weird page contents"));
 
147
    return;
 
148
  }
 
149
#ifdef PARSER_HAS_2_ARGS
 
150
  parser = new Parser(xref, new Lexer(xref, obj));
 
151
#else
 
152
  parser = new Parser(xref, new Lexer(xref, obj), gTrue);
 
153
#endif
 
154
  go();
 
155
  delete parser;
 
156
  parser = NULL;
 
157
}
 
158
 
 
159
void P2PGfx::go()
 
160
{
 
161
  Object obj;
 
162
  Object args[maxArgs];
 
163
  int numArgs, i;
 
164
 
 
165
  // scan a sequence of objects
 
166
  numArgs = 0;
 
167
  parser->getObj(&obj);
 
168
  while (!obj.isEOF()) {
 
169
 
 
170
    // got a command - execute it
 
171
    if (obj.isCmd()) {
 
172
      // Run the operation
 
173
      execOp(&obj, args, numArgs);
 
174
 
 
175
      obj.free();
 
176
      for (i = 0; i < numArgs; ++i)
 
177
        args[i].free();
 
178
      numArgs = 0;
 
179
    } else if (numArgs < maxArgs) {
 
180
      args[numArgs++] = obj;
 
181
 
 
182
    // too many arguments - something is wrong
 
183
    } else {
 
184
      error(getPos(), const_cast<char *>("Too many args in content stream"));
 
185
      obj.free();
 
186
    }
 
187
 
 
188
    // grab the next object
 
189
    parser->getObj(&obj);
 
190
  }
 
191
  obj.free();
 
192
 
 
193
  // args at end with no command
 
194
  if (numArgs > 0) {
 
195
    error(getPos(), const_cast<char *>("Leftover args in content stream"));
 
196
    for (i = 0; i < numArgs; ++i)
 
197
      args[i].free();
 
198
  }
 
199
}
 
200
 
 
201
void P2PGfx::outputOp(const char *name, Object args[], int numArgs)
 
202
{
 
203
  int i;
 
204
 
 
205
  for (i = 0;i < numArgs;i++) {
 
206
    P2POutput::outputObject(&args[i],str,xref);
 
207
    str->putchar(' ');
 
208
  }
 
209
  str->printf(" %s ",name);
 
210
}
 
211
 
 
212
void P2PGfx::execOp(Object *cmd, Object args[], int numArgs) {
 
213
  P2POperator *op;
 
214
  char *name;
 
215
  Object *argPtr;
 
216
  int i;
 
217
 
 
218
  // find operator
 
219
  name = cmd->getCmd();
 
220
  if (!(op = findOp(name))) {
 
221
    outputOp(name,args,numArgs);
 
222
    return;
 
223
  }
 
224
 
 
225
  // type check args
 
226
  argPtr = args;
 
227
  if (op->numArgs >= 0) {
 
228
    if (numArgs < op->numArgs) {
 
229
      error(getPos(), const_cast<char *>("Too few (%d) args to '%s' operator"),
 
230
         numArgs, name);
 
231
      return;
 
232
    }
 
233
    if (numArgs > op->numArgs) {
 
234
      argPtr += numArgs - op->numArgs;
 
235
      numArgs = op->numArgs;
 
236
    }
 
237
  } else {
 
238
    if (numArgs > -op->numArgs) {
 
239
      error(getPos(), const_cast<char *>("Too many (%d) args to '%s' operator"),
 
240
            numArgs, name);
 
241
      return;
 
242
    }
 
243
  }
 
244
  for (i = 0; i < numArgs; ++i) {
 
245
    if (!checkArg(&argPtr[i], op->tchk[i])) {
 
246
      error(getPos(),
 
247
            const_cast<char *>("Arg #%d to '%s' operator is wrong type (%s)"),
 
248
            i, name, argPtr[i].getTypeName());
 
249
      return;
 
250
    }
 
251
  }
 
252
 
 
253
  // do it
 
254
  (this->*op->func)(argPtr, numArgs);
 
255
}
 
256
 
 
257
P2PGfx::P2POperator *P2PGfx::findOp(char *name) {
 
258
  int a, b, m, cmp = 1;
 
259
 
 
260
  a = -1;
 
261
  b = numOps;
 
262
  // invariant: opTab[a] < name < opTab[b]
 
263
  while (b - a > 1) {
 
264
    m = (a + b) / 2;
 
265
    cmp = strcmp(opTab[m].name, name);
 
266
    if (cmp < 0)
 
267
      a = m;
 
268
    else if (cmp > 0)
 
269
      b = m;
 
270
    else
 
271
      a = b = m;
 
272
  }
 
273
  if (cmp != 0)
 
274
    return NULL;
 
275
  return &opTab[a];
 
276
}
 
277
 
 
278
GBool P2PGfx::checkArg(Object *arg, TchkType type) {
 
279
  switch (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;
 
289
  }
 
290
  return gFalse;
 
291
}
 
292
 
 
293
int P2PGfx::getPos() {
 
294
  return parser ? parser->getPos() : -1;
 
295
}
 
296
 
 
297
void P2PGfx::opSetStrokeColorSpace(Object args[], int numArgs)
 
298
{
 
299
  if (mappingTable != 0) {
 
300
    P2POutput::outputObject(&args[0],str,xref,
 
301
      mappingTable->tables[P2PResources::ColorSpace]);
 
302
  } else {
 
303
    P2POutput::outputObject(&args[0],str,xref);
 
304
  }
 
305
  str->puts(" CS ");
 
306
}
 
307
 
 
308
void P2PGfx::opXObject(Object args[], int numArgs)
 
309
{
 
310
  if (mappingTable != 0) {
 
311
    P2POutput::outputObject(&args[0],str,xref,
 
312
      mappingTable->tables[P2PResources::XObject]);
 
313
  } else {
 
314
    P2POutput::outputObject(&args[0],str,xref);
 
315
  }
 
316
  str->puts(" Do ");
 
317
}
 
318
 
 
319
void P2PGfx::opSetStrokeColorN(Object args[], int numArgs)
 
320
{
 
321
  int i;
 
322
 
 
323
  for (i = 0;i < numArgs-1;i++) {
 
324
    P2POutput::outputObject(&args[i],str,xref);
 
325
    str->putchar(' ');
 
326
  }
 
327
  if (mappingTable != 0 && args[i].isName()) {
 
328
    P2POutput::outputObject(&args[i],str,xref,
 
329
      mappingTable->tables[P2PResources::Pattern]);
 
330
    str->putchar(' ');
 
331
  } else {
 
332
    P2POutput::outputObject(&args[i],str,xref);
 
333
    str->putchar(' ');
 
334
  }
 
335
  if (args[i].isName() && resources != 0) {
 
336
    /* check pattern */
 
337
    Object obj;
 
338
 
 
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();
 
344
    }
 
345
    resources->refPattern(name,mat);
 
346
    obj.free();
 
347
  }
 
348
  str->puts("SCN ");
 
349
}
 
350
 
 
351
void P2PGfx::opSetFont(Object args[], int numArgs)
 
352
{
 
353
  if (mappingTable != 0) {
 
354
    P2POutput::outputObject(&args[0],str,xref,
 
355
      mappingTable->tables[P2PResources::Font]);
 
356
  } else {
 
357
    P2POutput::outputObject(&args[0],str,xref);
 
358
  }
 
359
  if (fontResource != 0) {
 
360
    if (mappingTable != 0) {
 
361
      Dict *map = mappingTable->tables[P2PResources::Font];
 
362
      if (map != 0) {
 
363
        Object obj;
 
364
#ifdef HAVE_UGOOSTRING_H
 
365
        UGooString nameStr(args[0].getName());
 
366
 
 
367
        map->lookupNF(nameStr,&obj);
 
368
#else
 
369
        map->lookupNF(args[0].getName(),&obj);
 
370
#endif
 
371
        if (obj.isName()) {
 
372
          state.setFont(fontResource->lookup(obj.getName()));
 
373
        }
 
374
        obj.free();
 
375
      }
 
376
    } else {
 
377
      state.setFont(fontResource->lookup(args[0].getName()));
 
378
    }
 
379
  }
 
380
  str->putchar(' ');
 
381
  P2POutput::outputObject(&args[1],str,xref);
 
382
  str->puts(" Tf ");
 
383
}
 
384
 
 
385
void P2PGfx::opSetFillColorSpace(Object args[], int numArgs)
 
386
{
 
387
  if (mappingTable != 0) {
 
388
    P2POutput::outputObject(&args[0],str,xref,
 
389
      mappingTable->tables[P2PResources::ColorSpace]);
 
390
  } else {
 
391
    P2POutput::outputObject(&args[0],str,xref);
 
392
  }
 
393
  str->puts(" cs ");
 
394
}
 
395
 
 
396
void P2PGfx::opSetExtGState(Object args[], int numArgs)
 
397
{
 
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];
 
403
      if (map != 0) {
 
404
        Object obj;
 
405
#ifdef HAVE_UGOOSTRING_H
 
406
        UGooString nameStr(args[0].getName());
 
407
 
 
408
        map->lookupNF(nameStr,&obj);
 
409
#else
 
410
        map->lookupNF(args[0].getName(),&obj);
 
411
#endif
 
412
        if (obj.isName()) {
 
413
          state.setFont(fontResource->lookupExtGState(obj.getName()));
 
414
        }
 
415
        obj.free();
 
416
      }
 
417
    }
 
418
  } else {
 
419
    P2POutput::outputObject(&args[0],str,xref);
 
420
    if (fontResource != 0) {
 
421
      if (args[0].isName()) {
 
422
        state.setFont(fontResource->lookupExtGState(args[0].getName()));
 
423
      }
 
424
    }
 
425
  }
 
426
  str->puts(" gs ");
 
427
}
 
428
 
 
429
void P2PGfx::opSetFillColorN(Object args[], int numArgs)
 
430
{
 
431
  int i;
 
432
 
 
433
  for (i = 0;i < numArgs-1;i++) {
 
434
    P2POutput::outputObject(&args[i],str,xref);
 
435
    str->putchar(' ');
 
436
  }
 
437
  if (mappingTable != 0 && args[i].isName()) {
 
438
    P2POutput::outputObject(&args[i],str,xref,
 
439
      mappingTable->tables[P2PResources::Pattern]);
 
440
    str->putchar(' ');
 
441
  } else {
 
442
    P2POutput::outputObject(&args[i],str,xref);
 
443
    str->putchar(' ');
 
444
  }
 
445
  if (args[i].isName() && resources != 0) {
 
446
    /* check pattern */
 
447
    Object obj;
 
448
 
 
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();
 
454
    }
 
455
    resources->refPattern(name,mat);
 
456
    obj.free();
 
457
  }
 
458
  str->puts("scn ");
 
459
}
 
460
 
 
461
void P2PGfx::opShFill(Object args[], int numArgs)
 
462
{
 
463
  if (mappingTable != 0) {
 
464
    P2POutput::outputObject(&args[0],str,xref,
 
465
      mappingTable->tables[P2PResources::Shading]);
 
466
  } else {
 
467
    P2POutput::outputObject(&args[0],str,xref);
 
468
  }
 
469
  str->puts(" sh ");
 
470
}
 
471
 
 
472
void P2PGfx::opMoveSetShowText(Object args[], int numArgs)
 
473
{
 
474
  P2PFontDict *f;
 
475
 
 
476
  if ((f = state.getFont()) != 0) f->showText(args[2].getString());
 
477
  outputOp("\"",args,numArgs);
 
478
}
 
479
 
 
480
void P2PGfx::opMoveShowText(Object args[], int numArgs)
 
481
{
 
482
  P2PFontDict *f;
 
483
 
 
484
  if ((f = state.getFont()) != 0) f->showText(args[0].getString());
 
485
  outputOp("'",args,numArgs);
 
486
}
 
487
 
 
488
void P2PGfx::opShowSpaceText(Object args[], int numArgs)
 
489
{
 
490
  P2PFontDict *f;
 
491
 
 
492
  if ((f = state.getFont()) != 0) {
 
493
    Array *a;
 
494
    int i, n;
 
495
 
 
496
    a = args[0].getArray();
 
497
    n = a->getLength();
 
498
    for (i = 0;i < n;i++) {
 
499
      Object obj;
 
500
 
 
501
      a->get(i,&obj);
 
502
      if (obj.isString()) {
 
503
        f->showText(obj.getString());
 
504
      }
 
505
      obj.free();
 
506
    }
 
507
  }
 
508
  outputOp("TJ",args,numArgs);
 
509
}
 
510
 
 
511
void P2PGfx::opShowText(Object args[], int numArgs)
 
512
{
 
513
  P2PFontDict *f;
 
514
 
 
515
  if ((f = state.getFont()) != 0) f->showText(args[0].getString());
 
516
  outputOp("Tj",args,numArgs);
 
517
}
 
518
 
 
519
void P2PGfx::opSave(Object args[], int numArgs)
 
520
{
 
521
  state.save();
 
522
  str->puts(" q ");
 
523
}
 
524
 
 
525
void P2PGfx::opRestore(Object args[], int numArgs)
 
526
{
 
527
  state.restore();
 
528
  str->puts(" Q ");
 
529
}
 
530
 
 
531
void P2PGfx::opBeginImage(Object args[], int numArgs)
 
532
{
 
533
  Object dict;
 
534
  char *key;
 
535
  Stream *imageStr;
 
536
  Object obj;
 
537
 
 
538
  /* output BI */
 
539
  str->puts(" BI");
 
540
  /* handle dictionary */
 
541
  dict.initDict(xref);
 
542
  parser->getObj(&obj);
 
543
  while (!obj.isCmd(const_cast<char *>("ID")) && !obj.isEOF()) {
 
544
    str->putchar(' ');
 
545
    if (!obj.isName()) {
 
546
      error(getPos(), const_cast<char *>("Inline image dictionary key must be a name object"));
 
547
      P2POutput::outputObject(&obj,str,xref);
 
548
      str->putchar(' ');
 
549
      obj.free();
 
550
    } else {
 
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);
 
556
        str->putchar(' ');
 
557
      }
 
558
      obj.free();
 
559
      parser->getObj(&obj);
 
560
      if (obj.isEOF() || obj.isError()) {
 
561
        gfree(key);
 
562
        break;
 
563
      }
 
564
      if (mappingTable != 0 &&
 
565
          (strcmp(key,"ColorSpace") == 0 || strcmp(key,"CS") == 0)) {
 
566
        /* colorspace */
 
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);
 
574
      }
 
575
      dict.dictAdd(key,&obj);
 
576
    }
 
577
    parser->getObj(&obj);
 
578
  }
 
579
 
 
580
  if (obj.isEOF()) {
 
581
    error(getPos(), const_cast<char *>("End of file in inline image"));
 
582
    obj.free();
 
583
    dict.free();
 
584
  } else if (obj.isError()) {
 
585
    error(getPos(), const_cast<char *>("Error in inline image"));
 
586
    obj.free();
 
587
    dict.free();
 
588
  } else {
 
589
    int c1, c2;
 
590
 
 
591
    /* ouput ID */
 
592
    str->putchar(' ');
 
593
    P2POutput::outputObject(&obj,str,xref);
 
594
    str->putchar('\n');
 
595
    obj.free();
 
596
 
 
597
    /* make image stream */
 
598
    imageStr = new EmbedStream(parser->getStream(), &dict, gFalse,0);
 
599
    imageStr = imageStr->addFilters(&dict);
 
600
    doImage(imageStr);
 
601
    /* handle EI */
 
602
    c1 = imageStr->getBaseStream()->getChar();
 
603
    c2 = imageStr->getBaseStream()->getChar();
 
604
    while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
 
605
      c1 = c2;
 
606
      c2 = imageStr->getBaseStream()->getChar();
 
607
    }
 
608
    delete imageStr;
 
609
    str->puts("EI\n");
 
610
  }
 
611
}
 
612
 
 
613
void P2PGfx::doImage(Stream *istr)
 
614
{
 
615
  Dict *dict;
 
616
  int width, height;
 
617
  int bits;
 
618
  GBool mask;
 
619
  Object obj1, obj2;
 
620
  int i, j;
 
621
  GfxColorSpace *colorSpace = NULL;
 
622
  int nComponents;
 
623
  int bytes;
 
624
  Guchar *lineBuf;
 
625
 
 
626
  // get info from the stream
 
627
  bits = 0;
 
628
 
 
629
  // get stream dict
 
630
  dict = istr->getDict();
 
631
 
 
632
  // get size
 
633
  dict->lookup(const_cast<char *>("Width"), &obj1);
 
634
  if (obj1.isNull()) {
 
635
    obj1.free();
 
636
    dict->lookup(const_cast<char *>("W"), &obj1);
 
637
  }
 
638
  if (!obj1.isInt())
 
639
    goto err2;
 
640
  width = obj1.getInt();
 
641
  obj1.free();
 
642
  dict->lookup(const_cast<char *>("Height"), &obj1);
 
643
  if (obj1.isNull()) {
 
644
    obj1.free();
 
645
    dict->lookup(const_cast<char *>("H"), &obj1);
 
646
  }
 
647
  if (!obj1.isInt())
 
648
    goto err2;
 
649
  height = obj1.getInt();
 
650
  obj1.free();
 
651
 
 
652
  // image or mask?
 
653
  dict->lookup(const_cast<char *>("ImageMask"), &obj1);
 
654
  if (obj1.isNull()) {
 
655
    obj1.free();
 
656
    dict->lookup(const_cast<char *>("IM"), &obj1);
 
657
  }
 
658
  mask = gFalse;
 
659
  if (obj1.isBool())
 
660
    mask = obj1.getBool();
 
661
  else if (!obj1.isNull())
 
662
    goto err2;
 
663
  obj1.free();
 
664
 
 
665
  // bit depth
 
666
  if (bits == 0) {
 
667
    dict->lookup(const_cast<char *>("BitsPerComponent"), &obj1);
 
668
    if (obj1.isNull()) {
 
669
      obj1.free();
 
670
      dict->lookup(const_cast<char *>("BPC"), &obj1);
 
671
    }
 
672
    if (obj1.isInt()) {
 
673
      bits = obj1.getInt();
 
674
    } else if (mask) {
 
675
      bits = 1;
 
676
    } else {
 
677
      goto err2;
 
678
    }
 
679
    obj1.free();
 
680
  }
 
681
 
 
682
  // display a mask
 
683
  if (mask) {
 
684
    nComponents = 1;
 
685
  } else {
 
686
    // get color space
 
687
    dict->lookup(const_cast<char *>("ColorSpace"), &obj1);
 
688
    if (obj1.isNull()) {
 
689
      obj1.free();
 
690
      dict->lookup(const_cast<char *>("CS"), &obj1);
 
691
    }
 
692
    if (obj1.isName() && orgCSResource != 0) {
 
693
      orgCSResource->lookup(obj1.getName(), &obj2);
 
694
      if (!obj2.isNull()) {
 
695
        obj1.free();
 
696
        obj1 = obj2;
 
697
      } else {
 
698
        obj2.free();
 
699
      }
 
700
    }
 
701
    if (!obj1.isNull()) {
 
702
      colorSpace = GfxColorSpace::parse(&obj1);
 
703
    }
 
704
    obj1.free();
 
705
    if (!colorSpace) {
 
706
      goto err1;
 
707
    }
 
708
    nComponents = colorSpace->getNComps();
 
709
    delete colorSpace;
 
710
  }
 
711
  istr->reset();
 
712
  /* number of bytes per line */
 
713
  bytes = (bits*nComponents*width+7)/8;
 
714
 
 
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();
 
720
    }
 
721
    str->write(lineBuf,bytes);
 
722
  }
 
723
  str->putchar('\n');
 
724
  delete[] lineBuf;
 
725
 
 
726
  return;
 
727
 
 
728
 err2:
 
729
  obj1.free();
 
730
 err1:
 
731
  error(getPos(), const_cast<char *>("Bad image parameters"));
 
732
}