diff options
author | Martin Kretzschmar <mkretzschmar@src.gnome.org> | 2002-09-18 20:32:18 (GMT) |
---|---|---|
committer | Martin Kretzschmar <mkretzschmar@src.gnome.org> | 2002-09-18 20:32:18 (GMT) |
commit | 7aac8dc8533347e21311b15186e0af82f1b22fd6 (patch) | |
tree | 02650bb02c8a1d8468c22f50ff151885d233016b /pdf/xpdf/PSOutputDev.cc | |
parent | d99fb4f4acd14fcdbda968abd907547dcc7af40c (diff) |
Synched with Xpdf 0.92
this adds "decryption" support
testing this code after six weeks immediately gives me segfaults (image drawing) :-O
must have fixed that later without knowing :-O
Diffstat (limited to 'pdf/xpdf/PSOutputDev.cc')
-rw-r--r-- | pdf/xpdf/PSOutputDev.cc | 1432 |
1 files changed, 1246 insertions, 186 deletions
diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc index edff5cd..53cf39d 100644 --- a/pdf/xpdf/PSOutputDev.cc +++ b/pdf/xpdf/PSOutputDev.cc @@ -25,8 +25,18 @@ #include "Catalog.h" #include "Page.h" #include "Stream.h" +#include "FormWidget.h" #include "PSOutputDev.h" +#if JAPANESE_SUPPORT +#include "Japan12ToRKSJ.h" +#endif + +#ifdef MACOS +// needed for setting type/creator of MacOS files +#include "ICSupport.h" +#endif + //------------------------------------------------------------------------ // Parameters //------------------------------------------------------------------------ @@ -34,6 +44,17 @@ // Generate Level 1 PostScript? GBool psOutLevel1 = gFalse; +// Generate Level 1 separable PostScript? +GBool psOutLevel1Sep = gFalse; + +// Generate Encapsulated PostScript? +GBool psOutEPS = gFalse; + +#if OPI_SUPPORT +// Generate OPI comments? +GBool psOutOPI = gFalse; +#endif + int paperWidth = defPaperWidth; int paperHeight = defPaperHeight; @@ -72,20 +93,26 @@ static char *prolog[] = { " /pdfHorizScaling 1 def", "} 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", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload length", + " dup 1 eq { pop setgray }", + " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload length", + " dup 1 eq { pop setgray }", + " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", "% build a font", "/pdfMakeFont {", - " 3 2 roll findfont", - " 3 2 roll 1 matrix scale makefont", + " 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", @@ -93,6 +120,7 @@ static char *prolog[] = { " end", " definefont pop", "} def", + "/pdfMakeFont16 { findfont definefont pop } def", "% graphics state operators", "/q { gsave pdfDictSize dict begin } def", "/Q { end grestore } def", @@ -105,12 +133,16 @@ static char *prolog[] = { "/w { setlinewidth } def", "% color operators", "/g { dup 1 array astore /pdfFill exch def setgray", - " /pdfLastFill true def /pdfLastStroke false def } def", + " /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", + " /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", "% path segment operators", "/m { moveto } def", @@ -118,6 +150,7 @@ static char *prolog[] = { "/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", "/f { fCol fill } def", @@ -155,6 +188,17 @@ static char *prolog[] = { " /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", @@ -233,8 +277,11 @@ PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog, GBool embedType11, GBool doForm1) { Page *page; Dict *resDict; + FormWidgets *formWidgets; char **p; int pg; + Object obj1, obj2; + int i; // initialize embedType1 = embedType11; @@ -242,6 +289,7 @@ PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog, fontIDs = NULL; fontFileIDs = NULL; fontFileNames = NULL; + embFontList = NULL; f = NULL; if (doForm) lastPage = firstPage; @@ -285,71 +333,151 @@ PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog, fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref)); fontFileNameSize = 64; fontFileNameLen = 0; - fontFileNames = (char **)gmalloc(fontFileNameSize * sizeof(char *)); + fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *)); + + // initialize embedded font resource comment list + embFontList = new GString(); // write header if (doForm) { writePS("%%!PS-Adobe-3.0 Resource-Form\n"); writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePS("%%%%LanguageLevel: %d\n", + (psOutLevel1 || psOutLevel1Sep) ? 1 : 2); + if (psOutLevel1Sep) { + writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n"); + } + writePS("%%%%EndComments\n"); + page = catalog->getPage(firstPage); + writePS("32 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"); + } else if (psOutEPS) { + writePS("%%!PS-Adobe-3.0 EPSF-3.0\n"); + writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePS("%%%%LanguageLevel: %d\n", + (psOutLevel1 || psOutLevel1Sep) ? 1 : 2); + if (psOutLevel1Sep) { + writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n"); + } + page = catalog->getPage(firstPage); + writePS("%%%%BoundingBox: %d %d %d %d\n", + (int)floor(page->getX1()), (int)floor(page->getY1()), + (int)ceil(page->getX2()), (int)ceil(page->getY2())); + if (floor(page->getX1()) != ceil(page->getX1()) || + floor(page->getY1()) != ceil(page->getY1()) || + floor(page->getX2()) != ceil(page->getX2()) || + floor(page->getY2()) != ceil(page->getY2())) { + writePS("%%%%HiResBoundingBox: %g %g %g %g\n", + page->getX1(), page->getY1(), + page->getX2(), page->getY2()); + } + writePS("%%%%DocumentSuppliedResources: (atend)\n"); writePS("%%%%EndComments\n"); } else { writePS("%%!PS-Adobe-3.0\n"); writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion); + writePS("%%%%LanguageLevel: %d\n", + (psOutLevel1 || psOutLevel1Sep) ? 1 : 2); + if (psOutLevel1Sep) { + writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n"); + } + writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n", + paperWidth, paperHeight); writePS("%%%%Pages: %d\n", lastPage - firstPage + 1); writePS("%%%%EndComments\n"); + writePS("%%%%BeginDefaults\n"); + writePS("%%%%PageMedia: plain\n"); + writePS("%%%%EndDefaults\n"); } // write prolog - if (!doForm) + if (!doForm) { writePS("%%%%BeginProlog\n"); - writePS("%%%%BeginResource: xpdf %s\n", xpdfVersion); - for (p = prolog; *p; ++p) + } + writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); + for (p = prolog; *p; ++p) { writePS("%s\n", *p); + } writePS("%%%%EndResource\n"); - if (!doForm) + if (!doForm) { writePS("%%%%EndProlog\n"); + } - // set up fonts - if (!doForm) + // set up fonts and images + type3Warning = gFalse; + if (doForm) { + // swap the form and xpdf dicts + writePS("xpdf end begin dup begin\n"); + } else { writePS("%%%%BeginSetup\n"); - writePS("xpdf begin\n"); + writePS("xpdf begin\n"); + } for (pg = firstPage; pg <= lastPage; ++pg) { - if ((resDict = catalog->getPage(pg)->getResourceDict())) - setupFonts(resDict); + page = catalog->getPage(pg); + if ((resDict = page->getResourceDict())) { + setupResources(resDict); + } + formWidgets = new FormWidgets(page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < formWidgets->getNumWidgets(); ++i) { + if (formWidgets->getWidget(i)->getAppearance(&obj1)->isStream()) { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) { + setupResources(obj2.getDict()); + } + obj2.free(); + } + obj1.free(); + } + delete formWidgets; } - if (doForm) { - writePS("end\n"); - } else { - writePS("%d %d pdfSetup\n", paperWidth, paperHeight); + if (!doForm) { +#if OPI_SUPPORT + if (psOutOPI) { + writePS("/opiMatrix matrix currentmatrix def\n"); + } +#endif + if (!psOutEPS) { + writePS("%d %d pdfSetup\n", paperWidth, paperHeight); + } 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; + +#if OPI_SUPPORT + // initialize OPI nesting levels + opi13Nest = 0; + opi20Nest = 0; +#endif } PSOutputDev::~PSOutputDev() { + int i; + if (f) { if (doForm) { - writePS("end\n"); writePS("/Foo exch /Form defineresource pop\n"); + } else if (psOutEPS) { + writePS("%%%%Trailer\n"); + writePS("end\n"); + writePS("%%%%DocumentSuppliedResources:\n"); + writePS("%s", embFontList->getCString()); + writePS("%%%%EOF\n"); } else { writePS("%%%%Trailer\n"); writePS("end\n"); writePS("%%%%EOF\n"); } if (fileType == psFile) { +#ifdef MACOS + ICS_MapRefNumAndAssign((short)f->handle); +#endif fclose(f); } #ifdef HAVE_POPEN @@ -361,30 +489,29 @@ PSOutputDev::~PSOutputDev() { } #endif } - if (fontIDs) + if (embFontList) { + delete embFontList; + } + if (fontIDs) { gfree(fontIDs); - if (fontFileIDs) + } + if (fontFileIDs) { gfree(fontFileIDs); - if (fontFileNames) + } + if (fontFileNames) { + for (i = 0; i < fontFileNameLen; ++i) { + delete fontFileNames[i]; + } gfree(fontFileNames); + } } -void PSOutputDev::setupFonts(Dict *resDict) { - Object fontDict, xObjDict, xObj, resObj; - GfxFontDict *gfxFontDict; - GfxFont *font; +void PSOutputDev::setupResources(Dict *resDict) { + Object xObjDict, xObj, resObj; 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(); + setupFonts(resDict); + setupImages(resDict); resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { @@ -392,8 +519,9 @@ void PSOutputDev::setupFonts(Dict *resDict) { xObjDict.dictGetVal(i, &xObj); if (xObj.isStream()) { xObj.streamGetDict()->lookup("Resources", &resObj); - if (resObj.isDict()) - setupFonts(resObj.getDict()); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } resObj.free(); } xObj.free(); @@ -402,12 +530,34 @@ void PSOutputDev::setupFonts(Dict *resDict) { 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(fontDict.getDict()); + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { + font = gfxFontDict->getFont(i); + setupFont(font); + } + delete gfxFontDict; + } + fontDict.free(); +} + void PSOutputDev::setupFont(GfxFont *font) { Ref fontFileID; GString *name; char *psName; char *charName; - double scale; + double xs, ys; + GBool do16Bit; + int code; + double w1, w2; + double *fm; int i, j; // check if font is already set up @@ -424,33 +574,40 @@ void PSOutputDev::setupFont(GfxFont *font) { } fontIDs[fontIDLen++] = font->getID(); + xs = ys = 1; + do16Bit = gFalse; + // check for embedded Type 1 font if (embedType1 && font->getType() == fontType1 && font->getEmbeddedFontID(&fontFileID)) { - setupEmbeddedType1Font(&fontFileID); psName = font->getEmbeddedFontName(); - scale = 1; + setupEmbeddedType1Font(&fontFileID, psName); // check for external Type 1 font file } else if (embedType1 && font->getType() == fontType1 && font->getExtFontFile()) { - setupEmbeddedType1Font(font->getExtFontFile()); // this assumes that the PS font name matches the PDF font name psName = font->getName()->getCString(); - scale = 1; + setupEmbeddedType1Font(font->getExtFontFile(), psName); // check for embedded Type 1C font } else if (embedType1 && font->getType() == fontType1C && font->getEmbeddedFontID(&fontFileID)) { - setupEmbeddedType1CFont(font, &fontFileID); psName = font->getEmbeddedFontName(); - scale = 1; + setupEmbeddedType1CFont(font, &fontFileID, psName); + + } else if (font->is16Bit() && font->getCharSet16() == font16AdobeJapan12) { + psName = "Ryumin-Light-RKSJ"; + do16Bit = gTrue; // do font substitution } else { + if (!type3Warning && font->getType() == fontType3) { + error(-1, "This document uses Type 3 fonts - some text may not be correctly printed"); + type3Warning = gTrue; + } name = font->getName(); psName = NULL; - scale = 1.0; if (name) { for (i = 0; psFonts[i].name; ++i) { if (name->cmp(psFonts[i].name) == 0) { @@ -471,27 +628,52 @@ void PSOutputDev::setupFont(GfxFont *font) { if (font->isItalic()) i += 1; psName = psSubstFonts[i].psName; - scale = font->getWidth('m') / psSubstFonts[i].mWidth; - if (scale < 0.1) - scale = 1; + if ((code = font->getCharCode("m")) >= 0) { + w1 = 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; + } } } // 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"); + if (do16Bit) { + writePS("/F%d_%d /%s pdfMakeFont16\n", + font->getID().num, font->getID().gen, psName); + } else { + writePS("/F%d_%d /%s %g %g\n", + font->getID().num, font->getID().gen, psName, xs, ys); + 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((i == 256-8) ? "]\n" : "\n"); + writePS("pdfMakeFont\n"); } - writePS("pdfMakeFont\n"); } -void PSOutputDev::setupEmbeddedType1Font(Ref *id) { +void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) { static char hexChar[17] = "0123456789abcdef"; Object refObj, strObj, obj1, obj2; Dict *dict; @@ -540,6 +722,14 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id) { obj1.free(); obj2.free(); + // beginning comment + if (psOutEPS) { + writePS("%%%%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) @@ -593,42 +783,63 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id) { "00000000000000000000000000000000\n"); writePS("cleartomark\n"); + // ending comment + if (psOutEPS) { + 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::setupEmbeddedType1Font(char *fileName) { +void PSOutputDev::setupEmbeddedType1Font(GString *fileName, char *psName) { FILE *fontFile; int c; int i; // check if font is already embedded for (i = 0; i < fontFileNameLen; ++i) { - if (!strcmp(fontFileNames[i], fileName)) + if (!fontFileNames[i]->cmp(fileName)) { return; + } } // add entry to fontFileNames list if (fontFileNameLen >= fontFileNameSize) { fontFileNameSize += 64; - fontFileNames = (char **)grealloc(fontFileNames, - fontFileNameSize * sizeof(char *)); + fontFileNames = (GString **)grealloc(fontFileNames, + fontFileNameSize * sizeof(GString *)); + } + fontFileNames[fontFileNameLen++] = fileName->copy(); + + // beginning comment + if (psOutEPS) { + writePS("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); } - fontFileNames[fontFileNameLen++] = fileName; // copy the font file - if (!(fontFile = fopen(fileName, "rb"))) { + if (!(fontFile = fopen(fileName->getCString(), "rb"))) { error(-1, "Couldn't open external font file"); return; } while ((c = fgetc(fontFile)) != EOF) fputc(c, f); fclose(fontFile); + + // ending comment + if (psOutEPS) { + writePS("%%%%EndResource\n"); + } } -void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id) { +void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, + char *psName) { char *fontBuf; int fontLen; Type1CFontConverter *cvt; @@ -648,23 +859,160 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id) { } fontFileIDs[fontFileIDLen++] = *id; + // beginning comment + if (psOutEPS) { + writePS("%%%%BeginResource: font %s\n", psName); + embFontList->append("%%+ font "); + embFontList->append(psName); + embFontList->append("\n"); + } + // convert it to a Type 1 font fontBuf = font->readEmbFontFile(&fontLen); cvt = new Type1CFontConverter(fontBuf, fontLen, f); cvt->convert(); delete cvt; gfree(fontBuf); + + // ending comment + if (psOutEPS) { + writePS("%%%%EndResource\n"); + } +} + +void PSOutputDev::setupImages(Dict *resDict) { + Object xObjDict, xObj, xObjRef, subtypeObj; + int i; + + if (!doForm) { + 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 + 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; + writePS("%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') { + fputc(c, f); + ++col; + } else { + fputc(c, f); + ++col; + for (i = 1; i <= 4; ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '~' || c == EOF) { + break; + } + fputc(c, f); + ++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; + writePS("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; - double xScale, yScale; if (doForm) { writePS("/PaintProc {\n"); writePS("begin xpdf begin\n"); - writePS("pdfSetup\n"); + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + landscape = gFalse; + + } else if (psOutEPS) { + + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + landscape = gFalse; } else { @@ -678,26 +1026,41 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { y2 = (int)(state->getY2() + 0.5); width = x2 - x1; height = y2 - y1; - if (width > height) { + if (width > height && width > paperWidth) { + landscape = gTrue; writePS("%%%%PageOrientation: Landscape\n"); writePS("pdfStartPage\n"); writePS("90 rotate\n"); - writePS("%d %d translate\n", -x1, -(y1 + paperWidth)); + tx = -x1; + ty = -(y1 + paperWidth); t = width; width = height; height = t; } else { + landscape = gFalse; writePS("%%%%PageOrientation: Portrait\n"); writePS("pdfStartPage\n"); - if (x1 != 0 || y1 != 0) - writePS("%d %d translate\n", -x1, -y1); + tx = -x1; + ty = -y1; + } + if (width < paperWidth) { + tx += (paperWidth - width) / 2; + } + if (height < paperHeight) { + ty += (paperHeight - height) / 2; + } + if (tx != 0 || ty != 0) { + writePS("%g %g translate\n", tx, ty); } if (width > paperWidth || height > paperHeight) { xScale = (double)paperWidth / (double)width; yScale = (double)paperHeight / (double)height; - if (yScale < xScale) + if (yScale < xScale) { xScale = yScale; + } writePS("%0.4f %0.4f scale\n", xScale, xScale); + } else { + xScale = yScale = 1; } writePS("%%%%EndPageSetup\n"); @@ -710,6 +1073,7 @@ void PSOutputDev::endPage() { writePS("pdfEndPage\n"); writePS("end end\n"); writePS("} def\n"); + writePS("end end\n"); } else { writePS("showpage\n"); writePS("%%%%PageTrailer\n"); @@ -763,31 +1127,37 @@ void PSOutputDev::updateLineWidth(GfxState *state) { } 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); + GfxRGB rgb; + GfxCMYK cmyk; + + if (psOutLevel1Sep) { + state->getFillCMYK(&cmyk); + writePS("%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) { + writePS("%g g\n", rgb.r); + } else { + writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.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); + GfxRGB rgb; + GfxCMYK cmyk; + + if (psOutLevel1Sep) { + state->getStrokeCMYK(&cmyk); + writePS("%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) { + writePS("%g G\n", rgb.r); + } else { + writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b); + } + } } void PSOutputDev::updateFont(GfxState *state) { @@ -909,6 +1279,9 @@ void PSOutputDev::doPath(GfxPath *path) { ++j; } } + if (subpath->isClosed()) { + writePS("h\n"); + } } } @@ -921,37 +1294,83 @@ void PSOutputDev::drawString(GfxState *state, GString *s) { writePS(" %g Tj\n", state->getFont()->getWidth(s)); } -void PSOutputDev::drawImageMask(GfxState *state, Stream *str, +void PSOutputDev::drawString16(GfxState *state, GString *s) { + int c1, c2; + double w; + int i; + + // check for invisible text -- this is used by Acrobat Capture + if ((state->getRender() & 3) == 3) + return; + + switch (state->getFont()->getCharSet16()) { + + case font16AdobeJapan12: +#if JAPANESE_SUPPORT + writePS("<"); + w = 0; + for (i = 0; i < s->getLength(); i += 2) { + c1 = ((s->getChar(i) & 0xff) << 8) + (s->getChar(i+1) & 0xff); + if (c1 <= 8285) { + c2 = japan12ToRKSJ[c1]; + } else { + c2 = 0x20; + } + if (c2 <= 0xff) { + writePS("%02x", c2); + } else { + writePS("%02x%02x", c2 >> 8, c2 & 0xff); + } + w += state->getFont()->getWidth16(c1); + } + writePS("> %g Tj\n", w); +#endif + break; + + case font16AdobeGB12: + break; + + case font16AdobeCNS13: + break; + } +} + +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 (psOutLevel1) + if (psOutLevel1 || psOutLevel1Sep) { doImageL1(NULL, invert, inlineImg, str, width, height, len); - else - doImage(NULL, invert, inlineImg, str, width, height, len); + } else { + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len); + } } -void PSOutputDev::drawImage(GfxState *state, Stream *str, int width, - int height, GfxImageColorMap *colorMap, +void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, GfxImageColorMap *colorMap, GBool inlineImg) { int len; len = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); - if (psOutLevel1) + if (psOutLevel1) { doImageL1(colorMap, gFalse, inlineImg, str, width, height, len); - else - doImage(colorMap, gFalse, inlineImg, str, width, height, len); + } else if (psOutLevel1Sep) { + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len); + } else { + doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len); + } } void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len) { ImageStream *imgStr; - Guchar pixBuf[4]; - GfxColor color; + Guchar pixBuf[gfxColorMaxComps]; + double gray; int x, y, i; // width, height, matrix, bits per component @@ -980,8 +1399,8 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, // write the line for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); - colorMap->getColor(pixBuf, &color); - fprintf(f, "%02x", (int)(color.getGray() * 255 + 0.5)); + colorMap->getGray(pixBuf, &gray); + fprintf(f, "%02x", (int)(gray * 255 + 0.5)); if (++i == 32) { fputc('\n', f); i = 0; @@ -1010,50 +1429,80 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, } } -void PSOutputDev::doImage(GfxImageColorMap *colorMap, - GBool invert, GBool inlineImg, - Stream *str, int width, int height, int len) { - GfxColorSpace *colorSpace; +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 + writePS("%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); + } + + // write one line of each color component + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + fprintf(f, "%02x", lineBuf[4*x + comp]); + if (++i == 32) { + fputc('\n', f); + i = 0; + } + } + } + } + + if (i != 0) { + fputc('\n', f); + } + + 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; - Guchar *color; GBool useRLE, useA85; int c; - int i, j, k; + int i; // 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"); - } + dumpColorSpaceL2(colorMap->getColorSpace()); + writePS(" setcolorspace\n"); + } + + // set up to use the array created by setupImages() + if (doForm && !inlineImg) { + writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); } // image dictionary @@ -1069,11 +1518,20 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, // 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)); + if (colorMap->getColorSpace()->getMode() == csSeparation) { + //~ this is a kludge -- see comment in dumpColorSpaceL2 + n = (1 << colorMap->getBits()) - 1; + writePS("%g %g", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); + } else { + 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 { @@ -1082,20 +1540,33 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, if (doForm) { - // data source - writePS(" /DataSource <~\n"); + if (inlineImg) { - // 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; + // data source + writePS(" /DataSource <~\n"); + + // write image data stream, using ASCII85 encode filter + str = new FixedLengthEncoder(str, len); + str = new ASCII85Encoder(str); + str->reset(); + while ((c = str->getChar()) != EOF) { + fputc(c, f); + } + fputc('\n', f); + delete str; + + } else { + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); + } // end of image dictionary writePS(">>\n%s\n", colorMap ? "image" : "imagemask"); + // get rid of the array and index + if (!inlineImg) { + writePS("pop pop\n"); + } + } else { // data source @@ -1117,11 +1588,6 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, 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); @@ -1134,6 +1600,31 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, if (useA85) 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 A85 and RLE filters) + str->reset(); + n = 0; + while ((c = str->getChar()) != EOF) { + ++n; + } + } + // +6/7 for "pdfIm\n" / "pdfImM\n" + // +8 for newline + trailer + n += colorMap ? 14 : 15; + writePS("%%%%BeginData: %d Hex Bytes\n", n); + } +#endif + writePS("%s\n", colorMap ? "pdfIm" : "pdfImM"); + // copy the stream data str->reset(); while ((c = str->getChar()) != EOF) @@ -1142,6 +1633,11 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, // add newline and trailer to the end fputc('\n', f); fputs("%-EOD-\n", f); +#if OPI_SUPPORT + if (opi13Nest) { + writePS("%%%%EndData\n"); + } +#endif // delete encoders if (useRLE || useA85) @@ -1149,7 +1645,571 @@ void PSOutputDev::doImage(GfxImageColorMap *colorMap, } } -void PSOutputDev::writePS(char *fmt, ...) { +void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { + GfxCalGrayColorSpace *calGrayCS; + GfxCalRGBColorSpace *calRGBCS; + GfxLabColorSpace *labCS; + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *separationCS; + Guchar *lookup; + double x[1], y[gfxColorMaxComps]; + int n, numComps; + int i, j, k; + + switch (colorSpace->getMode()) { + + case csDeviceGray: + writePS("/DeviceGray"); + break; + + case csCalGray: + calGrayCS = (GfxCalGrayColorSpace *)colorSpace; + writePS("[/CIEBasedA <<\n"); + writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); + writePS(" /MatrixA [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePS(" /WhitePoint [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePS(" /BlackPoint [%g %g %g]\n", + calGrayCS->getBlackX(), calGrayCS->getBlackY(), + calGrayCS->getBlackZ()); + writePS(">>]"); + break; + + case csDeviceRGB: + writePS("/DeviceRGB"); + break; + + case csCalRGB: + calRGBCS = (GfxCalRGBColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", + calRGBCS->getGammaR(), calRGBCS->getGammaG(), + calRGBCS->getGammaB()); + writePS(" /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]); + writePS(" /WhitePoint [%g %g %g]\n", + calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), + calRGBCS->getWhiteZ()); + writePS(" /BlackPoint [%g %g %g]\n", + calRGBCS->getBlackX(), calRGBCS->getBlackY(), + calRGBCS->getBlackZ()); + writePS(">>]"); + break; + + case csDeviceCMYK: + writePS("/DeviceCMYK"); + break; + + case csLab: + labCS = (GfxLabColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePS(" /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"); + writePS(" {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"); + writePS(" {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"); + writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", + labCS->getWhiteZ()); + writePS(" /WhitePoint [%g %g %g]\n", + labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); + writePS(" /BlackPoint [%g %g %g]\n", + labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); + writePS(">>]"); + break; + + case csICCBased: + dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt()); + break; + + case csIndexed: + indexedCS = (GfxIndexedColorSpace *)colorSpace; + writePS("[/Indexed "); + dumpColorSpaceL2(indexedCS->getBase()); + n = indexedCS->getIndexHigh(); + numComps = indexedCS->getBase()->getNComps(); + lookup = indexedCS->getLookup(); + writePS(" %d <\n", n); + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + writePS("%02x", lookup[j * numComps + k]); + } + } + writePS("\n"); + } + writePS(">]"); + break; + + case csSeparation: + //~ this is a kludge -- the correct thing would to ouput 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) { + writePS("%02x", (int)(255 * y[k] + 0.5)); + } + } + writePS("\n"); + } + writePS(">]"); + 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 (psOutOPI) { + 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)) { + writePS("%%%%ImageFileName: %s\n", + obj2.getString()->getCString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("MainImage", &obj1); + if (obj1.isString()) { + writePS("%%%%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(); + writePS("%%%%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(); + writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Inks", &obj1); + if (obj1.isName()) { + writePS("%%%%ImageInks: %s\n", obj1.getName()); + } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { + obj1.arrayGet(0, &obj2); + if (obj2.isName()) { + writePS("%%%%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()); + writePS(" %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(); + writePS("%%%%IncludedImageDimensions: %d %d\n", w, h); + } + obj1.free(); + + dict->lookup("IncludedImageQuality", &obj1); + if (obj1.isNum()) { + writePS("%%%%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)) { + writePS("%%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(); + writePS("%%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()) { + writePS("%%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()) { + writePS("%%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(); + writePS("%%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); + writePS(" %d", obj2.getInt()); + obj2.free(); + } + } + writePS("\n"); + } + obj1.free(); + + dict->lookup("ID", &obj1); + if (obj1.isString()) { + writePS("%%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(); + writePS("%%ALDImageType: %d %d\n", samples, bits); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePS("%%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); + writePS("%%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(); + writePS("%%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(); + writePS("%%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()) { + writePS("%%ALDImageTint: %g\n", obj1.getNum()); + } + obj1.free(); + + dict->lookup("Transparency", &obj1); + if (obj1.isBool()) { + writePS("%%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 (psOutOPI) { + 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::writePS(const char *fmt, ...) { va_list args; va_start(args, fmt); |