1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
28 #include "PSOutputDev.h"
30 //------------------------------------------------------------------------
32 //------------------------------------------------------------------------
34 // Generate Level 1 PostScript?
35 GBool psOutLevel1 = gFalse;
37 int paperWidth = defPaperWidth;
38 int paperHeight = defPaperHeight;
40 //------------------------------------------------------------------------
41 // PostScript prolog and setup
42 //------------------------------------------------------------------------
44 static char *prolog[] = {
45 "/xpdf 75 dict def xpdf begin",
46 "% PDF special state",
47 "/pdfDictSize 14 def",
50 " /setpagedevice where {",
51 " pop 3 dict dup begin",
52 " exch /PageSize exch def",
53 " /ImagingBBox null def",
54 " /Policies 1 dict dup begin /PageSize 3 def end def",
61 " pdfDictSize dict begin",
63 " /pdfStroke [0] def",
64 " /pdfLastFill false def",
65 " /pdfLastStroke false def",
66 " /pdfTextMat [1 0 0 1 0 0] def",
67 " /pdfFontSize 0 def",
68 " /pdfCharSpacing 0 def",
69 " /pdfTextRender 0 def",
70 " /pdfTextRise 0 def",
71 " /pdfWordSpacing 0 def",
72 " /pdfHorizScaling 1 def",
74 "/pdfEndPage { end } def",
75 "/sCol { pdfLastStroke not {",
76 " pdfStroke aload length",
77 " 1 eq { setgray } { setrgbcolor} ifelse",
78 " /pdfLastStroke true def /pdfLastFill false def",
80 "/fCol { pdfLastFill not {",
81 " pdfFill aload length",
82 " 1 eq { setgray } { setrgbcolor } ifelse",
83 " /pdfLastFill true def /pdfLastStroke false def",
88 " 3 2 roll 1 matrix scale makefont",
89 " dup length dict begin",
90 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
91 " /Encoding exch def",
96 "% graphics state operators",
97 "/q { gsave pdfDictSize dict begin } def",
98 "/Q { end grestore } def",
100 "/d { setdash } def",
101 "/i { setflat } def",
102 "/j { setlinejoin } def",
103 "/J { setlinecap } def",
104 "/M { setmiterlimit } def",
105 "/w { setlinewidth } def",
107 "/g { dup 1 array astore /pdfFill exch def setgray",
108 " /pdfLastFill true def /pdfLastStroke false def } def",
109 "/G { dup 1 array astore /pdfStroke exch def setgray",
110 " /pdfLastStroke true def /pdfLastFill false def } def",
111 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
112 " /pdfLastFill true def /pdfLastStroke false def } def",
113 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
114 " /pdfLastStroke true def /pdfLastFill false def } def",
115 "% path segment operators",
118 "/c { curveto } def",
119 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
120 " neg 0 rlineto closepath } def",
121 "% path painting operators",
122 "/S { sCol stroke } def",
123 "/f { fCol fill } def",
124 "/f* { fCol eofill } def",
125 "% clipping operators",
126 "/W { clip newpath } def",
127 "/W* { eoclip newpath } def",
128 "% text state operators",
129 "/Tc { /pdfCharSpacing exch def } def",
130 "/Tf { dup /pdfFontSize exch def",
131 " dup pdfHorizScaling mul exch matrix scale",
132 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
133 " exch findfont exch makefont setfont } def",
134 "/Tr { /pdfTextRender exch def } def",
135 "/Ts { /pdfTextRise exch def } def",
136 "/Tw { /pdfWordSpacing exch def } def",
137 "/Tz { /pdfHorizScaling exch def } def",
138 "% text positioning operators",
139 "/Td { pdfTextMat transform moveto } def",
140 "/Tm { /pdfTextMat exch def } def",
141 "% text string operators",
142 "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
143 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
144 " pdfFontSize mul pdfHorizScaling mul",
145 " 1 index stringwidth pdfTextMat idtransform pop",
146 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
147 " pdfWordSpacing 0 pdfTextMat dtransform 32",
148 " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
149 " 6 5 roll awidthshow",
150 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
151 "/TJm { pdfFontSize 0.001 mul mul neg 0",
152 " pdfTextMat dtransform rmoveto } def",
153 "% Level 1 image operators",
155 " /pdfImBuf1 4 index string def",
156 " { currentfile pdfImBuf1 readhexstring pop } image",
159 " /pdfImBuf1 4 index 7 add 8 idiv string def",
160 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
162 "% Level 2 image operators",
163 "/pdfImBuf 100 string def",
166 " { currentfile pdfImBuf readline",
167 " not { pop exit } if",
168 " (%-EOD-) eq { exit } if } loop",
172 " { currentfile pdfImBuf readline",
173 " not { pop exit } if",
174 " (%-EOD-) eq { exit } if } loop",
180 //------------------------------------------------------------------------
182 //------------------------------------------------------------------------
185 char *name; // PDF name
186 char *psName; // PostScript name
190 char *psName; // PostScript name
191 double mWidth; // width of 'm' character
194 static PSFont psFonts[] = {
195 {"Courier", "Courier"},
196 {"Courier-Bold", "Courier-Bold"},
197 {"Courier-Oblique", "Courier-Bold"},
198 {"Courier-BoldOblique", "Courier-BoldOblique"},
199 {"Helvetica", "Helvetica"},
200 {"Helvetica-Bold", "Helvetica-Bold"},
201 {"Helvetica-Oblique", "Helvetica-Oblique"},
202 {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
203 {"Symbol", "Symbol"},
204 {"Times-Roman", "Times-Roman"},
205 {"Times-Bold", "Times-Bold"},
206 {"Times-Italic", "Times-Italic"},
207 {"Times-BoldItalic", "Times-BoldItalic"},
208 {"ZapfDingbats", "ZapfDingbats"},
212 static PSSubstFont psSubstFonts[] = {
213 {"Helvetica", 0.833},
214 {"Helvetica-Oblique", 0.833},
215 {"Helvetica-Bold", 0.889},
216 {"Helvetica-BoldOblique", 0.889},
217 {"Times-Roman", 0.788},
218 {"Times-Italic", 0.722},
219 {"Times-Bold", 0.833},
220 {"Times-BoldItalic", 0.778},
222 {"Courier-Oblique", 0.600},
223 {"Courier-Bold", 0.600},
224 {"Courier-BoldOblique", 0.600}
227 //------------------------------------------------------------------------
229 //------------------------------------------------------------------------
231 PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
232 int firstPage, int lastPage,
233 GBool embedType11, GBool doForm1) {
240 embedType1 = embedType11;
244 fontFileNames = NULL;
247 lastPage = firstPage;
251 if (!strcmp(fileName, "-")) {
254 } else if (fileName[0] == '|') {
258 signal(SIGPIPE, (void (*)(int))SIG_IGN);
260 if (!(f = popen(fileName + 1, "w"))) {
261 error(-1, "Couldn't run print command '%s'", fileName);
266 error(-1, "Print commands are not supported ('%s')", fileName);
272 if (!(f = fopen(fileName, "w"))) {
273 error(-1, "Couldn't open PostScript file '%s'", fileName);
279 // initialize fontIDs, fontFileIDs, and fontFileNames lists
282 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
285 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
286 fontFileNameSize = 64;
288 fontFileNames = (char **)gmalloc(fontFileNameSize * sizeof(char *));
292 writePS("%%!PS-Adobe-3.0 Resource-Form\n");
293 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
294 writePS("%%%%EndComments\n");
296 writePS("%%!PS-Adobe-3.0\n");
297 writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
298 writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
299 writePS("%%%%EndComments\n");
304 writePS("%%%%BeginProlog\n");
305 writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion);
306 for (p = prolog; *p; ++p)
308 writePS("%%%%EndResource\n");
310 writePS("%%%%EndProlog\n");
314 writePS("%%%%BeginSetup\n");
315 writePS("xpdf begin\n");
316 for (pg = firstPage; pg <= lastPage; ++pg) {
317 if ((resDict = catalog->getPage(pg)->getResourceDict()))
323 writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
324 writePS("%%%%EndSetup\n");
329 page = catalog->getPage(firstPage);
330 writePS("4 dict dup begin\n");
331 writePS("/BBox [%d %d %d %d] def\n",
332 (int)page->getX1(), (int)page->getY1(),
333 (int)page->getX2(), (int)page->getY2());
334 writePS("/FormType 1 def\n");
335 writePS("/Matrix [1 0 0 1 0 0] def\n");
338 // initialize sequential page number
342 PSOutputDev::~PSOutputDev() {
346 writePS("/Foo exch /Form defineresource pop\n");
348 writePS("%%%%Trailer\n");
350 writePS("%%%%EOF\n");
352 if (fileType == psFile) {
356 else if (fileType == psPipe) {
359 signal(SIGPIPE, (void (*)(int))SIG_DFL);
369 gfree(fontFileNames);
372 void PSOutputDev::setupFonts(Dict *resDict) {
373 Object fontDict, xObjDict, xObj, resObj;
374 GfxFontDict *gfxFontDict;
378 resDict->lookup("Font", &fontDict);
379 if (fontDict.isDict()) {
380 gfxFontDict = new GfxFontDict(fontDict.getDict());
381 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
382 font = gfxFontDict->getFont(i);
389 resDict->lookup("XObject", &xObjDict);
390 if (xObjDict.isDict()) {
391 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
392 xObjDict.dictGetVal(i, &xObj);
393 if (xObj.isStream()) {
394 xObj.streamGetDict()->lookup("Resources", &resObj);
396 setupFonts(resObj.getDict());
405 void PSOutputDev::setupFont(GfxFont *font) {
413 // check if font is already set up
414 for (i = 0; i < fontIDLen; ++i) {
415 if (fontIDs[i].num == font->getID().num &&
416 fontIDs[i].gen == font->getID().gen)
420 // add entry to fontIDs list
421 if (fontIDLen >= fontIDSize) {
423 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
425 fontIDs[fontIDLen++] = font->getID();
427 // check for embedded Type 1 font
428 if (embedType1 && font->getType() == fontType1 &&
429 font->getEmbeddedFontID(&fontFileID)) {
430 setupEmbeddedType1Font(&fontFileID);
431 psName = font->getEmbeddedFontName();
434 // check for external Type 1 font file
435 } else if (embedType1 && font->getType() == fontType1 &&
436 font->getExtFontFile()) {
437 setupEmbeddedType1Font(font->getExtFontFile());
438 // this assumes that the PS font name matches the PDF font name
439 psName = font->getName()->getCString();
442 // check for embedded Type 1C font
443 } else if (embedType1 && font->getType() == fontType1C &&
444 font->getEmbeddedFontID(&fontFileID)) {
445 setupEmbeddedType1CFont(font, &fontFileID);
446 psName = font->getEmbeddedFontName();
449 // do font substitution
451 name = font->getName();
455 for (i = 0; psFonts[i].name; ++i) {
456 if (name->cmp(psFonts[i].name) == 0) {
457 psName = psFonts[i].psName;
463 if (font->isFixedWidth())
465 else if (font->isSerif())
471 if (font->isItalic())
473 psName = psSubstFonts[i].psName;
474 scale = font->getWidth('m') / psSubstFonts[i].mWidth;
480 // generate PostScript code to set up the font
481 writePS("/F%d_%d /%s %g\n",
482 font->getID().num, font->getID().gen, psName, scale);
483 for (i = 0; i < 256; i += 8) {
484 writePS((i == 0) ? "[ " : " ");
485 for (j = 0; j < 8; ++j) {
486 charName = font->getCharName(i+j);
487 writePS("/%s", charName ? charName : ".notdef");
489 writePS((i == 256-8) ? "]\n" : "\n");
491 writePS("pdfMakeFont\n");
494 void PSOutputDev::setupEmbeddedType1Font(Ref *id) {
495 static char hexChar[17] = "0123456789abcdef";
496 Object refObj, strObj, obj1, obj2;
498 int length1, length2;
504 // check if font is already embedded
505 for (i = 0; i < fontFileIDLen; ++i) {
506 if (fontFileIDs[i].num == id->num &&
507 fontFileIDs[i].gen == id->gen)
511 // add entry to fontFileIDs list
512 if (fontFileIDLen >= fontFileIDSize) {
513 fontFileIDSize += 64;
514 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
516 fontFileIDs[fontFileIDLen++] = *id;
518 // get the font stream and info
519 refObj.initRef(id->num, id->gen);
520 refObj.fetch(&strObj);
522 if (!strObj.isStream()) {
523 error(-1, "Embedded font file object is not a stream");
526 if (!(dict = strObj.streamGetDict())) {
527 error(-1, "Embedded font stream is missing its dictionary");
530 dict->lookup("Length1", &obj1);
531 dict->lookup("Length2", &obj2);
532 if (!obj1.isInt() || !obj2.isInt()) {
533 error(-1, "Missing length fields in embedded font stream dictionary");
538 length1 = obj1.getInt();
539 length2 = obj2.getInt();
543 // copy ASCII portion of font
544 strObj.streamReset();
545 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
548 // figure out if encrypted portion is binary or ASCII
550 for (i = 0; i < 4; ++i) {
551 start[i] = strObj.streamGetChar();
552 if (start[i] == EOF) {
553 error(-1, "Unexpected end of file in embedded font stream");
556 if (!((start[i] >= '0' && start[i] <= '9') ||
557 (start[i] >= 'A' && start[i] <= 'F') ||
558 (start[i] >= 'a' && start[i] <= 'f')))
562 // convert binary data to ASCII
564 for (i = 0; i < 4; ++i) {
565 fputc(hexChar[(start[i] >> 4) & 0x0f], f);
566 fputc(hexChar[start[i] & 0x0f], f);
568 while (i < length2) {
569 if ((c = strObj.streamGetChar()) == EOF)
571 fputc(hexChar[(c >> 4) & 0x0f], f);
572 fputc(hexChar[c & 0x0f], f);
579 // already in ASCII format -- just copy it
581 for (i = 0; i < 4; ++i)
583 for (i = 4; i < length2; ++i) {
584 if ((c = strObj.streamGetChar()) == EOF)
590 // write padding and "cleartomark"
591 for (i = 0; i < 8; ++i)
592 writePS("00000000000000000000000000000000"
593 "00000000000000000000000000000000\n");
594 writePS("cleartomark\n");
600 //~ This doesn't handle .pfb files or binary eexec data (which only
601 //~ happens in pfb files?).
602 void PSOutputDev::setupEmbeddedType1Font(char *fileName) {
607 // check if font is already embedded
608 for (i = 0; i < fontFileNameLen; ++i) {
609 if (!strcmp(fontFileNames[i], fileName))
613 // add entry to fontFileNames list
614 if (fontFileNameLen >= fontFileNameSize) {
615 fontFileNameSize += 64;
616 fontFileNames = (char **)grealloc(fontFileNames,
617 fontFileNameSize * sizeof(char *));
619 fontFileNames[fontFileNameLen++] = fileName;
621 // copy the font file
622 if (!(fontFile = fopen(fileName, "rb"))) {
623 error(-1, "Couldn't open external font file");
626 while ((c = fgetc(fontFile)) != EOF)
631 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id) {
634 Type1CFontConverter *cvt;
637 // check if font is already embedded
638 for (i = 0; i < fontFileIDLen; ++i) {
639 if (fontFileIDs[i].num == id->num &&
640 fontFileIDs[i].gen == id->gen)
644 // add entry to fontFileIDs list
645 if (fontFileIDLen >= fontFileIDSize) {
646 fontFileIDSize += 64;
647 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
649 fontFileIDs[fontFileIDLen++] = *id;
651 // convert it to a Type 1 font
652 fontBuf = font->readEmbFontFile(&fontLen);
653 cvt = new Type1CFontConverter(fontBuf, fontLen, f);
659 void PSOutputDev::startPage(int pageNum, GfxState *state) {
660 int x1, y1, x2, y2, width, height, t;
661 double xScale, yScale;
665 writePS("/PaintProc {\n");
666 writePS("begin xpdf begin\n");
667 writePS("pdfSetup\n");
671 writePS("%%%%Page: %d %d\n", pageNum, seqPage);
672 writePS("%%%%BeginPageSetup\n");
674 // rotate, translate, and scale page
675 x1 = (int)(state->getX1() + 0.5);
676 y1 = (int)(state->getY1() + 0.5);
677 x2 = (int)(state->getX2() + 0.5);
678 y2 = (int)(state->getY2() + 0.5);
681 if (width > height) {
682 writePS("%%%%PageOrientation: Landscape\n");
683 writePS("pdfStartPage\n");
684 writePS("90 rotate\n");
685 writePS("%d %d translate\n", -x1, -(y1 + paperWidth));
690 writePS("%%%%PageOrientation: Portrait\n");
691 writePS("pdfStartPage\n");
692 if (x1 != 0 || y1 != 0)
693 writePS("%d %d translate\n", -x1, -y1);
695 if (width > paperWidth || height > paperHeight) {
696 xScale = (double)paperWidth / (double)width;
697 yScale = (double)paperHeight / (double)height;
700 writePS("%0.4f %0.4f scale\n", xScale, xScale);
703 writePS("%%%%EndPageSetup\n");
708 void PSOutputDev::endPage() {
710 writePS("pdfEndPage\n");
711 writePS("end end\n");
714 writePS("showpage\n");
715 writePS("%%%%PageTrailer\n");
716 writePS("pdfEndPage\n");
720 void PSOutputDev::saveState(GfxState *state) {
724 void PSOutputDev::restoreState(GfxState *state) {
728 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
729 double m21, double m22, double m31, double m32) {
730 writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
733 void PSOutputDev::updateLineDash(GfxState *state) {
738 state->getLineDash(&dash, &length, &start);
740 for (i = 0; i < length; ++i)
741 writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
742 writePS("] %g d\n", start);
745 void PSOutputDev::updateFlatness(GfxState *state) {
746 writePS("%d i\n", state->getFlatness());
749 void PSOutputDev::updateLineJoin(GfxState *state) {
750 writePS("%d j\n", state->getLineJoin());
753 void PSOutputDev::updateLineCap(GfxState *state) {
754 writePS("%d J\n", state->getLineCap());
757 void PSOutputDev::updateMiterLimit(GfxState *state) {
758 writePS("%g M\n", state->getMiterLimit());
761 void PSOutputDev::updateLineWidth(GfxState *state) {
762 writePS("%g w\n", state->getLineWidth());
765 void PSOutputDev::updateFillColor(GfxState *state) {
769 color = state->getFillColor();
773 if (r == g && g == b)
774 writePS("%g g\n", r);
776 writePS("%g %g %g rg\n", r, g, b);
779 void PSOutputDev::updateStrokeColor(GfxState *state) {
783 color = state->getStrokeColor();
787 if (r == g && g == b)
788 writePS("%g G\n", r);
790 writePS("%g %g %g RG\n", r, g, b);
793 void PSOutputDev::updateFont(GfxState *state) {
794 if (state->getFont()) {
795 writePS("/F%d_%d %g Tf\n",
796 state->getFont()->getID().num, state->getFont()->getID().gen,
797 state->getFontSize());
801 void PSOutputDev::updateTextMat(GfxState *state) {
804 mat = state->getTextMat();
805 writePS("[%g %g %g %g %g %g] Tm\n",
806 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
809 void PSOutputDev::updateCharSpace(GfxState *state) {
810 writePS("%g Tc\n", state->getCharSpace());
813 void PSOutputDev::updateRender(GfxState *state) {
814 writePS("%d Tr\n", state->getRender());
817 void PSOutputDev::updateRise(GfxState *state) {
818 writePS("%g Ts\n", state->getRise());
821 void PSOutputDev::updateWordSpace(GfxState *state) {
822 writePS("%g Tw\n", state->getWordSpace());
825 void PSOutputDev::updateHorizScaling(GfxState *state) {
826 writePS("%g Tz\n", state->getHorizScaling());
829 void PSOutputDev::updateTextPos(GfxState *state) {
830 writePS("%g %g Td\n", state->getLineX(), state->getLineY());
833 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
834 writePS("%g TJm\n", shift);
837 void PSOutputDev::stroke(GfxState *state) {
838 doPath(state->getPath());
842 void PSOutputDev::fill(GfxState *state) {
843 doPath(state->getPath());
847 void PSOutputDev::eoFill(GfxState *state) {
848 doPath(state->getPath());
852 void PSOutputDev::clip(GfxState *state) {
853 doPath(state->getPath());
857 void PSOutputDev::eoClip(GfxState *state) {
858 doPath(state->getPath());
862 void PSOutputDev::doPath(GfxPath *path) {
864 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
867 n = path->getNumSubpaths();
869 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
870 subpath = path->getSubpath(0);
871 x0 = subpath->getX(0);
872 y0 = subpath->getY(0);
873 x4 = subpath->getX(4);
874 y4 = subpath->getY(4);
875 if (x4 == x0 && y4 == y0) {
876 x1 = subpath->getX(1);
877 y1 = subpath->getY(1);
878 x2 = subpath->getX(2);
879 y2 = subpath->getY(2);
880 x3 = subpath->getX(3);
881 y3 = subpath->getY(3);
882 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
883 writePS("%g %g %g %g re\n",
884 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
885 fabs(x2 - x0), fabs(y1 - y0));
887 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
888 writePS("%g %g %g %g re\n",
889 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
890 fabs(x1 - x0), fabs(y2 - y0));
896 for (i = 0; i < n; ++i) {
897 subpath = path->getSubpath(i);
898 m = subpath->getNumPoints();
899 writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
902 if (subpath->getCurve(j)) {
903 writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
904 subpath->getX(j+1), subpath->getY(j+1),
905 subpath->getX(j+2), subpath->getY(j+2));
908 writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
915 void PSOutputDev::drawString(GfxState *state, GString *s) {
916 // check for invisible text -- this is used by Acrobat Capture
917 if ((state->getRender() & 3) == 3)
921 writePS(" %g Tj\n", state->getFont()->getWidth(s));
924 void PSOutputDev::drawImageMask(GfxState *state, Stream *str,
925 int width, int height, GBool invert,
929 len = height * ((width + 7) / 8);
931 doImageL1(NULL, invert, inlineImg, str, width, height, len);
933 doImage(NULL, invert, inlineImg, str, width, height, len);
936 void PSOutputDev::drawImage(GfxState *state, Stream *str, int width,
937 int height, GfxImageColorMap *colorMap,
941 len = height * ((width * colorMap->getNumPixelComps() *
942 colorMap->getBits() + 7) / 8);
944 doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
946 doImage(colorMap, gFalse, inlineImg, str, width, height, len);
949 void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
950 GBool invert, GBool inlineImg,
951 Stream *str, int width, int height, int len) {
957 // width, height, matrix, bits per component
959 writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
961 width, -height, height);
963 writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
964 width, height, invert ? "true" : "false",
965 width, -height, height);
971 // set up to process the data stream
972 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
973 colorMap->getBits());
976 // process the data stream
978 for (y = 0; y < height; ++y) {
981 for (x = 0; x < width; ++x) {
982 imgStr->getPixel(pixBuf);
983 colorMap->getColor(pixBuf, &color);
984 fprintf(f, "%02x", (int)(color.getGray() * 255 + 0.5));
999 for (y = 0; y < height; ++y) {
1000 for (x = 0; x < width; x += 8) {
1001 fprintf(f, "%02x", str->getChar() & 0xff);
1013 void PSOutputDev::doImage(GfxImageColorMap *colorMap,
1014 GBool invert, GBool inlineImg,
1015 Stream *str, int width, int height, int len) {
1016 GfxColorSpace *colorSpace;
1020 GBool useRLE, useA85;
1026 colorSpace = colorMap->getColorSpace();
1027 if (colorSpace->isIndexed())
1028 writePS("[/Indexed ");
1029 switch (colorSpace->getMode()) {
1031 writePS("/DeviceGray ");
1034 writePS("/DeviceCMYK ");
1037 writePS("/DeviceRGB ");
1040 if (colorSpace->isIndexed()) {
1041 n = colorSpace->getIndexHigh();
1042 numComps = colorSpace->getNumColorComps();
1043 writePS("%d <\n", n);
1044 for (i = 0; i <= n; i += 8) {
1046 for (j = i; j < i+8 && j <= n; ++j) {
1047 color = colorSpace->getLookupVal(j);
1048 for (k = 0; k < numComps; ++k)
1049 writePS("%02x", color[k]);
1053 writePS("> ] setcolorspace\n");
1055 writePS("setcolorspace\n");
1060 writePS("<<\n /ImageType 1\n");
1062 // width, height, matrix, bits per component
1063 writePS(" /Width %d\n", width);
1064 writePS(" /Height %d\n", height);
1065 writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
1066 writePS(" /BitsPerComponent %d\n",
1067 colorMap ? colorMap->getBits() : 1);
1071 writePS(" /Decode [");
1072 numComps = colorMap->getNumPixelComps();
1073 for (i = 0; i < numComps; ++i) {
1076 writePS("%g %g", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
1080 writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
1086 writePS(" /DataSource <~\n");
1088 // write image data stream, using ASCII85 encode filter
1089 str = new ASCII85Encoder(str);
1091 while ((c = str->getChar()) != EOF)
1096 // end of image dictionary
1097 writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
1102 writePS(" /DataSource currentfile\n");
1103 s = str->getPSFilter(" ");
1104 if (inlineImg || !s) {
1109 useA85 = str->isBinary();
1112 writePS(" /ASCII85Decode filter\n");
1114 writePS(" /RunLengthDecode filter\n");
1116 writePS("%s", s->getCString());
1120 // end of image dictionary
1121 writePS(">>\n%s\n", colorMap ? "pdfIm" : "pdfImM");
1123 // write image data stream
1125 // cut off inline image streams at appropriate length
1127 str = new FixedLengthEncoder(str, len);
1129 str = str->getBaseStream();
1131 // add RunLengthEncode and ASCII85 encode filters
1133 str = new RunLengthEncoder(str);
1135 str = new ASCII85Encoder(str);
1137 // copy the stream data
1139 while ((c = str->getChar()) != EOF)
1142 // add newline and trailer to the end
1144 fputs("%-EOD-\n", f);
1147 if (useRLE || useA85)
1152 void PSOutputDev::writePS(char *fmt, ...) {
1155 va_start(args, fmt);
1156 vfprintf(f, fmt, args);
1160 void PSOutputDev::writePSString(GString *s) {
1165 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
1166 if (*p == '(' || *p == ')' || *p == '\\')
1167 fprintf(f, "\\%c", *p);
1168 else if (*p < 0x20 || *p >= 0x80)
1169 fprintf(f, "\\%03o", *p);