diff options
author | Arturo 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) |
commit | d9f9a6449f377b4c933b75d57541b19c6d088994 (patch) | |
tree | 04f7f0c54447ef792fbf83bc5039174f4681b3bb /pdf/xpdf/PSOutputDev.cc |
Initial revision
Diffstat (limited to 'pdf/xpdf/PSOutputDev.cc')
-rw-r--r-- | pdf/xpdf/PSOutputDev.cc | 1132 |
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); +} |