Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/PSOutputDev.cc
diff options
context:
space:
mode:
authorArturo Espinosa <unammx@src.gnome.org>1999-04-17 02:59:58 (GMT)
committer Arturo Espinosa <unammx@src.gnome.org>1999-04-17 02:59:58 (GMT)
commitd9f9a6449f377b4c933b75d57541b19c6d088994 (patch)
tree04f7f0c54447ef792fbf83bc5039174f4681b3bb /pdf/xpdf/PSOutputDev.cc
Initial revision
Diffstat (limited to 'pdf/xpdf/PSOutputDev.cc')
-rw-r--r--pdf/xpdf/PSOutputDev.cc1132
1 files changed, 1132 insertions, 0 deletions
diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc
new file mode 100644
index 0000000..bc7fb3c
--- /dev/null
+++ b/pdf/xpdf/PSOutputDev.cc
@@ -0,0 +1,1132 @@
+//========================================================================
+//
+// PSOutputDev.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <math.h>
+#include "GString.h"
+#include "config.h"
+#include "Object.h"
+#include "Error.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "Stream.h"
+#include "PSOutputDev.h"
+
+//------------------------------------------------------------------------
+// Parameters
+//------------------------------------------------------------------------
+
+// Generate Level 1 PostScript?
+GBool psOutLevel1 = gFalse;
+
+int paperWidth = defPaperWidth;
+int paperHeight = defPaperHeight;
+
+//------------------------------------------------------------------------
+// PostScript prolog and setup
+//------------------------------------------------------------------------
+
+static char *prolog[] = {
+ "/xpdf 75 dict def xpdf begin",
+ "% PDF special state",
+ "/pdfDictSize 14 def",
+ "/pdfSetup {",
+ " pdfDictSize dict begin",
+ " /pdfFill [0] def",
+ " /pdfStroke [0] def",
+ " /pdfLastFill false def",
+ " /pdfLastStroke false def",
+ " /pdfTextMat [1 0 0 1 0 0] def",
+ " /pdfFontSize 0 def",
+ " /pdfCharSpacing 0 def",
+ " /pdfTextRender 0 def",
+ " /pdfTextRise 0 def",
+ " /pdfWordSpacing 0 def",
+ " /pdfHorizScaling 1 def",
+ "} def",
+ "/pdfStartPage {",
+ " 2 array astore",
+ " pdfSetup",
+ " /setpagedevice where {",
+ " pop 2 dict dup begin",
+ " exch /PageSize exch def",
+ " /ImagingBBox null def",
+ " end setpagedevice",
+ " } {",
+ " pop",
+ " } ifelse",
+ "} def",
+ "/pdfEndPage { end } def",
+ "/sCol { pdfLastStroke not {",
+ " pdfStroke aload length",
+ " 1 eq { setgray } { setrgbcolor} ifelse",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if } def",
+ "/fCol { pdfLastFill not {",
+ " pdfFill aload length",
+ " 1 eq { setgray } { setrgbcolor } ifelse",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if } def",
+ "% build a font",
+ "/pdfMakeFont {",
+ " 3 2 roll findfont",
+ " 3 2 roll 1 matrix scale makefont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /Encoding exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "% graphics state operators",
+ "/q { gsave pdfDictSize dict begin } def",
+ "/Q { end grestore } def",
+ "/cm { concat } def",
+ "/d { setdash } def",
+ "/i { setflat } def",
+ "/j { setlinejoin } def",
+ "/J { setlinecap } def",
+ "/M { setmiterlimit } def",
+ "/w { setlinewidth } def",
+ "% color operators",
+ "/g { dup 1 array astore /pdfFill exch def setgray",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/G { dup 1 array astore /pdfStroke exch def setgray",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "% path segment operators",
+ "/m { moveto } def",
+ "/l { lineto } def",
+ "/c { curveto } def",
+ "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
+ " neg 0 rlineto closepath } def"
+ "% path painting operators",
+ "/S { sCol stroke } def",
+ "/f { fCol fill } def",
+ "/f* { fCol eofill } def",
+ "% clipping operators",
+ "/W { clip newpath } def",
+ "/W* { eoclip newpath } def",
+ "% text state operators",
+ "/Tc { /pdfCharSpacing exch def } def",
+ "/Tf { dup /pdfFontSize exch def",
+ " dup pdfHorizScaling mul exch matrix scale",
+ " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
+ " exch findfont exch makefont setfont } def",
+ "/Tr { /pdfTextRender exch def } def",
+ "/Ts { /pdfTextRise exch def } def",
+ "/Tw { /pdfWordSpacing exch def } def",
+ "/Tz { /pdfHorizScaling exch def } def",
+ "% text positioning operators",
+ "/Td { pdfTextMat transform moveto } def",
+ "/Tm { /pdfTextMat exch def } def",
+ "% text string operators",
+ "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " pdfFontSize mul pdfHorizScaling mul",
+ " 1 index stringwidth pdfTextMat idtransform pop",
+ " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+ " pdfWordSpacing 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
+ " 6 5 roll awidthshow",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
+ "/TJm { pdfFontSize 0.001 mul mul neg 0",
+ " pdfTextMat dtransform rmoveto } def",
+ "% Level 1 image operators",
+ "/pdfIm1 {",
+ " /pdfImBuf1 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop } image",
+ "} def",
+ "/pdfImM1 {",
+ " /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readhexstring pop } imagemask",
+ "} def",
+ "% Level 2 image operators",
+ "/pdfImBuf 100 string def",
+ "/pdfIm {",
+ " image",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "/pdfImM {",
+ " fCol imagemask",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "end",
+ NULL
+};
+
+//------------------------------------------------------------------------
+// Fonts
+//------------------------------------------------------------------------
+
+struct PSFont {
+ char *name; // PDF name
+ char *psName; // PostScript name
+};
+
+struct PSSubstFont {
+ char *psName; // PostScript name
+ double mWidth; // width of 'm' character
+};
+
+static PSFont psFonts[] = {
+ {"Courier", "Courier"},
+ {"Courier-Bold", "Courier-Bold"},
+ {"Courier-Oblique", "Courier-Bold"},
+ {"Courier-BoldOblique", "Courier-BoldOblique"},
+ {"Helvetica", "Helvetica"},
+ {"Helvetica-Bold", "Helvetica-Bold"},
+ {"Helvetica-Oblique", "Helvetica-Oblique"},
+ {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
+ {"Symbol", "Symbol"},
+ {"Times-Roman", "Times-Roman"},
+ {"Times-Bold", "Times-Bold"},
+ {"Times-Italic", "Times-Italic"},
+ {"Times-BoldItalic", "Times-BoldItalic"},
+ {"ZapfDingbats", "ZapfDingbats"},
+ {NULL}
+};
+
+static PSSubstFont psSubstFonts[] = {
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+ {"Helvetica-BoldOblique", 0.889},
+ {"Times-Roman", 0.788},
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+ {"Courier", 0.600},
+ {"Courier-Oblique", 0.600},
+ {"Courier-Bold", 0.600},
+ {"Courier-BoldOblique", 0.600}
+};
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
+ int firstPage, int lastPage,
+ GBool embedType11, GBool doForm1) {
+ Page *page;
+ Dict *resDict;
+ char **p;
+ int pg;
+
+ // initialize
+ embedType1 = embedType11;
+ doForm = doForm1;
+ fontIDs = NULL;
+ fontFileIDs = NULL;
+ fontFileNames = NULL;
+ f = NULL;
+ if (doForm)
+ lastPage = firstPage;
+
+ // open file or pipe
+ ok = gTrue;
+ if (!strcmp(fileName, "-")) {
+ fileType = psStdout;
+ f = stdout;
+ } else if (fileName[0] == '|') {
+ fileType = psPipe;
+#ifdef HAVE_POPEN
+#ifndef WIN32
+ signal(SIGPIPE, (void (*)(int))SIG_IGN);
+#endif
+ if (!(f = popen(fileName + 1, "w"))) {
+ error(-1, "Couldn't run print command '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+#else
+ error(-1, "Print commands are not supported ('%s')", fileName);
+ ok = gFalse;
+ return;
+#endif
+ } else {
+ fileType = psFile;
+ if (!(f = fopen(fileName, "w"))) {
+ error(-1, "Couldn't open PostScript file '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+ }
+
+ // initialize fontIDs, fontFileIDs, and fontFileNames lists
+ fontIDSize = 64;
+ fontIDLen = 0;
+ fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
+ fontFileIDSize = 64;
+ fontFileIDLen = 0;
+ fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
+ fontFileNameSize = 64;
+ fontFileNameLen = 0;
+ fontFileNames = (char **)gmalloc(fontFileNameSize * sizeof(char *));
+
+ // write header
+ if (doForm) {
+ writePS("%%!PS-Adobe-3.0 Resource-Form\n");
+ writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePS("%%%%EndComments\n");
+ } else {
+ writePS("%%!PS-Adobe-3.0\n");
+ writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
+ writePS("%%%%EndComments\n");
+ }
+
+ // write prolog
+ if (!doForm)
+ writePS("%%%%BeginProlog\n");
+ writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion);
+ for (p = prolog; *p; ++p)
+ writePS("%s\n", *p);
+ writePS("%%%%EndResource\n");
+ if (!doForm)
+ writePS("%%%%EndProlog\n");
+
+ // set up fonts
+ if (!doForm)
+ writePS("%%%%BeginSetup\n");
+ writePS("xpdf begin\n");
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ if ((resDict = catalog->getPage(pg)->getResourceDict()))
+ setupFonts(resDict);
+ }
+ if (doForm)
+ writePS("end\n");
+ else
+ writePS("%%%%EndSetup\n");
+
+ // write form header
+ if (doForm) {
+ page = catalog->getPage(firstPage);
+ writePS("4 dict dup begin\n");
+ writePS("/BBox [%d %d %d %d] def\n",
+ (int)page->getX1(), (int)page->getY1(),
+ (int)page->getX2(), (int)page->getY2());
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ }
+
+ // initialize sequential page number
+ seqPage = 1;
+}
+
+PSOutputDev::~PSOutputDev() {
+ if (f) {
+ if (doForm) {
+ writePS("end\n");
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("%%%%Trailer\n");
+ writePS("end\n");
+ writePS("%%%%EOF\n");
+ }
+ if (fileType == psFile) {
+ fclose(f);
+ }
+#ifdef HAVE_POPEN
+ else if (fileType == psPipe) {
+ pclose(f);
+#ifndef WIN32
+ signal(SIGPIPE, (void (*)(int))SIG_DFL);
+#endif
+ }
+#endif
+ }
+ if (fontIDs)
+ gfree(fontIDs);
+ if (fontFileIDs)
+ gfree(fontFileIDs);
+ if (fontFileNames)
+ gfree(fontFileNames);
+}
+
+void PSOutputDev::setupFonts(Dict *resDict) {
+ Object fontDict, xObjDict, xObj, resObj;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ resDict->lookup("Font", &fontDict);
+ if (fontDict.isDict()) {
+ gfxFontDict = new GfxFontDict(fontDict.getDict());
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+ font = gfxFontDict->getFont(i);
+ setupFont(font);
+ }
+ delete gfxFontDict;
+ }
+ fontDict.free();
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict())
+ setupFonts(resObj.getDict());
+ resObj.free();
+ }
+ xObj.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupFont(GfxFont *font) {
+ Ref fontFileID;
+ GString *name;
+ char *psName;
+ char *charName;
+ double scale;
+ int i, j;
+
+ // check if font is already set up
+ for (i = 0; i < fontIDLen; ++i) {
+ if (fontIDs[i].num == font->getID().num &&
+ fontIDs[i].gen == font->getID().gen)
+ return;
+ }
+
+ // add entry to fontIDs list
+ if (fontIDLen >= fontIDSize) {
+ fontIDSize += 64;
+ fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
+ }
+ fontIDs[fontIDLen++] = font->getID();
+
+ // check for embedded font
+ if (embedType1 && font->getType() == fontType1 &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ setupEmbeddedFont(&fontFileID);
+ psName = font->getEmbeddedFontName();
+ scale = 1;
+
+ // check for external font file
+ } else if (embedType1 && font->getType() == fontType1 &&
+ font->getExtFontFile()) {
+ setupEmbeddedFont(font->getExtFontFile());
+ // this assumes that the PS font name matches the PDF font name
+ psName = font->getName()->getCString();
+ scale = 1;
+
+ // do font substitution
+ } else {
+ name = font->getName();
+ psName = NULL;
+ scale = 1.0;
+ if (name) {
+ for (i = 0; psFonts[i].name; ++i) {
+ if (name->cmp(psFonts[i].name) == 0) {
+ psName = psFonts[i].psName;
+ break;
+ }
+ }
+ }
+ if (!psName) {
+ if (font->isFixedWidth())
+ i = 8;
+ else if (font->isSerif())
+ i = 4;
+ else
+ i = 0;
+ if (font->isBold())
+ i += 2;
+ if (font->isItalic())
+ i += 1;
+ psName = psSubstFonts[i].psName;
+ scale = font->getWidth('m') / psSubstFonts[i].mWidth;
+ if (scale < 0.1)
+ scale = 1;
+ }
+ }
+
+ // generate PostScript code to set up the font
+ writePS("/F%d_%d /%s %g\n",
+ font->getID().num, font->getID().gen, psName, scale);
+ for (i = 0; i < 256; i += 8) {
+ writePS((i == 0) ? "[ " : " ");
+ for (j = 0; j < 8; ++j) {
+ charName = font->getCharName(i+j);
+ writePS("/%s", charName ? charName : ".notdef");
+ }
+ writePS((i == 256-8) ? "]\n" : "\n");
+ }
+ writePS("pdfMakeFont\n");
+}
+
+void PSOutputDev::setupEmbeddedFont(Ref *id) {
+ static char hexChar[17] = "0123456789abcdef";
+ Object refObj, strObj, obj1, obj2;
+ Dict *dict;
+ int length1, length2;
+ int c;
+ int start[4];
+ GBool binMode;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // get the font stream and info
+ refObj.initRef(id->num, id->gen);
+ refObj.fetch(&strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+ error(-1, "Embedded font file object is not a stream");
+ goto err1;
+ }
+ if (!(dict = strObj.streamGetDict())) {
+ error(-1, "Embedded font stream is missing its dictionary");
+ goto err1;
+ }
+ dict->lookup("Length1", &obj1);
+ dict->lookup("Length2", &obj2);
+ if (!obj1.isInt() || !obj2.isInt()) {
+ error(-1, "Missing length fields in embedded font stream dictionary");
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ length1 = obj1.getInt();
+ length2 = obj2.getInt();
+ obj1.free();
+ obj2.free();
+
+ // copy ASCII portion of font
+ strObj.streamReset();
+ for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
+ fputc(c, f);
+
+ // figure out if encrypted portion is binary or ASCII
+ binMode = gFalse;
+ for (i = 0; i < 4; ++i) {
+ start[i] = strObj.streamGetChar();
+ if (start[i] == EOF) {
+ error(-1, "Unexpected end of file in embedded font stream");
+ goto err1;
+ }
+ if (!((start[i] >= '0' && start[i] <= '9') ||
+ (start[i] >= 'A' && start[i] <= 'F') ||
+ (start[i] >= 'a' && start[i] <= 'f')))
+ binMode = gTrue;
+ }
+
+ // convert binary data to ASCII
+ if (binMode) {
+ for (i = 0; i < 4; ++i) {
+ fputc(hexChar[(start[i] >> 4) & 0x0f], f);
+ fputc(hexChar[start[i] & 0x0f], f);
+ }
+ while (i < length2) {
+ if ((c = strObj.streamGetChar()) == EOF)
+ break;
+ fputc(hexChar[(c >> 4) & 0x0f], f);
+ fputc(hexChar[c & 0x0f], f);
+ if (++i % 32 == 0)
+ fputc('\n', f);
+ }
+ if (i % 32 > 0)
+ fputc('\n', f);
+
+ // already in ASCII format -- just copy it
+ } else {
+ for (i = 0; i < 4; ++i)
+ fputc(start[i], f);
+ for (i = 4; i < length2; ++i) {
+ if ((c = strObj.streamGetChar()) == EOF)
+ break;
+ fputc(c, f);
+ }
+ }
+
+ // write padding and "cleartomark"
+ for (i = 0; i < 8; ++i)
+ writePS("00000000000000000000000000000000"
+ "00000000000000000000000000000000\n");
+ writePS("cleartomark\n");
+
+ err1:
+ strObj.free();
+}
+
+//~ This doesn't handle .pfb files or binary eexec data (which only
+//~ happens in pfb files?).
+void PSOutputDev::setupEmbeddedFont(char *fileName) {
+ FILE *fontFile;
+ int c;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!strcmp(fontFileNames[i], fileName))
+ return;
+ }
+
+ // add entry to fontFileNames list
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames = (char **)grealloc(fontFileNames,
+ fontFileNameSize * sizeof(char *));
+ }
+ fontFileNames[fontFileNameLen++] = fileName;
+
+ // copy the font file
+ if (!(fontFile = fopen(fileName, "rb"))) {
+ error(-1, "Couldn't open external font file");
+ return;
+ }
+ while ((c = fgetc(fontFile)) != EOF)
+ fputc(c, f);
+ fclose(fontFile);
+}
+
+void PSOutputDev::startPage(int pageNum, GfxState *state) {
+ int x1, y1, x2, y2, width, height, t;
+ double xScale, yScale;
+
+ if (doForm) {
+
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfSetup\n");
+
+ } else {
+
+ writePS("%%%%Page: %d %d\n", pageNum, seqPage);
+ writePS("%%%%BeginPageSetup\n");
+
+ // rotate, translate, and scale page
+ x1 = (int)(state->getX1() + 0.5);
+ y1 = (int)(state->getY1() + 0.5);
+ x2 = (int)(state->getX2() + 0.5);
+ y2 = (int)(state->getY2() + 0.5);
+ width = x2 - x1;
+ height = y2 - y1;
+ if (width > height) {
+ writePS("%%%%PageOrientation: Landscape\n");
+ writePS("%d %d pdfStartPage\n", paperWidth, paperHeight);
+ writePS("90 rotate\n");
+ writePS("%d %d translate\n", -x1, -(y1 + paperWidth));
+ t = width;
+ width = height;
+ height = t;
+ } else {
+ writePS("%%%%PageOrientation: Portrait\n");
+ writePS("%d %d pdfStartPage\n", paperWidth, paperHeight);
+ if (x1 != 0 || y1 != 0)
+ writePS("%d %d translate\n", -x1, -y1);
+ }
+ if (width > paperWidth || height > paperHeight) {
+ xScale = (double)paperWidth / (double)width;
+ yScale = (double)paperHeight / (double)height;
+ if (yScale < xScale)
+ xScale = yScale;
+ writePS("%0.4f %0.4f scale\n", xScale, xScale);
+ }
+
+ writePS("%%%%EndPageSetup\n");
+ ++seqPage;
+ }
+}
+
+void PSOutputDev::endPage() {
+ if (doForm) {
+ writePS("pdfEndPage\n");
+ writePS("end end\n");
+ writePS("} def\n");
+ } else {
+ writePS("showpage\n");
+ writePS("%%%%PageTrailer\n");
+ writePS("pdfEndPage\n");
+ }
+}
+
+void PSOutputDev::saveState(GfxState *state) {
+ writePS("q\n");
+}
+
+void PSOutputDev::restoreState(GfxState *state) {
+ writePS("Q\n");
+}
+
+void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32) {
+ writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
+}
+
+void PSOutputDev::updateLineDash(GfxState *state) {
+ double *dash;
+ double start;
+ int length, i;
+
+ state->getLineDash(&dash, &length, &start);
+ writePS("[");
+ for (i = 0; i < length; ++i)
+ writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
+ writePS("] %g d\n", start);
+}
+
+void PSOutputDev::updateFlatness(GfxState *state) {
+ writePS("%d i\n", state->getFlatness());
+}
+
+void PSOutputDev::updateLineJoin(GfxState *state) {
+ writePS("%d j\n", state->getLineJoin());
+}
+
+void PSOutputDev::updateLineCap(GfxState *state) {
+ writePS("%d J\n", state->getLineCap());
+}
+
+void PSOutputDev::updateMiterLimit(GfxState *state) {
+ writePS("%g M\n", state->getMiterLimit());
+}
+
+void PSOutputDev::updateLineWidth(GfxState *state) {
+ writePS("%g w\n", state->getLineWidth());
+}
+
+void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor *color;
+ double r, g, b;
+
+ color = state->getFillColor();
+ r = color->getR();
+ g = color->getG();
+ b = color->getB();
+ if (r == g && g == b)
+ writePS("%g g\n", r);
+ else
+ writePS("%g %g %g rg\n", r, g, b);
+}
+
+void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor *color;
+ double r, g, b;
+
+ color = state->getStrokeColor();
+ r = color->getR();
+ g = color->getG();
+ b = color->getB();
+ if (r == g && g == b)
+ writePS("%g G\n", r);
+ else
+ writePS("%g %g %g RG\n", r, g, b);
+}
+
+void PSOutputDev::updateFont(GfxState *state) {
+ if (state->getFont()) {
+ writePS("/F%d_%d %g Tf\n",
+ state->getFont()->getID().num, state->getFont()->getID().gen,
+ state->getFontSize());
+ }
+}
+
+void PSOutputDev::updateTextMat(GfxState *state) {
+ double *mat;
+
+ mat = state->getTextMat();
+ writePS("[%g %g %g %g %g %g] Tm\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+}
+
+void PSOutputDev::updateCharSpace(GfxState *state) {
+ writePS("%g Tc\n", state->getCharSpace());
+}
+
+void PSOutputDev::updateRender(GfxState *state) {
+ writePS("%d Tr\n", state->getRender());
+}
+
+void PSOutputDev::updateRise(GfxState *state) {
+ writePS("%g Ts\n", state->getRise());
+}
+
+void PSOutputDev::updateWordSpace(GfxState *state) {
+ writePS("%g Tw\n", state->getWordSpace());
+}
+
+void PSOutputDev::updateHorizScaling(GfxState *state) {
+ writePS("%g Tz\n", state->getHorizScaling());
+}
+
+void PSOutputDev::updateTextPos(GfxState *state) {
+ writePS("%g %g Td\n", state->getLineX(), state->getLineY());
+}
+
+void PSOutputDev::updateTextShift(GfxState *state, double shift) {
+ writePS("%g TJm\n", shift);
+}
+
+void PSOutputDev::stroke(GfxState *state) {
+ doPath(state->getPath());
+ writePS("S\n");
+}
+
+void PSOutputDev::fill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f\n");
+}
+
+void PSOutputDev::eoFill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f*\n");
+}
+
+void PSOutputDev::clip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W\n");
+}
+
+void PSOutputDev::eoClip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W*\n");
+}
+
+void PSOutputDev::doPath(GfxPath *path) {
+ GfxSubpath *subpath;
+ double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
+ int n, m, i, j;
+
+ n = path->getNumSubpaths();
+
+ if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
+ subpath = path->getSubpath(0);
+ x0 = subpath->getX(0);
+ y0 = subpath->getY(0);
+ x4 = subpath->getX(4);
+ y4 = subpath->getY(4);
+ if (x4 == x0 && y4 == y0) {
+ x1 = subpath->getX(1);
+ y1 = subpath->getY(1);
+ x2 = subpath->getX(2);
+ y2 = subpath->getY(2);
+ x3 = subpath->getX(3);
+ y3 = subpath->getY(3);
+ if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
+ writePS("%g %g %g %g re\n",
+ x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+ fabs(x2 - x0), fabs(y1 - y0));
+ return;
+ } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
+ writePS("%g %g %g %g re\n",
+ x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+ fabs(x1 - x0), fabs(y2 - y0));
+ return;
+ }
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ subpath = path->getSubpath(i);
+ m = subpath->getNumPoints();
+ writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
+ j = 1;
+ while (j < m) {
+ if (subpath->getCurve(j)) {
+ writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ subpath->getX(j+2), subpath->getY(j+2));
+ j += 3;
+ } else {
+ writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
+ ++j;
+ }
+ }
+ }
+}
+
+void PSOutputDev::drawString(GfxState *state, GString *s) {
+ // check for invisible text -- this is used by Acrobat Capture
+ if ((state->getRender() & 3) == 3)
+ return;
+
+ writePSString(s);
+ writePS(" %g Tj\n", state->getFont()->getWidth(s));
+}
+
+void PSOutputDev::drawImageMask(GfxState *state, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg) {
+ int len;
+
+ len = height * ((width + 7) / 8);
+ if (psOutLevel1)
+ doImageL1(NULL, invert, inlineImg, str, width, height, len);
+ else
+ doImage(NULL, invert, inlineImg, str, width, height, len);
+}
+
+void PSOutputDev::drawImage(GfxState *state, Stream *str, int width,
+ int height, GfxImageColorMap *colorMap,
+ GBool inlineImg) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ if (psOutLevel1)
+ doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
+ else
+ doImage(colorMap, gFalse, inlineImg, str, width, height, len);
+}
+
+void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ Guchar pixBuf[4];
+ GfxColor color;
+ int x, y, i;
+
+ // width, height, matrix, bits per component
+ if (colorMap) {
+ writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
+ width, height,
+ width, -height, height);
+ } else {
+ writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ }
+
+ // image
+ if (colorMap) {
+
+ // set up to process the data stream
+ str->resetImage(width, colorMap->getNumPixelComps(), colorMap->getBits());
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // write the line
+ for (x = 0; x < width; ++x) {
+ str->getImagePixel(pixBuf);
+ colorMap->getColor(pixBuf, &color);
+ fprintf(f, "%02x", (int)(color.getGray() * 255 + 0.5));
+ if (++i == 32) {
+ fputc('\n', f);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0)
+ fputc('\n', f);
+
+ // imagemask
+ } else {
+ str->reset();
+ i = 0;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; x += 8) {
+ fprintf(f, "%02x", str->getChar() & 0xff);
+ if (++i == 32) {
+ fputc('\n', f);
+ i = 0;
+ }
+ }
+ }
+ if (i != 0)
+ fputc('\n', f);
+ }
+}
+
+void PSOutputDev::doImage(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ GfxColorSpace *colorSpace;
+ GString *s;
+ int n, numComps;
+ Guchar *color;
+ GBool useRLE, useA85;
+ int c;
+ int i, j, k;
+
+ // color space
+ if (colorMap) {
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->isIndexed())
+ writePS("[/Indexed ");
+ switch (colorSpace->getMode()) {
+ case colorGray:
+ writePS("/DeviceGray ");
+ break;
+ case colorCMYK:
+ writePS("/DeviceCMYK ");
+ break;
+ case colorRGB:
+ writePS("/DeviceRGB ");
+ break;
+ }
+ if (colorSpace->isIndexed()) {
+ n = colorSpace->getIndexHigh();
+ numComps = colorSpace->getNumColorComps();
+ writePS("%d <\n", n);
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ color = colorSpace->getLookupVal(j);
+ for (k = 0; k < numComps; ++k)
+ writePS("%02x", color[k]);
+ }
+ writePS("\n");
+ }
+ writePS("> ] setcolorspace\n");
+ } else {
+ writePS("setcolorspace\n");
+ }
+ }
+
+ // image dictionary
+ writePS("<<\n /ImageType 1\n");
+
+ // width, height, matrix, bits per component
+ writePS(" /Width %d\n", width);
+ writePS(" /Height %d\n", height);
+ writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
+ writePS(" /BitsPerComponent %d\n",
+ colorMap ? colorMap->getBits() : 1);
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0)
+ writePS(" ");
+ writePS("%g %g", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
+ }
+ writePS("]\n");
+ } else {
+ writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ if (doForm) {
+
+ // data source
+ writePS(" /DataSource <~\n");
+
+ // write image data stream, using ASCII85 encode filter
+ str = new ASCII85Encoder(str);
+ str->reset();
+ while ((c = str->getChar()) != EOF)
+ fputc(c, f);
+ fputc('\n', f);
+ delete str;
+
+ // end of image dictionary
+ writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
+
+ } else {
+
+ // data source
+ writePS(" /DataSource currentfile\n");
+ s = str->getPSFilter(" ");
+ if (inlineImg || !s) {
+ useRLE = gTrue;
+ useA85 = gTrue;
+ } else {
+ useRLE = gFalse;
+ useA85 = str->isBinary();
+ }
+ if (useA85)
+ writePS(" /ASCII85Decode filter\n");
+ if (useRLE)
+ writePS(" /RunLengthDecode filter\n");
+ else
+ writePS("%s", s->getCString());
+ if (s)
+ delete s;
+
+ // end of image dictionary
+ writePS(">>\n%s\n", colorMap ? "pdfIm" : "pdfImM");
+
+ // write image data stream
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg)
+ str = new FixedLengthEncoder(str, len);
+ else if (!useRLE)
+ str = str->getBaseStream();
+
+ // add RunLengthEncode and ASCII85 encode filters
+ if (useRLE)
+ str = new RunLengthEncoder(str);
+ if (useA85)
+ str = new ASCII85Encoder(str);
+
+ // copy the stream data
+ str->reset();
+ while ((c = str->getChar()) != EOF)
+ fputc(c, f);
+
+ // add newline and trailer to the end
+ fputc('\n', f);
+ fputs("%-EOD-\n", f);
+
+ // delete encoders
+ if (useRLE || useA85)
+ delete str;
+ }
+}
+
+void PSOutputDev::writePS(char *fmt, ...) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(f, fmt, args);
+ va_end(args);
+}
+
+void PSOutputDev::writePSString(GString *s) {
+ Guchar *p;
+ int n;
+
+ fputc('(', f);
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ if (*p == '(' || *p == ')' || *p == '\\')
+ fprintf(f, "\\%c", *p);
+ else if (*p < 0x20 || *p >= 0x80)
+ fprintf(f, "\\%03o", *p);
+ else
+ fputc(*p, f);
+ }
+ fputc(')', f);
+}