home *** CD-ROM | disk | FTP | other *** search
- //========================================================================
- //
- // 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((char*)((i == 0) ? "[ " : " "));
- for (j = 0; j < 8; ++j) {
- charName = font->getCharName(i+j);
- writePS("/%s", charName ? charName : ".notdef");
- }
- writePS((char*)((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);
- }
-