]>
Commit | Line | Data |
---|---|---|
9c72faab | 1 | //======================================================================== |
2 | // | |
3 | // Gfx.cc | |
4 | // | |
5 | // Copyright 1996 Derek B. Noonburg | |
6 | // | |
7 | //======================================================================== | |
8 | ||
9 | #ifdef __GNUC__ | |
10 | #pragma implementation | |
11 | #endif | |
12 | ||
13 | #include <stdio.h> | |
14 | #include <stddef.h> | |
15 | #include <string.h> | |
16 | #include "gmem.h" | |
17 | #include "Object.h" | |
18 | #include "Array.h" | |
19 | #include "Dict.h" | |
20 | #include "Stream.h" | |
21 | #include "Lexer.h" | |
22 | #include "Parser.h" | |
23 | #include "GfxFont.h" | |
24 | #include "GfxState.h" | |
25 | #include "OutputDev.h" | |
26 | #include "Params.h" | |
27 | #include "Error.h" | |
28 | #include "Gfx.h" | |
29 | ||
30 | //------------------------------------------------------------------------ | |
31 | // Operator table | |
32 | //------------------------------------------------------------------------ | |
33 | ||
34 | Operator Gfx::opTab[] = { | |
35 | {"\"", 3, {tchkNum, tchkNum, tchkString}, | |
36 | &Gfx::opMoveSetShowText}, | |
37 | {"'", 1, {tchkString}, | |
38 | &Gfx::opMoveShowText}, | |
39 | {"B", 0, {tchkNone}, | |
40 | &Gfx::opFillStroke}, | |
41 | {"B*", 0, {tchkNone}, | |
42 | &Gfx::opEOFillStroke}, | |
43 | {"BDC", 2, {tchkName, tchkProps}, | |
44 | &Gfx::opBeginMarkedContent}, | |
45 | {"BI", 0, {tchkNone}, | |
46 | &Gfx::opBeginImage}, | |
47 | {"BMC", 1, {tchkName}, | |
48 | &Gfx::opBeginMarkedContent}, | |
49 | {"BT", 0, {tchkNone}, | |
50 | &Gfx::opBeginText}, | |
51 | {"BX", 0, {tchkNone}, | |
52 | &Gfx::opBeginIgnoreUndef}, | |
53 | {"CS", 1, {tchkName}, | |
54 | &Gfx::opSetStrokeColorSpace}, | |
55 | {"DP", 2, {tchkName, tchkProps}, | |
56 | &Gfx::opMarkPoint}, | |
57 | {"Do", 1, {tchkName}, | |
58 | &Gfx::opXObject}, | |
59 | {"EI", 0, {tchkNone}, | |
60 | &Gfx::opEndImage}, | |
61 | {"EMC", 0, {tchkNone}, | |
62 | &Gfx::opEndMarkedContent}, | |
63 | {"ET", 0, {tchkNone}, | |
64 | &Gfx::opEndText}, | |
65 | {"EX", 0, {tchkNone}, | |
66 | &Gfx::opEndIgnoreUndef}, | |
67 | {"F", 0, {tchkNone}, | |
68 | &Gfx::opFill}, | |
69 | {"G", 1, {tchkNum}, | |
70 | &Gfx::opSetStrokeGray}, | |
71 | {"ID", 0, {tchkNone}, | |
72 | &Gfx::opImageData}, | |
73 | {"J", 1, {tchkInt}, | |
74 | &Gfx::opSetLineCap}, | |
75 | {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
76 | &Gfx::opSetStrokeCMYKColor}, | |
77 | {"M", 1, {tchkNum}, | |
78 | &Gfx::opSetMiterLimit}, | |
79 | {"MP", 1, {tchkName}, | |
80 | &Gfx::opMarkPoint}, | |
81 | {"Q", 0, {tchkNone}, | |
82 | &Gfx::opRestore}, | |
83 | {"RG", 3, {tchkNum, tchkNum, tchkNum}, | |
84 | &Gfx::opSetStrokeRGBColor}, | |
85 | {"S", 0, {tchkNone}, | |
86 | &Gfx::opStroke}, | |
87 | {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
88 | &Gfx::opSetStrokeColor}, | |
89 | {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, | |
90 | tchkSCN}, | |
91 | &Gfx::opSetStrokeColorN}, | |
92 | {"T*", 0, {tchkNone}, | |
93 | &Gfx::opTextNextLine}, | |
94 | {"TD", 2, {tchkNum, tchkNum}, | |
95 | &Gfx::opTextMoveSet}, | |
96 | {"TJ", 1, {tchkArray}, | |
97 | &Gfx::opShowSpaceText}, | |
98 | {"TL", 1, {tchkNum}, | |
99 | &Gfx::opSetTextLeading}, | |
100 | {"Tc", 1, {tchkNum}, | |
101 | &Gfx::opSetCharSpacing}, | |
102 | {"Td", 2, {tchkNum, tchkNum}, | |
103 | &Gfx::opTextMove}, | |
104 | {"Tf", 2, {tchkName, tchkNum}, | |
105 | &Gfx::opSetFont}, | |
106 | {"Tj", 1, {tchkString}, | |
107 | &Gfx::opShowText}, | |
108 | {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, | |
109 | tchkNum, tchkNum}, | |
110 | &Gfx::opSetTextMatrix}, | |
111 | {"Tr", 1, {tchkInt}, | |
112 | &Gfx::opSetTextRender}, | |
113 | {"Ts", 1, {tchkNum}, | |
114 | &Gfx::opSetTextRise}, | |
115 | {"Tw", 1, {tchkNum}, | |
116 | &Gfx::opSetWordSpacing}, | |
117 | {"Tz", 1, {tchkNum}, | |
118 | &Gfx::opSetHorizScaling}, | |
119 | {"W", 0, {tchkNone}, | |
120 | &Gfx::opClip}, | |
121 | {"W*", 0, {tchkNone}, | |
122 | &Gfx::opEOClip}, | |
123 | {"b", 0, {tchkNone}, | |
124 | &Gfx::opCloseFillStroke}, | |
125 | {"b*", 0, {tchkNone}, | |
126 | &Gfx::opCloseEOFillStroke}, | |
127 | {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum, | |
128 | tchkNum, tchkNum}, | |
129 | &Gfx::opCurveTo}, | |
130 | {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, | |
131 | tchkNum, tchkNum}, | |
132 | &Gfx::opConcat}, | |
133 | {"cs", 1, {tchkName}, | |
134 | &Gfx::opSetFillColorSpace}, | |
135 | {"d", 2, {tchkArray, tchkNum}, | |
136 | &Gfx::opSetDash}, | |
137 | {"d0", 2, {tchkNum, tchkNum}, | |
138 | &Gfx::opSetCharWidth}, | |
139 | {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum, | |
140 | tchkNum, tchkNum}, | |
141 | &Gfx::opSetCacheDevice}, | |
142 | {"f", 0, {tchkNone}, | |
143 | &Gfx::opFill}, | |
144 | {"f*", 0, {tchkNone}, | |
145 | &Gfx::opEOFill}, | |
146 | {"g", 1, {tchkNum}, | |
147 | &Gfx::opSetFillGray}, | |
148 | {"gs", 1, {tchkName}, | |
149 | &Gfx::opSetExtGState}, | |
150 | {"h", 0, {tchkNone}, | |
151 | &Gfx::opClosePath}, | |
152 | {"i", 1, {tchkNum}, | |
153 | &Gfx::opSetFlat}, | |
154 | {"j", 1, {tchkInt}, | |
155 | &Gfx::opSetLineJoin}, | |
156 | {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
157 | &Gfx::opSetFillCMYKColor}, | |
158 | {"l", 2, {tchkNum, tchkNum}, | |
159 | &Gfx::opLineTo}, | |
160 | {"m", 2, {tchkNum, tchkNum}, | |
161 | &Gfx::opMoveTo}, | |
162 | {"n", 0, {tchkNone}, | |
163 | &Gfx::opEndPath}, | |
164 | {"q", 0, {tchkNone}, | |
165 | &Gfx::opSave}, | |
166 | {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
167 | &Gfx::opRectangle}, | |
168 | {"rg", 3, {tchkNum, tchkNum, tchkNum}, | |
169 | &Gfx::opSetFillRGBColor}, | |
170 | {"ri", 1, {tchkName}, | |
171 | &Gfx::opSetRenderingIntent}, | |
172 | {"s", 0, {tchkNone}, | |
173 | &Gfx::opCloseStroke}, | |
174 | {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
175 | &Gfx::opSetFillColor}, | |
176 | {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, | |
177 | tchkSCN}, | |
178 | &Gfx::opSetFillColorN}, | |
179 | {"sh", 1, {tchkName}, | |
180 | &Gfx::opShFill}, | |
181 | {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
182 | &Gfx::opCurveTo1}, | |
183 | {"w", 1, {tchkNum}, | |
184 | &Gfx::opSetLineWidth}, | |
185 | {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, | |
186 | &Gfx::opCurveTo2}, | |
187 | }; | |
188 | ||
189 | #define numOps (sizeof(opTab) / sizeof(Operator)) | |
190 | ||
52118ca3 | 191 | //------------------------------------------------------------------------ |
192 | ||
193 | GBool printCommands = gFalse; | |
194 | ||
9c72faab | 195 | //------------------------------------------------------------------------ |
196 | // Gfx | |
197 | //------------------------------------------------------------------------ | |
198 | ||
199 | Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict, | |
200 | int dpi, double x1, double y1, double x2, double y2, GBool crop, | |
201 | double cropX1, double cropY1, double cropX2, double cropY2, | |
202 | int rotate) { | |
203 | Object obj1; | |
204 | ||
205 | // start the resource stack | |
206 | res = new GfxResources(NULL); | |
207 | ||
208 | // build font dictionary | |
209 | res->fonts = NULL; | |
210 | if (resDict) { | |
211 | resDict->lookup("Font", &obj1); | |
212 | if (obj1.isDict()) | |
213 | res->fonts = new GfxFontDict(obj1.getDict()); | |
214 | obj1.free(); | |
215 | } | |
216 | ||
217 | // get XObject dictionary | |
218 | if (resDict) | |
219 | resDict->lookup("XObject", &res->xObjDict); | |
220 | else | |
221 | res->xObjDict.initNull(); | |
222 | ||
223 | // get colorspace dictionary | |
224 | if (resDict) | |
225 | resDict->lookup("ColorSpace", &res->colorSpaceDict); | |
226 | else | |
227 | res->colorSpaceDict.initNull(); | |
228 | ||
229 | // initialize | |
230 | out = out1; | |
231 | state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown()); | |
232 | fontChanged = gFalse; | |
233 | clip = clipNone; | |
234 | ignoreUndef = 0; | |
235 | out->startPage(pageNum, state); | |
236 | out->setDefaultCTM(state->getCTM()); | |
237 | out->updateAll(state); | |
238 | ||
239 | // set crop box | |
240 | if (crop) { | |
241 | state->moveTo(cropX1, cropY1); | |
242 | state->lineTo(cropX2, cropY1); | |
243 | state->lineTo(cropX2, cropY2); | |
244 | state->lineTo(cropX1, cropY2); | |
245 | state->closePath(); | |
246 | out->clip(state); | |
247 | state->clearPath(); | |
248 | } | |
249 | } | |
250 | ||
251 | Gfx::~Gfx() { | |
252 | GfxResources *resPtr; | |
253 | ||
254 | while (state->hasSaves()) { | |
255 | state = state->restore(); | |
256 | out->restoreState(state); | |
257 | } | |
258 | out->endPage(); | |
259 | while (res) { | |
260 | resPtr = res->next; | |
261 | delete res; | |
262 | res = resPtr; | |
263 | } | |
264 | if (state) | |
265 | delete state; | |
266 | } | |
267 | ||
268 | GfxResources::~GfxResources() { | |
269 | if (fonts) | |
270 | delete fonts; | |
271 | xObjDict.free(); | |
272 | colorSpaceDict.free(); | |
273 | } | |
274 | ||
275 | void Gfx::display(Object *obj) { | |
276 | Object obj2; | |
277 | int i; | |
278 | ||
279 | if (obj->isArray()) { | |
280 | for (i = 0; i < obj->arrayGetLength(); ++i) { | |
281 | obj->arrayGet(i, &obj2); | |
282 | if (!obj2.isStream()) { | |
283 | error(-1, "Weird page contents"); | |
284 | obj2.free(); | |
285 | return; | |
286 | } | |
287 | obj2.free(); | |
288 | } | |
289 | } else if (!obj->isStream()) { | |
290 | error(-1, "Weird page contents"); | |
291 | return; | |
292 | } | |
293 | parser = new Parser(new Lexer(obj)); | |
294 | go(); | |
52118ca3 | 295 | delete parser; |
296 | parser = NULL; | |
9c72faab | 297 | } |
298 | ||
299 | void Gfx::go() { | |
300 | Object obj; | |
301 | Object args[maxArgs]; | |
302 | int numCmds, numArgs; | |
303 | int i; | |
304 | ||
305 | // scan a sequence of objects | |
306 | numCmds = 0; | |
307 | numArgs = 0; | |
308 | parser->getObj(&obj); | |
309 | while (!obj.isEOF()) { | |
310 | ||
311 | // got a command - execute it | |
312 | if (obj.isCmd()) { | |
313 | if (printCommands) { | |
314 | obj.print(stdout); | |
315 | for (i = 0; i < numArgs; ++i) { | |
316 | printf(" "); | |
317 | args[i].print(stdout); | |
318 | } | |
319 | printf("\n"); | |
320 | } | |
321 | execOp(&obj, args, numArgs); | |
322 | obj.free(); | |
323 | for (i = 0; i < numArgs; ++i) | |
324 | args[i].free(); | |
325 | numArgs = 0; | |
326 | ||
327 | // periodically update display | |
328 | if (++numCmds == 200) { | |
329 | out->dump(); | |
330 | numCmds = 0; | |
331 | } | |
332 | ||
333 | // got an argument - save it | |
334 | } else if (numArgs < maxArgs) { | |
335 | args[numArgs++] = obj; | |
336 | ||
337 | // too many arguments - something is wrong | |
338 | } else { | |
339 | error(getPos(), "Too many args in content stream"); | |
340 | if (printCommands) { | |
341 | printf("throwing away arg: "); | |
342 | obj.print(stdout); | |
343 | printf("\n"); | |
344 | } | |
345 | obj.free(); | |
346 | } | |
347 | ||
348 | // grab the next object | |
349 | parser->getObj(&obj); | |
350 | } | |
351 | obj.free(); | |
352 | ||
353 | // args at end with no command | |
354 | if (numArgs > 0) { | |
355 | error(getPos(), "Leftover args in content stream"); | |
356 | if (printCommands) { | |
357 | printf("%d leftovers:", numArgs); | |
358 | for (i = 0; i < numArgs; ++i) { | |
359 | printf(" "); | |
360 | args[i].print(stdout); | |
361 | } | |
362 | printf("\n"); | |
363 | } | |
364 | for (i = 0; i < numArgs; ++i) | |
365 | args[i].free(); | |
366 | } | |
367 | ||
368 | // update display | |
369 | if (numCmds > 0) | |
370 | out->dump(); | |
371 | ||
372 | // clean up | |
9c72faab | 373 | if (printCommands) |
374 | fflush(stdout); | |
375 | } | |
376 | ||
377 | void Gfx::execOp(Object *cmd, Object args[], int numArgs) { | |
378 | Operator *op; | |
aa530ae8 | 379 | const char *name; |
9c72faab | 380 | int i; |
381 | ||
382 | // find operator | |
383 | name = cmd->getName(); | |
384 | if (!(op = findOp(name))) { | |
385 | if (ignoreUndef == 0) | |
386 | error(getPos(), "Unknown operator '%s'", name); | |
387 | return; | |
388 | } | |
389 | ||
390 | // type check args | |
391 | if (op->numArgs >= 0) { | |
392 | if (numArgs != op->numArgs) { | |
393 | error(getPos(), "Wrong number (%d) of args to '%s' operator", | |
394 | numArgs, name); | |
395 | return; | |
396 | } | |
397 | } else { | |
398 | if (numArgs > -op->numArgs) { | |
399 | error(getPos(), "Too many (%d) args to '%s' operator", | |
400 | numArgs, name); | |
401 | return; | |
402 | } | |
403 | } | |
404 | for (i = 0; i < numArgs; ++i) { | |
405 | if (!checkArg(&args[i], op->tchk[i])) { | |
406 | error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", | |
407 | i, name, args[i].getTypeName()); | |
408 | return; | |
409 | } | |
410 | } | |
411 | ||
412 | // do it | |
413 | (this->*op->func)(args, numArgs); | |
414 | } | |
415 | ||
aa530ae8 | 416 | Operator *Gfx::findOp(const char *name) { |
9c72faab | 417 | int a, b, m, cmp; |
418 | ||
419 | a = -1; | |
420 | b = numOps; | |
421 | // invariant: opTab[a] < name < opTab[b] | |
422 | while (b - a > 1) { | |
423 | m = (a + b) / 2; | |
424 | cmp = strcmp(opTab[m].name, name); | |
425 | if (cmp < 0) | |
426 | a = m; | |
427 | else if (cmp > 0) | |
428 | b = m; | |
429 | else | |
430 | a = b = m; | |
431 | } | |
432 | if (cmp != 0) | |
433 | return NULL; | |
434 | return &opTab[a]; | |
435 | } | |
436 | ||
437 | GBool Gfx::checkArg(Object *arg, TchkType type) { | |
438 | switch (type) { | |
439 | case tchkBool: return arg->isBool(); | |
440 | case tchkInt: return arg->isInt(); | |
441 | case tchkNum: return arg->isNum(); | |
442 | case tchkString: return arg->isString(); | |
443 | case tchkName: return arg->isName(); | |
444 | case tchkArray: return arg->isArray(); | |
445 | case tchkProps: return arg->isDict() || arg->isName(); | |
446 | case tchkSCN: return arg->isNum() || arg->isName(); | |
447 | case tchkNone: return gFalse; | |
448 | } | |
449 | return gFalse; | |
450 | } | |
451 | ||
452 | int Gfx::getPos() { | |
52118ca3 | 453 | return parser ? parser->getPos() : -1; |
9c72faab | 454 | } |
455 | ||
aa530ae8 | 456 | GfxFont *Gfx::lookupFont(const char *name) { |
9c72faab | 457 | GfxFont *font; |
458 | GfxResources *resPtr; | |
459 | ||
460 | for (resPtr = res; resPtr; resPtr = resPtr->next) { | |
461 | if (resPtr->fonts) { | |
462 | if ((font = resPtr->fonts->lookup(name))) | |
463 | return font; | |
464 | } | |
465 | } | |
466 | error(getPos(), "unknown font tag '%s'", name); | |
467 | return NULL; | |
468 | } | |
469 | ||
aa530ae8 | 470 | GBool Gfx::lookupXObject(const char *name, Object *obj) { |
9c72faab | 471 | GfxResources *resPtr; |
472 | ||
473 | for (resPtr = res; resPtr; resPtr = resPtr->next) { | |
474 | if (resPtr->xObjDict.isDict()) { | |
475 | if (!resPtr->xObjDict.dictLookup(name, obj)->isNull()) | |
476 | return gTrue; | |
477 | obj->free(); | |
478 | } | |
479 | } | |
480 | error(getPos(), "XObject '%s' is unknown", name); | |
481 | return gFalse; | |
482 | } | |
483 | ||
aa530ae8 | 484 | void Gfx::lookupColorSpace(const char *name, Object *obj) { |
9c72faab | 485 | GfxResources *resPtr; |
486 | ||
487 | for (resPtr = res; resPtr; resPtr = resPtr->next) { | |
488 | if (resPtr->colorSpaceDict.isDict()) { | |
489 | if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) | |
490 | return; | |
491 | obj->free(); | |
492 | } | |
493 | } | |
494 | obj->initNull(); | |
495 | } | |
496 | ||
497 | //------------------------------------------------------------------------ | |
498 | // graphics state operators | |
499 | //------------------------------------------------------------------------ | |
500 | ||
501 | void Gfx::opSave(Object args[], int numArgs) { | |
a5f8b9e7 | 502 | (void)args; |
503 | (void)numArgs; | |
504 | ||
9c72faab | 505 | out->saveState(state); |
506 | state = state->save(); | |
507 | } | |
508 | ||
509 | void Gfx::opRestore(Object args[], int numArgs) { | |
a5f8b9e7 | 510 | (void)args; |
511 | (void)numArgs; | |
512 | ||
9c72faab | 513 | state = state->restore(); |
514 | out->restoreState(state); | |
52118ca3 | 515 | |
516 | // Some PDF producers (Macromedia FreeHand) generate a save (q) and | |
517 | // restore (Q) inside a path sequence. The PDF spec seems to imply | |
518 | // that this is illegal. Calling clearPath() here implements the | |
519 | // behavior apparently expected by this software. | |
520 | state->clearPath(); | |
9c72faab | 521 | } |
522 | ||
523 | void Gfx::opConcat(Object args[], int numArgs) { | |
a5f8b9e7 | 524 | (void)numArgs; |
525 | ||
9c72faab | 526 | state->concatCTM(args[0].getNum(), args[1].getNum(), |
527 | args[2].getNum(), args[3].getNum(), | |
528 | args[4].getNum(), args[5].getNum()); | |
529 | out->updateCTM(state, args[0].getNum(), args[1].getNum(), | |
530 | args[2].getNum(), args[3].getNum(), | |
531 | args[4].getNum(), args[5].getNum()); | |
532 | fontChanged = gTrue; | |
533 | } | |
534 | ||
535 | void Gfx::opSetDash(Object args[], int numArgs) { | |
536 | Array *a; | |
537 | int length; | |
538 | Object obj; | |
539 | double *dash; | |
540 | int i; | |
541 | ||
a5f8b9e7 | 542 | (void)numArgs; |
543 | ||
9c72faab | 544 | a = args[0].getArray(); |
545 | length = a->getLength(); | |
546 | if (length == 0) { | |
547 | dash = NULL; | |
548 | } else { | |
549 | dash = (double *)gmalloc(length * sizeof(double)); | |
550 | for (i = 0; i < length; ++i) { | |
551 | dash[i] = a->get(i, &obj)->getNum(); | |
552 | obj.free(); | |
553 | } | |
554 | } | |
555 | state->setLineDash(dash, length, args[1].getNum()); | |
556 | out->updateLineDash(state); | |
557 | } | |
558 | ||
559 | void Gfx::opSetFlat(Object args[], int numArgs) { | |
a5f8b9e7 | 560 | (void)numArgs; |
561 | ||
9c72faab | 562 | state->setFlatness((int)args[0].getNum()); |
563 | out->updateFlatness(state); | |
564 | } | |
565 | ||
566 | void Gfx::opSetLineJoin(Object args[], int numArgs) { | |
a5f8b9e7 | 567 | (void)numArgs; |
568 | ||
9c72faab | 569 | state->setLineJoin(args[0].getInt()); |
570 | out->updateLineJoin(state); | |
571 | } | |
572 | ||
573 | void Gfx::opSetLineCap(Object args[], int numArgs) { | |
a5f8b9e7 | 574 | (void)numArgs; |
575 | ||
9c72faab | 576 | state->setLineCap(args[0].getInt()); |
577 | out->updateLineCap(state); | |
578 | } | |
579 | ||
580 | void Gfx::opSetMiterLimit(Object args[], int numArgs) { | |
a5f8b9e7 | 581 | (void)numArgs; |
582 | ||
9c72faab | 583 | state->setMiterLimit(args[0].getNum()); |
584 | out->updateMiterLimit(state); | |
585 | } | |
586 | ||
587 | void Gfx::opSetLineWidth(Object args[], int numArgs) { | |
a5f8b9e7 | 588 | (void)numArgs; |
589 | ||
9c72faab | 590 | state->setLineWidth(args[0].getNum()); |
591 | out->updateLineWidth(state); | |
592 | } | |
593 | ||
594 | void Gfx::opSetExtGState(Object args[], int numArgs) { | |
a5f8b9e7 | 595 | (void)args; |
596 | (void)numArgs; | |
9c72faab | 597 | } |
598 | ||
599 | void Gfx::opSetRenderingIntent(Object args[], int numArgs) { | |
a5f8b9e7 | 600 | (void)args; |
601 | (void)numArgs; | |
9c72faab | 602 | } |
603 | ||
604 | //------------------------------------------------------------------------ | |
605 | // color operators | |
606 | //------------------------------------------------------------------------ | |
607 | ||
608 | void Gfx::opSetFillGray(Object args[], int numArgs) { | |
a5f8b9e7 | 609 | (void)numArgs; |
610 | ||
9c72faab | 611 | state->setFillColorSpace(new GfxColorSpace(colorGray)); |
612 | state->setFillGray(args[0].getNum()); | |
613 | out->updateFillColor(state); | |
614 | } | |
615 | ||
616 | void Gfx::opSetStrokeGray(Object args[], int numArgs) { | |
a5f8b9e7 | 617 | (void)numArgs; |
618 | ||
9c72faab | 619 | state->setStrokeColorSpace(new GfxColorSpace(colorGray)); |
620 | state->setStrokeGray(args[0].getNum()); | |
621 | out->updateStrokeColor(state); | |
622 | } | |
623 | ||
624 | void Gfx::opSetFillCMYKColor(Object args[], int numArgs) { | |
a5f8b9e7 | 625 | (void)numArgs; |
626 | ||
9c72faab | 627 | state->setFillColorSpace(new GfxColorSpace(colorCMYK)); |
628 | state->setFillCMYK(args[0].getNum(), args[1].getNum(), | |
629 | args[2].getNum(), args[3].getNum()); | |
630 | out->updateFillColor(state); | |
631 | } | |
632 | ||
633 | void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) { | |
a5f8b9e7 | 634 | (void)numArgs; |
635 | ||
9c72faab | 636 | state->setStrokeColorSpace(new GfxColorSpace(colorCMYK)); |
637 | state->setStrokeCMYK(args[0].getNum(), args[1].getNum(), | |
638 | args[2].getNum(), args[3].getNum()); | |
639 | out->updateStrokeColor(state); | |
640 | } | |
641 | ||
642 | void Gfx::opSetFillRGBColor(Object args[], int numArgs) { | |
a5f8b9e7 | 643 | (void)numArgs; |
644 | ||
9c72faab | 645 | state->setFillColorSpace(new GfxColorSpace(colorRGB)); |
646 | state->setFillRGB(args[0].getNum(), args[1].getNum(), args[2].getNum()); | |
647 | out->updateFillColor(state); | |
648 | } | |
649 | ||
650 | void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) { | |
a5f8b9e7 | 651 | (void)numArgs; |
652 | ||
9c72faab | 653 | state->setStrokeColorSpace(new GfxColorSpace(colorRGB)); |
654 | state->setStrokeRGB(args[0].getNum(), args[1].getNum(), args[2].getNum()); | |
655 | out->updateStrokeColor(state); | |
656 | } | |
657 | ||
658 | void Gfx::opSetFillColorSpace(Object args[], int numArgs) { | |
659 | Object obj; | |
660 | GfxColorSpace *colorSpace; | |
661 | double x[4]; | |
662 | ||
a5f8b9e7 | 663 | (void)numArgs; |
664 | ||
9c72faab | 665 | lookupColorSpace(args[0].getName(), &obj); |
666 | if (obj.isNull()) | |
667 | colorSpace = new GfxColorSpace(&args[0]); | |
668 | else | |
669 | colorSpace = new GfxColorSpace(&obj); | |
670 | obj.free(); | |
671 | if (colorSpace->isOk()) { | |
672 | state->setFillColorSpace(colorSpace); | |
673 | } else { | |
674 | delete colorSpace; | |
675 | error(getPos(), "Bad colorspace"); | |
676 | } | |
677 | x[0] = x[1] = x[2] = x[3] = 0; | |
678 | state->setFillColor(x); | |
679 | out->updateFillColor(state); | |
680 | } | |
681 | ||
682 | void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { | |
683 | Object obj; | |
684 | GfxColorSpace *colorSpace; | |
685 | double x[4]; | |
686 | ||
a5f8b9e7 | 687 | (void)numArgs; |
688 | ||
9c72faab | 689 | lookupColorSpace(args[0].getName(), &obj); |
690 | if (obj.isNull()) | |
691 | colorSpace = new GfxColorSpace(&args[0]); | |
692 | else | |
693 | colorSpace = new GfxColorSpace(&obj); | |
694 | obj.free(); | |
695 | if (colorSpace->isOk()) { | |
696 | state->setStrokeColorSpace(colorSpace); | |
697 | } else { | |
698 | delete colorSpace; | |
699 | error(getPos(), "Bad colorspace"); | |
700 | } | |
701 | x[0] = x[1] = x[2] = x[3] = 0; | |
702 | state->setStrokeColor(x); | |
703 | out->updateStrokeColor(state); | |
704 | } | |
705 | ||
706 | void Gfx::opSetFillColor(Object args[], int numArgs) { | |
707 | double x[4]; | |
708 | int i; | |
709 | ||
710 | x[0] = x[1] = x[2] = x[3] = 0; | |
711 | for (i = 0; i < numArgs; ++i) | |
712 | x[i] = args[i].getNum(); | |
713 | state->setFillColor(x); | |
714 | out->updateFillColor(state); | |
715 | } | |
716 | ||
717 | void Gfx::opSetStrokeColor(Object args[], int numArgs) { | |
718 | double x[4]; | |
719 | int i; | |
720 | ||
721 | x[0] = x[1] = x[2] = x[3] = 0; | |
722 | for (i = 0; i < numArgs; ++i) | |
723 | x[i] = args[i].getNum(); | |
724 | state->setStrokeColor(x); | |
725 | out->updateStrokeColor(state); | |
726 | } | |
727 | ||
728 | void Gfx::opSetFillColorN(Object args[], int numArgs) { | |
729 | double x[4]; | |
730 | int i; | |
731 | ||
732 | x[0] = x[1] = x[2] = x[3] = 0; | |
733 | for (i = 0; i < numArgs && i < 4; ++i) { | |
734 | if (args[i].isNum()) | |
735 | x[i] = args[i].getNum(); | |
736 | else | |
737 | break; | |
738 | } | |
739 | state->setFillColor(x); | |
740 | out->updateFillColor(state); | |
741 | } | |
742 | ||
743 | void Gfx::opSetStrokeColorN(Object args[], int numArgs) { | |
744 | double x[4]; | |
745 | int i; | |
746 | ||
747 | x[0] = x[1] = x[2] = x[3] = 0; | |
748 | for (i = 0; i < numArgs && i < 4; ++i) { | |
749 | if (args[i].isNum()) | |
750 | x[i] = args[i].getNum(); | |
751 | else | |
752 | break; | |
753 | } | |
754 | state->setStrokeColor(x); | |
755 | out->updateStrokeColor(state); | |
756 | } | |
757 | ||
758 | //------------------------------------------------------------------------ | |
759 | // path segment operators | |
760 | //------------------------------------------------------------------------ | |
761 | ||
762 | void Gfx::opMoveTo(Object args[], int numArgs) { | |
a5f8b9e7 | 763 | (void)numArgs; |
764 | ||
9c72faab | 765 | state->moveTo(args[0].getNum(), args[1].getNum()); |
766 | } | |
767 | ||
768 | void Gfx::opLineTo(Object args[], int numArgs) { | |
a5f8b9e7 | 769 | (void)numArgs; |
770 | ||
9c72faab | 771 | if (!state->isCurPt()) { |
772 | error(getPos(), "No current point in lineto"); | |
773 | return; | |
774 | } | |
775 | state->lineTo(args[0].getNum(), args[1].getNum()); | |
776 | } | |
777 | ||
778 | void Gfx::opCurveTo(Object args[], int numArgs) { | |
779 | double x1, y1, x2, y2, x3, y3; | |
780 | ||
a5f8b9e7 | 781 | (void)numArgs; |
782 | ||
9c72faab | 783 | if (!state->isCurPt()) { |
784 | error(getPos(), "No current point in curveto"); | |
785 | return; | |
786 | } | |
787 | x1 = args[0].getNum(); | |
788 | y1 = args[1].getNum(); | |
789 | x2 = args[2].getNum(); | |
790 | y2 = args[3].getNum(); | |
791 | x3 = args[4].getNum(); | |
792 | y3 = args[5].getNum(); | |
793 | state->curveTo(x1, y1, x2, y2, x3, y3); | |
794 | } | |
795 | ||
796 | void Gfx::opCurveTo1(Object args[], int numArgs) { | |
797 | double x1, y1, x2, y2, x3, y3; | |
798 | ||
a5f8b9e7 | 799 | (void)numArgs; |
800 | ||
9c72faab | 801 | if (!state->isCurPt()) { |
802 | error(getPos(), "No current point in curveto1"); | |
803 | return; | |
804 | } | |
805 | x1 = state->getCurX(); | |
806 | y1 = state->getCurY(); | |
807 | x2 = args[0].getNum(); | |
808 | y2 = args[1].getNum(); | |
809 | x3 = args[2].getNum(); | |
810 | y3 = args[3].getNum(); | |
811 | state->curveTo(x1, y1, x2, y2, x3, y3); | |
812 | } | |
813 | ||
814 | void Gfx::opCurveTo2(Object args[], int numArgs) { | |
815 | double x1, y1, x2, y2, x3, y3; | |
816 | ||
a5f8b9e7 | 817 | (void)numArgs; |
818 | ||
9c72faab | 819 | if (!state->isCurPt()) { |
820 | error(getPos(), "No current point in curveto2"); | |
821 | return; | |
822 | } | |
823 | x1 = args[0].getNum(); | |
824 | y1 = args[1].getNum(); | |
825 | x2 = args[2].getNum(); | |
826 | y2 = args[3].getNum(); | |
827 | x3 = x2; | |
828 | y3 = y2; | |
829 | state->curveTo(x1, y1, x2, y2, x3, y3); | |
830 | } | |
831 | ||
832 | void Gfx::opRectangle(Object args[], int numArgs) { | |
833 | double x, y, w, h; | |
834 | ||
a5f8b9e7 | 835 | (void)numArgs; |
836 | ||
9c72faab | 837 | x = args[0].getNum(); |
838 | y = args[1].getNum(); | |
839 | w = args[2].getNum(); | |
840 | h = args[3].getNum(); | |
841 | state->moveTo(x, y); | |
842 | state->lineTo(x + w, y); | |
843 | state->lineTo(x + w, y + h); | |
844 | state->lineTo(x, y + h); | |
845 | state->closePath(); | |
846 | } | |
847 | ||
848 | void Gfx::opClosePath(Object args[], int numArgs) { | |
a5f8b9e7 | 849 | (void)args; |
850 | (void)numArgs; | |
851 | ||
9c72faab | 852 | if (!state->isPath()) { |
853 | error(getPos(), "No current point in closepath"); | |
854 | return; | |
855 | } | |
856 | state->closePath(); | |
857 | } | |
858 | ||
859 | //------------------------------------------------------------------------ | |
860 | // path painting operators | |
861 | //------------------------------------------------------------------------ | |
862 | ||
863 | void Gfx::opEndPath(Object args[], int numArgs) { | |
a5f8b9e7 | 864 | (void)args; |
865 | (void)numArgs; | |
866 | ||
9c72faab | 867 | doEndPath(); |
868 | } | |
869 | ||
870 | void Gfx::opStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 871 | (void)args; |
872 | (void)numArgs; | |
873 | ||
9c72faab | 874 | if (!state->isCurPt()) { |
875 | //error(getPos(), "No path in stroke"); | |
876 | return; | |
877 | } | |
878 | if (state->isPath()) | |
879 | out->stroke(state); | |
880 | doEndPath(); | |
881 | } | |
882 | ||
883 | void Gfx::opCloseStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 884 | (void)args; |
885 | (void)numArgs; | |
886 | ||
9c72faab | 887 | if (!state->isCurPt()) { |
888 | //error(getPos(), "No path in closepath/stroke"); | |
889 | return; | |
890 | } | |
891 | if (state->isPath()) { | |
892 | state->closePath(); | |
893 | out->stroke(state); | |
894 | } | |
895 | doEndPath(); | |
896 | } | |
897 | ||
898 | void Gfx::opFill(Object args[], int numArgs) { | |
a5f8b9e7 | 899 | (void)args; |
900 | (void)numArgs; | |
901 | ||
9c72faab | 902 | if (!state->isCurPt()) { |
903 | //error(getPos(), "No path in fill"); | |
904 | return; | |
905 | } | |
906 | if (state->isPath()) | |
907 | out->fill(state); | |
908 | doEndPath(); | |
909 | } | |
910 | ||
911 | void Gfx::opEOFill(Object args[], int numArgs) { | |
a5f8b9e7 | 912 | (void)args; |
913 | (void)numArgs; | |
914 | ||
9c72faab | 915 | if (!state->isCurPt()) { |
916 | //error(getPos(), "No path in eofill"); | |
917 | return; | |
918 | } | |
919 | if (state->isPath()) | |
920 | out->eoFill(state); | |
921 | doEndPath(); | |
922 | } | |
923 | ||
924 | void Gfx::opFillStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 925 | (void)args; |
926 | (void)numArgs; | |
927 | ||
9c72faab | 928 | if (!state->isCurPt()) { |
929 | //error(getPos(), "No path in fill/stroke"); | |
930 | return; | |
931 | } | |
932 | if (state->isPath()) { | |
933 | out->fill(state); | |
934 | out->stroke(state); | |
935 | } | |
936 | doEndPath(); | |
937 | } | |
938 | ||
939 | void Gfx::opCloseFillStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 940 | (void)args; |
941 | (void)numArgs; | |
942 | ||
9c72faab | 943 | if (!state->isCurPt()) { |
944 | //error(getPos(), "No path in closepath/fill/stroke"); | |
945 | return; | |
946 | } | |
947 | if (state->isPath()) { | |
948 | state->closePath(); | |
949 | out->fill(state); | |
950 | out->stroke(state); | |
951 | } | |
952 | doEndPath(); | |
953 | } | |
954 | ||
955 | void Gfx::opEOFillStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 956 | (void)args; |
957 | (void)numArgs; | |
958 | ||
9c72faab | 959 | if (!state->isCurPt()) { |
960 | //error(getPos(), "No path in eofill/stroke"); | |
961 | return; | |
962 | } | |
963 | if (state->isPath()) { | |
964 | out->eoFill(state); | |
965 | out->stroke(state); | |
966 | } | |
967 | doEndPath(); | |
968 | } | |
969 | ||
970 | void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { | |
a5f8b9e7 | 971 | (void)args; |
972 | (void)numArgs; | |
973 | ||
9c72faab | 974 | if (!state->isCurPt()) { |
975 | //error(getPos(), "No path in closepath/eofill/stroke"); | |
976 | return; | |
977 | } | |
978 | if (state->isPath()) { | |
979 | state->closePath(); | |
980 | out->eoFill(state); | |
981 | out->stroke(state); | |
982 | } | |
983 | doEndPath(); | |
984 | } | |
985 | ||
986 | void Gfx::opShFill(Object args[], int numArgs) { | |
a5f8b9e7 | 987 | (void)args; |
988 | (void)numArgs; | |
9c72faab | 989 | } |
990 | ||
991 | void Gfx::doEndPath() { | |
992 | if (state->isPath()) { | |
993 | if (clip == clipNormal) | |
994 | out->clip(state); | |
995 | else if (clip == clipEO) | |
996 | out->eoClip(state); | |
997 | } | |
998 | clip = clipNone; | |
999 | state->clearPath(); | |
1000 | } | |
1001 | ||
1002 | //------------------------------------------------------------------------ | |
1003 | // path clipping operators | |
1004 | //------------------------------------------------------------------------ | |
1005 | ||
1006 | void Gfx::opClip(Object args[], int numArgs) { | |
a5f8b9e7 | 1007 | (void)args; |
1008 | (void)numArgs; | |
1009 | ||
9c72faab | 1010 | clip = clipNormal; |
1011 | } | |
1012 | ||
1013 | void Gfx::opEOClip(Object args[], int numArgs) { | |
a5f8b9e7 | 1014 | (void)args; |
1015 | (void)numArgs; | |
1016 | ||
9c72faab | 1017 | clip = clipEO; |
1018 | } | |
1019 | ||
1020 | //------------------------------------------------------------------------ | |
1021 | // text object operators | |
1022 | //------------------------------------------------------------------------ | |
1023 | ||
1024 | void Gfx::opBeginText(Object args[], int numArgs) { | |
a5f8b9e7 | 1025 | (void)args; |
1026 | (void)numArgs; | |
1027 | ||
9c72faab | 1028 | state->setTextMat(1, 0, 0, 1, 0, 0); |
1029 | state->textMoveTo(0, 0); | |
1030 | out->updateTextMat(state); | |
1031 | out->updateTextPos(state); | |
1032 | fontChanged = gTrue; | |
1033 | } | |
1034 | ||
1035 | void Gfx::opEndText(Object args[], int numArgs) { | |
a5f8b9e7 | 1036 | (void)args; |
1037 | (void)numArgs; | |
9c72faab | 1038 | } |
1039 | ||
1040 | //------------------------------------------------------------------------ | |
1041 | // text state operators | |
1042 | //------------------------------------------------------------------------ | |
1043 | ||
1044 | void Gfx::opSetCharSpacing(Object args[], int numArgs) { | |
a5f8b9e7 | 1045 | (void)args; |
1046 | (void)numArgs; | |
1047 | ||
9c72faab | 1048 | state->setCharSpace(args[0].getNum()); |
1049 | out->updateCharSpace(state); | |
1050 | } | |
1051 | ||
1052 | void Gfx::opSetFont(Object args[], int numArgs) { | |
1053 | GfxFont *font; | |
1054 | ||
a5f8b9e7 | 1055 | (void)numArgs; |
1056 | ||
9c72faab | 1057 | if (!(font = lookupFont(args[0].getName()))) |
1058 | return; | |
1059 | if (printCommands) { | |
1060 | printf(" font: '%s' %g\n", | |
1061 | font->getName() ? font->getName()->getCString() : "???", | |
1062 | args[1].getNum()); | |
1063 | } | |
1064 | state->setFont(font, args[1].getNum()); | |
1065 | fontChanged = gTrue; | |
1066 | } | |
1067 | ||
1068 | void Gfx::opSetTextLeading(Object args[], int numArgs) { | |
a5f8b9e7 | 1069 | (void)numArgs; |
1070 | ||
9c72faab | 1071 | state->setLeading(args[0].getNum()); |
1072 | } | |
1073 | ||
1074 | void Gfx::opSetTextRender(Object args[], int numArgs) { | |
a5f8b9e7 | 1075 | (void)numArgs; |
1076 | ||
9c72faab | 1077 | state->setRender(args[0].getInt()); |
1078 | out->updateRender(state); | |
1079 | } | |
1080 | ||
1081 | void Gfx::opSetTextRise(Object args[], int numArgs) { | |
a5f8b9e7 | 1082 | (void)numArgs; |
1083 | ||
9c72faab | 1084 | state->setRise(args[0].getNum()); |
1085 | out->updateRise(state); | |
1086 | } | |
1087 | ||
1088 | void Gfx::opSetWordSpacing(Object args[], int numArgs) { | |
a5f8b9e7 | 1089 | (void)numArgs; |
1090 | ||
9c72faab | 1091 | state->setWordSpace(args[0].getNum()); |
1092 | out->updateWordSpace(state); | |
1093 | } | |
1094 | ||
1095 | void Gfx::opSetHorizScaling(Object args[], int numArgs) { | |
a5f8b9e7 | 1096 | (void)numArgs; |
1097 | ||
9c72faab | 1098 | state->setHorizScaling(args[0].getNum()); |
1099 | out->updateHorizScaling(state); | |
1100 | } | |
1101 | ||
1102 | //------------------------------------------------------------------------ | |
1103 | // text positioning operators | |
1104 | //------------------------------------------------------------------------ | |
1105 | ||
1106 | void Gfx::opTextMove(Object args[], int numArgs) { | |
1107 | double tx, ty; | |
1108 | ||
a5f8b9e7 | 1109 | (void)numArgs; |
1110 | ||
9c72faab | 1111 | tx = state->getLineX() + args[0].getNum(); |
1112 | ty = state->getLineY() + args[1].getNum(); | |
1113 | state->textMoveTo(tx, ty); | |
1114 | out->updateTextPos(state); | |
1115 | } | |
1116 | ||
1117 | void Gfx::opTextMoveSet(Object args[], int numArgs) { | |
1118 | double tx, ty; | |
1119 | ||
a5f8b9e7 | 1120 | (void)numArgs; |
1121 | ||
9c72faab | 1122 | tx = state->getLineX() + args[0].getNum(); |
1123 | ty = args[1].getNum(); | |
1124 | state->setLeading(-ty); | |
1125 | ty += state->getLineY(); | |
1126 | state->textMoveTo(tx, ty); | |
1127 | out->updateTextPos(state); | |
1128 | } | |
1129 | ||
1130 | void Gfx::opSetTextMatrix(Object args[], int numArgs) { | |
a5f8b9e7 | 1131 | (void)numArgs; |
1132 | ||
9c72faab | 1133 | state->setTextMat(args[0].getNum(), args[1].getNum(), |
1134 | args[2].getNum(), args[3].getNum(), | |
1135 | args[4].getNum(), args[5].getNum()); | |
1136 | state->textMoveTo(0, 0); | |
1137 | out->updateTextMat(state); | |
1138 | out->updateTextPos(state); | |
1139 | fontChanged = gTrue; | |
1140 | } | |
1141 | ||
1142 | void Gfx::opTextNextLine(Object args[], int numArgs) { | |
1143 | double tx, ty; | |
1144 | ||
a5f8b9e7 | 1145 | (void)args; |
1146 | (void)numArgs; | |
1147 | ||
9c72faab | 1148 | tx = state->getLineX(); |
1149 | ty = state->getLineY() - state->getLeading(); | |
1150 | state->textMoveTo(tx, ty); | |
1151 | out->updateTextPos(state); | |
1152 | } | |
1153 | ||
1154 | //------------------------------------------------------------------------ | |
1155 | // text string operators | |
1156 | //------------------------------------------------------------------------ | |
1157 | ||
1158 | void Gfx::opShowText(Object args[], int numArgs) { | |
a5f8b9e7 | 1159 | (void)numArgs; |
1160 | ||
9c72faab | 1161 | if (!state->getFont()) { |
1162 | error(getPos(), "No font in show"); | |
1163 | return; | |
1164 | } | |
1165 | doShowText(args[0].getString()); | |
1166 | } | |
1167 | ||
1168 | void Gfx::opMoveShowText(Object args[], int numArgs) { | |
1169 | double tx, ty; | |
1170 | ||
a5f8b9e7 | 1171 | (void)numArgs; |
1172 | ||
9c72faab | 1173 | if (!state->getFont()) { |
1174 | error(getPos(), "No font in move/show"); | |
1175 | return; | |
1176 | } | |
1177 | tx = state->getLineX(); | |
1178 | ty = state->getLineY() - state->getLeading(); | |
1179 | state->textMoveTo(tx, ty); | |
1180 | out->updateTextPos(state); | |
1181 | doShowText(args[0].getString()); | |
1182 | } | |
1183 | ||
1184 | void Gfx::opMoveSetShowText(Object args[], int numArgs) { | |
1185 | double tx, ty; | |
1186 | ||
a5f8b9e7 | 1187 | (void)numArgs; |
1188 | ||
9c72faab | 1189 | if (!state->getFont()) { |
1190 | error(getPos(), "No font in move/set/show"); | |
1191 | return; | |
1192 | } | |
1193 | state->setWordSpace(args[0].getNum()); | |
1194 | state->setCharSpace(args[1].getNum()); | |
1195 | tx = state->getLineX(); | |
1196 | ty = state->getLineY() - state->getLeading(); | |
1197 | state->textMoveTo(tx, ty); | |
1198 | out->updateWordSpace(state); | |
1199 | out->updateCharSpace(state); | |
1200 | out->updateTextPos(state); | |
1201 | doShowText(args[2].getString()); | |
1202 | } | |
1203 | ||
1204 | void Gfx::opShowSpaceText(Object args[], int numArgs) { | |
1205 | Array *a; | |
1206 | Object obj; | |
1207 | int i; | |
1208 | ||
a5f8b9e7 | 1209 | (void)numArgs; |
1210 | ||
9c72faab | 1211 | if (!state->getFont()) { |
1212 | error(getPos(), "No font in show/space"); | |
1213 | return; | |
1214 | } | |
1215 | a = args[0].getArray(); | |
1216 | for (i = 0; i < a->getLength(); ++i) { | |
1217 | a->get(i, &obj); | |
1218 | if (obj.isNum()) { | |
1219 | state->textShift(-obj.getNum() * 0.001 * state->getFontSize()); | |
1220 | out->updateTextShift(state, obj.getNum()); | |
1221 | } else if (obj.isString()) { | |
1222 | doShowText(obj.getString()); | |
1223 | } else { | |
1224 | error(getPos(), "Element of show/space array must be number or string"); | |
1225 | } | |
1226 | obj.free(); | |
1227 | } | |
1228 | } | |
1229 | ||
1230 | void Gfx::doShowText(GString *s) { | |
1231 | GfxFont *font; | |
1232 | GfxFontEncoding16 *enc; | |
1233 | Guchar *p; | |
1234 | Guchar c8; | |
1235 | int c16; | |
1236 | GString *s16; | |
52118ca3 | 1237 | char s16a[2]; |
9c72faab | 1238 | int m, n; |
52118ca3 | 1239 | #if 0 //~type3 |
1240 | double dx, dy, width, height, w, h, x, y; | |
1241 | double oldCTM[6], newCTM[6]; | |
1242 | double *mat; | |
1243 | Object charProc; | |
1244 | Parser *oldParser; | |
1245 | int i; | |
1246 | #else | |
1247 | double dx, dy, width, height, w, h, sWidth, sHeight; | |
1248 | #endif | |
9c72faab | 1249 | |
1250 | if (fontChanged) { | |
1251 | out->updateFont(state); | |
1252 | fontChanged = gFalse; | |
1253 | } | |
1254 | font = state->getFont(); | |
1255 | ||
1256 | //----- 16-bit font | |
1257 | if (font->is16Bit()) { | |
1258 | enc = font->getEncoding16(); | |
1259 | if (out->useDrawChar()) { | |
1260 | out->beginString(state, s); | |
1261 | s16 = NULL; | |
1262 | } else { | |
52118ca3 | 1263 | s16 = new GString(); |
9c72faab | 1264 | } |
52118ca3 | 1265 | sWidth = sHeight = 0; |
9c72faab | 1266 | state->textTransformDelta(0, state->getRise(), &dx, &dy); |
1267 | p = (Guchar *)s->getCString(); | |
1268 | n = s->getLength(); | |
1269 | while (n > 0) { | |
1270 | m = getNextChar16(enc, p, &c16); | |
1271 | if (enc->wMode == 0) { | |
1272 | width = state->getFontSize() * state->getHorizScaling() * | |
1273 | font->getWidth16(c16) + | |
1274 | state->getCharSpace(); | |
1275 | if (c16 == ' ') { | |
1276 | width += state->getWordSpace(); | |
1277 | } | |
1278 | height = 0; | |
1279 | } else { | |
1280 | width = 0; | |
1281 | height = state->getFontSize() * font->getHeight16(c16); | |
1282 | } | |
1283 | state->textTransformDelta(width, height, &w, &h); | |
1284 | if (out->useDrawChar()) { | |
1285 | out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy, | |
1286 | w, h, c16); | |
52118ca3 | 1287 | state->textShift(width, height); |
9c72faab | 1288 | } else { |
52118ca3 | 1289 | s16a[0] = (char)(c16 >> 8); |
1290 | s16a[1] = (char)c16; | |
1291 | s16->append(s16a, 2); | |
1292 | sWidth += w; | |
1293 | sHeight += h; | |
9c72faab | 1294 | } |
9c72faab | 1295 | n -= m; |
1296 | p += m; | |
1297 | } | |
52118ca3 | 1298 | if (out->useDrawChar()) { |
9c72faab | 1299 | out->endString(state); |
52118ca3 | 1300 | } else { |
1301 | out->drawString16(state, s16); | |
9c72faab | 1302 | delete s16; |
52118ca3 | 1303 | state->textShift(sWidth, sHeight); |
1304 | } | |
9c72faab | 1305 | |
1306 | //----- 8-bit font | |
1307 | } else { | |
52118ca3 | 1308 | #if 0 //~type3 |
1309 | //~ also check out->renderType3() | |
1310 | if (font->getType() == fontType3) { | |
1311 | out->beginString(state, s); | |
1312 | mat = state->getCTM(); | |
1313 | for (i = 0; i < 6; ++i) { | |
1314 | oldCTM[i] = mat[i]; | |
1315 | } | |
1316 | mat = state->getTextMat(); | |
1317 | newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; | |
1318 | newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; | |
1319 | newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; | |
1320 | newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; | |
1321 | mat = font->getFontMatrix(); | |
1322 | newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; | |
1323 | newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; | |
1324 | newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; | |
1325 | newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; | |
1326 | newCTM[0] *= state->getFontSize(); | |
1327 | newCTM[3] *= state->getFontSize(); | |
1328 | newCTM[0] *= state->getHorizScaling(); | |
1329 | newCTM[2] *= state->getHorizScaling(); | |
1330 | state->textTransformDelta(0, state->getRise(), &dx, &dy); | |
1331 | oldParser = parser; | |
1332 | for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { | |
1333 | c8 = *p; | |
1334 | font->getCharProc(c8, &charProc); | |
1335 | state->transform(state->getCurX() + dx, state->getCurY() + dy, &x, &y); | |
1336 | state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); | |
1337 | //~ out->updateCTM(???) | |
1338 | if (charProc.isStream()) { | |
1339 | display(&charProc); | |
1340 | } else { | |
1341 | error(getPos(), "Missing or bad Type3 CharProc entry"); | |
1342 | } | |
1343 | state->setCTM(oldCTM[0], oldCTM[1], oldCTM[2], | |
1344 | oldCTM[3], oldCTM[4], oldCTM[5]); | |
1345 | //~ out->updateCTM(???) - use gsave/grestore instead? | |
1346 | charProc.free(); | |
1347 | width = state->getFontSize() * state->getHorizScaling() * | |
1348 | font->getWidth(c8) + | |
1349 | state->getCharSpace(); | |
1350 | if (c8 == ' ') { | |
1351 | width += state->getWordSpace(); | |
1352 | } | |
1353 | state->textShift(width); | |
1354 | } | |
1355 | parser = oldParser; | |
1356 | out->endString(state); | |
1357 | } else | |
1358 | #endif | |
9c72faab | 1359 | if (out->useDrawChar()) { |
1360 | out->beginString(state, s); | |
1361 | state->textTransformDelta(0, state->getRise(), &dx, &dy); | |
1362 | for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { | |
1363 | c8 = *p; | |
1364 | width = state->getFontSize() * state->getHorizScaling() * | |
1365 | font->getWidth(c8) + | |
1366 | state->getCharSpace(); | |
1367 | if (c8 == ' ') | |
1368 | width += state->getWordSpace(); | |
1369 | state->textTransformDelta(width, 0, &w, &h); | |
1370 | out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy, | |
1371 | w, h, c8); | |
1372 | state->textShift(width); | |
1373 | } | |
1374 | out->endString(state); | |
1375 | } else { | |
1376 | out->drawString(state, s); | |
1377 | width = state->getFontSize() * state->getHorizScaling() * | |
1378 | font->getWidth(s) + | |
1379 | s->getLength() * state->getCharSpace(); | |
1380 | for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { | |
1381 | if (*p == ' ') | |
1382 | width += state->getWordSpace(); | |
1383 | } | |
1384 | state->textShift(width); | |
1385 | } | |
1386 | } | |
1387 | } | |
1388 | ||
1389 | int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) { | |
1390 | int n; | |
1391 | int code; | |
1392 | int a, b, m; | |
1393 | ||
1394 | n = enc->codeLen[*p]; | |
1395 | if (n == 1) { | |
1396 | *c16 = enc->map1[*p]; | |
1397 | } else { | |
1398 | code = (p[0] << 8) + p[1]; | |
1399 | a = 0; | |
1400 | b = enc->map2Len; | |
1401 | // invariant: map2[2*a] <= code < map2[2*b] | |
1402 | while (b - a > 1) { | |
1403 | m = (a + b) / 2; | |
1404 | if (enc->map2[2*m] <= code) | |
1405 | a = m; | |
1406 | else if (enc->map2[2*m] > code) | |
1407 | b = m; | |
1408 | else | |
1409 | break; | |
1410 | } | |
1411 | *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]); | |
1412 | } | |
1413 | return n; | |
1414 | } | |
1415 | ||
1416 | //------------------------------------------------------------------------ | |
1417 | // XObject operators | |
1418 | //------------------------------------------------------------------------ | |
1419 | ||
1420 | void Gfx::opXObject(Object args[], int numArgs) { | |
1421 | Object obj1, obj2; | |
52118ca3 | 1422 | #if OPI_SUPPORT |
1423 | Object opiDict; | |
1424 | #endif | |
9c72faab | 1425 | |
a5f8b9e7 | 1426 | (void)numArgs; |
1427 | ||
9c72faab | 1428 | if (!lookupXObject(args[0].getName(), &obj1)) |
1429 | return; | |
52118ca3 | 1430 | if (!obj1.isStream()) { |
9c72faab | 1431 | error(getPos(), "XObject '%s' is wrong type", args[0].getName()); |
1432 | obj1.free(); | |
1433 | return; | |
1434 | } | |
52118ca3 | 1435 | #if OPI_SUPPORT |
1436 | obj1.streamGetDict()->lookup("OPI", &opiDict); | |
1437 | if (opiDict.isDict()) { | |
1438 | out->opiBegin(state, opiDict.getDict()); | |
1439 | } | |
1440 | #endif | |
9c72faab | 1441 | obj1.streamGetDict()->lookup("Subtype", &obj2); |
1442 | if (obj2.isName("Image")) | |
1443 | doImage(obj1.getStream(), gFalse); | |
1444 | else if (obj2.isName("Form")) | |
1445 | doForm(&obj1); | |
1446 | else if (obj2.isName()) | |
1447 | error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); | |
1448 | else | |
1449 | error(getPos(), "XObject subtype is missing or wrong type"); | |
1450 | obj2.free(); | |
52118ca3 | 1451 | #if OPI_SUPPORT |
1452 | if (opiDict.isDict()) { | |
1453 | out->opiEnd(state, opiDict.getDict()); | |
1454 | } | |
1455 | opiDict.free(); | |
1456 | #endif | |
9c72faab | 1457 | obj1.free(); |
1458 | } | |
1459 | ||
1460 | void Gfx::doImage(Stream *str, GBool inlineImg) { | |
1461 | Dict *dict; | |
1462 | Object obj1, obj2; | |
1463 | int width, height; | |
1464 | int bits; | |
1465 | GBool mask; | |
1466 | GfxColorSpace *colorSpace; | |
1467 | GfxImageColorMap *colorMap; | |
1468 | GBool invert; | |
1469 | ||
1470 | // get stream dict | |
1471 | dict = str->getDict(); | |
1472 | ||
1473 | // get size | |
1474 | dict->lookup("Width", &obj1); | |
1475 | if (obj1.isNull()) { | |
1476 | obj1.free(); | |
1477 | dict->lookup("W", &obj1); | |
1478 | } | |
1479 | if (!obj1.isInt()) | |
1480 | goto err2; | |
1481 | width = obj1.getInt(); | |
1482 | obj1.free(); | |
1483 | dict->lookup("Height", &obj1); | |
1484 | if (obj1.isNull()) { | |
1485 | obj1.free(); | |
1486 | dict->lookup("H", &obj1); | |
1487 | } | |
1488 | if (!obj1.isInt()) | |
1489 | goto err2; | |
1490 | height = obj1.getInt(); | |
1491 | obj1.free(); | |
1492 | ||
1493 | // image or mask? | |
1494 | dict->lookup("ImageMask", &obj1); | |
1495 | if (obj1.isNull()) { | |
1496 | obj1.free(); | |
1497 | dict->lookup("IM", &obj1); | |
1498 | } | |
1499 | mask = gFalse; | |
1500 | if (obj1.isBool()) | |
1501 | mask = obj1.getBool(); | |
1502 | else if (!obj1.isNull()) | |
1503 | goto err2; | |
1504 | obj1.free(); | |
1505 | ||
1506 | // bit depth | |
1507 | dict->lookup("BitsPerComponent", &obj1); | |
1508 | if (obj1.isNull()) { | |
1509 | obj1.free(); | |
1510 | dict->lookup("BPC", &obj1); | |
1511 | } | |
1512 | if (!obj1.isInt()) | |
1513 | goto err2; | |
1514 | bits = obj1.getInt(); | |
1515 | obj1.free(); | |
1516 | ||
1517 | // display a mask | |
1518 | if (mask) { | |
1519 | ||
1520 | // check for inverted mask | |
1521 | if (bits != 1) | |
1522 | goto err1; | |
1523 | invert = gFalse; | |
1524 | dict->lookup("Decode", &obj1); | |
1525 | if (obj1.isNull()) { | |
1526 | obj1.free(); | |
1527 | dict->lookup("D", &obj1); | |
1528 | } | |
1529 | if (obj1.isArray()) { | |
1530 | obj1.arrayGet(0, &obj2); | |
1531 | if (obj2.isInt() && obj2.getInt() == 1) | |
1532 | invert = gTrue; | |
1533 | obj2.free(); | |
1534 | } else if (!obj1.isNull()) { | |
1535 | goto err2; | |
1536 | } | |
1537 | obj1.free(); | |
1538 | ||
1539 | // draw it | |
1540 | out->drawImageMask(state, str, width, height, invert, inlineImg); | |
1541 | ||
1542 | } else { | |
1543 | ||
1544 | // get color space and color map | |
1545 | dict->lookup("ColorSpace", &obj1); | |
1546 | if (obj1.isNull()) { | |
1547 | obj1.free(); | |
1548 | dict->lookup("CS", &obj1); | |
1549 | } | |
1550 | if (obj1.isName()) { | |
1551 | lookupColorSpace(obj1.getName(), &obj2); | |
1552 | if (!obj2.isNull()) { | |
1553 | obj1.free(); | |
1554 | obj1 = obj2; | |
1555 | } else { | |
1556 | obj2.free(); | |
1557 | } | |
1558 | } | |
1559 | colorSpace = new GfxColorSpace(&obj1); | |
1560 | obj1.free(); | |
1561 | if (!colorSpace->isOk()) { | |
1562 | delete colorSpace; | |
1563 | goto err1; | |
1564 | } | |
1565 | dict->lookup("Decode", &obj1); | |
1566 | if (obj1.isNull()) { | |
1567 | obj1.free(); | |
1568 | dict->lookup("D", &obj1); | |
1569 | } | |
1570 | colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); | |
1571 | obj1.free(); | |
1572 | if (!colorMap->isOk()) { | |
1573 | delete colorSpace; | |
1574 | goto err1; | |
1575 | } | |
1576 | ||
1577 | // draw it | |
1578 | out->drawImage(state, str, width, height, colorMap, inlineImg); | |
1579 | delete colorMap; | |
1580 | } | |
1581 | ||
1582 | return; | |
1583 | ||
1584 | err2: | |
1585 | obj1.free(); | |
1586 | err1: | |
1587 | error(getPos(), "Bad image parameters"); | |
1588 | } | |
1589 | ||
1590 | void Gfx::doForm(Object *str) { | |
9c72faab | 1591 | Dict *dict; |
9c72faab | 1592 | Object matrixObj, bboxObj; |
52118ca3 | 1593 | Object obj1; |
9c72faab | 1594 | |
1595 | // get stream dict | |
1596 | dict = str->streamGetDict(); | |
1597 | ||
1598 | // check form type | |
1599 | dict->lookup("FormType", &obj1); | |
1600 | if (!(obj1.isInt() && obj1.getInt() == 1)) { | |
1601 | error(getPos(), "Unknown form type"); | |
1602 | } | |
1603 | obj1.free(); | |
1604 | ||
1605 | // get matrix and bounding box | |
1606 | dict->lookup("Matrix", &matrixObj); | |
1607 | if (!matrixObj.isArray()) { | |
1608 | matrixObj.free(); | |
1609 | error(getPos(), "Bad form matrix"); | |
1610 | return; | |
1611 | } | |
1612 | dict->lookup("BBox", &bboxObj); | |
1613 | if (!bboxObj.isArray()) { | |
1614 | matrixObj.free(); | |
1615 | bboxObj.free(); | |
1616 | error(getPos(), "Bad form bounding box"); | |
1617 | return; | |
1618 | } | |
1619 | ||
52118ca3 | 1620 | doForm1(str, dict, &matrixObj, &bboxObj); |
1621 | ||
1622 | matrixObj.free(); | |
1623 | bboxObj.free(); | |
1624 | } | |
1625 | ||
1626 | void Gfx::doWidgetForm(Object *str, double x, double y) { | |
1627 | Dict *dict; | |
1628 | Object matrixObj, bboxObj; | |
1629 | Object obj1; | |
1630 | ||
1631 | // get stream dict | |
1632 | dict = str->streamGetDict(); | |
1633 | ||
1634 | // get bounding box | |
1635 | dict->lookup("BBox", &bboxObj); | |
1636 | if (!bboxObj.isArray()) { | |
1637 | bboxObj.free(); | |
1638 | error(getPos(), "Bad form bounding box"); | |
1639 | return; | |
1640 | } | |
1641 | ||
1642 | // construct matrix | |
1643 | matrixObj.initArray(); | |
1644 | obj1.initReal(1); | |
1645 | matrixObj.arrayAdd(&obj1); | |
1646 | obj1.initReal(0); | |
1647 | matrixObj.arrayAdd(&obj1); | |
1648 | obj1.initReal(0); | |
1649 | matrixObj.arrayAdd(&obj1); | |
1650 | obj1.initReal(1); | |
1651 | matrixObj.arrayAdd(&obj1); | |
1652 | obj1.initReal(x); | |
1653 | matrixObj.arrayAdd(&obj1); | |
1654 | obj1.initReal(y); | |
1655 | matrixObj.arrayAdd(&obj1); | |
1656 | ||
1657 | doForm1(str, dict, &matrixObj, &bboxObj); | |
1658 | ||
1659 | matrixObj.free(); | |
1660 | bboxObj.free(); | |
1661 | } | |
1662 | ||
1663 | void Gfx::doForm1(Object *str, Dict *dict, | |
1664 | Object *matrixObj, Object *bboxObj) { | |
1665 | Parser *oldParser; | |
1666 | GfxResources *resPtr; | |
1667 | Dict *resDict; | |
1668 | double m[6]; | |
1669 | Object obj1, obj2; | |
1670 | int i; | |
1671 | ||
9c72faab | 1672 | // push new resources on stack |
1673 | res = new GfxResources(res); | |
1674 | dict->lookup("Resources", &obj1); | |
1675 | if (obj1.isDict()) { | |
1676 | resDict = obj1.getDict(); | |
1677 | res->fonts = NULL; | |
1678 | resDict->lookup("Font", &obj2); | |
1679 | if (obj2.isDict()) | |
1680 | res->fonts = new GfxFontDict(obj2.getDict()); | |
1681 | obj2.free(); | |
1682 | resDict->lookup("XObject", &res->xObjDict); | |
1683 | resDict->lookup("ColorSpace", &res->colorSpaceDict); | |
1684 | obj1.free(); | |
1685 | } | |
1686 | ||
1687 | // save current graphics state | |
1688 | out->saveState(state); | |
1689 | state = state->save(); | |
1690 | ||
1691 | // save current parser | |
1692 | oldParser = parser; | |
1693 | ||
1694 | // set form transformation matrix | |
1695 | for (i = 0; i < 6; ++i) { | |
52118ca3 | 1696 | matrixObj->arrayGet(i, &obj1); |
9c72faab | 1697 | m[i] = obj1.getNum(); |
1698 | obj1.free(); | |
1699 | } | |
1700 | state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); | |
1701 | out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); | |
1702 | ||
1703 | // set form bounding box | |
1704 | for (i = 0; i < 4; ++i) { | |
52118ca3 | 1705 | bboxObj->arrayGet(i, &obj1); |
9c72faab | 1706 | m[i] = obj1.getNum(); |
1707 | obj1.free(); | |
1708 | } | |
1709 | state->moveTo(m[0], m[1]); | |
52118ca3 | 1710 | state->lineTo(m[2], m[1]); |
1711 | state->lineTo(m[2], m[3]); | |
1712 | state->lineTo(m[0], m[3]); | |
9c72faab | 1713 | state->closePath(); |
1714 | out->clip(state); | |
1715 | state->clearPath(); | |
1716 | ||
1717 | // draw the form | |
1718 | display(str); | |
1719 | ||
9c72faab | 1720 | // restore parser |
1721 | parser = oldParser; | |
1722 | ||
1723 | // restore graphics state | |
1724 | state = state->restore(); | |
1725 | out->restoreState(state); | |
1726 | ||
1727 | // pop resource stack | |
1728 | resPtr = res->next; | |
1729 | delete res; | |
1730 | res = resPtr; | |
1731 | ||
1732 | return; | |
1733 | } | |
1734 | ||
1735 | //------------------------------------------------------------------------ | |
1736 | // in-line image operators | |
1737 | //------------------------------------------------------------------------ | |
1738 | ||
1739 | void Gfx::opBeginImage(Object args[], int numArgs) { | |
1740 | Stream *str; | |
1741 | int c1, c2; | |
1742 | ||
a5f8b9e7 | 1743 | (void)args; |
1744 | (void)numArgs; | |
1745 | ||
9c72faab | 1746 | // build dict/stream |
1747 | str = buildImageStream(); | |
1748 | ||
1749 | // display the image | |
1750 | if (str) { | |
1751 | doImage(str, gTrue); | |
1752 | ||
1753 | // skip 'EI' tag | |
1754 | c1 = str->getBaseStream()->getChar(); | |
1755 | c2 = str->getBaseStream()->getChar(); | |
1756 | while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { | |
1757 | c1 = c2; | |
1758 | c2 = str->getBaseStream()->getChar(); | |
1759 | } | |
1760 | delete str; | |
1761 | } | |
1762 | } | |
1763 | ||
1764 | Stream *Gfx::buildImageStream() { | |
1765 | Object dict; | |
1766 | Object obj; | |
aa530ae8 | 1767 | const char *key; |
9c72faab | 1768 | Stream *str; |
1769 | ||
1770 | // build dictionary | |
1771 | dict.initDict(); | |
1772 | parser->getObj(&obj); | |
1773 | while (!obj.isCmd("ID") && !obj.isEOF()) { | |
1774 | if (!obj.isName()) { | |
1775 | error(getPos(), "Inline image dictionary key must be a name object"); | |
1776 | obj.free(); | |
1777 | parser->getObj(&obj); | |
1778 | } else { | |
1779 | key = copyString(obj.getName()); | |
1780 | obj.free(); | |
1781 | parser->getObj(&obj); | |
1782 | if (obj.isEOF() || obj.isError()) | |
1783 | break; | |
1784 | dict.dictAdd(key, &obj); | |
1785 | } | |
1786 | parser->getObj(&obj); | |
1787 | } | |
1788 | if (obj.isEOF()) | |
1789 | error(getPos(), "End of file in inline image"); | |
1790 | obj.free(); | |
1791 | ||
1792 | // make stream | |
52118ca3 | 1793 | str = new EmbedStream(parser->getStream(), &dict); |
9c72faab | 1794 | str = str->addFilters(&dict); |
1795 | ||
1796 | return str; | |
1797 | } | |
1798 | ||
1799 | void Gfx::opImageData(Object args[], int numArgs) { | |
a5f8b9e7 | 1800 | (void)args; |
1801 | (void)numArgs; | |
1802 | ||
9c72faab | 1803 | error(getPos(), "Internal: got 'ID' operator"); |
1804 | } | |
1805 | ||
1806 | void Gfx::opEndImage(Object args[], int numArgs) { | |
a5f8b9e7 | 1807 | (void)args; |
1808 | (void)numArgs; | |
1809 | ||
9c72faab | 1810 | error(getPos(), "Internal: got 'EI' operator"); |
1811 | } | |
1812 | ||
1813 | //------------------------------------------------------------------------ | |
1814 | // type 3 font operators | |
1815 | //------------------------------------------------------------------------ | |
1816 | ||
1817 | void Gfx::opSetCharWidth(Object args[], int numArgs) { | |
a5f8b9e7 | 1818 | (void)args; |
1819 | (void)numArgs; | |
1820 | ||
9c72faab | 1821 | error(getPos(), "Encountered 'd0' operator in content stream"); |
1822 | } | |
1823 | ||
1824 | void Gfx::opSetCacheDevice(Object args[], int numArgs) { | |
a5f8b9e7 | 1825 | (void)args; |
1826 | (void)numArgs; | |
1827 | ||
9c72faab | 1828 | error(getPos(), "Encountered 'd1' operator in content stream"); |
1829 | } | |
1830 | ||
1831 | //------------------------------------------------------------------------ | |
1832 | // compatibility operators | |
1833 | //------------------------------------------------------------------------ | |
1834 | ||
1835 | void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) { | |
a5f8b9e7 | 1836 | (void)args; |
1837 | (void)numArgs; | |
1838 | ||
9c72faab | 1839 | ++ignoreUndef; |
1840 | } | |
1841 | ||
1842 | void Gfx::opEndIgnoreUndef(Object args[], int numArgs) { | |
a5f8b9e7 | 1843 | (void)args; |
1844 | (void)numArgs; | |
1845 | ||
9c72faab | 1846 | if (ignoreUndef > 0) |
1847 | --ignoreUndef; | |
1848 | } | |
1849 | ||
1850 | //------------------------------------------------------------------------ | |
1851 | // marked content operators | |
1852 | //------------------------------------------------------------------------ | |
1853 | ||
1854 | void Gfx::opBeginMarkedContent(Object args[], int numArgs) { | |
a5f8b9e7 | 1855 | (void)numArgs; |
1856 | ||
9c72faab | 1857 | if (printCommands) { |
1858 | printf(" marked content: %s ", args[0].getName()); | |
1859 | if (numArgs == 2) | |
1860 | args[2].print(stdout); | |
1861 | printf("\n"); | |
1862 | } | |
1863 | } | |
1864 | ||
1865 | void Gfx::opEndMarkedContent(Object args[], int numArgs) { | |
a5f8b9e7 | 1866 | (void)args; |
1867 | (void)numArgs; | |
9c72faab | 1868 | } |
1869 | ||
1870 | void Gfx::opMarkPoint(Object args[], int numArgs) { | |
a5f8b9e7 | 1871 | (void)numArgs; |
1872 | ||
9c72faab | 1873 | if (printCommands) { |
1874 | printf(" mark point: %s ", args[0].getName()); | |
1875 | if (numArgs == 2) | |
1876 | args[2].print(stdout); | |
1877 | printf("\n"); | |
1878 | } | |
1879 | } |