Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/PSOutputDev.cc
diff options
context:
space:
mode:
authorMartin 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)
commit7aac8dc8533347e21311b15186e0af82f1b22fd6 (patch)
tree02650bb02c8a1d8468c22f50ff151885d233016b /pdf/xpdf/PSOutputDev.cc
parentd99fb4f4acd14fcdbda968abd907547dcc7af40c (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.cc1432
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);