1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
27 #include "PSOutputDev.h"
29 //------------------------------------------------------------------------
31 //------------------------------------------------------------------------
33 // Generate Level 1 PostScript?
34 GBool psOutLevel1 = gFalse;
36 int paperWidth = defPaperWidth;
37 int paperHeight = defPaperHeight;
39 //------------------------------------------------------------------------
40 // PostScript prolog and setup
41 //------------------------------------------------------------------------
43 static char *prolog[] = {
44 "/xpdf 75 dict def xpdf begin",
45 "% PDF special state",
46 "/pdfDictSize 14 def",
48 " pdfDictSize dict begin",
50 " /pdfStroke [0] def",
51 " /pdfLastFill false def",
52 " /pdfLastStroke false def",
53 " /pdfTextMat [1 0 0 1 0 0] def",
54 " /pdfFontSize 0 def",
55 " /pdfCharSpacing 0 def",
56 " /pdfTextRender 0 def",
57 " /pdfTextRise 0 def",
58 " /pdfWordSpacing 0 def",
59 " /pdfHorizScaling 1 def",
64 " /setpagedevice where {",
65 " pop 2 dict dup begin",
66 " exch /PageSize exch def",
67 " /ImagingBBox null def",
73 "/pdfEndPage { end } def",
74 "/sCol { pdfLastStroke not {",
75 " pdfStroke aload length",
76 " 1 eq { setgray } { setrgbcolor} ifelse",
77 " /pdfLastStroke true def /pdfLastFill false def",
79 "/fCol { pdfLastFill not {",
80 " pdfFill aload length",
81 " 1 eq { setgray } { setrgbcolor } ifelse",
82 " /pdfLastFill true def /pdfLastStroke false def",
87 " 3 2 roll 1 matrix scale makefont",
88 " dup length dict begin",
89 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
90 " /Encoding exch def",
95 "% graphics state operators",
96 "/q { gsave pdfDictSize dict begin } def",
97 "/Q { end grestore } def",
100 "/i { setflat } def",
101 "/j { setlinejoin } def",
102 "/J { setlinecap } def",
103 "/M { setmiterlimit } def",
104 "/w { setlinewidth } def",
106 "/g { dup 1 array astore /pdfFill exch def setgray",
107 " /pdfLastFill true def /pdfLastStroke false def } def",
108 "/G { dup 1 array astore /pdfStroke exch def setgray",
109 " /pdfLastStroke true def /pdfLastFill false def } def",
110 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
111 " /pdfLastFill true def /pdfLastStroke false def } def",
112 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
113 " /pdfLastStroke true def /pdfLastFill false def } def",
114 "% path segment operators",
117 "/c { curveto } def",
118 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
119 " neg 0 rlineto closepath } def"
120 "% path painting operators",
121 "/S { sCol stroke } def",
122 "/f { fCol fill } def",
123 "/f* { fCol eofill } def",
124 "% clipping operators",
125 "/W { clip newpath } def",
126 "/W* { eoclip newpath } def",
127 "% text state operators",
128 "/Tc { /pdfCharSpacing exch def } def",
129 "/Tf { dup /pdfFontSize exch def",
130 " dup pdfHorizScaling mul exch matrix scale",
131 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
132 " exch findfont exch makefont setfont } def",
133 "/Tr { /pdfTextRender exch def } def",
134 "/Ts { /pdfTextRise exch def } def",
135 "/Tw { /pdfWordSpacing exch def } def",
136 "/Tz { /pdfHorizScaling exch def } def",
137 "% text positioning operators",
138 "/Td { pdfTextMat transform moveto } def",
139 "/Tm { /pdfTextMat exch def } def",
140 "% text string operators",
141 "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
142 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
143 " pdfFontSize mul pdfHorizScaling mul",
144 " 1 index stringwidth pdfTextMat idtransform pop",
145 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
146 " pdfWordSpacing 0 pdfTextMat dtransform 32",
147 " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
148 " 6 5 roll awidthshow",
149 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
150 "/TJm { pdfFontSize 0.001 mul mul neg 0",
151 " pdfTextMat dtransform rmoveto } def",
152 "% Level 1 image operators",
154 " /pdfImBuf1 4 index string def",
155 " { currentfile pdfImBuf1 readhexstring pop } image",
158 " /pdfImBuf1 4 index 7 add 8 idiv string def",
159 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
161 "% Level 2 image operators",
162 "/pdfImBuf 100 string def",
165 " { currentfile pdfImBuf readline",
166 " not { pop exit } if",
167 " (%-EOD-) eq { exit } if } loop",
171 " { currentfile pdfImBuf readline",
172 " not { pop exit } if",
173 " (%-EOD-) eq { exit } if } loop",
179 //------------------------------------------------------------------------
181 //------------------------------------------------------------------------
184 char *name; // PDF name
185 char *psName; // PostScript name
189 char *psName; // PostScript name
190 double mWidth; // width of 'm' character
193 static PSFont psFonts[] = {
194 {"Courier", "Courier"},
195 {"Courier-Bold", "Courier-Bold"},
196 {"Courier-Oblique", "Courier-Bold"},
197 {"Courier-BoldOblique", "Courier-BoldOblique"},
198 {"Helvetica", "Helvetica"},
199 {"Helvetica-Bold", "Helvetica-Bold"},
200 {"Helvetica-Oblique", "Helvetica-Oblique"},
201 {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
202 {"Symbol", "Symbol"},
203 {"Times-Roman", "Times-Roman"},
204 {"Times-Bold", "Times-Bold"},
205 {"Times-Italic", "Times-Italic"},
206 {"Times-BoldItalic", "Times-BoldItalic"},
207 {"ZapfDingbats", "ZapfDingbats"},
211 static PSSubstFont psSubstFonts[] = {
212 {"Helvetica", 0.833},
213 {"Helvetica-Oblique", 0.833},
214 {"Helvetica-Bold", 0.889},
215 {"Helvetica-BoldOblique", 0.889},
216 {"Times-Roman", 0.788},
217 {"Times-Italic", 0.722},
218 {"Times-Bold", 0.833},
219 {"Times-BoldItalic", 0.778},
221 {"Courier-Oblique", 0.600},
222 {"Courier-Bold", 0.600},
223 {"Courier-BoldOblique", 0.600}
226 //------------------------------------------------------------------------
228 //------------------------------------------------------------------------
230 PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
231 int firstPage, int lastPage,
232 GBool embedType11, GBool doForm1) {
239 embedType1 = embedType11;
243 fontFileNames = NULL;
246 lastPage = firstPage;
250 if (!strcmp(fileName, "-")) {
253 } else if (fileName[0] == '|') {
257 signal(SIGPIPE, (void (*)(int))SIG_IGN);
259 if (!(f = popen(fileName + 1, "w"))) {
260 error(-1, "Couldn't run print command '%s'", fileName);
265 error(-1, "Print commands are not supported ('%s')", fileName);
271 if (!(f = fopen(fileName, "w"))) {
272 error(-1, "Couldn't open PostScript file '%s'", fileName);
278 // initialize fontIDs, fontFileIDs, and fontFileNames lists
281 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
284 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
285 fontFileNameSize = 64;
287 fontFileNames = (char **)gmalloc(fontFileNameSize * sizeof(char *));
291 writePS("%%!PS-Adobe-3.0 Resource-Form\n");
292 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
293 writePS("%%%%EndComments\n");
295 writePS("%%!PS-Adobe-3.0\n");
296 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
297 writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
298 writePS("%%%%EndComments\n");
303 writePS("%%%%BeginProlog\n");
304 writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion);
305 for (p = prolog; *p; ++p)
307 writePS("%%%%EndResource\n");
309 writePS("%%%%EndProlog\n");
313 writePS("%%%%BeginSetup\n");
314 writePS("xpdf begin\n");
315 for (pg = firstPage; pg <= lastPage; ++pg) {
316 if ((resDict = catalog->getPage(pg)->getResourceDict()))
322 writePS("%%%%EndSetup\n");
326 page = catalog->getPage(firstPage);
327 writePS("4 dict dup begin\n");
328 writePS("/BBox [%d %d %d %d] def\n",
329 (int)page->getX1(), (int)page->getY1(),
330 (int)page->getX2(), (int)page->getY2());
331 writePS("/FormType 1 def\n");
332 writePS("/Matrix [1 0 0 1 0 0] def\n");
335 // initialize sequential page number
339 PSOutputDev::~PSOutputDev() {
343 writePS("/Foo exch /Form defineresource pop\n");
345 writePS("%%%%Trailer\n");
347 writePS("%%%%EOF\n");
349 if (fileType == psFile) {
353 else if (fileType == psPipe) {
356 signal(SIGPIPE, (void (*)(int))SIG_DFL);
366 gfree(fontFileNames);
369 void PSOutputDev::setupFonts(Dict *resDict) {
370 Object fontDict, xObjDict, xObj, resObj;
371 GfxFontDict *gfxFontDict;
375 resDict->lookup("Font", &fontDict);
376 if (fontDict.isDict()) {
377 gfxFontDict = new GfxFontDict(fontDict.getDict());
378 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
379 font = gfxFontDict->getFont(i);
386 resDict->lookup("XObject", &xObjDict);
387 if (xObjDict.isDict()) {
388 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
389 xObjDict.dictGetVal(i, &xObj);
390 if (xObj.isStream()) {
391 xObj.streamGetDict()->lookup("Resources", &resObj);
393 setupFonts(resObj.getDict());
402 void PSOutputDev::setupFont(GfxFont *font) {
410 // check if font is already set up
411 for (i = 0; i < fontIDLen; ++i) {
412 if (fontIDs[i].num == font->getID().num &&
413 fontIDs[i].gen == font->getID().gen)
417 // add entry to fontIDs list
418 if (fontIDLen >= fontIDSize) {
420 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
422 fontIDs[fontIDLen++] = font->getID();
424 // check for embedded font
425 if (embedType1 && font->getType() == fontType1 &&
426 font->getEmbeddedFontID(&fontFileID)) {
427 setupEmbeddedFont(&fontFileID);
428 psName = font->getEmbeddedFontName();
431 // check for external font file
432 } else if (embedType1 && font->getType() == fontType1 &&
433 font->getExtFontFile()) {
434 setupEmbeddedFont(font->getExtFontFile());
435 // this assumes that the PS font name matches the PDF font name
436 psName = font->getName()->getCString();
439 // do font substitution
441 name = font->getName();
445 for (i = 0; psFonts[i].name; ++i) {
446 if (name->cmp(psFonts[i].name) == 0) {
447 psName = psFonts[i].psName;
453 if (font->isFixedWidth())
455 else if (font->isSerif())
461 if (font->isItalic())
463 psName = psSubstFonts[i].psName;
464 scale = font->getWidth('m') / psSubstFonts[i].mWidth;
470 // generate PostScript code to set up the font
471 writePS("/F%d_%d /%s %g\n",
472 font->getID().num, font->getID().gen, psName, scale);
473 for (i = 0; i < 256; i += 8) {
474 writePS((i == 0) ? "[ " : " ");
475 for (j = 0; j < 8; ++j) {
476 charName = font->getCharName(i+j);
477 writePS("/%s", charName ? charName : ".notdef");
479 writePS((i == 256-8) ? "]\n" : "\n");
481 writePS("pdfMakeFont\n");
484 void PSOutputDev::setupEmbeddedFont(Ref *id) {
485 static char hexChar[17] = "0123456789abcdef";
486 Object refObj, strObj, obj1, obj2;
488 int length1, length2;
494 // check if font is already embedded
495 for (i = 0; i < fontFileIDLen; ++i) {
496 if (fontFileIDs[i].num == id->num &&
497 fontFileIDs[i].gen == id->gen)
501 // add entry to fontFileIDs list
502 if (fontFileIDLen >= fontFileIDSize) {
503 fontFileIDSize += 64;
504 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
506 fontFileIDs[fontFileIDLen++] = *id;
508 // get the font stream and info
509 refObj.initRef(id->num, id->gen);
510 refObj.fetch(&strObj);
512 if (!strObj.isStream()) {
513 error(-1, "Embedded font file object is not a stream");
516 if (!(dict = strObj.streamGetDict())) {
517 error(-1, "Embedded font stream is missing its dictionary");
520 dict->lookup("Length1", &obj1);
521 dict->lookup("Length2", &obj2);
522 if (!obj1.isInt() || !obj2.isInt()) {
523 error(-1, "Missing length fields in embedded font stream dictionary");
528 length1 = obj1.getInt();
529 length2 = obj2.getInt();
533 // copy ASCII portion of font
534 strObj.streamReset();
535 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
538 // figure out if encrypted portion is binary or ASCII
540 for (i = 0; i < 4; ++i) {
541 start[i] = strObj.streamGetChar();
542 if (start[i] == EOF) {
543 error(-1, "Unexpected end of file in embedded font stream");
546 if (!((start[i] >= '0' && start[i] <= '9') ||
547 (start[i] >= 'A' && start[i] <= 'F') ||
548 (start[i] >= 'a' && start[i] <= 'f')))
552 // convert binary data to ASCII
554 for (i = 0; i < 4; ++i) {
555 fputc(hexChar[(start[i] >> 4) & 0x0f], f);
556 fputc(hexChar[start[i] & 0x0f], f);
558 while (i < length2) {
559 if ((c = strObj.streamGetChar()) == EOF)
561 fputc(hexChar[(c >> 4) & 0x0f], f);
562 fputc(hexChar[c & 0x0f], f);
569 // already in ASCII format -- just copy it
571 for (i = 0; i < 4; ++i)
573 for (i = 4; i < length2; ++i) {
574 if ((c = strObj.streamGetChar()) == EOF)
580 // write padding and "cleartomark"
581 for (i = 0; i < 8; ++i)
582 writePS("00000000000000000000000000000000"
583 "00000000000000000000000000000000\n");
584 writePS("cleartomark\n");
590 //~ This doesn't handle .pfb files or binary eexec data (which only
591 //~ happens in pfb files?).
592 void PSOutputDev::setupEmbeddedFont(char *fileName) {
597 // check if font is already embedded
598 for (i = 0; i < fontFileNameLen; ++i) {
599 if (!strcmp(fontFileNames[i], fileName))
603 // add entry to fontFileNames list
604 if (fontFileNameLen >= fontFileNameSize) {
605 fontFileNameSize += 64;
606 fontFileNames = (char **)grealloc(fontFileNames,
607 fontFileNameSize * sizeof(char *));
609 fontFileNames[fontFileNameLen++] = fileName;
611 // copy the font file
612 if (!(fontFile = fopen(fileName, "rb"))) {
613 error(-1, "Couldn't open external font file");
616 while ((c = fgetc(fontFile)) != EOF)
621 void PSOutputDev::startPage(int pageNum, GfxState *state) {
622 int x1, y1, x2, y2, width, height, t;
623 double xScale, yScale;
627 writePS("/PaintProc {\n");
628 writePS("begin xpdf begin\n");
629 writePS("pdfSetup\n");
633 writePS("%%%%Page: %d %d\n", pageNum, seqPage);
634 writePS("%%%%BeginPageSetup\n");
636 // rotate, translate, and scale page
637 x1 = (int)(state->getX1() + 0.5);
638 y1 = (int)(state->getY1() + 0.5);
639 x2 = (int)(state->getX2() + 0.5);
640 y2 = (int)(state->getY2() + 0.5);
643 if (width > height) {
644 writePS("%%%%PageOrientation: Landscape\n");
645 writePS("%d %d pdfStartPage\n", paperWidth, paperHeight);
646 writePS("90 rotate\n");
647 writePS("%d %d translate\n", -x1, -(y1 + paperWidth));
652 writePS("%%%%PageOrientation: Portrait\n");
653 writePS("%d %d pdfStartPage\n", paperWidth, paperHeight);
654 if (x1 != 0 || y1 != 0)
655 writePS("%d %d translate\n", -x1, -y1);
657 if (width > paperWidth || height > paperHeight) {
658 xScale = (double)paperWidth / (double)width;
659 yScale = (double)paperHeight / (double)height;
662 writePS("%0.4f %0.4f scale\n", xScale, xScale);
665 writePS("%%%%EndPageSetup\n");
670 void PSOutputDev::endPage() {
672 writePS("pdfEndPage\n");
673 writePS("end end\n");
676 writePS("showpage\n");
677 writePS("%%%%PageTrailer\n");
678 writePS("pdfEndPage\n");
682 void PSOutputDev::saveState(GfxState *state) {
686 void PSOutputDev::restoreState(GfxState *state) {
690 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
691 double m21, double m22, double m31, double m32) {
692 writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
695 void PSOutputDev::updateLineDash(GfxState *state) {
700 state->getLineDash(&dash, &length, &start);
702 for (i = 0; i < length; ++i)
703 writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
704 writePS("] %g d\n", start);
707 void PSOutputDev::updateFlatness(GfxState *state) {
708 writePS("%d i\n", state->getFlatness());
711 void PSOutputDev::updateLineJoin(GfxState *state) {
712 writePS("%d j\n", state->getLineJoin());
715 void PSOutputDev::updateLineCap(GfxState *state) {
716 writePS("%d J\n", state->getLineCap());
719 void PSOutputDev::updateMiterLimit(GfxState *state) {
720 writePS("%g M\n", state->getMiterLimit());
723 void PSOutputDev::updateLineWidth(GfxState *state) {
724 writePS("%g w\n", state->getLineWidth());
727 void PSOutputDev::updateFillColor(GfxState *state) {
731 color = state->getFillColor();
735 if (r == g && g == b)
736 writePS("%g g\n", r);
738 writePS("%g %g %g rg\n", r, g, b);
741 void PSOutputDev::updateStrokeColor(GfxState *state) {
745 color = state->getStrokeColor();
749 if (r == g && g == b)
750 writePS("%g G\n", r);
752 writePS("%g %g %g RG\n", r, g, b);
755 void PSOutputDev::updateFont(GfxState *state) {
756 if (state->getFont()) {
757 writePS("/F%d_%d %g Tf\n",
758 state->getFont()->getID().num, state->getFont()->getID().gen,
759 state->getFontSize());
763 void PSOutputDev::updateTextMat(GfxState *state) {
766 mat = state->getTextMat();
767 writePS("[%g %g %g %g %g %g] Tm\n",
768 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
771 void PSOutputDev::updateCharSpace(GfxState *state) {
772 writePS("%g Tc\n", state->getCharSpace());
775 void PSOutputDev::updateRender(GfxState *state) {
776 writePS("%d Tr\n", state->getRender());
779 void PSOutputDev::updateRise(GfxState *state) {
780 writePS("%g Ts\n", state->getRise());
783 void PSOutputDev::updateWordSpace(GfxState *state) {
784 writePS("%g Tw\n", state->getWordSpace());
787 void PSOutputDev::updateHorizScaling(GfxState *state) {
788 writePS("%g Tz\n", state->getHorizScaling());
791 void PSOutputDev::updateTextPos(GfxState *state) {
792 writePS("%g %g Td\n", state->getLineX(), state->getLineY());
795 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
796 writePS("%g TJm\n", shift);
799 void PSOutputDev::stroke(GfxState *state) {
800 doPath(state->getPath());
804 void PSOutputDev::fill(GfxState *state) {
805 doPath(state->getPath());
809 void PSOutputDev::eoFill(GfxState *state) {
810 doPath(state->getPath());
814 void PSOutputDev::clip(GfxState *state) {
815 doPath(state->getPath());
819 void PSOutputDev::eoClip(GfxState *state) {
820 doPath(state->getPath());
824 void PSOutputDev::doPath(GfxPath *path) {
826 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
829 n = path->getNumSubpaths();
831 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
832 subpath = path->getSubpath(0);
833 x0 = subpath->getX(0);
834 y0 = subpath->getY(0);
835 x4 = subpath->getX(4);
836 y4 = subpath->getY(4);
837 if (x4 == x0 && y4 == y0) {
838 x1 = subpath->getX(1);
839 y1 = subpath->getY(1);
840 x2 = subpath->getX(2);
841 y2 = subpath->getY(2);
842 x3 = subpath->getX(3);
843 y3 = subpath->getY(3);
844 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
845 writePS("%g %g %g %g re\n",
846 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
847 fabs(x2 - x0), fabs(y1 - y0));
849 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
850 writePS("%g %g %g %g re\n",
851 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
852 fabs(x1 - x0), fabs(y2 - y0));
858 for (i = 0; i < n; ++i) {
859 subpath = path->getSubpath(i);
860 m = subpath->getNumPoints();
861 writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
864 if (subpath->getCurve(j)) {
865 writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
866 subpath->getX(j+1), subpath->getY(j+1),
867 subpath->getX(j+2), subpath->getY(j+2));
870 writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
877 void PSOutputDev::drawString(GfxState *state, GString *s) {
878 // check for invisible text -- this is used by Acrobat Capture
879 if ((state->getRender() & 3) == 3)
883 writePS(" %g Tj\n", state->getFont()->getWidth(s));
886 void PSOutputDev::drawImageMask(GfxState *state, Stream *str,
887 int width, int height, GBool invert,
891 len = height * ((width + 7) / 8);
893 doImageL1(NULL, invert, inlineImg, str, width, height, len);
895 doImage(NULL, invert, inlineImg, str, width, height, len);
898 void PSOutputDev::drawImage(GfxState *state, Stream *str, int width,
899 int height, GfxImageColorMap *colorMap,
903 len = height * ((width * colorMap->getNumPixelComps() *
904 colorMap->getBits() + 7) / 8);
906 doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
908 doImage(colorMap, gFalse, inlineImg, str, width, height, len);
911 void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
912 GBool invert, GBool inlineImg,
913 Stream *str, int width, int height, int len) {
918 // width, height, matrix, bits per component
920 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
922 width, -height, height);
924 writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
925 width, height, invert ? "true" : "false",
926 width, -height, height);
932 // set up to process the data stream
933 str->resetImage(width, colorMap->getNumPixelComps(), colorMap->getBits());
935 // process the data stream
937 for (y = 0; y < height; ++y) {
940 for (x = 0; x < width; ++x) {
941 str->getImagePixel(pixBuf);
942 colorMap->getColor(pixBuf, &color);
943 fprintf(f, "%02x", (int)(color.getGray() * 255 + 0.5));
957 for (y = 0; y < height; ++y) {
958 for (x = 0; x < width; x += 8) {
959 fprintf(f, "%02x", str->getChar() & 0xff);
971 void PSOutputDev::doImage(GfxImageColorMap *colorMap,
972 GBool invert, GBool inlineImg,
973 Stream *str, int width, int height, int len) {
974 GfxColorSpace *colorSpace;
978 GBool useRLE, useA85;
984 colorSpace = colorMap->getColorSpace();
985 if (colorSpace->isIndexed())
986 writePS("[/Indexed ");
987 switch (colorSpace->getMode()) {
989 writePS("/DeviceGray ");
992 writePS("/DeviceCMYK ");
995 writePS("/DeviceRGB ");
998 if (colorSpace->isIndexed()) {
999 n = colorSpace->getIndexHigh();
1000 numComps = colorSpace->getNumColorComps();
1001 writePS("%d <\n", n);
1002 for (i = 0; i <= n; i += 8) {
1004 for (j = i; j < i+8 && j <= n; ++j) {
1005 color = colorSpace->getLookupVal(j);
1006 for (k = 0; k < numComps; ++k)
1007 writePS("%02x", color[k]);
1011 writePS("> ] setcolorspace\n");
1013 writePS("setcolorspace\n");
1018 writePS("<<\n /ImageType 1\n");
1020 // width, height, matrix, bits per component
1021 writePS(" /Width %d\n", width);
1022 writePS(" /Height %d\n", height);
1023 writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
1024 writePS(" /BitsPerComponent %d\n",
1025 colorMap ? colorMap->getBits() : 1);
1029 writePS(" /Decode [");
1030 numComps = colorMap->getNumPixelComps();
1031 for (i = 0; i < numComps; ++i) {
1034 writePS("%g %g", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
1038 writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
1044 writePS(" /DataSource <~\n");
1046 // write image data stream, using ASCII85 encode filter
1047 str = new ASCII85Encoder(str);
1049 while ((c = str->getChar()) != EOF)
1054 // end of image dictionary
1055 writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
1060 writePS(" /DataSource currentfile\n");
1061 s = str->getPSFilter(" ");
1062 if (inlineImg || !s) {
1067 useA85 = str->isBinary();
1070 writePS(" /ASCII85Decode filter\n");
1072 writePS(" /RunLengthDecode filter\n");
1074 writePS("%s", s->getCString());
1078 // end of image dictionary
1079 writePS(">>\n%s\n", colorMap ? "pdfIm" : "pdfImM");
1081 // write image data stream
1083 // cut off inline image streams at appropriate length
1085 str = new FixedLengthEncoder(str, len);
1087 str = str->getBaseStream();
1089 // add RunLengthEncode and ASCII85 encode filters
1091 str = new RunLengthEncoder(str);
1093 str = new ASCII85Encoder(str);
1095 // copy the stream data
1097 while ((c = str->getChar()) != EOF)
1100 // add newline and trailer to the end
1102 fputs("%-EOD-\n", f);
1105 if (useRLE || useA85)
1110 void PSOutputDev::writePS(char *fmt, ...) {
1113 va_start(args, fmt);
1114 vfprintf(f, fmt, args);
1118 void PSOutputDev::writePSString(GString *s) {
1123 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
1124 if (*p == '(' || *p == ')' || *p == '\\')
1125 fprintf(f, "\\%c", *p);
1126 else if (*p < 0x20 || *p >= 0x80)
1127 fprintf(f, "\\%03o", *p);