]>
git.ipfire.org Git - thirdparty/cups.git/blob - pdftops/Gfx.cxx
1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
26 #include "OutputDev.h"
31 //------------------------------------------------------------------------
33 //------------------------------------------------------------------------
35 Operator
Gfx::opTab
[] = {
36 {"\"", 3, {tchkNum
, tchkNum
, tchkString
},
37 &Gfx::opMoveSetShowText
},
38 {"'", 1, {tchkString
},
39 &Gfx::opMoveShowText
},
43 &Gfx::opEOFillStroke
},
44 {"BDC", 2, {tchkName
, tchkProps
},
45 &Gfx::opBeginMarkedContent
},
48 {"BMC", 1, {tchkName
},
49 &Gfx::opBeginMarkedContent
},
53 &Gfx::opBeginIgnoreUndef
},
55 &Gfx::opSetStrokeColorSpace
},
56 {"DP", 2, {tchkName
, tchkProps
},
62 {"EMC", 0, {tchkNone
},
63 &Gfx::opEndMarkedContent
},
67 &Gfx::opEndIgnoreUndef
},
71 &Gfx::opSetStrokeGray
},
76 {"K", 4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
77 &Gfx::opSetStrokeCMYKColor
},
79 &Gfx::opSetMiterLimit
},
84 {"RG", 3, {tchkNum
, tchkNum
, tchkNum
},
85 &Gfx::opSetStrokeRGBColor
},
88 {"SC", -4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
89 &Gfx::opSetStrokeColor
},
90 {"SCN", -5, {tchkSCN
, tchkSCN
, tchkSCN
, tchkSCN
,
92 &Gfx::opSetStrokeColorN
},
94 &Gfx::opTextNextLine
},
95 {"TD", 2, {tchkNum
, tchkNum
},
97 {"TJ", 1, {tchkArray
},
98 &Gfx::opShowSpaceText
},
100 &Gfx::opSetTextLeading
},
102 &Gfx::opSetCharSpacing
},
103 {"Td", 2, {tchkNum
, tchkNum
},
105 {"Tf", 2, {tchkName
, tchkNum
},
107 {"Tj", 1, {tchkString
},
109 {"Tm", 6, {tchkNum
, tchkNum
, tchkNum
, tchkNum
,
111 &Gfx::opSetTextMatrix
},
113 &Gfx::opSetTextRender
},
115 &Gfx::opSetTextRise
},
117 &Gfx::opSetWordSpacing
},
119 &Gfx::opSetHorizScaling
},
122 {"W*", 0, {tchkNone
},
125 &Gfx::opCloseFillStroke
},
126 {"b*", 0, {tchkNone
},
127 &Gfx::opCloseEOFillStroke
},
128 {"c", 6, {tchkNum
, tchkNum
, tchkNum
, tchkNum
,
131 {"cm", 6, {tchkNum
, tchkNum
, tchkNum
, tchkNum
,
134 {"cs", 1, {tchkName
},
135 &Gfx::opSetFillColorSpace
},
136 {"d", 2, {tchkArray
, tchkNum
},
138 {"d0", 2, {tchkNum
, tchkNum
},
139 &Gfx::opSetCharWidth
},
140 {"d1", 6, {tchkNum
, tchkNum
, tchkNum
, tchkNum
,
142 &Gfx::opSetCacheDevice
},
145 {"f*", 0, {tchkNone
},
148 &Gfx::opSetFillGray
},
149 {"gs", 1, {tchkName
},
150 &Gfx::opSetExtGState
},
156 &Gfx::opSetLineJoin
},
157 {"k", 4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
158 &Gfx::opSetFillCMYKColor
},
159 {"l", 2, {tchkNum
, tchkNum
},
161 {"m", 2, {tchkNum
, tchkNum
},
167 {"re", 4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
169 {"rg", 3, {tchkNum
, tchkNum
, tchkNum
},
170 &Gfx::opSetFillRGBColor
},
171 {"ri", 1, {tchkName
},
172 &Gfx::opSetRenderingIntent
},
174 &Gfx::opCloseStroke
},
175 {"sc", -4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
176 &Gfx::opSetFillColor
},
177 {"scn", -5, {tchkSCN
, tchkSCN
, tchkSCN
, tchkSCN
,
179 &Gfx::opSetFillColorN
},
180 {"sh", 1, {tchkName
},
182 {"v", 4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
185 &Gfx::opSetLineWidth
},
186 {"y", 4, {tchkNum
, tchkNum
, tchkNum
, tchkNum
},
190 #define numOps (sizeof(opTab) / sizeof(Operator))
192 //------------------------------------------------------------------------
194 GBool printCommands
= gFalse
;
196 //------------------------------------------------------------------------
198 //------------------------------------------------------------------------
200 GfxResources::GfxResources(Dict
*resDict
, GfxResources
*next
) {
205 // build font dictionary
207 resDict
->lookup("Font", &obj1
);
209 fonts
= new GfxFontDict(obj1
.getDict());
213 // get XObject dictionary
214 resDict
->lookup("XObject", &xObjDict
);
216 // get color space dictionary
217 resDict
->lookup("ColorSpace", &colorSpaceDict
);
219 // get pattern dictionary
220 resDict
->lookup("Pattern", &patternDict
);
222 // get graphics state parameter dictionary
223 resDict
->lookup("ExtGState", &gStateDict
);
228 colorSpaceDict
.initNull();
229 patternDict
.initNull();
230 gStateDict
.initNull();
236 GfxResources::~GfxResources() {
241 colorSpaceDict
.free();
246 GfxFont
*GfxResources::lookupFont(const char *name
) {
248 GfxResources
*resPtr
;
250 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
252 if ((font
= resPtr
->fonts
->lookup(name
)))
256 error(-1, "Unknown font tag '%s'", name
);
260 GBool
GfxResources::lookupXObject(const char *name
, Object
*obj
) {
261 GfxResources
*resPtr
;
263 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
264 if (resPtr
->xObjDict
.isDict()) {
265 if (!resPtr
->xObjDict
.dictLookup(name
, obj
)->isNull())
270 error(-1, "XObject '%s' is unknown", name
);
274 GBool
GfxResources::lookupXObjectNF(const char *name
, Object
*obj
) {
275 GfxResources
*resPtr
;
277 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
278 if (resPtr
->xObjDict
.isDict()) {
279 if (!resPtr
->xObjDict
.dictLookupNF(name
, obj
)->isNull())
284 error(-1, "XObject '%s' is unknown", name
);
288 void GfxResources::lookupColorSpace(const char *name
, Object
*obj
) {
289 GfxResources
*resPtr
;
291 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
292 if (resPtr
->colorSpaceDict
.isDict()) {
293 if (!resPtr
->colorSpaceDict
.dictLookup(name
, obj
)->isNull()) {
302 GfxPattern
*GfxResources::lookupPattern(const char *name
) {
303 GfxResources
*resPtr
;
307 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
308 if (resPtr
->patternDict
.isDict()) {
309 if (!resPtr
->patternDict
.dictLookup(name
, &obj
)->isNull()) {
310 pattern
= GfxPattern::parse(&obj
);
317 error(-1, "Unknown pattern '%s'", name
);
321 GBool
GfxResources::lookupGState(const char *name
, Object
*obj
) {
322 GfxResources
*resPtr
;
324 for (resPtr
= this; resPtr
; resPtr
= resPtr
->next
) {
325 if (resPtr
->gStateDict
.isDict()) {
326 if (!resPtr
->gStateDict
.dictLookup(name
, obj
)->isNull()) {
332 error(-1, "ExtGState '%s' is unknown", name
);
336 //------------------------------------------------------------------------
338 //------------------------------------------------------------------------
340 Gfx::Gfx(OutputDev
*out1
, int pageNum
, Dict
*resDict
,
341 double dpi
, double x1
, double y1
, double x2
, double y2
, GBool crop
,
342 double cropX1
, double cropY1
, double cropX2
, double cropY2
,
346 // start the resource stack
347 res
= new GfxResources(resDict
, NULL
);
351 state
= new GfxState(dpi
, x1
, y1
, x2
, y2
, rotate
, out
->upsideDown());
352 fontChanged
= gFalse
;
355 out
->startPage(pageNum
, state
);
356 out
->setDefaultCTM(state
->getCTM());
357 out
->updateAll(state
);
358 for (i
= 0; i
< 6; ++i
) {
359 baseMatrix
[i
] = state
->getCTM()[i
];
364 state
->moveTo(cropX1
, cropY1
);
365 state
->lineTo(cropX2
, cropY1
);
366 state
->lineTo(cropX2
, cropY2
);
367 state
->lineTo(cropX1
, cropY2
);
375 GfxResources
*resPtr
;
377 while (state
->hasSaves()) {
378 state
= state
->restore();
379 out
->restoreState(state
);
383 resPtr
= res
->getNext();
391 void Gfx::display(Object
*obj
, GBool topLevel
) {
395 if (obj
->isArray()) {
396 for (i
= 0; i
< obj
->arrayGetLength(); ++i
) {
397 obj
->arrayGet(i
, &obj2
);
398 if (!obj2
.isStream()) {
399 error(-1, "Weird page contents");
405 } else if (!obj
->isStream()) {
406 error(-1, "Weird page contents");
409 parser
= new Parser(new Lexer(obj
));
415 void Gfx::go(GBool topLevel
) {
417 Object args
[maxArgs
];
418 int numCmds
, numArgs
;
421 // scan a sequence of objects
424 parser
->getObj(&obj
);
425 while (!obj
.isEOF()) {
427 // got a command - execute it
431 for (i
= 0; i
< numArgs
; ++i
) {
433 args
[i
].print(stdout
);
437 execOp(&obj
, args
, numArgs
);
439 for (i
= 0; i
< numArgs
; ++i
)
443 // periodically update display
444 if (++numCmds
== 200) {
449 // got an argument - save it
450 } else if (numArgs
< maxArgs
) {
451 args
[numArgs
++] = obj
;
453 // too many arguments - something is wrong
455 error(getPos(), "Too many args in content stream");
457 printf("throwing away arg: ");
464 // grab the next object
465 parser
->getObj(&obj
);
469 // args at end with no command
471 error(getPos(), "Leftover args in content stream");
473 printf("%d leftovers:", numArgs
);
474 for (i
= 0; i
< numArgs
; ++i
) {
476 args
[i
].print(stdout
);
480 for (i
= 0; i
< numArgs
; ++i
)
485 if (topLevel
&& numCmds
> 0) {
495 void Gfx::execOp(Object
*cmd
, Object args
[], int numArgs
) {
501 name
= cmd
->getName();
502 if (!(op
= findOp(name
))) {
503 if (ignoreUndef
== 0)
504 error(getPos(), "Unknown operator '%s'", name
);
509 if (op
->numArgs
>= 0) {
510 if (numArgs
!= op
->numArgs
) {
511 error(getPos(), "Wrong number (%d) of args to '%s' operator",
516 if (numArgs
> -op
->numArgs
) {
517 error(getPos(), "Too many (%d) args to '%s' operator",
522 for (i
= 0; i
< numArgs
; ++i
) {
523 if (!checkArg(&args
[i
], op
->tchk
[i
])) {
524 error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
525 i
, name
, args
[i
].getTypeName());
531 (this->*op
->func
)(args
, numArgs
);
534 Operator
*Gfx::findOp(const char *name
) {
539 // invariant: opTab[a] < name < opTab[b]
542 cmp
= strcmp(opTab
[m
].name
, name
);
555 GBool
Gfx::checkArg(Object
*arg
, TchkType type
) {
557 case tchkBool
: return arg
->isBool();
558 case tchkInt
: return arg
->isInt();
559 case tchkNum
: return arg
->isNum();
560 case tchkString
: return arg
->isString();
561 case tchkName
: return arg
->isName();
562 case tchkArray
: return arg
->isArray();
563 case tchkProps
: return arg
->isDict() || arg
->isName();
564 case tchkSCN
: return arg
->isNum() || arg
->isName();
565 case tchkNone
: return gFalse
;
571 return parser
? parser
->getPos() : -1;
574 //------------------------------------------------------------------------
575 // graphics state operators
576 //------------------------------------------------------------------------
578 void Gfx::opSave(Object args
[], int numArgs
) {
582 out
->saveState(state
);
583 state
= state
->save();
586 void Gfx::opRestore(Object args
[], int numArgs
) {
590 state
= state
->restore();
591 out
->restoreState(state
);
593 // Some PDF producers (Macromedia FreeHand) generate a save (q) and
594 // restore (Q) inside a path sequence. The PDF spec seems to imply
595 // that this is illegal. Calling clearPath() here implements the
596 // behavior apparently expected by this software.
600 void Gfx::opConcat(Object args
[], int numArgs
) {
603 state
->concatCTM(args
[0].getNum(), args
[1].getNum(),
604 args
[2].getNum(), args
[3].getNum(),
605 args
[4].getNum(), args
[5].getNum());
606 out
->updateCTM(state
, args
[0].getNum(), args
[1].getNum(),
607 args
[2].getNum(), args
[3].getNum(),
608 args
[4].getNum(), args
[5].getNum());
612 void Gfx::opSetDash(Object args
[], int numArgs
) {
621 a
= args
[0].getArray();
622 length
= a
->getLength();
626 dash
= (double *)gmalloc(length
* sizeof(double));
627 for (i
= 0; i
< length
; ++i
) {
628 dash
[i
] = a
->get(i
, &obj
)->getNum();
632 state
->setLineDash(dash
, length
, args
[1].getNum());
633 out
->updateLineDash(state
);
636 void Gfx::opSetFlat(Object args
[], int numArgs
) {
637 state
->setFlatness((int)args
[0].getNum());
638 out
->updateFlatness(state
);
641 void Gfx::opSetLineJoin(Object args
[], int numArgs
) {
642 state
->setLineJoin(args
[0].getInt());
643 out
->updateLineJoin(state
);
646 void Gfx::opSetLineCap(Object args
[], int numArgs
) {
647 state
->setLineCap(args
[0].getInt());
648 out
->updateLineCap(state
);
651 void Gfx::opSetMiterLimit(Object args
[], int numArgs
) {
652 state
->setMiterLimit(args
[0].getNum());
653 out
->updateMiterLimit(state
);
656 void Gfx::opSetLineWidth(Object args
[], int numArgs
) {
657 state
->setLineWidth(args
[0].getNum());
658 out
->updateLineWidth(state
);
661 void Gfx::opSetExtGState(Object args
[], int numArgs
) {
664 if (!res
->lookupGState(args
[0].getName(), &obj1
)) {
667 if (!obj1
.isDict()) {
668 error(getPos(), "ExtGState '%s' is wrong type", args
[0].getName());
672 if (obj1
.dictLookup("ca", &obj2
)->isNum()) {
673 state
->setFillOpacity(obj2
.getNum());
674 out
->updateFillOpacity(state
);
677 if (obj1
.dictLookup("CA", &obj2
)->isNum()) {
678 state
->setStrokeOpacity(obj2
.getNum());
679 out
->updateStrokeOpacity(state
);
685 void Gfx::opSetRenderingIntent(Object args
[], int numArgs
) {
688 //------------------------------------------------------------------------
690 //------------------------------------------------------------------------
692 void Gfx::opSetFillGray(Object args
[], int numArgs
) {
695 state
->setFillPattern(NULL
);
696 state
->setFillColorSpace(new GfxDeviceGrayColorSpace());
697 color
.c
[0] = args
[0].getNum();
698 state
->setFillColor(&color
);
699 out
->updateFillColor(state
);
702 void Gfx::opSetStrokeGray(Object args
[], int numArgs
) {
705 state
->setStrokePattern(NULL
);
706 state
->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
707 color
.c
[0] = args
[0].getNum();
708 state
->setStrokeColor(&color
);
709 out
->updateStrokeColor(state
);
712 void Gfx::opSetFillCMYKColor(Object args
[], int numArgs
) {
716 state
->setFillPattern(NULL
);
717 state
->setFillColorSpace(new GfxDeviceCMYKColorSpace());
718 for (i
= 0; i
< 4; ++i
) {
719 color
.c
[i
] = args
[i
].getNum();
721 state
->setFillColor(&color
);
722 out
->updateFillColor(state
);
725 void Gfx::opSetStrokeCMYKColor(Object args
[], int numArgs
) {
729 state
->setStrokePattern(NULL
);
730 state
->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
731 for (i
= 0; i
< 4; ++i
) {
732 color
.c
[i
] = args
[i
].getNum();
734 state
->setStrokeColor(&color
);
735 out
->updateStrokeColor(state
);
738 void Gfx::opSetFillRGBColor(Object args
[], int numArgs
) {
742 state
->setFillPattern(NULL
);
743 state
->setFillColorSpace(new GfxDeviceRGBColorSpace());
744 for (i
= 0; i
< 3; ++i
) {
745 color
.c
[i
] = args
[i
].getNum();
747 state
->setFillColor(&color
);
748 out
->updateFillColor(state
);
751 void Gfx::opSetStrokeRGBColor(Object args
[], int numArgs
) {
755 state
->setStrokePattern(NULL
);
756 state
->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
757 for (i
= 0; i
< 3; ++i
) {
758 color
.c
[i
] = args
[i
].getNum();
760 state
->setStrokeColor(&color
);
761 out
->updateStrokeColor(state
);
764 void Gfx::opSetFillColorSpace(Object args
[], int numArgs
) {
766 GfxColorSpace
*colorSpace
;
770 state
->setFillPattern(NULL
);
771 res
->lookupColorSpace(args
[0].getName(), &obj
);
773 colorSpace
= GfxColorSpace::parse(&args
[0]);
775 colorSpace
= GfxColorSpace::parse(&obj
);
779 state
->setFillColorSpace(colorSpace
);
781 error(getPos(), "Bad color space");
783 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
786 state
->setFillColor(&color
);
787 out
->updateFillColor(state
);
790 void Gfx::opSetStrokeColorSpace(Object args
[], int numArgs
) {
792 GfxColorSpace
*colorSpace
;
796 state
->setStrokePattern(NULL
);
797 res
->lookupColorSpace(args
[0].getName(), &obj
);
799 colorSpace
= GfxColorSpace::parse(&args
[0]);
801 colorSpace
= GfxColorSpace::parse(&obj
);
805 state
->setStrokeColorSpace(colorSpace
);
807 error(getPos(), "Bad color space");
809 for (i
= 0; i
< gfxColorMaxComps
; ++i
) {
812 state
->setStrokeColor(&color
);
813 out
->updateStrokeColor(state
);
816 void Gfx::opSetFillColor(Object args
[], int numArgs
) {
820 state
->setFillPattern(NULL
);
821 for (i
= 0; i
< numArgs
; ++i
) {
822 color
.c
[i
] = args
[i
].getNum();
824 state
->setFillColor(&color
);
825 out
->updateFillColor(state
);
828 void Gfx::opSetStrokeColor(Object args
[], int numArgs
) {
832 state
->setStrokePattern(NULL
);
833 for (i
= 0; i
< numArgs
; ++i
) {
834 color
.c
[i
] = args
[i
].getNum();
836 state
->setStrokeColor(&color
);
837 out
->updateStrokeColor(state
);
840 void Gfx::opSetFillColorN(Object args
[], int numArgs
) {
845 if (state
->getFillColorSpace()->getMode() == csPattern
) {
847 for (i
= 0; i
< numArgs
&& i
< 4; ++i
) {
848 if (args
[i
].isNum()) {
849 color
.c
[i
] = args
[i
].getNum();
852 state
->setFillColor(&color
);
853 out
->updateFillColor(state
);
855 if (args
[numArgs
-1].isName() &&
856 (pattern
= res
->lookupPattern(args
[numArgs
-1].getName()))) {
857 state
->setFillPattern(pattern
);
861 state
->setFillPattern(NULL
);
862 for (i
= 0; i
< numArgs
&& i
< 4; ++i
) {
863 if (args
[i
].isNum()) {
864 color
.c
[i
] = args
[i
].getNum();
867 state
->setFillColor(&color
);
868 out
->updateFillColor(state
);
872 void Gfx::opSetStrokeColorN(Object args
[], int numArgs
) {
877 if (state
->getStrokeColorSpace()->getMode() == csPattern
) {
879 for (i
= 0; i
< numArgs
&& i
< 4; ++i
) {
880 if (args
[i
].isNum()) {
881 color
.c
[i
] = args
[i
].getNum();
884 state
->setStrokeColor(&color
);
885 out
->updateStrokeColor(state
);
887 if (args
[numArgs
-1].isName() &&
888 (pattern
= res
->lookupPattern(args
[numArgs
-1].getName()))) {
889 state
->setStrokePattern(pattern
);
893 state
->setStrokePattern(NULL
);
894 for (i
= 0; i
< numArgs
&& i
< 4; ++i
) {
895 if (args
[i
].isNum()) {
896 color
.c
[i
] = args
[i
].getNum();
899 state
->setStrokeColor(&color
);
900 out
->updateStrokeColor(state
);
904 //------------------------------------------------------------------------
905 // path segment operators
906 //------------------------------------------------------------------------
908 void Gfx::opMoveTo(Object args
[], int numArgs
) {
911 state
->moveTo(args
[0].getNum(), args
[1].getNum());
914 void Gfx::opLineTo(Object args
[], int numArgs
) {
917 if (!state
->isCurPt()) {
918 error(getPos(), "No current point in lineto");
921 state
->lineTo(args
[0].getNum(), args
[1].getNum());
924 void Gfx::opCurveTo(Object args
[], int numArgs
) {
925 double x1
, y1
, x2
, y2
, x3
, y3
;
929 if (!state
->isCurPt()) {
930 error(getPos(), "No current point in curveto");
933 x1
= args
[0].getNum();
934 y1
= args
[1].getNum();
935 x2
= args
[2].getNum();
936 y2
= args
[3].getNum();
937 x3
= args
[4].getNum();
938 y3
= args
[5].getNum();
939 state
->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
942 void Gfx::opCurveTo1(Object args
[], int numArgs
) {
943 double x1
, y1
, x2
, y2
, x3
, y3
;
947 if (!state
->isCurPt()) {
948 error(getPos(), "No current point in curveto1");
951 x1
= state
->getCurX();
952 y1
= state
->getCurY();
953 x2
= args
[0].getNum();
954 y2
= args
[1].getNum();
955 x3
= args
[2].getNum();
956 y3
= args
[3].getNum();
957 state
->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
960 void Gfx::opCurveTo2(Object args
[], int numArgs
) {
961 double x1
, y1
, x2
, y2
, x3
, y3
;
965 if (!state
->isCurPt()) {
966 error(getPos(), "No current point in curveto2");
969 x1
= args
[0].getNum();
970 y1
= args
[1].getNum();
971 x2
= args
[2].getNum();
972 y2
= args
[3].getNum();
975 state
->curveTo(x1
, y1
, x2
, y2
, x3
, y3
);
978 void Gfx::opRectangle(Object args
[], int numArgs
) {
983 x
= args
[0].getNum();
984 y
= args
[1].getNum();
985 w
= args
[2].getNum();
986 h
= args
[3].getNum();
988 state
->lineTo(x
+ w
, y
);
989 state
->lineTo(x
+ w
, y
+ h
);
990 state
->lineTo(x
, y
+ h
);
994 void Gfx::opClosePath(Object args
[], int numArgs
) {
998 if (!state
->isPath()) {
999 error(getPos(), "No current point in closepath");
1005 //------------------------------------------------------------------------
1006 // path painting operators
1007 //------------------------------------------------------------------------
1009 void Gfx::opEndPath(Object args
[], int numArgs
) {
1016 void Gfx::opStroke(Object args
[], int numArgs
) {
1020 if (!state
->isCurPt()) {
1021 //error(getPos(), "No path in stroke");
1024 if (state
->isPath())
1029 void Gfx::opCloseStroke(Object args
[], int numArgs
) {
1033 if (!state
->isCurPt()) {
1034 //error(getPos(), "No path in closepath/stroke");
1037 if (state
->isPath()) {
1044 void Gfx::opFill(Object args
[], int numArgs
) {
1048 if (!state
->isCurPt()) {
1049 //error(getPos(), "No path in fill");
1052 if (state
->isPath()) {
1053 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1054 doPatternFill(gFalse
);
1062 void Gfx::opEOFill(Object args
[], int numArgs
) {
1066 if (!state
->isCurPt()) {
1067 //error(getPos(), "No path in eofill");
1070 if (state
->isPath()) {
1071 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1072 doPatternFill(gTrue
);
1080 void Gfx::opFillStroke(Object args
[], int numArgs
) {
1084 if (!state
->isCurPt()) {
1085 //error(getPos(), "No path in fill/stroke");
1088 if (state
->isPath()) {
1089 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1090 doPatternFill(gFalse
);
1099 void Gfx::opCloseFillStroke(Object args
[], int numArgs
) {
1103 if (!state
->isCurPt()) {
1104 //error(getPos(), "No path in closepath/fill/stroke");
1107 if (state
->isPath()) {
1109 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1110 doPatternFill(gFalse
);
1119 void Gfx::opEOFillStroke(Object args
[], int numArgs
) {
1123 if (!state
->isCurPt()) {
1124 //error(getPos(), "No path in eofill/stroke");
1127 if (state
->isPath()) {
1128 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1129 doPatternFill(gTrue
);
1138 void Gfx::opCloseEOFillStroke(Object args
[], int numArgs
) {
1142 if (!state
->isCurPt()) {
1143 //error(getPos(), "No path in closepath/eofill/stroke");
1146 if (state
->isPath()) {
1148 if (state
->getFillColorSpace()->getMode() == csPattern
) {
1149 doPatternFill(gTrue
);
1158 void Gfx::opShFill(Object args
[], int numArgs
) {
1163 void Gfx::doPatternFill(GBool eoFill
) {
1164 GfxPatternColorSpace
*patCS
;
1165 GfxPattern
*pattern
;
1166 GfxTilingPattern
*tPat
;
1169 GfxSubpath
*subpath
;
1170 double xMin
, yMin
, xMax
, yMax
, x
, y
, x1
, y1
;
1171 int xi0
, yi0
, xi1
, yi1
, xi
, yi
;
1172 double *ctm
, *btm
, *ptm
;
1173 double m
[6], ictm
[6], m1
[6], im
[6];
1175 double xstep
, ystep
;
1179 patCS
= (GfxPatternColorSpace
*)state
->getFillColorSpace();
1182 if (!(pattern
= state
->getFillPattern())) {
1185 if (pattern
->getType() != 1) {
1188 tPat
= (GfxTilingPattern
*)pattern
;
1190 // construct a (pattern space) -> (current space) transform matrix
1191 ctm
= state
->getCTM();
1193 ptm
= tPat
->getMatrix();
1194 // iCTM = invert CTM
1195 det
= 1 / (ctm
[0] * ctm
[3] - ctm
[1] * ctm
[2]);
1196 ictm
[0] = ctm
[3] * det
;
1197 ictm
[1] = -ctm
[1] * det
;
1198 ictm
[2] = -ctm
[2] * det
;
1199 ictm
[3] = ctm
[0] * det
;
1200 ictm
[4] = (ctm
[2] * ctm
[5] - ctm
[3] * ctm
[4]) * det
;
1201 ictm
[5] = (ctm
[1] * ctm
[4] - ctm
[0] * ctm
[5]) * det
;
1202 // m1 = PTM * BTM = PTM * base transform matrix
1203 m1
[0] = ptm
[0] * btm
[0] + ptm
[1] * btm
[2];
1204 m1
[1] = ptm
[0] * btm
[1] + ptm
[1] * btm
[3];
1205 m1
[2] = ptm
[2] * btm
[0] + ptm
[3] * btm
[2];
1206 m1
[3] = ptm
[2] * btm
[1] + ptm
[3] * btm
[3];
1207 m1
[4] = ptm
[4] * btm
[0] + ptm
[5] * btm
[2] + btm
[4];
1208 m1
[5] = ptm
[4] * btm
[1] + ptm
[5] * btm
[3] + btm
[5];
1209 // m = m1 * iCTM = (PTM * BTM) * (iCTM)
1210 m
[0] = m1
[0] * ictm
[0] + m1
[1] * ictm
[2];
1211 m
[1] = m1
[0] * ictm
[1] + m1
[1] * ictm
[3];
1212 m
[2] = m1
[2] * ictm
[0] + m1
[3] * ictm
[2];
1213 m
[3] = m1
[2] * ictm
[1] + m1
[3] * ictm
[3];
1214 m
[4] = m1
[4] * ictm
[0] + m1
[5] * ictm
[2] + ictm
[4];
1215 m
[5] = m1
[4] * ictm
[1] + m1
[5] * ictm
[3] + ictm
[5];
1217 // construct a (current space) -> (pattern space) transform matrix
1218 det
= 1 / (m
[0] * m
[3] - m
[1] * m
[2]);
1220 im
[1] = -m
[1] * det
;
1221 im
[2] = -m
[2] * det
;
1223 im
[4] = (m
[2] * m
[5] - m
[3] * m
[4]) * det
;
1224 im
[5] = (m
[1] * m
[4] - m
[0] * m
[5]) * det
;
1226 // compute bounding box of current path, in pattern space
1227 xMin
= xMax
= yMin
= yMax
= 0; // make gcc happy
1228 path
= state
->getPath();
1229 for (i
= 0; i
< path
->getNumSubpaths(); ++i
) {
1230 subpath
= path
->getSubpath(i
);
1231 for (j
= 0; j
< subpath
->getNumPoints(); ++j
) {
1232 x
= subpath
->getX(j
);
1233 y
= subpath
->getY(j
);
1234 x1
= x
* im
[0] + y
* im
[2] + im
[4];
1235 y1
= x
* im
[1] + y
* im
[3] + im
[5];
1236 if (i
== 0 && j
== 0) {
1242 } else if (x1
> xMax
) {
1247 } else if (y1
> yMax
) {
1254 // save current graphics state
1255 out
->saveState(state
);
1256 state
= state
->save();
1258 // set underlying color space (for uncolored tiling patterns)
1259 if (tPat
->getPaintType() == 2 && (cs
= patCS
->getUnder())) {
1260 state
->setFillColorSpace(cs
->copy());
1262 state
->setFillColorSpace(new GfxDeviceGrayColorSpace());
1264 state
->setFillPattern(NULL
);
1265 out
->updateFillColor(state
);
1267 // clip to current path
1276 //~ this should treat negative steps differently -- start at right/top
1277 //~ edge instead of left/bottom (?)
1278 xstep
= fabs(tPat
->getXStep());
1279 ystep
= fabs(tPat
->getYStep());
1280 xi0
= (int)floor(xMin
/ xstep
);
1281 xi1
= (int)ceil(xMax
/ xstep
);
1282 yi0
= (int)floor(yMin
/ ystep
);
1283 yi1
= (int)ceil(yMax
/ ystep
);
1284 for (i
= 0; i
< 4; ++i
) {
1287 for (yi
= yi0
; yi
< yi1
; ++yi
) {
1288 for (xi
= xi0
; xi
< xi1
; ++xi
) {
1291 m1
[4] = x
* m
[0] + y
* m
[2] + m
[4];
1292 m1
[5] = x
* m
[1] + y
* m
[3] + m
[5];
1293 doForm1(tPat
->getContentStream(), tPat
->getResDict(),
1294 m1
, tPat
->getBBox());
1298 // restore graphics state
1299 state
= state
->restore();
1300 out
->restoreState(state
);
1303 void Gfx::doEndPath() {
1304 if (state
->isPath()) {
1305 if (clip
== clipNormal
)
1307 else if (clip
== clipEO
)
1314 //------------------------------------------------------------------------
1315 // path clipping operators
1316 //------------------------------------------------------------------------
1318 void Gfx::opClip(Object args
[], int numArgs
) {
1325 void Gfx::opEOClip(Object args
[], int numArgs
) {
1332 //------------------------------------------------------------------------
1333 // text object operators
1334 //------------------------------------------------------------------------
1336 void Gfx::opBeginText(Object args
[], int numArgs
) {
1340 state
->setTextMat(1, 0, 0, 1, 0, 0);
1341 state
->textMoveTo(0, 0);
1342 out
->updateTextMat(state
);
1343 out
->updateTextPos(state
);
1344 fontChanged
= gTrue
;
1347 void Gfx::opEndText(Object args
[], int numArgs
) {
1352 //------------------------------------------------------------------------
1353 // text state operators
1354 //------------------------------------------------------------------------
1356 void Gfx::opSetCharSpacing(Object args
[], int numArgs
) {
1360 state
->setCharSpace(args
[0].getNum());
1361 out
->updateCharSpace(state
);
1364 void Gfx::opSetFont(Object args
[], int numArgs
) {
1367 if (!(font
= res
->lookupFont(args
[0].getName()))) {
1370 if (printCommands
) {
1371 printf(" font: '%s' %g\n",
1372 font
->getName() ? font
->getName()->getCString() : "???",
1375 state
->setFont(font
, args
[1].getNum());
1376 fontChanged
= gTrue
;
1379 void Gfx::opSetTextLeading(Object args
[], int numArgs
) {
1382 state
->setLeading(args
[0].getNum());
1385 void Gfx::opSetTextRender(Object args
[], int numArgs
) {
1388 state
->setRender(args
[0].getInt());
1389 out
->updateRender(state
);
1392 void Gfx::opSetTextRise(Object args
[], int numArgs
) {
1395 state
->setRise(args
[0].getNum());
1396 out
->updateRise(state
);
1399 void Gfx::opSetWordSpacing(Object args
[], int numArgs
) {
1402 state
->setWordSpace(args
[0].getNum());
1403 out
->updateWordSpace(state
);
1406 void Gfx::opSetHorizScaling(Object args
[], int numArgs
) {
1409 state
->setHorizScaling(args
[0].getNum());
1410 out
->updateHorizScaling(state
);
1413 //------------------------------------------------------------------------
1414 // text positioning operators
1415 //------------------------------------------------------------------------
1417 void Gfx::opTextMove(Object args
[], int numArgs
) {
1422 tx
= state
->getLineX() + args
[0].getNum();
1423 ty
= state
->getLineY() + args
[1].getNum();
1424 state
->textMoveTo(tx
, ty
);
1425 out
->updateTextPos(state
);
1428 void Gfx::opTextMoveSet(Object args
[], int numArgs
) {
1433 tx
= state
->getLineX() + args
[0].getNum();
1434 ty
= args
[1].getNum();
1435 state
->setLeading(-ty
);
1436 ty
+= state
->getLineY();
1437 state
->textMoveTo(tx
, ty
);
1438 out
->updateTextPos(state
);
1441 void Gfx::opSetTextMatrix(Object args
[], int numArgs
) {
1444 state
->setTextMat(args
[0].getNum(), args
[1].getNum(),
1445 args
[2].getNum(), args
[3].getNum(),
1446 args
[4].getNum(), args
[5].getNum());
1447 state
->textMoveTo(0, 0);
1448 out
->updateTextMat(state
);
1449 out
->updateTextPos(state
);
1450 fontChanged
= gTrue
;
1453 void Gfx::opTextNextLine(Object args
[], int numArgs
) {
1459 tx
= state
->getLineX();
1460 ty
= state
->getLineY() - state
->getLeading();
1461 state
->textMoveTo(tx
, ty
);
1462 out
->updateTextPos(state
);
1465 //------------------------------------------------------------------------
1466 // text string operators
1467 //------------------------------------------------------------------------
1469 void Gfx::opShowText(Object args
[], int numArgs
) {
1472 if (!state
->getFont()) {
1473 error(getPos(), "No font in show");
1476 doShowText(args
[0].getString());
1479 void Gfx::opMoveShowText(Object args
[], int numArgs
) {
1484 if (!state
->getFont()) {
1485 error(getPos(), "No font in move/show");
1488 tx
= state
->getLineX();
1489 ty
= state
->getLineY() - state
->getLeading();
1490 state
->textMoveTo(tx
, ty
);
1491 out
->updateTextPos(state
);
1492 doShowText(args
[0].getString());
1495 void Gfx::opMoveSetShowText(Object args
[], int numArgs
) {
1500 if (!state
->getFont()) {
1501 error(getPos(), "No font in move/set/show");
1504 state
->setWordSpace(args
[0].getNum());
1505 state
->setCharSpace(args
[1].getNum());
1506 tx
= state
->getLineX();
1507 ty
= state
->getLineY() - state
->getLeading();
1508 state
->textMoveTo(tx
, ty
);
1509 out
->updateWordSpace(state
);
1510 out
->updateCharSpace(state
);
1511 out
->updateTextPos(state
);
1512 doShowText(args
[2].getString());
1515 void Gfx::opShowSpaceText(Object args
[], int numArgs
) {
1522 if (!state
->getFont()) {
1523 error(getPos(), "No font in show/space");
1526 a
= args
[0].getArray();
1527 for (i
= 0; i
< a
->getLength(); ++i
) {
1530 state
->textShift(-obj
.getNum() * 0.001 * state
->getFontSize());
1531 out
->updateTextShift(state
, obj
.getNum());
1532 } else if (obj
.isString()) {
1533 doShowText(obj
.getString());
1535 error(getPos(), "Element of show/space array must be number or string");
1541 void Gfx::doShowText(GString
*s
) {
1543 GfxFontEncoding16
*enc
;
1551 double dx
, dy
, width
, height
, w
, h
, x
, y
;
1552 double oldCTM
[6], newCTM
[6];
1558 double dx
, dy
, width
, height
, w
, h
, sWidth
, sHeight
;
1562 out
->updateFont(state
);
1563 fontChanged
= gFalse
;
1565 font
= state
->getFont();
1568 if (font
->is16Bit()) {
1569 enc
= font
->getEncoding16();
1570 if (out
->useDrawChar()) {
1571 out
->beginString(state
, s
);
1574 s16
= new GString();
1576 sWidth
= sHeight
= 0;
1577 state
->textTransformDelta(0, state
->getRise(), &dx
, &dy
);
1578 p
= (Guchar
*)s
->getCString();
1581 m
= getNextChar16(enc
, p
, &c16
);
1582 if (enc
->wMode
== 0) {
1583 width
= state
->getFontSize() * state
->getHorizScaling() *
1584 font
->getWidth16(c16
) +
1585 state
->getCharSpace();
1587 width
+= state
->getWordSpace();
1592 height
= state
->getFontSize() * font
->getHeight16(c16
);
1594 state
->textTransformDelta(width
, height
, &w
, &h
);
1595 if (out
->useDrawChar()) {
1596 out
->drawChar16(state
, state
->getCurX() + dx
, state
->getCurY() + dy
,
1598 state
->textShift(width
, height
);
1600 s16a
[0] = (char)(c16
>> 8);
1601 s16a
[1] = (char)c16
;
1602 s16
->append(s16a
, 2);
1609 if (out
->useDrawChar()) {
1610 out
->endString(state
);
1612 out
->drawString16(state
, s16
);
1614 state
->textShift(sWidth
, sHeight
);
1620 //~ also check out->renderType3()
1621 if (font
->getType() == fontType3
) {
1622 out
->beginString(state
, s
);
1623 mat
= state
->getCTM();
1624 for (i
= 0; i
< 6; ++i
) {
1627 mat
= state
->getTextMat();
1628 newCTM
[0] = mat
[0] * oldCTM
[0] + mat
[1] * oldCTM
[2];
1629 newCTM
[1] = mat
[0] * oldCTM
[1] + mat
[1] * oldCTM
[3];
1630 newCTM
[2] = mat
[2] * oldCTM
[0] + mat
[3] * oldCTM
[2];
1631 newCTM
[3] = mat
[2] * oldCTM
[1] + mat
[3] * oldCTM
[3];
1632 mat
= font
->getFontMatrix();
1633 newCTM
[0] = mat
[0] * newCTM
[0] + mat
[1] * newCTM
[2];
1634 newCTM
[1] = mat
[0] * newCTM
[1] + mat
[1] * newCTM
[3];
1635 newCTM
[2] = mat
[2] * newCTM
[0] + mat
[3] * newCTM
[2];
1636 newCTM
[3] = mat
[2] * newCTM
[1] + mat
[3] * newCTM
[3];
1637 newCTM
[0] *= state
->getFontSize();
1638 newCTM
[3] *= state
->getFontSize();
1639 newCTM
[0] *= state
->getHorizScaling();
1640 newCTM
[2] *= state
->getHorizScaling();
1641 state
->textTransformDelta(0, state
->getRise(), &dx
, &dy
);
1643 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
1645 font
->getCharProc(c8
, &charProc
);
1646 state
->transform(state
->getCurX() + dx
, state
->getCurY() + dy
, &x
, &y
);
1647 state
->setCTM(newCTM
[0], newCTM
[1], newCTM
[2], newCTM
[3], x
, y
);
1648 //~ out->updateCTM(???)
1649 if (charProc
.isStream()) {
1650 display(&charProc
, gFalse
);
1652 error(getPos(), "Missing or bad Type3 CharProc entry");
1654 state
->setCTM(oldCTM
[0], oldCTM
[1], oldCTM
[2],
1655 oldCTM
[3], oldCTM
[4], oldCTM
[5]);
1656 //~ out->updateCTM(???) - use gsave/grestore instead?
1658 width
= state
->getFontSize() * state
->getHorizScaling() *
1659 font
->getWidth(c8
) +
1660 state
->getCharSpace();
1662 width
+= state
->getWordSpace();
1664 state
->textShift(width
);
1667 out
->endString(state
);
1670 if (out
->useDrawChar()) {
1671 out
->beginString(state
, s
);
1672 state
->textTransformDelta(0, state
->getRise(), &dx
, &dy
);
1673 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
1675 width
= state
->getFontSize() * state
->getHorizScaling() *
1676 font
->getWidth(c8
) +
1677 state
->getCharSpace();
1679 width
+= state
->getWordSpace();
1680 state
->textTransformDelta(width
, 0, &w
, &h
);
1681 out
->drawChar(state
, state
->getCurX() + dx
, state
->getCurY() + dy
,
1683 state
->textShift(width
);
1685 out
->endString(state
);
1687 out
->drawString(state
, s
);
1688 width
= state
->getFontSize() * state
->getHorizScaling() *
1690 s
->getLength() * state
->getCharSpace();
1691 for (p
= (Guchar
*)s
->getCString(), n
= s
->getLength(); n
; ++p
, --n
) {
1693 width
+= state
->getWordSpace();
1695 state
->textShift(width
);
1700 int Gfx::getNextChar16(GfxFontEncoding16
*enc
, Guchar
*p
, int *c16
) {
1705 n
= enc
->codeLen
[*p
];
1707 *c16
= enc
->map1
[*p
];
1709 code
= (p
[0] << 8) + p
[1];
1712 // invariant: map2[2*a] <= code < map2[2*b]
1715 if (enc
->map2
[2*m
] <= code
)
1717 else if (enc
->map2
[2*m
] > code
)
1722 *c16
= enc
->map2
[2*a
+1] + (code
- enc
->map2
[2*a
]);
1727 //------------------------------------------------------------------------
1728 // XObject operators
1729 //------------------------------------------------------------------------
1731 void Gfx::opXObject(Object args
[], int numArgs
) {
1732 Object obj1
, obj2
, refObj
;
1737 if (!res
->lookupXObject(args
[0].getName(), &obj1
)) {
1740 if (!obj1
.isStream()) {
1741 error(getPos(), "XObject '%s' is wrong type", args
[0].getName());
1746 obj1
.streamGetDict()->lookup("OPI", &opiDict
);
1747 if (opiDict
.isDict()) {
1748 out
->opiBegin(state
, opiDict
.getDict());
1751 obj1
.streamGetDict()->lookup("Subtype", &obj2
);
1752 if (obj2
.isName("Image")) {
1753 res
->lookupXObjectNF(args
[0].getName(), &refObj
);
1754 doImage(&refObj
, obj1
.getStream(), gFalse
);
1756 } else if (obj2
.isName("Form")) {
1758 } else if (obj2
.isName()) {
1759 error(getPos(), "Unknown XObject subtype '%s'", obj2
.getName());
1761 error(getPos(), "XObject subtype is missing or wrong type");
1765 if (opiDict
.isDict()) {
1766 out
->opiEnd(state
, opiDict
.getDict());
1773 void Gfx::doImage(Object
*ref
, Stream
*str
, GBool inlineImg
) {
1779 GfxColorSpace
*colorSpace
;
1780 GfxImageColorMap
*colorMap
;
1784 dict
= str
->getDict();
1787 dict
->lookup("Width", &obj1
);
1788 if (obj1
.isNull()) {
1790 dict
->lookup("W", &obj1
);
1794 width
= obj1
.getInt();
1796 dict
->lookup("Height", &obj1
);
1797 if (obj1
.isNull()) {
1799 dict
->lookup("H", &obj1
);
1803 height
= obj1
.getInt();
1807 dict
->lookup("ImageMask", &obj1
);
1808 if (obj1
.isNull()) {
1810 dict
->lookup("IM", &obj1
);
1814 mask
= obj1
.getBool();
1815 else if (!obj1
.isNull())
1820 dict
->lookup("BitsPerComponent", &obj1
);
1821 if (obj1
.isNull()) {
1823 dict
->lookup("BPC", &obj1
);
1827 bits
= obj1
.getInt();
1833 // check for inverted mask
1837 dict
->lookup("Decode", &obj1
);
1838 if (obj1
.isNull()) {
1840 dict
->lookup("D", &obj1
);
1842 if (obj1
.isArray()) {
1843 obj1
.arrayGet(0, &obj2
);
1844 if (obj2
.isInt() && obj2
.getInt() == 1)
1847 } else if (!obj1
.isNull()) {
1853 out
->drawImageMask(state
, ref
, str
, width
, height
, invert
, inlineImg
);
1857 // get color space and color map
1858 dict
->lookup("ColorSpace", &obj1
);
1859 if (obj1
.isNull()) {
1861 dict
->lookup("CS", &obj1
);
1863 if (obj1
.isName()) {
1864 res
->lookupColorSpace(obj1
.getName(), &obj2
);
1865 if (!obj2
.isNull()) {
1872 colorSpace
= GfxColorSpace::parse(&obj1
);
1877 dict
->lookup("Decode", &obj1
);
1878 if (obj1
.isNull()) {
1880 dict
->lookup("D", &obj1
);
1882 colorMap
= new GfxImageColorMap(bits
, &obj1
, colorSpace
);
1884 if (!colorMap
->isOk()) {
1890 out
->drawImage(state
, ref
, str
, width
, height
, colorMap
, inlineImg
);
1900 error(getPos(), "Bad image parameters");
1903 void Gfx::doForm(Object
*str
) {
1905 Object matrixObj
, bboxObj
;
1906 double m
[6], bbox
[6];
1913 dict
= str
->streamGetDict();
1916 dict
->lookup("FormType", &obj1
);
1917 if (!(obj1
.isInt() && obj1
.getInt() == 1)) {
1918 error(getPos(), "Unknown form type");
1923 dict
->lookup("BBox", &bboxObj
);
1924 if (!bboxObj
.isArray()) {
1927 error(getPos(), "Bad form bounding box");
1930 for (i
= 0; i
< 4; ++i
) {
1931 bboxObj
.arrayGet(i
, &obj1
);
1932 bbox
[i
] = obj1
.getNum();
1938 dict
->lookup("Matrix", &matrixObj
);
1939 if (matrixObj
.isArray()) {
1940 for (i
= 0; i
< 6; ++i
) {
1941 matrixObj
.arrayGet(i
, &obj1
);
1942 m
[i
] = obj1
.getNum();
1953 dict
->lookup("Resources", &resObj
);
1954 resDict
= resObj
.isDict() ? resObj
.getDict() : NULL
;
1957 doForm1(str
, resDict
, m
, bbox
);
1962 void Gfx::doWidgetForm(Object
*str
, double xMin
, double yMin
,
1963 double xMax
, double yMax
) {
1964 Dict
*dict
, *resDict
;
1965 Object matrixObj
, bboxObj
, resObj
;
1967 double m
[6], bbox
[6];
1972 dict
= str
->streamGetDict();
1975 dict
->lookup("BBox", &bboxObj
);
1976 if (!bboxObj
.isArray()) {
1978 error(getPos(), "Bad form bounding box");
1981 for (i
= 0; i
< 4; ++i
) {
1982 bboxObj
.arrayGet(i
, &obj1
);
1983 bbox
[i
] = obj1
.getNum();
1989 dict
->lookup("Matrix", &matrixObj
);
1990 if (matrixObj
.isArray()) {
1991 for (i
= 0; i
< 6; ++i
) {
1992 matrixObj
.arrayGet(i
, &obj1
);
1993 m
[i
] = obj1
.getNum();
2003 // scale form bbox to widget rectangle
2004 sx
= fabs((xMax
- xMin
) / (bbox
[2] - bbox
[0]));
2005 sy
= fabs((yMax
- yMin
) / (bbox
[3] - bbox
[1]));
2006 m
[0] *= sx
; m
[1] *= sy
;
2007 m
[2] *= sx
; m
[3] *= sy
;
2008 m
[4] *= sx
; m
[5] *= sy
;
2010 // translate to widget rectangle
2015 dict
->lookup("Resources", &resObj
);
2016 resDict
= resObj
.isDict() ? resObj
.getDict() : NULL
;
2019 doForm1(str
, resDict
, m
, bbox
);
2025 void Gfx::doForm1(Object
*str
, Dict
*resDict
, double *matrix
, double *bbox
) {
2027 double oldBaseMatrix
[6];
2028 GfxResources
*resPtr
;
2031 // push new resources on stack
2032 res
= new GfxResources(resDict
, res
);
2034 // save current graphics state
2035 out
->saveState(state
);
2036 state
= state
->save();
2038 // save current parser
2041 // set form transformation matrix
2042 state
->concatCTM(matrix
[0], matrix
[1], matrix
[2],
2043 matrix
[3], matrix
[4], matrix
[5]);
2044 out
->updateCTM(state
, matrix
[0], matrix
[1], matrix
[2],
2045 matrix
[3], matrix
[4], matrix
[5]);
2047 // set new base matrix
2048 for (i
= 0; i
< 6; ++i
) {
2049 oldBaseMatrix
[i
] = baseMatrix
[i
];
2050 baseMatrix
[i
] = state
->getCTM()[i
];
2053 // set form bounding box
2054 state
->moveTo(bbox
[0], bbox
[1]);
2055 state
->lineTo(bbox
[2], bbox
[1]);
2056 state
->lineTo(bbox
[2], bbox
[3]);
2057 state
->lineTo(bbox
[0], bbox
[3]);
2063 display(str
, gFalse
);
2065 // restore base matrix
2066 for (i
= 0; i
< 6; ++i
) {
2067 baseMatrix
[i
] = oldBaseMatrix
[i
];
2073 // restore graphics state
2074 state
= state
->restore();
2075 out
->restoreState(state
);
2077 // pop resource stack
2078 resPtr
= res
->getNext();
2085 //------------------------------------------------------------------------
2086 // in-line image operators
2087 //------------------------------------------------------------------------
2089 void Gfx::opBeginImage(Object args
[], int numArgs
) {
2096 // build dict/stream
2097 str
= buildImageStream();
2099 // display the image
2101 doImage(NULL
, str
, gTrue
);
2104 c1
= str
->getBaseStream()->getChar();
2105 c2
= str
->getBaseStream()->getChar();
2106 while (!(c1
== 'E' && c2
== 'I') && c2
!= EOF
) {
2108 c2
= str
->getBaseStream()->getChar();
2114 Stream
*Gfx::buildImageStream() {
2122 parser
->getObj(&obj
);
2123 while (!obj
.isCmd("ID") && !obj
.isEOF()) {
2124 if (!obj
.isName()) {
2125 error(getPos(), "Inline image dictionary key must be a name object");
2127 parser
->getObj(&obj
);
2129 key
= copyString(obj
.getName());
2131 parser
->getObj(&obj
);
2132 if (obj
.isEOF() || obj
.isError())
2134 dict
.dictAdd(key
, &obj
);
2136 parser
->getObj(&obj
);
2139 error(getPos(), "End of file in inline image");
2143 str
= new EmbedStream(parser
->getStream(), &dict
);
2144 str
= str
->addFilters(&dict
);
2149 void Gfx::opImageData(Object args
[], int numArgs
) {
2153 error(getPos(), "Internal: got 'ID' operator");
2156 void Gfx::opEndImage(Object args
[], int numArgs
) {
2160 error(getPos(), "Internal: got 'EI' operator");
2163 //------------------------------------------------------------------------
2164 // type 3 font operators
2165 //------------------------------------------------------------------------
2167 void Gfx::opSetCharWidth(Object args
[], int numArgs
) {
2171 error(getPos(), "Encountered 'd0' operator in content stream");
2174 void Gfx::opSetCacheDevice(Object args
[], int numArgs
) {
2178 error(getPos(), "Encountered 'd1' operator in content stream");
2181 //------------------------------------------------------------------------
2182 // compatibility operators
2183 //------------------------------------------------------------------------
2185 void Gfx::opBeginIgnoreUndef(Object args
[], int numArgs
) {
2192 void Gfx::opEndIgnoreUndef(Object args
[], int numArgs
) {
2196 if (ignoreUndef
> 0)
2200 //------------------------------------------------------------------------
2201 // marked content operators
2202 //------------------------------------------------------------------------
2204 void Gfx::opBeginMarkedContent(Object args
[], int numArgs
) {
2207 if (printCommands
) {
2208 printf(" marked content: %s ", args
[0].getName());
2210 args
[2].print(stdout
);
2215 void Gfx::opEndMarkedContent(Object args
[], int numArgs
) {
2220 void Gfx::opMarkPoint(Object args
[], int numArgs
) {
2223 if (printCommands
) {
2224 printf(" mark point: %s ", args
[0].getName());
2226 args
[2].print(stdout
);