diff options
Diffstat (limited to 'filters/kword/pdf/xpdf/xpdf/PSOutputDev.cpp')
-rw-r--r-- | filters/kword/pdf/xpdf/xpdf/PSOutputDev.cpp | 3325 |
1 files changed, 3325 insertions, 0 deletions
diff --git a/filters/kword/pdf/xpdf/xpdf/PSOutputDev.cpp b/filters/kword/pdf/xpdf/xpdf/PSOutputDev.cpp new file mode 100644 index 000000000..66fd3fa6a --- /dev/null +++ b/filters/kword/pdf/xpdf/xpdf/PSOutputDev.cpp @@ -0,0 +1,3325 @@ +//======================================================================== +// +// PSOutputDev.cpp +// +// Copyright 1996-2002 Glyph & Cog, LLC +// +//======================================================================== + +#include <aconf.h> + +#ifdef USE_GCC_PRAGMAS +#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 "GlobalParams.h" +#include "Object.h" +#include "Error.h" +#include "Function.h" +#include "Gfx.h" +#include "GfxState.h" +#include "GfxFont.h" +#include "CharCodeToUnicode.h" +#include "UnicodeMap.h" +#include "FontFile.h" +#include "Catalog.h" +#include "Page.h" +#include "Stream.h" +#include "Annot.h" +#include "PSOutputDev.h" + +#ifdef MACOS +// needed for setting type/creator of MacOS files +#include "ICSupport.h" +#endif + +//------------------------------------------------------------------------ +// PostScript prolog and setup +//------------------------------------------------------------------------ + +static char *prolog[] = { + "/xpdf 75 dict def xpdf begin", + "% PDF special state", + "/pdfDictSize 14 def", + "/pdfSetup {", + " 3 1 roll 2 array astore", + " /setpagedevice where {", + " pop 3 dict begin", + " /PageSize exch def", + " /ImagingBBox null def", + " /Policies 1 dict dup begin /PageSize 3 def end def", + " { /Duplex true def } if", + " currentdict end setpagedevice", + " } {", + " pop pop", + " } ifelse", + "} def", + "/pdfStartPage {", + " 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", + "/pdfEndPage { end } def", + "% separation convention operators", + "/findcmykcustomcolor where {", + " pop", + "}{", + " /findcmykcustomcolor { 5 array astore } def", + "} ifelse", + "/setcustomcolor where {", + " pop", + "}{", + " /setcustomcolor {", + " exch", + " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", + " 0 4 getinterval cvx", + " [ exch /dup load exch { mul exch dup } /forall load", + " /pop load dup ] cvx", + " ] setcolorspace setcolor", + " } def", + "} ifelse", + "/customcolorimage where {", + " pop", + "}{", + " /customcolorimage {", + " gsave", + " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", + " 0 4 getinterval cvx", + " [ exch /dup load exch { mul exch dup } /forall load", + " /pop load dup ] cvx", + " ] setcolorspace", + " 10 dict begin", + " /ImageType 1 def", + " /DataSource exch def", + " /ImageMatrix exch def", + " /BitsPerComponent exch def", + " /Height exch def", + " /Width exch def", + " /Decode [1 0] def", + " currentdict end", + " image", + " grestore", + " } def", + "} ifelse", + "% PDF color state", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload length", + " dup 1 eq {", + " pop setgray", + " }{", + " dup 3 eq {", + " pop setrgbcolor", + " }{", + " 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " } ifelse", + " } ifelse", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload length", + " dup 1 eq {", + " pop setgray", + " }{", + " dup 3 eq {", + " pop setrgbcolor", + " }{", + " 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " } ifelse", + " } ifelse", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "% build a font", + "/pdfMakeFont {", + " 4 3 roll findfont", + " 4 2 roll matrix scale makefont", + " dup length dict begin", + " { 1 index /FID ne { def } { pop pop } ifelse } forall", + " /Encoding exch def", + " currentdict", + " end", + " definefont pop", + "} def", + "/pdfMakeFont16 {", + " exch findfont", + " dup length dict begin", + " { 1 index /FID ne { def } { pop pop } ifelse } forall", + " /WMode exch def", + " currentdict", + " end", + " definefont pop", + "} def", + "/pdfMakeFont16L3 {", + " 1 index /CIDFont resourcestatus {", + " pop pop 1 index /CIDFont findresource /CIDFontType known", + " } {", + " false", + " } ifelse", + " {", + " 0 eq { /Identity-H } { /Identity-V } ifelse", + " exch 1 array astore composefont pop", + " } {", + " pdfMakeFont16", + " } ifelse", + "} 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", + "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/ck { 6 copy 6 array astore /pdfFill exch def", + " findcmykcustomcolor exch setcustomcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/CK { 6 copy 6 array astore /pdfStroke exch def", + " findcmykcustomcolor exch setcustomcolor", + " /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", + "/h { closepath } def", + "% path painting operators", + "/S { sCol stroke } def", + "/Sf { fCol 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", + "/awcp { % awidthcharpath", + " exch {", + " 1 string dup 0 3 index put 2 index charpath", + " 3 index 3 index rmoveto", + " 4 index eq { 5 index 5 index rmoveto } if", + " } forall", + " 6 {pop} repeat", + "} def", + "/Tj { fCol", // because stringwidth has to draw Type 3 chars + " 0 pdfTextRise pdfTextMat dtransform rmoveto", + " 1 index stringwidth pdfTextMat idtransform pop", + " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse", + " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", + " pdfTextMat dtransform", + " 6 5 roll", + " currentpoint 8 2 roll", + " pdfTextRender 1 and 0 eq {", + " 6 copy awidthshow", + " } if", + " pdfTextRender 3 and dup 1 eq exch 2 eq or {", + " 8 6 roll moveto", + " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", + " false awcp currentpoint stroke moveto", + " } {", + " 8 {pop} repeat", + " } ifelse", + " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def", + "/Tj16 { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse", + " 0 pdfTextRise pdfTextMat dtransform rmoveto", + " 2 index stringwidth pdfTextMat idtransform pop", + " sub exch div", + " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", + " pdfTextMat dtransform", + " 6 5 roll awidthshow", + " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def", + "/Tj16V { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse", + " 0 pdfTextRise pdfTextMat dtransform rmoveto", + " 2 index stringwidth pdfTextMat idtransform exch pop", + " sub exch div", + " 0 pdfWordSpacing pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing add 0 exch", + " 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", + "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch", + " pdfTextMat dtransform rmoveto } def", + "% Level 1 image operators", + "/pdfIm1 {", + " /pdfImBuf1 4 index string def", + " { currentfile pdfImBuf1 readhexstring pop } image", + "} def", + "/pdfIm1Sep {", + " /pdfImBuf1 4 index string def", + " /pdfImBuf2 4 index string def", + " /pdfImBuf3 4 index string def", + " /pdfImBuf4 4 index string def", + " { currentfile pdfImBuf1 readhexstring pop }", + " { currentfile pdfImBuf2 readhexstring pop }", + " { currentfile pdfImBuf3 readhexstring pop }", + " { currentfile pdfImBuf4 readhexstring pop }", + " true 4 colorimage", + "} 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", + "/pdfImSep {", + " findcmykcustomcolor exch", + " dup /Width get /pdfImBuf1 exch string def", + " begin Width Height BitsPerComponent ImageMatrix DataSource end", + " /pdfImData exch def", + " { pdfImData pdfImBuf1 readstring pop", + " 0 1 2 index length 1 sub {", + " 1 index exch 2 copy get 255 exch sub put", + " } for }", + " 6 5 roll customcolorimage", + " { 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 +}; + +static char *cmapProlog[] = { + "/CIDInit /ProcSet findresource begin", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-H def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " 1 begincodespacerange", + " <0000> <ffff>", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> <ffff> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-V def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " /WMode 1 def", + " 1 begincodespacerange", + " <0000> <ffff>", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> <ffff> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "end", + NULL +}; + +//------------------------------------------------------------------------ +// Fonts +//------------------------------------------------------------------------ + +struct PSSubstFont { + char *psName; // PostScript name + double mWidth; // width of 'm' character +}; + +static char *psFonts[] = { + "Courier", + "Courier-Bold", + "Courier-Oblique", + "Courier-BoldOblique", + "Helvetica", + "Helvetica-Bold", + "Helvetica-Oblique", + "Helvetica-BoldOblique", + "Symbol", + "Times-Roman", + "Times-Bold", + "Times-Italic", + "Times-BoldItalic", + "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} +}; + +// Encoding info for substitute 16-bit font +struct PSFont16Enc { + Ref fontID; + GString *enc; +}; + +//------------------------------------------------------------------------ +// process colors +//------------------------------------------------------------------------ + +#define psProcessCyan 1 +#define psProcessMagenta 2 +#define psProcessYellow 4 +#define psProcessBlack 8 +#define psProcessCMYK 15 + +//------------------------------------------------------------------------ +// PSOutCustomColor +//------------------------------------------------------------------------ + +class PSOutCustomColor { +public: + + PSOutCustomColor(double cA, double mA, + double yA, double kA, GString *nameA); + ~PSOutCustomColor(); + + double c, m, y, k; + GString *name; + PSOutCustomColor *next; +}; + +PSOutCustomColor::PSOutCustomColor(double cA, double mA, + double yA, double kA, GString *nameA) { + c = cA; + m = mA; + y = yA; + k = kA; + name = nameA; + next = NULL; +} + +PSOutCustomColor::~PSOutCustomColor() { + delete name; +} + +//------------------------------------------------------------------------ +// PSOutputDev +//------------------------------------------------------------------------ + +extern "C" { +typedef void (*SignalFunc)(int); +} + +static void outputToFile(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA) { + FILE *f; + PSFileType fileTypeA; + + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font16Enc = NULL; + embFontList = NULL; + customColors = NULL; + t3String = NULL; + + // open file or pipe + if (!strcmp(fileName, "-")) { + fileTypeA = psStdout; + f = stdout; + } else if (fileName[0] == '|') { + fileTypeA = psPipe; +#ifdef HAVE_POPEN +#ifndef WIN32 + signal(SIGPIPE, (SignalFunc)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 { + fileTypeA = psFile; + if (!(f = fopen(fileName, "w"))) { + error(-1, "Couldn't open PostScript file '%s'", fileName); + ok = gFalse; + return; + } + } + + init(outputToFile, f, fileTypeA, + xrefA, catalog, firstPage, lastPage, modeA); +} + +PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA) { + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font16Enc = NULL; + embFontList = NULL; + customColors = NULL; + t3String = NULL; + + init(outputFuncA, outputStreamA, psGeneric, + xrefA, catalog, firstPage, lastPage, modeA); +} + +void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA) { + Page *page; + PDFRectangle *box; + Dict *resDict; + Annots *annots; + char **p; + int pg; + Object obj1, obj2; + int i; + + // initialize + ok = gTrue; + outputFunc = outputFuncA; + outputStream = outputStreamA; + fileType = fileTypeA; + xref = xrefA; + level = globalParams->getPSLevel(); + mode = modeA; + paperWidth = globalParams->getPSPaperWidth(); + paperHeight = globalParams->getPSPaperHeight(); + if (mode == psModeForm) { + lastPage = firstPage; + } + processColors = 0; + inType3Char = gFalse; + +#if OPI_SUPPORT + // initialize OPI nesting levels + opi13Nest = 0; + opi20Nest = 0; +#endif + + // 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 = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); + font16EncLen = 0; + font16EncSize = 0; + + // initialize embedded font resource comment list + embFontList = new GString(); + + // write header + switch (mode) { + case psModePS: + writePS("%!PS-Adobe-3.0\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n", + paperWidth, paperHeight); + writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1); + writePS("%%EndComments\n"); + writePS("%%BeginDefaults\n"); + writePS("%%PageMedia: plain\n"); + writePS("%%EndDefaults\n"); + break; + case psModeEPS: + writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + page = catalog->getPage(firstPage); + box = page->getBox(); + writePSFmt("%%%%BoundingBox: %d %d %d %d\n", + (int)floor(box->x1), (int)floor(box->y1), + (int)ceil(box->x2), (int)ceil(box->y2)); + if (floor(box->x1) != ceil(box->x1) || + floor(box->y1) != ceil(box->y1) || + floor(box->x2) != ceil(box->x2) || + floor(box->y2) != ceil(box->y2)) { + writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", + box->x1, box->y1, box->x2, box->y2); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePS("%%EndComments\n"); + break; + case psModeForm: + writePS("%!PS-Adobe-3.0 Resource-Form\n"); + writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + writePS("%%EndComments\n"); + page = catalog->getPage(firstPage); + box = page->getBox(); + writePS("32 dict dup begin\n"); + writePSFmt("/BBox [%d %d %d %d] def\n", + (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2); + writePS("/FormType 1 def\n"); + writePS("/Matrix [1 0 0 1 0 0] def\n"); + break; + } + + // write prolog + if (mode != psModeForm) { + writePS("%%BeginProlog\n"); + } + writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); + for (p = prolog; *p; ++p) { + writePSFmt("%s\n", *p); + } + writePS("%%EndResource\n"); + if (level >= psLevel3) { + for (p = cmapProlog; *p; ++p) { + writePSFmt("%s\n", *p); + } + } + if (mode != psModeForm) { + writePS("%%EndProlog\n"); + } + + // set up fonts and images + if (mode == psModeForm) { + // swap the form and xpdf dicts + writePS("xpdf end begin dup begin\n"); + } else { + writePS("%%BeginSetup\n"); + writePS("xpdf begin\n"); + } + for (pg = firstPage; pg <= lastPage; ++pg) { + page = catalog->getPage(pg); + if ((resDict = page->getResourceDict())) { + setupResources(resDict); + } + annots = new Annots(xref, page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < annots->getNumAnnots(); ++i) { + if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) { + setupResources(obj2.getDict()); + } + obj2.free(); + } + obj1.free(); + } + delete annots; + } + if (mode != psModeForm) { + if (mode != psModeEPS) { + writePSFmt("%d %d %s pdfSetup\n", + paperWidth, paperHeight, + globalParams->getPSDuplex() ? "true" : "false"); + } +#if OPI_SUPPORT + if (globalParams->getPSOPI()) { + writePS("/opiMatrix matrix currentmatrix def\n"); + } +#endif + writePS("%%EndSetup\n"); + } + + // initialize sequential page number + seqPage = 1; +} + +PSOutputDev::~PSOutputDev() { + PSOutCustomColor *cc; + int i; + + if (ok) { + if (mode == psModeForm) { + writePS("/Foo exch /Form defineresource pop\n"); + } else { + writePS("%%Trailer\n"); + writePS("end\n"); + writePS("%%DocumentSuppliedResources:\n"); + writePS(embFontList->getCString()); + if (level == psLevel1Sep || level == psLevel2Sep || + level == psLevel3Sep) { + writePS("%%DocumentProcessColors:"); + if (processColors & psProcessCyan) { + writePS(" Cyan"); + } + if (processColors & psProcessMagenta) { + writePS(" Magenta"); + } + if (processColors & psProcessYellow) { + writePS(" Yellow"); + } + if (processColors & psProcessBlack) { + writePS(" Black"); + } + writePS("\n"); + writePS("%%DocumentCustomColors:"); + for (cc = customColors; cc; cc = cc->next) { + writePSFmt(" (%s)", cc->name->getCString()); + } + writePS("\n"); + writePS("%%CMYKCustomColor:\n"); + for (cc = customColors; cc; cc = cc->next) { + writePSFmt("%%%%+ %g %g %g %g (%s)\n", + cc->c, cc->m, cc->y, cc->k, cc->name->getCString()); + } + } + writePS("%%EOF\n"); + } + if (fileType == psFile) { +#ifdef MACOS + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); +#endif + fclose((FILE *)outputStream); + } +#ifdef HAVE_POPEN + else if (fileType == psPipe) { + pclose((FILE *)outputStream); +#ifndef WIN32 + signal(SIGPIPE, (SignalFunc)SIG_DFL); +#endif + } +#endif + } + if (embFontList) { + delete embFontList; + } + if (fontIDs) { + gfree(fontIDs); + } + if (fontFileIDs) { + gfree(fontFileIDs); + } + if (fontFileNames) { + for (i = 0; i < fontFileNameLen; ++i) { + delete fontFileNames[i]; + } + gfree(fontFileNames); + } + if (font16Enc) { + for (i = 0; i < font16EncLen; ++i) { + delete font16Enc[i].enc; + } + gfree(font16Enc); + } + while (customColors) { + cc = customColors; + customColors = cc->next; + delete cc; + } +} + +void PSOutputDev::setupResources(Dict *resDict) { + Object xObjDict, xObj, resObj; + int i; + + setupFonts(resDict); + setupImages(resDict); + + 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()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + xObj.free(); + } + } + xObjDict.free(); +} + +void PSOutputDev::setupFonts(Dict *resDict) { + Object fontDict; + GfxFontDict *gfxFontDict; + GfxFont *font; + int i; + + resDict->lookup("Font", &fontDict); + if (fontDict.isDict()) { + gfxFontDict = new GfxFontDict(xref, fontDict.getDict()); + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { + font = gfxFontDict->getFont(i); + setupFont(font, resDict); + } + delete gfxFontDict; + } + fontDict.free(); +} + +void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { + Ref fontFileID; + GString *name; + PSFontParam *fontParam; + GString *psNameStr; + char *psName; + char type3Name[64], buf[16]; + UnicodeMap *uMap; + char *charName; + double xs, ys; + int code; + double w1, w2; + double *fm; + 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(); + + xs = ys = 1; + psNameStr = NULL; + + // check for resident 8-bit font + if (font->getName() && + (fontParam = globalParams->getPSFont(font->getName()))) { + psName = fontParam->psFontName->getCString(); + + // check for embedded Type 1 font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getEmbeddedFontID(&fontFileID)) { + psNameStr = filterPSName(font->getEmbeddedFontName()); + psName = psNameStr->getCString(); + setupEmbeddedType1Font(&fontFileID, psName); + + // check for embedded Type 1C font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1C && + font->getEmbeddedFontID(&fontFileID)) { + psNameStr = filterPSName(font->getEmbeddedFontName()); + psName = psNameStr->getCString(); + setupEmbeddedType1CFont(font, &fontFileID, psName); + + // check for external Type 1 font file + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getExtFontFile()) { + // this assumes that the PS font name matches the PDF font name + psName = font->getName()->getCString(); + setupExternalType1Font(font->getExtFontFile(), psName); + + // check for embedded TrueType font + } else if (globalParams->getPSEmbedTrueType() && + font->getType() == fontTrueType && + font->getEmbeddedFontID(&fontFileID)) { + psNameStr = filterPSName(font->getEmbeddedFontName()); + psName = psNameStr->getCString(); + setupEmbeddedTrueTypeFont(font, &fontFileID, psName); + + // check for external TrueType font file + } else if (globalParams->getPSEmbedTrueType() && + font->getType() == fontTrueType && + font->getExtFontFile()) { + psNameStr = filterPSName(font->getName()); + psName = psNameStr->getCString(); + setupExternalTrueTypeFont(font, psName); + + // check for embedded CID PostScript font + } else if (globalParams->getPSEmbedCIDPostScript() && + font->getType() == fontCIDType0C && + font->getEmbeddedFontID(&fontFileID)) { + psNameStr = filterPSName(font->getEmbeddedFontName()); + psName = psNameStr->getCString(); + setupEmbeddedCIDType0Font(font, &fontFileID, psName); + + // check for embedded CID TrueType font + } else if (globalParams->getPSEmbedCIDTrueType() && + font->getType() == fontCIDType2 && + font->getEmbeddedFontID(&fontFileID)) { + psNameStr = filterPSName(font->getEmbeddedFontName()); + psName = psNameStr->getCString(); + setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName); + + } else if (font->getType() == fontType3) { + sprintf(type3Name, "T3_%d_%d", + font->getID()->num, font->getID()->gen); + psName = type3Name; + setupType3Font(font, psName, parentResDict); + + // do 8-bit font substitution + } else if (!font->isCIDFont()) { + name = font->getName(); + psName = NULL; + if (name) { + for (i = 0; psFonts[i]; ++i) { + if (name->cmp(psFonts[i]) == 0) { + psName = psFonts[i]; + 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; + for (code = 0; code < 256; ++code) { + if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && + charName[0] == 'm' && charName[1] == '\0') { + break; + } + } + if (code < 256) { + w1 = ((Gfx8BitFont *)font)->getWidth(code); + } else { + w1 = 0; + } + w2 = psSubstFonts[i].mWidth; + xs = w1 / w2; + if (xs < 0.1) { + xs = 1; + } + if (font->getType() == fontType3) { + // This is a hack which makes it possible to substitute for some + // Type 3 fonts. The problem is that it's impossible to know what + // the base coordinate system used in the font is without actually + // rendering the font. + ys = xs; + fm = font->getFontMatrix(); + if (fm[0] != 0) { + ys *= fm[3] / fm[0]; + } + } else { + ys = 1; + } + } + + // do 16-bit font substitution + } else if ((fontParam = globalParams-> + getPSFont16(font->getName(), + ((GfxCIDFont *)font)->getCollection(), + font->getWMode()))) { + psName = fontParam->psFontName->getCString(); + if (font16EncLen >= font16EncSize) { + font16EncSize += 16; + font16Enc = (PSFont16Enc *)grealloc(font16Enc, + font16EncSize * sizeof(PSFont16Enc)); + } + font16Enc[font16EncLen].fontID = *font->getID(); + font16Enc[font16EncLen].enc = fontParam->encoding->copy(); + if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { + uMap->decRefCnt(); + ++font16EncLen; + } else { + error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", + font16Enc[font16EncLen].enc->getCString()); + } + + // give up - can't do anything with this font + } else { + error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", + font->getName() ? font->getName()->getCString() : "(unnamed)", + ((GfxCIDFont *)font)->getCollection() + ? ((GfxCIDFont *)font)->getCollection()->getCString() + : "(unknown)"); + return; + } + + // generate PostScript code to set up the font + if (font->isCIDFont()) { + if (level == psLevel3 || level == psLevel3Sep) { + writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); + } else { + writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n", + font->getID()->num, font->getID()->gen, psName, + font->getWMode()); + } + } else { + writePSFmt("/F%d_%d /%s %g %g\n", + font->getID()->num, font->getID()->gen, psName, xs, ys); + for (i = 0; i < 256; i += 8) { + writePSFmt((i == 0) ? "[ " : " "); + for (j = 0; j < 8; ++j) { + if (font->getType() == fontTrueType && + !((Gfx8BitFont *)font)->getHasEncoding()) { + sprintf(buf, "c%02x", i+j); + charName = buf; + } else { + charName = ((Gfx8BitFont *)font)->getCharName(i+j); + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (i+j == 32 && charName && !strcmp(charName, ".notdef")) { + charName = "space"; + } + } + writePS("/"); + writePSName(charName ? charName : (char *)".notdef"); + } + writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); + } + writePS("pdfMakeFont\n"); + } + + if (psNameStr) { + delete psNameStr; + } +} + +void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) { + 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(xref, &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(); + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // copy ASCII portion of font + strObj.streamReset(); + for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) { + writePSChar(c); + } + + // 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) { + writePSChar(hexChar[(start[i] >> 4) & 0x0f]); + writePSChar(hexChar[start[i] & 0x0f]); + } + while (i < length2) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(hexChar[(c >> 4) & 0x0f]); + writePSChar(hexChar[c & 0x0f]); + if (++i % 32 == 0) { + writePSChar('\n'); + } + } + if (i % 32 > 0) { + writePSChar('\n'); + } + + // already in ASCII format -- just copy it + } else { + for (i = 0; i < 4; ++i) { + writePSChar(start[i]); + } + for (i = 4; i < length2; ++i) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(c); + } + } + + // write padding and "cleartomark" + for (i = 0; i < 8; ++i) { + writePS("00000000000000000000000000000000" + "00000000000000000000000000000000\n"); + } + writePS("cleartomark\n"); + + // ending comment + writePS("%%EndResource\n"); + + err1: + strObj.streamClose(); + strObj.free(); +} + +//~ This doesn't handle .pfb files or binary eexec data (which only +//~ happens in pfb files?). +void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) { + FILE *fontFile; + int c; + int i; + + // check if font is already embedded + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(fileName)) { + return; + } + } + + // add entry to fontFileNames list + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = (GString **)grealloc(fontFileNames, + fontFileNameSize * sizeof(GString *)); + } + fontFileNames[fontFileNameLen++] = fileName->copy(); + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // copy the font file + if (!(fontFile = fopen(fileName->getCString(), "rb"))) { + error(-1, "Couldn't open external font file"); + return; + } + while ((c = fgetc(fontFile)) != EOF) { + writePSChar(c); + } + fclose(fontFile); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, + char *psName) { + char *fontBuf; + int fontLen; + Type1CFontFile *t1cFile; + 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; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // convert it to a Type 1 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + t1cFile = new Type1CFontFile(fontBuf, fontLen); + t1cFile->convertToType1(outputFunc, outputStream); + delete t1cFile; + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, + char *psName) { + char *fontBuf; + int fontLen; + TrueTypeFontFile *ttFile; + CharCodeToUnicode *ctu; + 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; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + ttFile = new TrueTypeFontFile(fontBuf, fontLen); + ctu = ((Gfx8BitFont *)font)->getToUnicode(); + ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), + ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + outputFunc, outputStream); + ctu->decRefCnt(); + delete ttFile; + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) { + GString *fileName; + char *fontBuf; + int fontLen; + TrueTypeFontFile *ttFile; + CharCodeToUnicode *ctu; + int i; + + // check if font is already embedded + fileName = font->getExtFontFile(); + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(fileName)) { + return; + } + } + + // add entry to fontFileNames list + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = (GString **)grealloc(fontFileNames, + fontFileNameSize * sizeof(GString *)); + } + fontFileNames[fontFileNameLen++] = fileName->copy(); + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readExtFontFile(&fontLen); + ttFile = new TrueTypeFontFile(fontBuf, fontLen); + ctu = ((Gfx8BitFont *)font)->getToUnicode(); + ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(), + ctu, ((Gfx8BitFont *)font)->getHasEncoding(), + outputFunc, outputStream); + ctu->decRefCnt(); + delete ttFile; + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, + char *psName) { + char *fontBuf; + int fontLen; + Type1CFontFile *t1cFile; + 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; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + t1cFile = new Type1CFontFile(fontBuf, fontLen); + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + t1cFile->convertToCIDType0(psName, outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + t1cFile->convertToType0(psName, outputFunc, outputStream); + } + delete t1cFile; + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, + char *psName) { + char *fontBuf; + int fontLen; + TrueTypeFontFile *ttFile; + 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; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + ttFile = new TrueTypeFontFile(fontBuf, fontLen); + if (globalParams->getPSLevel() >= psLevel3) { + ttFile->convertToCIDType2(psName, + ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + outputFunc, outputStream); + } + delete ttFile; + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupType3Font(GfxFont *font, char *psName, + Dict *parentResDict) { + Dict *resDict; + Dict *charProcs; + Object charProc; + Gfx *gfx; + PDFRectangle box; + double *m; + char buf[256]; + int i; + + // set up resources used by font + if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + setupResources(resDict); + } else { + resDict = parentResDict; + } + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + + // font dictionary + writePS("7 dict begin\n"); + writePS("/FontType 3 def\n"); + m = font->getFontMatrix(); + writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n", + m[0], m[1], m[2], m[3], m[4], m[5]); + m = font->getFontBBox(); + writePSFmt("/FontBBox [%g %g %g %g] def\n", + m[0], m[1], m[2], m[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { + writePSFmt("/CharProcs %d dict def\n", charProcs->getLength()); + writePS("CharProcs begin\n"); + box.x1 = m[0]; + box.y1 = m[1]; + box.x2 = m[2]; + box.y2 = m[3]; + gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL); + inType3Char = gTrue; + t3Cacheable = gFalse; + for (i = 0; i < charProcs->getLength(); ++i) { + writePS("/"); + writePSName(charProcs->getKey(i)); + writePS(" {\n"); + gfx->display(charProcs->getVal(i, &charProc)); + charProc.free(); + if (t3String) { + if (t3Cacheable) { + sprintf(buf, "%g %g %g %g %g %g setcachedevice\n", + t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); + } else { + sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY); + } + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, t3String->getCString(), + t3String->getLength()); + delete t3String; + t3String = NULL; + } + (*outputFunc)(outputStream, "Q\n", 2); + writePS("} def\n"); + } + inType3Char = gFalse; + delete gfx; + writePS("end\n"); + } + writePS("currentdict end\n"); + writePSFmt("/%s exch definefont pop\n", psName); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupImages(Dict *resDict) { + Object xObjDict, xObj, xObjRef, subtypeObj; + int i; + + if (mode != psModeForm) { + return; + } + + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + xObjDict.dictGetValNF(i, &xObjRef); + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Subtype", &subtypeObj); + if (subtypeObj.isName("Image")) { + if (xObjRef.isRef()) { + setupImage(xObjRef.getRef(), xObj.getStream()); + } else { + error(-1, "Image in resource dict is not an indirect reference"); + } + } + subtypeObj.free(); + } + xObj.free(); + xObjRef.free(); + } + } + xObjDict.free(); +} + +void PSOutputDev::setupImage(Ref id, Stream *str) { + int c; + int size, line, col, i; + + // construct an encoder stream + if (globalParams->getPSASCIIHex()) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + + // compute image data size + str->reset(); + col = size = 0; + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + if (c == 'z') { + ++col; + } else { + ++col; + for (i = 1; i <= 4; ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + ++col; + } + } + if (col > 225) { + ++size; + col = 0; + } + } while (c != '~' && c != EOF); + ++size; + writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); + + // write the data into the array + str->reset(); + line = col = 0; + writePS("dup 0 <~"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= 4; ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "dup nnnnn <~...data...~> put<eol>" + // so max data length = 255 - 20 = 235 + // chunks are 1 or 4 bytes each, so we have to stop at 232 + // but make it 225 just to be safe + if (col > 225) { + writePS("~> put\n"); + ++line; + writePSFmt("dup %d <~", line); + col = 0; + } + } while (c != '~' && c != EOF); + writePS("~> put\n"); + writePS("pop\n"); + + delete str; +} + +void PSOutputDev::startPage(int pageNum, GfxState *state) { + int x1, y1, x2, y2, width, height, t; + + + switch (mode) { + + case psModePS: + writePSFmt("%%%%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 && width > paperWidth) { + landscape = gTrue; + writePSFmt("%%%%PageQt::Orientation: %s\n", + state->getCTM()[0] ? "Landscape" : "Portrait"); + writePS("pdfStartPage\n"); + writePS("90 rotate\n"); + tx = -x1; + ty = -(y1 + paperWidth); + t = width; + width = height; + height = t; + } else { + landscape = gFalse; + writePSFmt("%%%%PageQt::Orientation: %s\n", + state->getCTM()[0] ? "Portrait" : "Landscape"); + writePS("pdfStartPage\n"); + tx = -x1; + ty = -y1; + } + if (width < paperWidth) { + tx += (paperWidth - width) / 2; + } + if (height < paperHeight) { + ty += (paperHeight - height) / 2; + } + if (tx != 0 || ty != 0) { + writePSFmt("%g %g translate\n", tx, ty); + } + if (width > paperWidth || height > paperHeight) { + xScale = (double)paperWidth / (double)width; + yScale = (double)paperHeight / (double)height; + if (yScale < xScale) { + xScale = yScale; + } else { + yScale = xScale; + } + writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); + } else { + xScale = yScale = 1; + } + + writePS("%%EndPageSetup\n"); + ++seqPage; + break; + + case psModeEPS: + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + landscape = gFalse; + break; + + case psModeForm: + writePS("/PaintProc {\n"); + writePS("begin xpdf begin\n"); + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + landscape = gFalse; + break; + } +} + +void PSOutputDev::endPage() { + + if (mode == psModeForm) { + writePS("pdfEndPage\n"); + writePS("end end\n"); + writePS("} def\n"); + writePS("end end\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) { + writePSFmt("[%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) + writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " "); + writePSFmt("] %g d\n", start); +} + +void PSOutputDev::updateFlatness(GfxState *state) { + writePSFmt("%d i\n", state->getFlatness()); +} + +void PSOutputDev::updateLineJoin(GfxState *state) { + writePSFmt("%d j\n", state->getLineJoin()); +} + +void PSOutputDev::updateLineCap(GfxState *state) { + writePSFmt("%d J\n", state->getLineCap()); +} + +void PSOutputDev::updateMiterLimit(GfxState *state) { + writePSFmt("%g M\n", state->getMiterLimit()); +} + +void PSOutputDev::updateLineWidth(GfxState *state) { + writePSFmt("%g w\n", state->getLineWidth()); +} + +void PSOutputDev::updateFillColor(GfxState *state) { + GfxColor color; + double gray; + GfxRGB rgb; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + + switch (level) { + case psLevel1: + state->getFillGray(&gray); + writePSFmt("%g g\n", gray); + break; + case psLevel1Sep: + state->getFillCMYK(&cmyk); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() == csDeviceCMYK) { + state->getFillCMYK(&cmyk); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } else { + state->getFillRGB(&rgb); + if (rgb.r == rgb.g && rgb.g == rgb.b) { + writePSFmt("%g g\n", rgb.r); + } else { + writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b); + } + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getFillColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); + color.c[0] = 1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g %g (%s) ck\n", + state->getFillColor()->c[0], + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); + addCustomColor(sepCS); + } else { + state->getFillCMYK(&cmyk); + writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::updateStrokeColor(GfxState *state) { + GfxColor color; + double gray; + GfxRGB rgb; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + + switch (level) { + case psLevel1: + state->getStrokeGray(&gray); + writePSFmt("%g G\n", gray); + break; + case psLevel1Sep: + state->getStrokeCMYK(&cmyk); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) { + state->getStrokeCMYK(&cmyk); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } else { + state->getStrokeRGB(&rgb); + if (rgb.r == rgb.g && rgb.g == rgb.b) { + writePSFmt("%g G\n", rgb.r); + } else { + writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b); + } + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getStrokeColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); + color.c[0] = 1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g %g (%s) CK\n", + state->getStrokeColor()->c[0], + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); + addCustomColor(sepCS); + } else { + state->getStrokeCMYK(&cmyk); + writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::addProcessColor(double c, double m, double y, double k) { + if (c > 0) { + processColors |= psProcessCyan; + } + if (m > 0) { + processColors |= psProcessMagenta; + } + if (y > 0) { + processColors |= psProcessYellow; + } + if (k > 0) { + processColors |= psProcessBlack; + } +} + +void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { + PSOutCustomColor *cc; + GfxColor color; + GfxCMYK cmyk; + + for (cc = customColors; cc; cc = cc->next) { + if (!cc->name->cmp(sepCS->getName())) { + return; + } + } + color.c[0] = 1; + sepCS->getCMYK(&color, &cmyk); + cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->copy()); + cc->next = customColors; + customColors = cc; +} + +void PSOutputDev::updateFont(GfxState *state) { + if (state->getFont()) { + writePSFmt("/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(); + writePSFmt("[%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) { + writePSFmt("%g Tc\n", state->getCharSpace()); +} + +void PSOutputDev::updateRender(GfxState *state) { + int rm; + + rm = state->getRender(); + writePSFmt("%d Tr\n", rm); + rm &= 3; + if (rm != 0 && rm != 3) { + t3Cacheable = gFalse; + } +} + +void PSOutputDev::updateRise(GfxState *state) { + writePSFmt("%g Ts\n", state->getRise()); +} + +void PSOutputDev::updateWordSpace(GfxState *state) { + writePSFmt("%g Tw\n", state->getWordSpace()); +} + +void PSOutputDev::updateHorizScaling(GfxState *state) { + writePSFmt("%g Tz\n", state->getHorizScaling()); +} + +void PSOutputDev::updateTextPos(GfxState *state) { + writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY()); +} + +void PSOutputDev::updateTextShift(GfxState *state, double shift) { + if (state->getFont()->getWMode()) { + writePSFmt("%g TJmV\n", shift); + } else { + writePSFmt("%g TJm\n", shift); + } +} + +void PSOutputDev::stroke(GfxState *state) { + doPath(state->getPath()); + if (t3String) { + // if we're construct a cacheable Type 3 glyph, we need to do + // everything in the fill color + writePS("Sf\n"); + } else { + 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) { + writePSFmt("%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) { + writePSFmt("%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(); + writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0)); + j = 1; + while (j < m) { + if (subpath->getCurve(j)) { + writePSFmt("%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 { + writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j)); + ++j; + } + } + if (subpath->isClosed()) { + writePS("h\n"); + } + } +} + +void PSOutputDev::drawString(GfxState *state, GString *s) { + GfxFont *font; + int wMode; + GString *s2; + double dx, dy, dx2, dy2, originX, originY; + char *p; + UnicodeMap *uMap; + CharCode code; + Unicode u[8]; + char buf[8]; + int len, nChars, uLen, n, m, i, j; + + // check for invisible text -- this is used by Acrobat Capture + if ((state->getRender() & 3) == 3) { + return; + } + + // ignore empty strings + if (s->getLength() == 0) { + return; + } + + // get the font + if (!(font = state->getFont())) { + return; + } + wMode = font->getWMode(); + + // check for a subtitute 16-bit font + uMap = NULL; + if (font->isCIDFont()) { + for (i = 0; i < font16EncLen; ++i) { + if (font->getID()->num == font16Enc[i].fontID.num && + font->getID()->gen == font16Enc[i].fontID.gen) { + uMap = globalParams->getUnicodeMap(font16Enc[i].enc); + break; + } + } + } + + // compute width of chars in string, ignoring char spacing and word + // spacing -- the Tj operator will adjust for the metrics of the + // font that's actually used + dx = dy = 0; + nChars = 0; + p = s->getCString(); + len = s->getLength(); + if (font->isCIDFont()) { + s2 = new GString(); + } else { + s2 = s; + } + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); + if (font->isCIDFont()) { + if (uMap) { + for (i = 0; i < uLen; ++i) { + m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); + for (j = 0; j < m; ++j) { + s2->append(buf[j]); + } + } + //~ this really needs to get the number of chars in the target + //~ encoding - which may be more than the number of Unicode + //~ chars + nChars += uLen; + } else { + s2->append((char)((code >> 8) & 0xff)); + s2->append((char)(code & 0xff)); + ++nChars; + } + } + dx += dx2; + dy += dy2; + p += n; + len -= n; + } + dx *= state->getFontSize() * state->getHorizScaling(); + dy *= state->getFontSize(); + if (uMap) { + uMap->decRefCnt(); + } + + if (s2->getLength() > 0) { + writePSString(s2); + if (font->isCIDFont()) { + if (wMode) { + writePSFmt(" %d %g Tj16V\n", nChars, dy); + } else { + writePSFmt(" %d %g Tj16\n", nChars, dx); + } + } else { + writePSFmt(" %g Tj\n", dx); + } + } + if (font->isCIDFont()) { + delete s2; + } +} + +void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) { + int len; + + len = height * ((width + 7) / 8); + if (level == psLevel1 || level == psLevel1Sep) { + doImageL1(NULL, invert, inlineImg, str, width, height, len); + } else { + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len); + } +} + +void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) { + int len; + + len = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + switch (level) { + case psLevel1: + doImageL1(colorMap, gFalse, inlineImg, str, width, height, len); + break; + case psLevel1Sep: + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + case psLevel3: + case psLevel3Sep: + doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len) { + ImageStream *imgStr; + Guchar pixBuf[gfxColorMaxComps]; + double gray; + int x, y, i; + + // width, height, matrix, bits per component + if (colorMap) { + writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", + width, height, + width, -height, height); + } else { + writePSFmt("%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 + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + + // process the data stream + i = 0; + for (y = 0; y < height; ++y) { + + // write the line + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getGray(pixBuf, &gray); + writePSFmt("%02x", (int)(gray * 255 + 0.5)); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + delete imgStr; + + // imagemask + } else { + str->reset(); + i = 0; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 8) { + writePSFmt("%02x", str->getChar() & 0xff); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + str->close(); + } +} + +void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len) { + ImageStream *imgStr; + Guchar *lineBuf; + Guchar pixBuf[gfxColorMaxComps]; + GfxCMYK cmyk; + int x, y, i, comp; + + // width, height, matrix, bits per component + writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n", + width, height, + width, -height, height); + + // allocate a line buffer + lineBuf = (Guchar *)gmalloc(4 * width); + + // set up to process the data stream + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); + + // process the data stream + i = 0; + for (y = 0; y < height; ++y) { + + // read the line + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getCMYK(pixBuf, &cmyk); + lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5); + lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5); + lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5); + lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + + // write one line of each color component + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + writePSFmt("%02x", lineBuf[4*x + comp]); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + } + + if (i != 0) { + writePSChar('\n'); + } + + delete imgStr; + gfree(lineBuf); +} + +void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len) { + GString *s; + int n, numComps; + GBool useRLE, useASCII, useCompressed; + GfxSeparationColorSpace *sepCS; + GfxColor color; + GfxCMYK cmyk; + int c; + int line, col, i; + + // color space + if (colorMap) { + dumpColorSpaceL2(colorMap->getColorSpace()); + writePS(" setcolorspace\n"); + } + + // set up the image data + if (mode == psModeForm || inType3Char) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + if (globalParams->getPSASCIIHex()) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + str->reset(); + line = col = 0; + writePS("[<~"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= 4; ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "dup nnnnn <~...data...~> put<eol>" + // so max data length = 255 - 20 = 235 + // chunks are 1 or 4 bytes each, so we have to stop at 232 + // but make it 225 just to be safe + if (col > 225) { + writePS("~>\n"); + ++line; + writePSFmt("<~", line); + col = 0; + } + } while (c != '~' && c != EOF); + writePS("~>]\n"); + writePS("0\n"); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image dictionary + writePS("<<\n /ImageType 1\n"); + + // width, height, matrix, bits per component + writePSFmt(" /Width %d\n", width); + writePSFmt(" /Height %d\n", height); + writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); + writePSFmt(" /BitsPerComponent %d\n", + colorMap ? colorMap->getBits() : 1); + + // decode + if (colorMap) { + writePS(" /Decode ["); + if (colorMap->getColorSpace()->getMode() == csSeparation) { + //~ this is a kludge -- see comment in dumpColorSpaceL2 + n = (1 << colorMap->getBits()) - 1; + writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); + } else { + numComps = colorMap->getNumPixelComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("%g %g", colorMap->getDecodeLow(i), + colorMap->getDecodeHigh(i)); + } + } + writePS("]\n"); + } else { + writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1); + } + + if (mode == psModeForm || inType3Char) { + + // data source + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); + + // end of image dictionary + writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask"); + + // get rid of the array and index + writePS("pop pop\n"); + + } else { + + // data source + writePS(" /DataSource currentfile\n"); + s = str->getPSFilter(" "); + if (inlineImg || !s) { + useRLE = gTrue; + useASCII = gTrue; + useCompressed = gFalse; + } else { + useRLE = gFalse; + useASCII = str->isBinary(); + useCompressed = gTrue; + } + if (useASCII) { + writePSFmt(" /ASCII%sDecode filter\n", + globalParams->getPSASCIIHex() ? "Hex" : "85"); + } + if (useRLE) { + writePS(" /RunLengthDecode filter\n"); + } + if (useCompressed) { + writePS(s->getCString()); + } + if (s) { + delete s; + } + + // cut off inline image streams at appropriate length + if (inlineImg) { + str = new FixedLengthEncoder(str, len); + } else if (useCompressed) { + str = str->getBaseStream(); + } + + // add RunLengthEncode and ASCIIHex/85 encode filters + if (useRLE) { + str = new RunLengthEncoder(str); + } + if (useASCII) { + if (globalParams->getPSASCIIHex()) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + } + + // end of image dictionary + writePS(">>\n"); +#if OPI_SUPPORT + if (opi13Nest) { + if (inlineImg) { + // this can't happen -- OPI dictionaries are in XObjects + error(-1, "Internal: OPI in inline image"); + n = 0; + } else { + // need to read the stream to count characters -- the length + // is data-dependent (because of ASCII and RLE filters) + str->reset(); + n = 0; + while ((c = str->getChar()) != EOF) { + ++n; + } + str->close(); + } + // +6/7 for "pdfIm\n" / "pdfImM\n" + // +8 for newline + trailer + n += colorMap ? 14 : 15; + writePSFmt("%%%%BeginData: %d Hex Bytes\n", n); + } +#endif + if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && + colorMap->getColorSpace()->getMode() == csSeparation) { + color.c[0] = 1; + sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g (%s) pdfImSep\n", + cmyk.c, cmyk.m, cmyk.y, cmyk.k, + sepCS->getName()->getCString()); + } else { + writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM"); + } + + // copy the stream data + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); + + // add newline and trailer to the end + writePSChar('\n'); + writePS("%-EOD-\n"); +#if OPI_SUPPORT + if (opi13Nest) { + writePS("%%EndData\n"); + } +#endif + + // delete encoders + if (useRLE || useASCII || inlineImg) { + delete str; + } + } +} + +void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { + GfxCalGrayColorSpace *calGrayCS; + GfxCalRGBColorSpace *calRGBCS; + GfxLabColorSpace *labCS; + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *separationCS; + GfxColorSpace *baseCS; + Guchar *lookup, *p; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; + GfxColor color; + GfxCMYK cmyk; + Function *func; + int n, numComps, numAltComps; + int byte; + int i, j, k; + + switch (colorSpace->getMode()) { + + case csDeviceGray: + writePS("/DeviceGray"); + processColors |= psProcessBlack; + break; + + case csCalGray: + calGrayCS = (GfxCalGrayColorSpace *)colorSpace; + writePS("[/CIEBasedA <<\n"); + writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); + writePSFmt(" /MatrixA [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calGrayCS->getBlackX(), calGrayCS->getBlackY(), + calGrayCS->getBlackZ()); + writePS(">>]"); + processColors |= psProcessBlack; + break; + + case csDeviceRGB: + writePS("/DeviceRGB"); + processColors |= psProcessCMYK; + break; + + case csCalRGB: + calRGBCS = (GfxCalRGBColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", + calRGBCS->getGammaR(), calRGBCS->getGammaG(), + calRGBCS->getGammaB()); + writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n", + calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], + calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], + calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], + calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], + calRGBCS->getMatrix()[8]); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), + calRGBCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calRGBCS->getBlackX(), calRGBCS->getBlackY(), + calRGBCS->getBlackZ()); + writePS(">>]"); + processColors |= psProcessCMYK; + break; + + case csDeviceCMYK: + writePS("/DeviceCMYK"); + processColors |= psProcessCMYK; + break; + + case csLab: + labCS = (GfxLabColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n", + labCS->getAMin(), labCS->getAMax(), + labCS->getBMin(), labCS->getBMax()); + writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n"); + writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n"); + writePS(" /DecodeLMN\n"); + writePS(" [{dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", + labCS->getWhiteX()); + writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n", + labCS->getWhiteY()); + writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", + labCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); + writePS(">>]"); + processColors |= psProcessCMYK; + break; + + case csICCBased: + dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt()); + break; + + case csIndexed: + indexedCS = (GfxIndexedColorSpace *)colorSpace; + baseCS = indexedCS->getBase(); + writePS("[/Indexed "); + dumpColorSpaceL2(baseCS); + n = indexedCS->getIndexHigh(); + numComps = baseCS->getNComps(); + lookup = indexedCS->getLookup(); + writePSFmt(" %d <\n", n); + if (baseCS->getMode() == csDeviceN) { + func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); + numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); + p = lookup; + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + x[k] = *p++ / 255.0; + } + func->transform(x, y); + for (k = 0; k < numAltComps; ++k) { + byte = (int)(y[k] * 255 + 0.5); + if (byte < 0) { + byte = 0; + } else if (byte > 255) { + byte = 255; + } + writePSFmt("%02x", byte); + } + color.c[0] = j; + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + writePS("\n"); + } + } else { + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + writePSFmt("%02x", lookup[j * numComps + k]); + } + color.c[0] = j; + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k); + } + writePS("\n"); + } + } + writePS(">]"); + break; + + case csSeparation: + //~ this is a kludge -- the correct thing would to output a + //~ separation color space, with the specified alternate color + //~ space and tint transform + separationCS = (GfxSeparationColorSpace *)colorSpace; + writePS("[/Indexed "); + dumpColorSpaceL2(separationCS->getAlt()); + writePS(" 255 <\n"); + numComps = separationCS->getAlt()->getNComps(); + for (i = 0; i <= 255; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= 255; ++j) { + x[0] = (double)j / 255.0; + separationCS->getFunc()->transform(x, y); + for (k = 0; k < numComps; ++k) { + writePSFmt("%02x", (int)(255 * y[k] + 0.5)); + } + } + writePS("\n"); + } + writePS(">]"); + addCustomColor(separationCS); + break; + + case csDeviceN: + // DeviceN color spaces are a Level 3 PostScript feature. + dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt()); + break; + + case csPattern: + //~ unimplemented + break; + + } +} + +#if OPI_SUPPORT +void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + opiDict->lookup("2.0", &dict); + if (dict.isDict()) { + opiBegin20(state, dict.getDict()); + dict.free(); + } else { + dict.free(); + opiDict->lookup("1.3", &dict); + if (dict.isDict()) { + opiBegin13(state, dict.getDict()); + } + dict.free(); + } + } +} + +void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { + Object obj1, obj2, obj3, obj4; + double width, height, left, right, top, bottom; + int w, h; + int i; + + writePS("%%BeginOPI: 2.0\n"); + writePS("%%Distilled\n"); + + dict->lookup("F", &obj1); + if (getFileSpec(&obj1, &obj2)) { + writePSFmt("%%%%ImageFileName: %s\n", + obj2.getString()->getCString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("MainImage", &obj1); + if (obj1.isString()) { + writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString()); + } + obj1.free(); + + //~ ignoring 'Tags' entry + //~ need to use writePSString() and deal with >255-char lines + + dict->lookup("Size", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + width = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + height = obj2.getNum(); + obj2.free(); + writePSFmt("%%%%ImageDimensions: %g %g\n", width, height); + } + obj1.free(); + + dict->lookup("CropRect", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 4) { + obj1.arrayGet(0, &obj2); + left = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + top = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + right = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + bottom = obj2.getNum(); + obj2.free(); + writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Inks", &obj1); + if (obj1.isName()) { + writePSFmt("%%%%ImageInks: %s\n", obj1.getName()); + } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { + obj1.arrayGet(0, &obj2); + if (obj2.isName()) { + writePSFmt("%%%%ImageInks: %s %d", + obj2.getName(), (obj1.arrayGetLength() - 1) / 2); + for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { + obj1.arrayGet(i, &obj3); + obj1.arrayGet(i+1, &obj4); + if (obj3.isString() && obj4.isNum()) { + writePS(" "); + writePSString(obj3.getString()); + writePSFmt(" %g", obj4.getNum()); + } + obj3.free(); + obj4.free(); + } + writePS("\n"); + } + obj2.free(); + } + obj1.free(); + + writePS("gsave\n"); + + writePS("%%BeginIncludedImage\n"); + + dict->lookup("IncludedImageDimensions", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + w = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + h = obj2.getInt(); + obj2.free(); + writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h); + } + obj1.free(); + + dict->lookup("IncludedImageQuality", &obj1); + if (obj1.isNum()) { + writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum()); + } + obj1.free(); + + ++opi20Nest; +} + +void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { + Object obj1, obj2; + int left, right, top, bottom, samples, bits, width, height; + double c, m, y, k; + double llx, lly, ulx, uly, urx, ury, lrx, lry; + double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry; + double horiz, vert; + int i, j; + + writePS("save\n"); + writePS("/opiMatrix2 matrix currentmatrix def\n"); + writePS("opiMatrix setmatrix\n"); + + dict->lookup("F", &obj1); + if (getFileSpec(&obj1, &obj2)) { + writePSFmt("%%ALDImageFileName: %s\n", + obj2.getString()->getCString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("CropRect", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 4) { + obj1.arrayGet(0, &obj2); + left = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + top = obj2.getInt(); + obj2.free(); + obj1.arrayGet(2, &obj2); + right = obj2.getInt(); + obj2.free(); + obj1.arrayGet(3, &obj2); + bottom = obj2.getInt(); + obj2.free(); + writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Color", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 5) { + obj1.arrayGet(0, &obj2); + c = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + m = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + y = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + k = obj2.getNum(); + obj2.free(); + obj1.arrayGet(4, &obj2); + if (obj2.isString()) { + writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k); + writePSString(obj2.getString()); + writePS("\n"); + } + obj2.free(); + } + obj1.free(); + + dict->lookup("ColorType", &obj1); + if (obj1.isName()) { + writePSFmt("%%ALDImageColorType: %s\n", obj1.getName()); + } + obj1.free(); + + //~ ignores 'Comments' entry + //~ need to handle multiple lines + + dict->lookup("CropFixed", &obj1); + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); + ulx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + uly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + lrx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + lry = obj2.getNum(); + obj2.free(); + writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry); + } + obj1.free(); + + dict->lookup("GrayMap", &obj1); + if (obj1.isArray()) { + writePS("%ALDImageGrayMap:"); + for (i = 0; i < obj1.arrayGetLength(); i += 16) { + if (i > 0) { + writePS("\n%%+"); + } + for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) { + obj1.arrayGet(i+j, &obj2); + writePSFmt(" %d", obj2.getInt()); + obj2.free(); + } + } + writePS("\n"); + } + obj1.free(); + + dict->lookup("ID", &obj1); + if (obj1.isString()) { + writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString()); + } + obj1.free(); + + dict->lookup("ImageType", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + samples = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + bits = obj2.getInt(); + obj2.free(); + writePSFmt("%%ALDImageType: %d %d\n", samples, bits); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Position", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 8) { + obj1.arrayGet(0, &obj2); + llx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + lly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(2, &obj2); + ulx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(3, &obj2); + uly = obj2.getNum(); + obj2.free(); + obj1.arrayGet(4, &obj2); + urx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(5, &obj2); + ury = obj2.getNum(); + obj2.free(); + obj1.arrayGet(6, &obj2); + lrx = obj2.getNum(); + obj2.free(); + obj1.arrayGet(7, &obj2); + lry = obj2.getNum(); + obj2.free(); + opiTransform(state, llx, lly, &tllx, &tlly); + opiTransform(state, ulx, uly, &tulx, &tuly); + opiTransform(state, urx, ury, &turx, &tury); + opiTransform(state, lrx, lry, &tlrx, &tlry); + writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n", + tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); + obj2.free(); + } + obj1.free(); + + dict->lookup("Resolution", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + horiz = obj2.getNum(); + obj2.free(); + obj1.arrayGet(1, &obj2); + vert = obj2.getNum(); + obj2.free(); + writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert); + obj2.free(); + } + obj1.free(); + + dict->lookup("Size", &obj1); + if (obj1.isArray() && obj1.arrayGetLength() == 2) { + obj1.arrayGet(0, &obj2); + width = obj2.getInt(); + obj2.free(); + obj1.arrayGet(1, &obj2); + height = obj2.getInt(); + obj2.free(); + writePSFmt("%%ALDImageDimensions: %d %d\n", width, height); + } + obj1.free(); + + //~ ignoring 'Tags' entry + //~ need to use writePSString() and deal with >255-char lines + + dict->lookup("Tint", &obj1); + if (obj1.isNum()) { + writePSFmt("%%ALDImageTint: %g\n", obj1.getNum()); + } + obj1.free(); + + dict->lookup("Transparency", &obj1); + if (obj1.isBool()) { + writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + writePS("%%BeginObject: image\n"); + writePS("opiMatrix2 setmatrix\n"); + ++opi13Nest; +} + +// Convert PDF user space coordinates to PostScript default user space +// coordinates. This has to account for both the PDF CTM and the +// PSOutputDev page-fitting transform. +void PSOutputDev::opiTransform(GfxState *state, double x0, double y0, + double *x1, double *y1) { + double t; + + state->transform(x0, y0, x1, y1); + *x1 += tx; + *y1 += ty; + if (landscape) { + t = *x1; + *x1 = -*y1; + *y1 = t; + } + *x1 *= xScale; + *y1 *= yScale; +} + +void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + opiDict->lookup("2.0", &dict); + if (dict.isDict()) { + writePS("%%EndIncludedImage\n"); + writePS("%%EndOPI\n"); + writePS("grestore\n"); + --opi20Nest; + dict.free(); + } else { + dict.free(); + opiDict->lookup("1.3", &dict); + if (dict.isDict()) { + writePS("%%EndObject\n"); + writePS("restore\n"); + --opi13Nest; + } + dict.free(); + } + } +} + +GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) { + if (fileSpec->isString()) { + fileSpec->copy(fileName); + return gTrue; + } + if (fileSpec->isDict()) { + fileSpec->dictLookup("DOS", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("Mac", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("Unix", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + fileSpec->dictLookup("F", fileName); + if (fileName->isString()) { + return gTrue; + } + fileName->free(); + } + return gFalse; +} +#endif // OPI_SUPPORT + +void PSOutputDev::type3D0(GfxState *state, double wx, double wy) { + writePSFmt("%g %g setcharwidth\n", wx, wy); + writePS("q\n"); +} + +void PSOutputDev::type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury) { + t3WX = wx; + t3WY = wy; + t3LLX = llx; + t3LLY = lly; + t3URX = urx; + t3URY = ury; + t3String = new GString(); + writePS("q\n"); + t3Cacheable = gTrue; +} + +void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { + Stream *str; + int c; + + if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) { + str = level1Stream; + } else { + str = psStream; + } + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); +} + +void PSOutputDev::writePSChar(char c) { + if (t3String) { + t3String->append(c); + } else { + (*outputFunc)(outputStream, &c, 1); + } +} + +void PSOutputDev::writePS(char *s) { + if (t3String) { + t3String->append(s); + } else { + (*outputFunc)(outputStream, s, strlen(s)); + } +} + +void PSOutputDev::writePSFmt(const char *fmt, ...) { + va_list args; + char buf[512]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + if (t3String) { + t3String->append(buf); + } else { + (*outputFunc)(outputStream, buf, strlen(buf)); + } +} + +void PSOutputDev::writePSString(GString *s) { + Guchar *p; + int n; + char buf[8]; + + writePSChar('('); + for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { + if (*p == '(' || *p == ')' || *p == '\\') { + writePSChar('\\'); + writePSChar((char)*p); + } else if (*p < 0x20 || *p >= 0x80) { + sprintf(buf, "\\%03o", *p); + if (t3String) { + t3String->append(buf); + } else { + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } else { + writePSChar((char)*p); + } + } + writePSChar(')'); +} + +void PSOutputDev::writePSName(char *s) { + char *p; + char c; + + p = s; + while ((c = *p++)) { + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + writePSFmt("#%02x", c & 0xff); + } else { + writePSChar(c); + } + } +} + +GString *PSOutputDev::filterPSName(GString *name) { + GString *name2; + char buf[8]; + int i; + char c; + + name2 = new GString(); + for (i = 0; i < name->getLength(); ++i) { + c = name->getChar(i); + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + sprintf(buf, "#%02x", c & 0xff); + name2->append(buf); + } else { + name2->append(c); + } + } + return name2; +} |