summaryrefslogtreecommitdiff
path: root/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc')
-rw-r--r--Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc2786
1 files changed, 1985 insertions, 801 deletions
diff --git a/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc b/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
index 9521f6ce0e5..050311a3b1d 100644
--- a/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
+++ b/Build/source/libs/xpdf/xpdf-src/xpdf/PSOutputDev.cc
@@ -17,6 +17,7 @@
#include <stdarg.h>
#include <signal.h>
#include <math.h>
+#include "gmempp.h"
#include "GString.h"
#include "GList.h"
#include "GHash.h"
@@ -48,11 +49,6 @@
#endif
#include "PSOutputDev.h"
-#ifdef MACOS
-// needed for setting type/creator of MacOS files
-#include "ICSupport.h"
-#endif
-
// the MSVC math.h doesn't define this
#ifndef M_PI
#define M_PI 3.14159265358979323846
@@ -65,22 +61,22 @@
// The '~' escapes mark prolog code that is emitted only in certain
// levels:
//
-// ~[123][sn]
-// ^ ^----- s=psLevel*Sep, n=psLevel*
-// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
+// ~[123][ngs]
+// ^ ^----- n=psLevel_, g=psLevel_Gray, s=psLevel_Sep
+// +----- 1=psLevel1__, 2=psLevel2__, 3=psLevel3__
static const char *prolog[] = {
"/xpdf 75 dict def xpdf begin",
"% PDF special state",
"/pdfDictSize 15 def",
- "~1sn",
+ "~1ns",
"/pdfStates 64 array def",
" 0 1 63 {",
" pdfStates exch pdfDictSize dict",
" dup /pdfStateIdx 3 index put",
" put",
" } for",
- "~123sn",
+ "~123ngs",
"/pdfSetup {",
" /pdfDuplex exch def",
" /setpagedevice where {",
@@ -107,17 +103,17 @@ static const char *prolog[] = {
" pop pop",
" } ifelse",
"} def",
- "~1sn",
+ "~1ns",
"/pdfOpNames [",
" /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
" /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
" /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
"] def",
- "~123sn",
+ "~123ngs",
"/pdfStartPage {",
- "~1sn",
+ "~1ns",
" pdfStates 0 get begin",
- "~23sn",
+ "~23ngs",
" pdfDictSize dict begin",
"~23n",
" /pdfFillCS [] def",
@@ -130,12 +126,15 @@ static const char *prolog[] = {
"~1s",
" /pdfFill [0 0 0 1] def",
" /pdfStroke [0 0 0 1] def",
- "~23sn",
+ "~23g",
+ " /pdfFill 0 def",
+ " /pdfStroke 0 def",
+ "~23ns",
" /pdfFill [0] def",
" /pdfStroke [0] def",
" /pdfFillOP false def",
" /pdfStrokeOP false def",
- "~123sn",
+ "~123ngs",
" /pdfLastFill false def",
" /pdfLastStroke false def",
" /pdfTextMat [1 0 0 1 0 0] def",
@@ -190,7 +189,7 @@ static const char *prolog[] = {
" grestore",
" } def",
"} ifelse",
- "~123sn",
+ "~123ngs",
"% PDF color state",
"~1n",
"/g { dup /pdfFill exch def setgray",
@@ -231,12 +230,16 @@ static const char *prolog[] = {
" setcolorspace } def",
"/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
" setcolorspace } def",
- "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
+ "/sc { pdfLastFill not {",
+ " pdfFillCS setcolorspace pdfFillOP setoverprint",
+ " } if",
" dup /pdfFill exch def aload pop pdfFillXform setcolor",
- " /pdfLastFill true def /pdfLastStroke false def } def",
- "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/SC { pdfLastStroke not {",
+ " pdfStrokeCS setcolorspace pdfStrokeOP setoverprint",
+ " } if",
" dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
- " /pdfLastStroke true def /pdfLastFill false def } def",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
"/op { /pdfFillOP exch def",
" pdfLastFill { pdfFillOP setoverprint } if } def",
"/OP { /pdfStrokeOP exch def",
@@ -257,16 +260,37 @@ static const char *prolog[] = {
" /pdfLastStroke true def /pdfLastFill false def",
" } if",
"} def",
+ "~23g",
+ "/g { dup /pdfFill exch def setgray",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/G { dup /pdfStroke exch def setgray",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill setgray",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke setgray",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
"~23s",
"/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " pdfFillOP setoverprint",
" /pdfLastFill true def /pdfLastStroke false def } def",
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " pdfStrokeOP setoverprint",
" /pdfLastStroke true def /pdfLastFill false def } def",
"/ck { 6 copy 6 array astore /pdfFill exch def",
" findcmykcustomcolor exch setcustomcolor",
+ " pdfFillOP setoverprint",
" /pdfLastFill true def /pdfLastStroke false def } def",
"/CK { 6 copy 6 array astore /pdfStroke exch def",
" findcmykcustomcolor exch setcustomcolor",
+ " pdfStrokeOP setoverprint",
" /pdfLastStroke true def /pdfLastFill false def } def",
"/op { /pdfFillOP exch def",
" pdfLastFill { pdfFillOP setoverprint } if } def",
@@ -294,7 +318,11 @@ static const char *prolog[] = {
" /pdfLastStroke true def /pdfLastFill false def",
" } if",
"} def",
- "~123sn",
+ "~3ns",
+ "/opm {",
+ " /setoverprintmode where { pop setoverprintmode } { pop } ifelse",
+ "} def",
+ "~123ngs",
"% build a font",
"/pdfMakeFont {",
" 4 3 roll findfont",
@@ -315,7 +343,7 @@ static const char *prolog[] = {
" end",
" definefont pop",
"} def",
- "~3sn",
+ "~3ngs",
"/pdfMakeFont16L3 {",
" 1 index /CIDFont resourcestatus {",
" pop pop 1 index /CIDFont findresource /CIDFontType known",
@@ -329,9 +357,9 @@ static const char *prolog[] = {
" pdfMakeFont16",
" } ifelse",
"} def",
- "~123sn",
+ "~123ngs",
"% graphics state operators",
- "~1sn",
+ "~1ns",
"/q {",
" gsave",
" pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
@@ -339,20 +367,12 @@ static const char *prolog[] = {
" pdfOpNames { exch def } forall",
"} def",
"/Q { end grestore } def",
- "~23sn",
+ "~23ngs",
"/q { gsave pdfDictSize dict begin } def",
"/Q {",
" end grestore",
- " /pdfLastFill where {",
- " pop",
- " pdfLastFill {",
- " pdfFillOP setoverprint",
- " } {",
- " pdfStrokeOP setoverprint",
- " } ifelse",
- " } if",
"} def",
- "~123sn",
+ "~123ngs",
"/cm { concat } def",
"/d { setdash } def",
"/i { setflat } def",
@@ -478,6 +498,16 @@ static const char *prolog[] = {
" } ifelse",
" 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
"} def",
+ "/Tj3 {",
+ " pdfTextRender 3 and 3 ne {"
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " xyshow2",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ " } {",
+ " pop pop",
+ " } ifelse",
+ "} def",
"/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0",
" pdfTextMat dtransform rmoveto } def",
"/TJmV { 0.001 mul pdfFontSize mul neg 0 exch",
@@ -519,7 +549,7 @@ static const char *prolog[] = {
" { pdfImStr } imagemask",
" pop pop",
"} def",
- "~23sn",
+ "~23ngs",
"% Level 2/3 image operators",
"/pdfImBuf 100 string def",
"/pdfImStr {",
@@ -535,7 +565,7 @@ static const char *prolog[] = {
" (%-EOD-) eq { exit } if } loop",
"} def",
"/pdfIm { image skipEOD } def",
- "~3sn",
+ "~3ngs",
"/pdfMask {",
" /ReusableStreamDecode filter",
" skipEOD",
@@ -571,7 +601,7 @@ static const char *prolog[] = {
" 6 5 roll customcolorimage",
" skipEOD",
"} def",
- "~23sn",
+ "~23ngs",
"/pdfImM { fCol imagemask skipEOD } def",
"/pr {",
" 4 2 roll exch 5 index div exch 4 index div moveto",
@@ -582,7 +612,7 @@ static const char *prolog[] = {
"} def",
"/pdfImClip { gsave clip } def",
"/pdfImClipEnd { grestore } def",
- "~23sn",
+ "~23ns",
"% shading operators",
"/colordelta {",
" false 0 1 3 index length 1 sub {",
@@ -623,7 +653,7 @@ static const char *prolog[] = {
" funcCol sc",
"~23s",
" funcCol aload pop k",
- "~23sn",
+ "~23ns",
" dup 4 index exch mat transform m",
" 3 index 3 index mat transform l",
" 1 index 3 index mat transform l",
@@ -662,7 +692,7 @@ static const char *prolog[] = {
" axialCol sc",
"~23s",
" axialCol aload pop k",
- "~23sn",
+ "~23ns",
" exch dup dx mul x0 add exch dy mul y0 add",
" 3 2 roll dup dx mul x0 add exch dy mul y0 add",
" dx abs dy abs ge {",
@@ -711,7 +741,7 @@ static const char *prolog[] = {
" radialCol sc",
"~23s",
" radialCol aload pop k",
- "~23sn",
+ "~23ns",
" encl {",
" exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
" 0 360 arc h",
@@ -730,7 +760,7 @@ static const char *prolog[] = {
" } ifelse",
" } ifelse",
"} def",
- "~123sn",
+ "~123ngs",
"end",
NULL
};
@@ -868,6 +898,7 @@ PSFontFileInfo::PSFontFileInfo(GString *psNameA, GfxFontType typeA,
extFileName = NULL;
encoding = NULL;
codeToGID = NULL;
+ codeToGIDLen = 0;
}
PSFontFileInfo::~PSFontFileInfo() {
@@ -946,13 +977,15 @@ public:
DeviceNRecoder(Stream *strA, int widthA, int heightA,
GfxImageColorMap *colorMapA);
virtual ~DeviceNRecoder();
+ virtual Stream *copy();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
+ virtual void close();
virtual int getChar()
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
virtual int lookChar()
{ return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
- virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
virtual GBool isEncoder() { return gTrue; }
@@ -986,20 +1019,28 @@ DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
}
DeviceNRecoder::~DeviceNRecoder() {
- if (imgStr) {
- delete imgStr;
- }
if (str->isEncoder()) {
delete str;
}
}
+Stream *DeviceNRecoder::copy() {
+ error(errInternal, -1, "Called copy() on DeviceNRecoder");
+ return NULL;
+}
+
void DeviceNRecoder::reset() {
imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
colorMap->getBits());
imgStr->reset();
}
+void DeviceNRecoder::close() {
+ delete imgStr;
+ imgStr = NULL;
+ str->close();
+}
+
GBool DeviceNRecoder::fillBuf() {
Guchar pixBuf[gfxColorMaxComps];
GfxColor color;
@@ -1026,6 +1067,202 @@ GBool DeviceNRecoder::fillBuf() {
}
//------------------------------------------------------------------------
+// GrayRecoder
+//------------------------------------------------------------------------
+
+class GrayRecoder: public FilterStream {
+public:
+
+ GrayRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA);
+ virtual ~GrayRecoder();
+ virtual Stream *copy();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufIdx >= width && !fillBuf()) ? EOF : buf[bufIdx++]; }
+ virtual int lookChar()
+ { return (bufIdx >= width && !fillBuf()) ? EOF : buf[bufIdx]; }
+ virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ GBool fillBuf();
+
+ int width, height;
+ GfxImageColorMap *colorMap;
+ ImageStream *imgStr;
+ Guchar *buf;
+ int bufIdx;
+};
+
+GrayRecoder::GrayRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA):
+ FilterStream(strA) {
+ width = widthA;
+ height = heightA;
+ colorMap = colorMapA;
+ imgStr = NULL;
+ buf = (Guchar *)gmalloc(width);
+ bufIdx = width;
+}
+
+GrayRecoder::~GrayRecoder() {
+ gfree(buf);
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+Stream *GrayRecoder::copy() {
+ error(errInternal, -1, "Called copy() on GrayRecoder");
+ return NULL;
+}
+
+void GrayRecoder::reset() {
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+}
+
+void GrayRecoder::close() {
+ delete imgStr;
+ imgStr = NULL;
+ str->close();
+}
+
+GBool GrayRecoder::fillBuf() {
+ Guchar *line;
+
+ if (!(line = imgStr->getLine())) {
+ bufIdx = width;
+ return gFalse;
+ }
+ //~ this should probably use the rendering intent from the image
+ //~ dict, or from the content stream
+ colorMap->getGrayByteLine(line, buf, width,
+ gfxRenderingIntentRelativeColorimetric);
+ bufIdx = 0;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// ColorKeyToMaskEncoder
+//------------------------------------------------------------------------
+
+class ColorKeyToMaskEncoder: public FilterStream {
+public:
+
+ ColorKeyToMaskEncoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA, int *maskColorsA);
+ virtual ~ColorKeyToMaskEncoder();
+ virtual Stream *copy();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
+ virtual int lookChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
+ virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ GBool fillBuf();
+
+ int width, height;
+ GfxImageColorMap *colorMap;
+ int numComps;
+ int *maskColors;
+ ImageStream *imgStr;
+ Guchar *buf;
+ int bufIdx;
+ int bufSize;
+};
+
+ColorKeyToMaskEncoder::ColorKeyToMaskEncoder(Stream *strA,
+ int widthA, int heightA,
+ GfxImageColorMap *colorMapA,
+ int *maskColorsA):
+ FilterStream(strA)
+{
+ width = widthA;
+ height = heightA;
+ colorMap = colorMapA;
+ numComps = colorMap->getNumPixelComps();
+ maskColors = maskColorsA;
+ imgStr = NULL;
+ bufSize = (width + 7) / 8;
+ buf = (Guchar *)gmalloc(bufSize);
+ bufIdx = width;
+}
+
+ColorKeyToMaskEncoder::~ColorKeyToMaskEncoder() {
+ gfree(buf);
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+Stream *ColorKeyToMaskEncoder::copy() {
+ error(errInternal, -1, "Called copy() on ColorKeyToMaskEncoder");
+ return NULL;
+}
+
+void ColorKeyToMaskEncoder::reset() {
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+}
+
+void ColorKeyToMaskEncoder::close() {
+ delete imgStr;
+ imgStr = NULL;
+ str->close();
+}
+
+GBool ColorKeyToMaskEncoder::fillBuf() {
+ Guchar *line, *linePtr, *bufPtr;
+ Guchar byte;
+ int x, xx, i;
+
+ if (!(line = imgStr->getLine())) {
+ bufIdx = width;
+ return gFalse;
+ }
+ linePtr = line;
+ bufPtr = buf;
+ for (x = 0; x < width; x += 8) {
+ byte = 0;
+ for (xx = 0; xx < 8; ++xx) {
+ byte <<= 1;
+ if (x + xx < width) {
+ for (i = 0; i < numComps; ++i) {
+ if (linePtr[i] < maskColors[2 * i] ||
+ linePtr[i] > maskColors[2 * i + 1]) {
+ break;
+ }
+ }
+ if (i >= numComps) {
+ byte |= 1;
+ }
+ linePtr += numComps;
+ } else {
+ byte |= 1;
+ }
+ }
+ *bufPtr++ = byte;
+ }
+ bufIdx = 0;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
// PSOutputDev
//------------------------------------------------------------------------
@@ -1038,11 +1275,12 @@ static void outputToFile(void *stream, const char *data, int len) {
}
PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
+ int firstPageA, int lastPageA, PSOutMode modeA,
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
GBool manualCtrlA,
PSOutCustomCodeCbk customCodeCbkA,
- void *customCodeCbkDataA) {
+ void *customCodeCbkDataA,
+ GBool honorUserUnitA) {
FILE *f;
PSFileType fileTypeA;
@@ -1053,11 +1291,13 @@ PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA,
customCodeCbk = customCodeCbkA;
customCodeCbkData = customCodeCbkDataA;
+ rasterizePage = NULL;
fontInfo = new GList();
fontFileInfo = new GHash();
imgIDs = NULL;
formIDs = NULL;
xobjStack = NULL;
+ saveStack = NULL;
paperSizes = NULL;
embFontList = NULL;
customColors = NULL;
@@ -1094,17 +1334,18 @@ PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA,
}
init(outputToFile, f, fileTypeA,
- docA, firstPage, lastPage, modeA,
- imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+ docA, firstPageA, lastPageA, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, honorUserUnitA);
}
PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
+ int firstPageA, int lastPageA, PSOutMode modeA,
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
GBool manualCtrlA,
PSOutCustomCodeCbk customCodeCbkA,
- void *customCodeCbkDataA) {
+ void *customCodeCbkDataA,
+ GBool honorUserUnitA) {
underlayCbk = NULL;
underlayCbkData = NULL;
overlayCbk = NULL;
@@ -1112,11 +1353,13 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
customCodeCbk = customCodeCbkA;
customCodeCbkData = customCodeCbkDataA;
+ rasterizePage = NULL;
fontInfo = new GList();
fontFileInfo = new GHash();
imgIDs = NULL;
formIDs = NULL;
xobjStack = NULL;
+ saveStack = NULL;
paperSizes = NULL;
embFontList = NULL;
customColors = NULL;
@@ -1124,21 +1367,22 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
t3String = NULL;
init(outputFuncA, outputStreamA, psGeneric,
- docA, firstPage, lastPage, modeA,
- imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+ docA, firstPageA, lastPageA, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, honorUserUnitA);
}
void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
PSFileType fileTypeA, PDFDoc *docA,
- int firstPage, int lastPage, PSOutMode modeA,
+ int firstPageA, int lastPageA, PSOutMode modeA,
int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
- GBool manualCtrlA) {
+ GBool manualCtrlA, GBool honorUserUnitA) {
Catalog *catalog;
Page *page;
PDFRectangle *box;
PSOutPaperSize *size;
PSFontFileInfo *ff;
GList *names;
+ double userUnit;
int pg, w, h, i;
// initialize
@@ -1149,8 +1393,15 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
doc = docA;
xref = doc->getXRef();
catalog = doc->getCatalog();
+ if ((firstPage = firstPageA) < 1) {
+ firstPage = 1;
+ }
+ if ((lastPage = lastPageA) > doc->getNumPages()) {
+ lastPage = doc->getNumPages();
+ }
level = globalParams->getPSLevel();
mode = modeA;
+ honorUserUnit = honorUserUnitA;
paperWidth = globalParams->getPSPaperWidth();
paperHeight = globalParams->getPSPaperHeight();
imgLLX = imgLLXA;
@@ -1164,16 +1415,19 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
paperMatch = gTrue;
paperSizes = new GList();
paperWidth = paperHeight = 1; // in case the document has zero pages
- for (pg = (firstPage >= 1) ? firstPage : 1;
- pg <= lastPage && pg <= catalog->getNumPages();
- ++pg) {
+ for (pg = firstPage; pg <= lastPage; ++pg) {
page = catalog->getPage(pg);
+ if (honorUserUnit) {
+ userUnit = page->getUserUnit();
+ } else {
+ userUnit = 1;
+ }
if (globalParams->getPSUseCropBoxAsPage()) {
- w = (int)ceil(page->getCropWidth());
- h = (int)ceil(page->getCropHeight());
+ w = (int)ceil(page->getCropWidth() * userUnit);
+ h = (int)ceil(page->getCropHeight() * userUnit);
} else {
- w = (int)ceil(page->getMediaWidth());
- h = (int)ceil(page->getMediaHeight());
+ w = (int)ceil(page->getMediaWidth() * userUnit);
+ h = (int)ceil(page->getMediaHeight() * userUnit);
}
for (i = 0; i < paperSizes->getLength(); ++i) {
size = (PSOutPaperSize *)paperSizes->get(i);
@@ -1236,7 +1490,8 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
formIDSize = 0;
xobjStack = new GList();
- numSaves = 0;
+ noStateChanges = gFalse;
+ saveStack = new GList();
numTilingPatterns = 0;
nextFunc = 0;
@@ -1245,14 +1500,13 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
if (!manualCtrl) {
// this check is needed in case the document has zero pages
- if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
- writeHeader(firstPage, lastPage,
- catalog->getPage(firstPage)->getMediaBox(),
+ if (firstPage <= catalog->getNumPages()) {
+ writeHeader(catalog->getPage(firstPage)->getMediaBox(),
catalog->getPage(firstPage)->getCropBox(),
catalog->getPage(firstPage)->getRotate());
} else {
box = new PDFRectangle(0, 0, 1, 1);
- writeHeader(firstPage, lastPage, box, box, 0);
+ writeHeader(box, box, 0);
delete box;
}
if (mode != psModeForm) {
@@ -1263,7 +1517,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
writePS("%%EndProlog\n");
writePS("%%BeginSetup\n");
}
- writeDocSetup(catalog, firstPage, lastPage);
+ writeDocSetup(catalog);
if (mode != psModeForm) {
writePS("%%EndSetup\n");
}
@@ -1285,9 +1539,6 @@ PSOutputDev::~PSOutputDev() {
}
}
if (fileType == psFile) {
-#ifdef MACOS
- ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
-#endif
fclose((FILE *)outputStream);
}
#ifdef HAVE_POPEN
@@ -1299,6 +1550,7 @@ PSOutputDev::~PSOutputDev() {
}
#endif
}
+ gfree(rasterizePage);
if (paperSizes) {
deleteGList(paperSizes, PSOutPaperSize);
}
@@ -1312,6 +1564,9 @@ PSOutputDev::~PSOutputDev() {
if (xobjStack) {
delete xobjStack;
}
+ if (saveStack) {
+ delete saveStack;
+ }
while (customColors) {
cc = customColors;
customColors = cc->next;
@@ -1329,8 +1584,7 @@ GBool PSOutputDev::checkIO() {
return gTrue;
}
-void PSOutputDev::writeHeader(int firstPage, int lastPage,
- PDFRectangle *mediaBox, PDFRectangle *cropBox,
+void PSOutputDev::writeHeader(PDFRectangle *mediaBox, PDFRectangle *cropBox,
int pageRotate) {
Object info, obj1;
PSOutPaperSize *size;
@@ -1363,8 +1617,7 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage,
obj1.free();
info.free();
writePSFmt("%%LanguageLevel: {0:d}\n",
- (level == psLevel1 || level == psLevel1Sep) ? 1 :
- (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ level >= psLevel3 ? 3 : level >= psLevel2 ? 2 : 1);
if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
writePS("%%DocumentProcessColors: (atend)\n");
writePS("%%DocumentCustomColors: (atend)\n");
@@ -1430,31 +1683,34 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage,
}
void PSOutputDev::writeXpdfProcset() {
- GBool lev1, lev2, lev3, sep, nonSep;
+ GBool lev1, lev2, lev3, nonSep, gray, sep;
const char **p;
const char *q;
double w;
writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", xpdfVersion);
writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
- lev1 = lev2 = lev3 = sep = nonSep = gTrue;
+ lev1 = lev2 = lev3 = nonSep = gray = sep = gTrue;
for (p = prolog; *p; ++p) {
if ((*p)[0] == '~') {
- lev1 = lev2 = lev3 = sep = nonSep = gFalse;
+ lev1 = lev2 = lev3 = nonSep = gray = sep = gFalse;
for (q = *p + 1; *q; ++q) {
switch (*q) {
case '1': lev1 = gTrue; break;
case '2': lev2 = gTrue; break;
case '3': lev3 = gTrue; break;
- case 's': sep = gTrue; break;
+ case 'g': gray = gTrue; break;
case 'n': nonSep = gTrue; break;
+ case 's': sep = gTrue; break;
}
}
} else if ((level == psLevel1 && lev1 && nonSep) ||
(level == psLevel1Sep && lev1 && sep) ||
(level == psLevel2 && lev2 && nonSep) ||
+ (level == psLevel2Gray && lev2 && gray) ||
(level == psLevel2Sep && lev2 && sep) ||
(level == psLevel3 && lev3 && nonSep) ||
+ (level == psLevel3Gray && lev3 && gray) ||
(level == psLevel3Sep && lev3 && sep)) {
writePSFmt("{0:s}\n", *p);
}
@@ -1474,8 +1730,7 @@ void PSOutputDev::writeXpdfProcset() {
}
}
-void PSOutputDev::writeDocSetup(Catalog *catalog,
- int firstPage, int lastPage) {
+void PSOutputDev::writeDocSetup(Catalog *catalog) {
Page *page;
Dict *resDict;
Annots *annots;
@@ -1484,6 +1739,16 @@ void PSOutputDev::writeDocSetup(Catalog *catalog,
GString *s;
int pg, i, j;
+ // check to see which pages will be rasterized
+ if (firstPage <= lastPage) {
+ rasterizePage = (char *)gmalloc(lastPage - firstPage + 1);
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ rasterizePage[pg - firstPage] = (char)checkIfPageNeedsToBeRasterized(pg);
+ }
+ } else {
+ rasterizePage = NULL;
+ }
+
if (mode == psModeForm) {
// swap the form and xpdf dicts
writePS("xpdf end begin dup begin\n");
@@ -1491,6 +1756,9 @@ void PSOutputDev::writeDocSetup(Catalog *catalog,
writePS("xpdf begin\n");
}
for (pg = firstPage; pg <= lastPage; ++pg) {
+ if (rasterizePage[pg - firstPage]) {
+ continue;
+ }
page = catalog->getPage(pg);
if ((resDict = page->getResourceDict())) {
setupResources(resDict);
@@ -1599,6 +1867,31 @@ void PSOutputDev::writeTrailer() {
}
}
+GBool PSOutputDev::checkIfPageNeedsToBeRasterized(int pg) {
+ PreScanOutputDev *scan;
+ GBool rasterize;
+
+ if (globalParams->getPSAlwaysRasterize()) {
+ rasterize = gTrue;
+ } else {
+ scan = new PreScanOutputDev();
+ //~ this could depend on the printing flag, e.g., if an annotation
+ //~ uses transparency --> need to pass the printing flag into
+ //~ constructor, init, writeDocSetup
+ doc->getCatalog()->getPage(pg)->display(scan, 72, 72, 0,
+ gTrue, gTrue, gTrue);
+ rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
+ delete scan;
+ if (rasterize && globalParams->getPSNeverRasterize()) {
+ error(errSyntaxWarning, -1,
+ "PDF page uses transparency and the psNeverRasterize option is "
+ "set - output may not be correct");
+ rasterize = gFalse;
+ }
+ }
+ return rasterize;
+}
+
void PSOutputDev::setupResources(Dict *resDict) {
Object xObjDict, xObjRef, xObj, patDict, patRef, pat;
Object gsDict, gsRef, gs, smask, smaskGroup, resObj;
@@ -1931,7 +2224,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
// generate PostScript code to set up the font
if (font->isCIDFont()) {
- if (level == psLevel3 || level == psLevel3Sep) {
+ if (level >= psLevel3) {
writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
font->getID()->num, font->getID()->gen, fi->ff->psName,
font->getWMode());
@@ -1970,26 +2263,34 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
}
PSFontFileInfo *PSOutputDev::setupEmbeddedType1Font(GfxFont *font, Ref *id) {
- static char hexChar[17] = "0123456789abcdef";
- GString *psName;
+ GString *psName, *origFont, *cleanFont;
PSFontFileInfo *ff;
Object refObj, strObj, obj1, obj2;
Dict *dict;
- int length1, length2;
- int c;
- int start[6];
- GBool binMode;
- int n, i;
+ char buf[4096];
+ GBool rename;
+ int length1, length2, n;
// check if font is already embedded
if ((ff = (PSFontFileInfo *)
fontFileInfo->lookup(font->getEmbeddedFontName()))) {
- return ff;
+ if (ff->loc == psFontFileEmbedded &&
+ ff->embFontID.num == id->num &&
+ ff->embFontID.gen == id->gen) {
+ return ff;
+ }
+ rename = gTrue;
+ } else {
+ rename = gFalse;
}
// generate name
// (this assumes that the PS font name matches the PDF font name)
- psName = font->getEmbeddedFontName()->copy();
+ if (rename) {
+ psName = makePSFontName(font, id);
+ } else {
+ psName = font->getEmbeddedFontName()->copy();
+ }
// get the font stream and info
refObj.initRef(id->num, id->gen);
@@ -2018,144 +2319,39 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedType1Font(GfxFont *font, Ref *id) {
obj1.free();
obj2.free();
+ // read the font file
+ origFont = new GString();
+ strObj.streamReset();
+ while ((n = strObj.streamGetBlock(buf, sizeof(buf))) > 0) {
+ origFont->append(buf, n);
+ }
+ strObj.streamClose();
+ strObj.free();
+
// beginning comment
writePSFmt("%%BeginResource: font {0:t}\n", psName);
embFontList->append("%%+ font ");
embFontList->append(psName->getCString());
embFontList->append("\n");
- // check for PFB format
- strObj.streamReset();
- start[0] = strObj.streamGetChar();
- start[1] = strObj.streamGetChar();
- if (start[0] == 0x80 && start[1] == 0x01) {
- error(errSyntaxWarning, -1, "Embedded Type 1 font is in PFB format");
- while (1) {
- for (i = 2; i < 6; ++i) {
- start[i] = strObj.streamGetChar();
- }
- if (start[2] == EOF || start[3] == EOF ||
- start[4] == EOF || start[5] == EOF) {
- break;
- }
- n = start[2] + (start[3] << 8) + (start[4] << 16) + (start[5] << 24);
- if (start[1] == 0x01) {
- for (i = 0; i < n; ++i) {
- if ((c = strObj.streamGetChar()) == EOF) {
- break;
- }
- writePSChar(c);
- }
- } else {
- for (i = 0; i < n; ++i) {
- if ((c = strObj.streamGetChar()) == EOF) {
- break;
- }
- writePSChar(hexChar[(c >> 4) & 0x0f]);
- writePSChar(hexChar[c & 0x0f]);
- if (i % 32 == 31) {
- writePSChar('\n');
- }
- }
- }
- start[0] = strObj.streamGetChar();
- start[1] = strObj.streamGetChar();
- if (start[0] == EOF || start[1] == EOF ||
- (start[0] == 0x80 && start[1] == 0x03)) {
- break;
- } else if (!(start[0] == 0x80 &&
- (start[1] == 0x01 || start[1] == 0x02))) {
- error(errSyntaxError, -1,
- "Invalid PFB header in embedded font stream");
- break;
- }
- }
- writePSChar('\n');
-
- // plain text (PFA) format
- } else {
-
- // copy ASCII portion of font
- writePSChar(start[0]);
- writePSChar(start[1]);
- for (i = 2; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
- writePSChar(c);
- }
-
- // figure out if encrypted portion is binary or ASCII
- binMode = gFalse;
- for (i = 0; i < 4; ++i) {
- start[i] = strObj.streamGetChar();
- if (start[i] == EOF) {
- error(errSyntaxError, -1,
- "Unexpected end of file in embedded font stream");
- goto err1;
- }
- if (!((start[i] >= '0' && start[i] <= '9') ||
- (start[i] >= 'A' && start[i] <= 'F') ||
- (start[i] >= 'a' && start[i] <= 'f')))
- binMode = gTrue;
- }
-
- // convert binary data to ASCII
- if (binMode) {
- for (i = 0; i < 4; ++i) {
- writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
- writePSChar(hexChar[start[i] & 0x0f]);
- }
-#if 0 // this causes trouble for various PostScript printers
- // if Length2 is incorrect (too small), font data gets chopped, so
- // we take a few extra characters from the trailer just in case
- length2 += length3 >= 8 ? 8 : length3;
-#endif
- while (i < length2) {
- if ((c = strObj.streamGetChar()) == EOF) {
- break;
- }
- writePSChar(hexChar[(c >> 4) & 0x0f]);
- writePSChar(hexChar[c & 0x0f]);
- if (++i % 32 == 0) {
- writePSChar('\n');
- }
- }
- if (i % 32 > 0) {
- writePSChar('\n');
- }
-
- // already in ASCII format -- just copy it
- } else {
- for (i = 0; i < 4; ++i) {
- writePSChar(start[i]);
- }
- for (i = 4; i < length2; ++i) {
- if ((c = strObj.streamGetChar()) == EOF) {
- break;
- }
- writePSChar(c);
- }
- }
-
- // write padding and "cleartomark"
- for (i = 0; i < 8; ++i) {
- writePS("00000000000000000000000000000000"
- "00000000000000000000000000000000\n");
- }
- writePS("cleartomark\n");
+ // clean up the font file
+ cleanFont = fixType1Font(origFont, length1, length2);
+ if (rename) {
+ renameType1Font(cleanFont, psName);
}
+ writePSBlock(cleanFont->getCString(), cleanFont->getLength());
+ delete cleanFont;
+ delete origFont;
// ending comment
writePS("%%EndResource\n");
- strObj.streamClose();
- strObj.free();
-
ff = new PSFontFileInfo(psName, font->getType(), psFontFileEmbedded);
ff->embFontID = *id;
fontFileInfo->add(ff->psName, ff);
return ff;
err1:
- strObj.streamClose();
strObj.free();
delete psName;
return NULL;
@@ -2338,7 +2534,7 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font,
// convert it to a Type 1 font
if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen, 0))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen, 0, gTrue))) {
if (ffTT->isOpenTypeCFF()) {
ffTT->convertToType1(psName->getCString(), NULL, gTrue,
outputFunc, outputStream);
@@ -2380,6 +2576,7 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id) {
fontFileInfo->startIter(&iter);
while (fontFileInfo->getNext(&iter, &psName, (void **)&ff)) {
if (ff->loc == psFontFileEmbedded &&
+ ff->type == font->getType() &&
ff->embFontID.num == id->num &&
ff->embFontID.gen == id->gen &&
ff->codeToGIDLen == 256 &&
@@ -2512,11 +2709,15 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id) {
if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
if (globalParams->getPSLevel() >= psLevel3) {
// Level 3: use a CID font
- ffT1C->convertToCIDType0(psName->getCString(), NULL, 0,
+ ffT1C->convertToCIDType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
outputFunc, outputStream);
} else {
// otherwise: use a non-CID composite font
- ffT1C->convertToType0(psName->getCString(), NULL, 0,
+ ffT1C->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
outputFunc, outputStream);
}
delete ffT1C;
@@ -2553,6 +2754,7 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedCIDTrueTypeFont(
fontFileInfo->startIter(&iter);
while (fontFileInfo->getNext(&iter, &psName, (void **)&ff)) {
if (ff->loc == psFontFileEmbedded &&
+ ff->type == font->getType() &&
ff->embFontID.num == id->num &&
ff->embFontID.gen == id->gen &&
ff->codeToGIDLen == codeToGIDLen &&
@@ -2620,7 +2822,7 @@ PSFontFileInfo *PSOutputDev::setupExternalCIDTrueTypeFont(
int codeToGIDLen;
CharCodeToUnicode *ctu;
Unicode uBuf[8];
- int cmap, code;
+ int cmap, cmapPlatform, cmapEncoding, code;
GHashIter *iter;
// create a code-to-GID mapping, via Unicode
@@ -2636,9 +2838,10 @@ PSFontFileInfo *PSOutputDev::setupExternalCIDTrueTypeFont(
}
// look for a Unicode cmap
for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) {
- if ((ffTT->getCmapPlatform(cmap) == 3 &&
- ffTT->getCmapEncoding(cmap) == 1) ||
- ffTT->getCmapPlatform(cmap) == 0) {
+ cmapPlatform = ffTT->getCmapPlatform(cmap);
+ cmapEncoding = ffTT->getCmapEncoding(cmap);
+ if ((cmapPlatform == 3 && cmapEncoding == 1) ||
+ (cmapPlatform == 0 && cmapEncoding <= 4)) {
break;
}
}
@@ -2761,7 +2964,7 @@ PSFontFileInfo *PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font,
// convert it to a Type 0 font
if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) {
- if ((ffTT = FoFiTrueType::make(fontBuf, fontLen, 0))) {
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen, 0, gTrue))) {
if (ffTT->isOpenTypeCFF()) {
if (globalParams->getPSLevel() >= psLevel3) {
// Level 3: use a CID font
@@ -2932,6 +3135,428 @@ GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) {
return psName;
}
+GString *PSOutputDev::fixType1Font(GString *font, int length1, int length2) {
+ Guchar *fontData;
+ GString *out, *binSection;
+ GBool pfb;
+ int fontSize, i;
+
+ fontData = (Guchar *)font->getCString();
+ fontSize = font->getLength();
+
+ // check for PFB
+ pfb = fontSize >= 6 && fontData[0] == 0x80 && fontData[1] == 0x01;
+ out = new GString();
+ binSection = new GString();
+ if (pfb) {
+ if (!splitType1PFB(fontData, fontSize, out, binSection)) {
+ delete out;
+ delete binSection;
+ return copyType1PFB(fontData, fontSize);
+ }
+ } else {
+ if (!splitType1PFA(fontData, fontSize, length1, length2,
+ out, binSection)) {
+ delete out;
+ delete binSection;
+ return copyType1PFA(fontData, fontSize);
+ }
+ }
+
+ out->append('\n');
+
+ binSection = asciiHexDecodeType1EexecSection(binSection);
+
+ if (!fixType1EexecSection(binSection, out)) {
+ delete out;
+ delete binSection;
+ return pfb ? copyType1PFB(fontData, fontSize)
+ : copyType1PFA(fontData, fontSize);
+ }
+ delete binSection;
+
+ for (i = 0; i < 8; ++i) {
+ out->append("0000000000000000000000000000000000000000000000000000000000000000\n");
+ }
+ out->append("cleartomark\n");
+
+ return out;
+}
+
+// Split a Type 1 font in PFA format into a text section and a binary
+// section.
+GBool PSOutputDev::splitType1PFA(Guchar *font, int fontSize,
+ int length1, int length2,
+ GString *textSection, GString *binSection) {
+ int textLength, binStart, binLength, lastSpace, i;
+
+ //--- extract the text section
+
+ // Length1 is correct, and the text section ends with whitespace
+ if (length1 <= fontSize &&
+ length1 >= 18 &&
+ !memcmp(font + length1 - 18, "currentfile eexec", 17)) {
+ textLength = length1 - 1;
+
+ // Length1 is correct, but the trailing whitespace is missing
+ } else if (length1 <= fontSize &&
+ length1 >= 17 &&
+ !memcmp(font + length1 - 17, "currentfile eexec", 17)) {
+ textLength = length1;
+
+ // Length1 is incorrect
+ } else {
+ for (textLength = 17; textLength <= fontSize; ++textLength) {
+ if (!memcmp(font + textLength - 17, "currentfile eexec", 17)) {
+ break;
+ }
+ }
+ if (textLength > fontSize) {
+ return gFalse;
+ }
+ }
+
+ textSection->append((char *)font, textLength);
+
+ //--- skip whitespace between the text section and the binary section
+
+ for (i = 0, binStart = textLength;
+ i < 8 && binStart < fontSize;
+ ++i, ++binStart) {
+ if (font[binStart] != ' ' && font[binStart] != '\t' &&
+ font[binStart] != '\n' && font[binStart] != '\r') {
+ break;
+ }
+ }
+ if (i == 8) {
+ return gFalse;
+ }
+
+ //--- extract binary section
+
+ // if we see "0000", assume Length2 is correct
+ // (if Length2 is too long, it will be corrected by fixType1EexecSection)
+ if (length2 > 0 && length2 < INT_MAX - 4 &&
+ binStart <= fontSize - length2 - 4 &&
+ !memcmp(font + binStart + length2, "0000", 4)) {
+ binLength = length2;
+
+ } else {
+
+ // look for "0000" near the end of the font (note that there can
+ // be intervening "\n", "\r\n", etc.), then search backward
+ if (fontSize - binStart < 512) {
+ return gFalse;
+ }
+ if (!memcmp(font + fontSize - 256, "0000", 4) ||
+ !memcmp(font + fontSize - 255, "0000", 4) ||
+ !memcmp(font + fontSize - 254, "0000", 4) ||
+ !memcmp(font + fontSize - 253, "0000", 4) ||
+ !memcmp(font + fontSize - 252, "0000", 4) ||
+ !memcmp(font + fontSize - 251, "0000", 4)) {
+ i = fontSize - 252;
+ lastSpace = -1;
+ while (i >= binStart) {
+ if (font[i] == ' ' || font[i] == '\t' ||
+ font[i] == '\n' || font[i] == '\r') {
+ lastSpace = i;
+ --i;
+ } else if (font[i] == '0') {
+ --i;
+ } else {
+ break;
+ }
+ }
+ if (lastSpace < 0) {
+ return gFalse;
+ }
+ // check for the case where the newline/space is missing between
+ // the binary section and the first set of 64 '0' chars
+ if (lastSpace - binStart > 64 &&
+ !memcmp(font + lastSpace - 64,
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 64)) {
+ binLength = lastSpace - 64 - binStart;
+ } else {
+ binLength = lastSpace - binStart;
+ }
+
+ // couldn't find zeros after binary section -- assume they're
+ // missing and the binary section extends to the end of the file
+ } else {
+ binLength = fontSize - binStart;
+ }
+ }
+
+ binSection->append((char *)(font + binStart), binLength);
+
+ return gTrue;
+}
+
+// Split a Type 1 font in PFB format into a text section and a binary
+// section.
+GBool PSOutputDev::splitType1PFB(Guchar *font, int fontSize,
+ GString *textSection, GString *binSection) {
+ Guchar *p;
+ int state, remain, len, n;
+
+ // states:
+ // 0: text section
+ // 1: binary section
+ // 2: trailer section
+ // 3: eof
+
+ state = 0;
+ p = font;
+ remain = fontSize;
+ while (remain >= 2) {
+ if (p[0] != 0x80) {
+ return gFalse;
+ }
+ switch (state) {
+ case 0:
+ if (p[1] == 0x02) {
+ state = 1;
+ } else if (p[1] != 0x01) {
+ return gFalse;
+ }
+ break;
+ case 1:
+ if (p[1] == 0x01) {
+ state = 2;
+ } else if (p[1] != 0x02) {
+ return gFalse;
+ }
+ break;
+ case 2:
+ if (p[1] == 0x03) {
+ state = 3;
+ } else if (p[1] != 0x01) {
+ return gFalse;
+ }
+ break;
+ default: // shouldn't happen
+ return gFalse;
+ }
+ if (state == 3) {
+ break;
+ }
+
+ if (remain < 6) {
+ break;
+ }
+ len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24);
+ if (len < 0 || len > remain - 6) {
+ return gFalse;
+ }
+
+ switch (state) {
+ case 0:
+ textSection->append((char *)(p + 6), len);
+ break;
+ case 1:
+ binSection->append((char *)(p + 6), len);
+ break;
+ case 2:
+ // we don't use the trailer
+ break;
+ default: // shouldn't happen
+ return gFalse;
+ }
+
+ p += len + 6;
+ remain -= len + 6;
+ }
+
+ if (state != 3) {
+ return gFalse;
+ }
+
+ n = textSection->getLength();
+ if (n >= 18 && !memcmp(textSection->getCString() + n - 18,
+ "currentfile eexec", 17)) {
+ // remove the trailing whitespace
+ textSection->del(n - 1, 1);
+ } else if (n >= 17 && !memcmp(textSection->getCString() + n - 17,
+ "currentfile eexec", 17)) {
+ // missing whitespace at end -- leave as-is
+ } else {
+ return gFalse;
+ }
+
+ return gTrue;
+}
+
+// If <in> is ASCIIHex-encoded, decode it, delete <in>, and return the
+// binary version. Else return <in> unchanged.
+GString *PSOutputDev::asciiHexDecodeType1EexecSection(GString *in) {
+ GString *out;
+ char c;
+ Guchar byte;
+ int state, i;
+
+ out = new GString();
+ state = 0;
+ byte = 0;
+ for (i = 0; i < in->getLength(); ++i) {
+ c = in->getChar(i);
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\r') {
+ continue;
+ }
+ if (c >= '0' && c <= '9') {
+ byte += c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ byte += c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ byte += c - 'a' + 10;
+ } else {
+ delete out;
+ return in;
+ }
+ if (state == 0) {
+ byte <<= 4;
+ state = 1;
+ } else {
+ out->append((char)byte);
+ state = 0;
+ byte = 0;
+ }
+ }
+ delete in;
+ return out;
+}
+
+GBool PSOutputDev::fixType1EexecSection(GString *binSection, GString *out) {
+ static char hexChars[17] = "0123456789abcdef";
+ Guchar buf[16], buf2[16];
+ Guchar byte;
+ int r, i, j;
+
+ // eexec-decode the binary section, keeping the last 16 bytes
+ r = 55665;
+ for (i = 0; i < binSection->getLength(); ++i) {
+ byte = (Guchar)binSection->getChar(i);
+ buf[i & 15] = byte ^ (Guchar)(r >> 8);
+ r = ((r + byte) * 52845 + 22719) & 0xffff;
+ }
+ for (j = 0; j < 16; ++j) {
+ buf2[j] = buf[(i + j) & 15];
+ }
+
+ // look for 'closefile'
+ for (i = 0; i <= 16 - 9; ++i) {
+ if (!memcmp(buf2 + i, "closefile", 9)) {
+ break;
+ }
+ }
+ if (i > 16 - 9) {
+ return gFalse;
+ }
+ // three cases:
+ // - short: missing space after "closefile" (i == 16 - 9)
+ // - correct: exactly one space after "closefile" (i == 16 - 10)
+ // - long: extra chars after "closefile" (i < 16 - 10)
+ if (i == 16 - 9) {
+ binSection->append((char)((Guchar)'\n' ^ (Guchar)(r >> 8)));
+ } else if (i < 16 - 10) {
+ binSection->del(binSection->getLength() - (16 - 10 - i), 16 - 10 - i);
+ }
+
+ // ASCIIHex encode
+ for (i = 0; i < binSection->getLength(); i += 32) {
+ for (j = 0; j < 32 && i+j < binSection->getLength(); ++j) {
+ byte = (Guchar)binSection->getChar(i+j);
+ out->append(hexChars[(byte >> 4) & 0x0f]);
+ out->append(hexChars[byte & 0x0f]);
+ }
+ out->append('\n');
+ }
+
+ return gTrue;
+}
+
+// The Type 1 cleanup code failed -- assume it's a valid PFA-format
+// font and copy it to the output.
+GString *PSOutputDev::copyType1PFA(Guchar *font, int fontSize) {
+ GString *out;
+
+ error(errSyntaxWarning, -1, "Couldn't parse embedded Type 1 font");
+
+ out = new GString((char *)font, fontSize);
+ // append a newline to avoid problems where the original font
+ // doesn't end with one
+ out->append('\n');
+ return out;
+}
+
+// The Type 1 cleanup code failed -- assume it's a valid PFB-format
+// font, decode the PFB blocks, and copy them to the output.
+GString *PSOutputDev::copyType1PFB(Guchar *font, int fontSize) {
+ static char hexChars[17] = "0123456789abcdef";
+ GString *out;
+ Guchar *p;
+ int remain, len, i, j;
+
+ error(errSyntaxWarning, -1, "Couldn't parse embedded Type 1 (PFB) font");
+
+ out = new GString();
+ p = font;
+ remain = fontSize;
+ while (remain >= 6 &&
+ p[0] == 0x80 &&
+ (p[1] == 0x01 || p[1] == 0x02)) {
+ len = p[2] + (p[3] << 8) + (p[4] << 16) + (p[5] << 24);
+ if (len > remain - 6) {
+ break;
+ }
+ if (p[1] == 0x01) {
+ out->append((char *)(p + 6), len);
+ } else {
+ for (i = 0; i < len; i += 32) {
+ for (j = 0; j < 32 && i+j < len; ++j) {
+ out->append(hexChars[(p[6+i+j] >> 4) & 0x0f]);
+ out->append(hexChars[p[6+i+j] & 0x0f]);
+ }
+ out->append('\n');
+ }
+ }
+ p += len + 6;
+ remain -= len + 6;
+ }
+ // append a newline to avoid problems where the original font
+ // doesn't end with one
+ out->append('\n');
+ return out;
+}
+
+void PSOutputDev::renameType1Font(GString *font, GString *name) {
+ char *p1, *p2;
+ int i;
+
+ if (!(p1 = strstr(font->getCString(), "\n/FontName")) &&
+ !(p1 = strstr(font->getCString(), "\r/FontName"))) {
+ return;
+ }
+ p1 += 10;
+ while (*p1 == ' ' || *p1 == '\t' || *p1 == '\n' || *p1 == '\r') {
+ ++p1;
+ }
+ if (*p1 != '/') {
+ return;
+ }
+ ++p1;
+ p2 = p1;
+ while (*p2 && *p2 != ' ' && *p2 != '\t' && *p2 != '\n' && *p2 != '\r') {
+ ++p2;
+ }
+ if (!*p2) {
+ return;
+ }
+ i = (int)(p1 - font->getCString());
+ font->del(i, (int)(p2 - p1));
+ font->insert(i, name);
+}
+
void PSOutputDev::setupImages(Dict *resDict) {
Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef;
Ref imgID;
@@ -2987,21 +3612,101 @@ void PSOutputDev::setupImages(Dict *resDict) {
xObjDict.free();
}
+//~ this doesn't currently handle color key masks in psLevel3Gray
+//~ (which need to be converted to explicit masks)
void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
- GBool useLZW, useRLE, useCompressed, useASCIIHex;
+ StreamColorSpaceMode csMode;
+ GfxColorSpace *colorSpace;
+ GfxImageColorMap *colorMap;
+ Object obj1;
+ GBool imageMask, useLZW, useRLE, useCompressed, useASCIIHex;
GString *s;
- int c;
- int size, line, col, i;
+ int c, width, height, bits, size, line, col, i;
+
+ // check for mask
+ str->getDict()->lookup("ImageMask", &obj1);
+ if (obj1.isBool()) {
+ imageMask = obj1.getBool();
+ } else {
+ imageMask = gFalse;
+ }
+ obj1.free();
+
+ // get image size
+ str->getDict()->lookup("Width", &obj1);
+ if (!obj1.isInt() || obj1.getInt() <= 0) {
+ error(errSyntaxError, -1, "Invalid Width in image");
+ obj1.free();
+ return;
+ }
+ width = obj1.getInt();
+ obj1.free();
+ str->getDict()->lookup("Height", &obj1);
+ if (!obj1.isInt() || obj1.getInt() <= 0) {
+ error(errSyntaxError, -1, "Invalid Height in image");
+ obj1.free();
+ return;
+ }
+ height = obj1.getInt();
+ obj1.free();
+
+ // build the color map
+ if (mask || imageMask) {
+ colorMap = NULL;
+ } else {
+ bits = 0;
+ csMode = streamCSNone;
+ str->getImageParams(&bits, &csMode);
+ if (bits == 0) {
+ str->getDict()->lookup("BitsPerComponent", &obj1);
+ if (!obj1.isInt()) {
+ error(errSyntaxError, -1, "Invalid BitsPerComponent in image");
+ obj1.free();
+ return;
+ }
+ bits = obj1.getInt();
+ obj1.free();
+ }
+ str->getDict()->lookup("ColorSpace", &obj1);
+ if (!obj1.isNull()) {
+ colorSpace = GfxColorSpace::parse(&obj1
+ );
+ } else if (csMode == streamCSDeviceGray) {
+ colorSpace = GfxColorSpace::create(csDeviceGray);
+ } else if (csMode == streamCSDeviceRGB) {
+ colorSpace = GfxColorSpace::create(csDeviceRGB);
+ } else if (csMode == streamCSDeviceCMYK) {
+ colorSpace = GfxColorSpace::create(csDeviceCMYK);
+ } else {
+ colorSpace = NULL;
+ }
+ obj1.free();
+ if (!colorSpace) {
+ error(errSyntaxError, -1, "Invalid ColorSpace in image");
+ return;
+ }
+ str->getDict()->lookup("Decode", &obj1);
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
+ obj1.free();
+ }
// filters
- //~ this does not correctly handle the DeviceN color space
- //~ -- need to use DeviceNRecoder
if (level < psLevel2) {
useLZW = useRLE = gFalse;
useCompressed = gFalse;
useASCIIHex = gTrue;
} else {
- if (globalParams->getPSUncompressPreloadedImages()) {
+ if (colorMap && (colorMap->getColorSpace()->getMode() == csDeviceN ||
+ level == psLevel2Gray || level == psLevel3Gray)) {
+ if (globalParams->getPSLZW()) {
+ useLZW = gTrue;
+ useRLE = gFalse;
+ } else {
+ useRLE = gTrue;
+ useLZW = gFalse;
+ }
+ useCompressed = gFalse;
+ } else if (globalParams->getPSUncompressPreloadedImages()) {
useLZW = useRLE = gFalse;
useCompressed = gFalse;
} else {
@@ -3026,6 +3731,11 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
if (useCompressed) {
str = str->getUndecodedStream();
}
+ if (colorMap && (level == psLevel2Gray || level == psLevel3Gray)) {
+ str = new GrayRecoder(str, width, height, colorMap);
+ } else if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ str = new DeviceNRecoder(str, width, height, colorMap);
+ }
if (useLZW) {
str = new LZWEncoder(str);
} else if (useRLE) {
@@ -3125,6 +3835,10 @@ void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) {
str->close();
delete str;
+
+ if (colorMap) {
+ delete colorMap;
+ }
}
void PSOutputDev::setupForms(Dict *resDict) {
@@ -3247,8 +3961,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
GBool printing,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData) {
- PreScanOutputDev *scan;
- GBool rasterize;
+ int pg;
#if HAVE_SPLASH
GBool mono;
GBool useLZW;
@@ -3263,34 +3976,36 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
Guchar *p;
Guchar col[4];
char buf[4096];
- double hDPI2, vDPI2;
+ double userUnit, hDPI2, vDPI2;
double m0, m1, m2, m3, m4, m5;
int nStripes, stripeH, stripeY;
int w, h, x, y, comp, i, n;
#endif
- if (globalParams->getPSAlwaysRasterize()) {
- rasterize = gTrue;
- } else {
- scan = new PreScanOutputDev();
- page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
- sliceX, sliceY, sliceW, sliceH,
- printing, abortCheckCbk, abortCheckCbkData);
- rasterize = scan->usesTransparency() || scan->usesPatternImageMask();
- delete scan;
- }
- if (!rasterize) {
+ pg = page->getNum();
+ if (!(pg >= firstPage && pg <= lastPage &&
+ rasterizePage[pg - firstPage])) {
return gTrue;
}
#if HAVE_SPLASH
// get the rasterization parameters
dpi = globalParams->getPSRasterResolution();
- mono = globalParams->getPSRasterMono();
+ mono = globalParams->getPSRasterMono() ||
+ level == psLevel1 ||
+ level == psLevel2Gray ||
+ level == psLevel3Gray;
useLZW = globalParams->getPSLZW();
+ // get the UserUnit
+ if (honorUserUnit) {
+ userUnit = page->getUserUnit();
+ } else {
+ userUnit = 1;
+ }
+
// start the PS page
- page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse,
+ page->makeBox(userUnit * dpi, userUnit * dpi, rotateA, useMediaBox, gFalse,
sliceX, sliceY, sliceW, sliceH, &box, &crop);
rotateA += page->getRotate();
if (rotateA >= 360) {
@@ -3303,7 +4018,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
delete state;
// set up the SplashOutputDev
- if (mono || level == psLevel1) {
+ if (mono) {
paperColor[0] = 0xff;
splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
paperColor, gFalse,
@@ -3324,6 +4039,7 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
splashOut->startDoc(xref);
// break the page into stripes
+ // NB: startPage() has already multiplied xScale and yScale by UserUnit
hDPI2 = xScale * dpi;
vDPI2 = yScale * dpi;
if (sliceW < 0 || sliceH < 0) {
@@ -3419,8 +4135,10 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
}
break;
case psLevel2:
+ case psLevel2Gray:
case psLevel2Sep:
case psLevel3:
+ case psLevel3Gray:
case psLevel3Sep:
if (mono) {
writePS("/DeviceGray setcolorspace\n");
@@ -3495,22 +4213,29 @@ GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI,
void PSOutputDev::startPage(int pageNum, GfxState *state) {
Page *page;
+ double userUnit;
int x1, y1, x2, y2, width, height, t;
int imgWidth, imgHeight, imgWidth2, imgHeight2;
GBool landscape;
GString *s;
+ page = doc->getCatalog()->getPage(pageNum);
+ if (honorUserUnit) {
+ userUnit = page->getUserUnit();
+ } else {
+ userUnit = 1;
+ }
+
if (mode == psModePS) {
writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
if (paperMatch) {
- page = doc->getCatalog()->getPage(pageNum);
imgLLX = imgLLY = 0;
if (globalParams->getPSUseCropBoxAsPage()) {
- imgURX = (int)ceil(page->getCropWidth());
- imgURY = (int)ceil(page->getCropHeight());
+ imgURX = (int)ceil(page->getCropWidth() * userUnit);
+ imgURY = (int)ceil(page->getCropHeight() * userUnit);
} else {
- imgURX = (int)ceil(page->getMediaWidth());
- imgURY = (int)ceil(page->getMediaHeight());
+ imgURX = (int)ceil(page->getMediaWidth() * userUnit);
+ imgURY = (int)ceil(page->getMediaHeight() * userUnit);
}
if (state->getRotate() == 90 || state->getRotate() == 270) {
t = imgURX;
@@ -3526,6 +4251,12 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
writePS("xpdf begin\n");
}
+ // set up paper size for paper=match mode
+ // NB: this must be done *before* the saveState() for overlays.
+ if (mode == psModePS && paperMatch) {
+ writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
+ }
+
// underlays
if (underlayCbk) {
(*underlayCbk)(this, underlayCbkData);
@@ -3576,9 +4307,6 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
}
writePSFmt("%%PageOrientation: {0:s}\n",
landscape ? "Landscape" : "Portrait");
- if (paperMatch) {
- writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY);
- }
writePS("pdfStartPage\n");
if (rotate == 0) {
imgWidth2 = imgWidth;
@@ -3602,12 +4330,14 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
}
// shrink or expand
if (xScale0 > 0 && yScale0 > 0) {
- xScale = xScale0;
- yScale = yScale0;
+ xScale = xScale0 * userUnit;
+ yScale = yScale0 * userUnit;
} else if ((globalParams->getPSShrinkLarger() &&
- (width > imgWidth2 || height > imgHeight2)) ||
+ (width * userUnit > imgWidth2 ||
+ height * userUnit > imgHeight2)) ||
(globalParams->getPSExpandSmaller() &&
- (width < imgWidth2 && height < imgHeight2))) {
+ (width * userUnit < imgWidth2 &&
+ height * userUnit < imgHeight2))) {
xScale = (double)imgWidth2 / (double)width;
yScale = (double)imgHeight2 / (double)height;
if (yScale < xScale) {
@@ -3616,7 +4346,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
yScale = xScale;
}
} else {
- xScale = yScale = 1;
+ xScale = yScale = userUnit;
}
// deal with odd bounding boxes or clipping
if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
@@ -3691,6 +4421,10 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
break;
}
+ if (level == psLevel2Gray || level == psLevel3Gray) {
+ writePS("/DeviceGray setcolorspace\n");
+ }
+
if (customCodeCbk) {
if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum,
customCodeCbkData))) {
@@ -3702,6 +4436,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
if (mode == psModePS) {
writePS("%%EndPageSetup\n");
}
+
+ noStateChanges = gFalse;
}
void PSOutputDev::endPage() {
@@ -3726,24 +4462,47 @@ void PSOutputDev::endPage() {
}
void PSOutputDev::saveState(GfxState *state) {
- writePS("q\n");
- ++numSaves;
+ // The noStateChanges and saveStack fields are used to implement an
+ // optimization to reduce gsave/grestore nesting. The idea is to
+ // look for sequences like this:
+ // q q AAA Q BBB Q (where AAA and BBB are sequences of operations)
+ // and transform them to:
+ // q AAA Q q BBB Q
+ if (noStateChanges) {
+ // any non-NULL pointer will work here
+ saveStack->append(this);
+ } else {
+ saveStack->append((PSOutputDev *)NULL);
+ writePS("q\n");
+ noStateChanges = gTrue;
+ }
}
void PSOutputDev::restoreState(GfxState *state) {
- writePS("Q\n");
- --numSaves;
+ if (saveStack->getLength()) {
+ writePS("Q\n");
+ if (saveStack->del(saveStack->getLength() - 1)) {
+ writePS("q\n");
+ noStateChanges = gTrue;
+ } else {
+ noStateChanges = gFalse;
+ }
+ }
}
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
double m21, double m22, double m31, double m32) {
- if (fabs(m11 * m22 - m12 * m21) < 0.00001) {
+ if (m11 == 1 && m12 == 0 && m21 == 0 && m22 == 1 && m31 == 0 && m32 == 0) {
+ return;
+ }
+ if (fabs(m11 * m22 - m12 * m21) < 1e-10) {
// avoid a singular (or close-to-singular) matrix
- writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", m31, m32);
+ writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] cm\n", m31, m32);
} else {
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] cm\n",
m11, m12, m21, m22, m31, m32);
}
+ noStateChanges = gFalse;
}
void PSOutputDev::updateLineDash(GfxState *state) {
@@ -3759,26 +4518,32 @@ void PSOutputDev::updateLineDash(GfxState *state) {
(i == length-1) ? 0 : 1);
}
writePSFmt("] {0:.6g} d\n", start);
+ noStateChanges = gFalse;
}
void PSOutputDev::updateFlatness(GfxState *state) {
- writePSFmt("{0:d} i\n", state->getFlatness());
+ writePSFmt("{0:.4g} i\n", state->getFlatness());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateLineJoin(GfxState *state) {
writePSFmt("{0:d} j\n", state->getLineJoin());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateLineCap(GfxState *state) {
writePSFmt("{0:d} J\n", state->getLineCap());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateMiterLimit(GfxState *state) {
writePSFmt("{0:.4g} M\n", state->getMiterLimit());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateLineWidth(GfxState *state) {
writePSFmt("{0:.6g} w\n", state->getLineWidth());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateFillColorSpace(GfxState *state) {
@@ -3789,10 +4554,14 @@ void PSOutputDev::updateFillColorSpace(GfxState *state) {
case psLevel2:
case psLevel3:
if (state->getFillColorSpace()->getMode() != csPattern) {
- dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
+ dumpColorSpaceL2(state, state->getFillColorSpace(),
+ gTrue, gFalse, gFalse);
writePS(" cs\n");
+ noStateChanges = gFalse;
}
break;
+ case psLevel2Gray:
+ case psLevel3Gray:
case psLevel2Sep:
case psLevel3Sep:
break;
@@ -3807,10 +4576,14 @@ void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
case psLevel2:
case psLevel3:
if (state->getStrokeColorSpace()->getMode() != csPattern) {
- dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
+ dumpColorSpaceL2(state, state->getStrokeColorSpace(),
+ gTrue, gFalse, gFalse);
writePS(" CS\n");
+ noStateChanges = gFalse;
}
break;
+ case psLevel2Gray:
+ case psLevel3Gray:
case psLevel2Sep:
case psLevel3Sep:
break;
@@ -3828,6 +4601,8 @@ void PSOutputDev::updateFillColor(GfxState *state) {
switch (level) {
case psLevel1:
+ case psLevel2Gray:
+ case psLevel3Gray:
state->getFillGray(&gray);
writePSFmt("{0:.4g} g\n", colToDbl(gray));
break;
@@ -3859,13 +4634,13 @@ void PSOutputDev::updateFillColor(GfxState *state) {
if (state->getFillColorSpace()->getMode() == csSeparation) {
sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
color.c[0] = gfxColorComp1;
- sepCS->getCMYK(&color, &cmyk);
+ sepCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
colToDbl(state->getFillColor()->c[0]),
colToDbl(cmyk.c), colToDbl(cmyk.m),
colToDbl(cmyk.y), colToDbl(cmyk.k),
sepCS->getName());
- addCustomColor(sepCS);
+ addCustomColor(state, sepCS);
} else {
state->getFillCMYK(&cmyk);
c = colToDbl(cmyk.c);
@@ -3878,6 +4653,7 @@ void PSOutputDev::updateFillColor(GfxState *state) {
break;
}
t3Cacheable = gFalse;
+ noStateChanges = gFalse;
}
void PSOutputDev::updateStrokeColor(GfxState *state) {
@@ -3891,6 +4667,8 @@ void PSOutputDev::updateStrokeColor(GfxState *state) {
switch (level) {
case psLevel1:
+ case psLevel2Gray:
+ case psLevel3Gray:
state->getStrokeGray(&gray);
writePSFmt("{0:.4g} G\n", colToDbl(gray));
break;
@@ -3922,13 +4700,13 @@ void PSOutputDev::updateStrokeColor(GfxState *state) {
if (state->getStrokeColorSpace()->getMode() == csSeparation) {
sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
color.c[0] = gfxColorComp1;
- sepCS->getCMYK(&color, &cmyk);
+ sepCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
colToDbl(state->getStrokeColor()->c[0]),
colToDbl(cmyk.c), colToDbl(cmyk.m),
colToDbl(cmyk.y), colToDbl(cmyk.k),
sepCS->getName());
- addCustomColor(sepCS);
+ addCustomColor(state, sepCS);
} else {
state->getStrokeCMYK(&cmyk);
c = colToDbl(cmyk.c);
@@ -3941,6 +4719,7 @@ void PSOutputDev::updateStrokeColor(GfxState *state) {
break;
}
t3Cacheable = gFalse;
+ noStateChanges = gFalse;
}
void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
@@ -3958,7 +4737,8 @@ void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
}
}
-void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+void PSOutputDev::addCustomColor(GfxState *state,
+ GfxSeparationColorSpace *sepCS) {
PSOutCustomColor *cc;
GfxColor color;
GfxCMYK cmyk;
@@ -3969,7 +4749,7 @@ void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
}
}
color.c[0] = gfxColorComp1;
- sepCS->getCMYK(&color, &cmyk);
+ sepCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
colToDbl(cmyk.y), colToDbl(cmyk.k),
sepCS->getName()->copy());
@@ -3977,15 +4757,56 @@ void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
customColors = cc;
}
+void PSOutputDev::addCustomColors(GfxState *state,
+ GfxDeviceNColorSpace *devnCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int i;
+
+ for (i = 0; i < devnCS->getNComps(); ++i) {
+ color.c[i] = 0;
+ }
+ for (i = 0; i < devnCS->getNComps(); ++i) {
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(devnCS->getColorantName(i))) {
+ break;
+ }
+ }
+ if (cc) {
+ continue;
+ }
+ color.c[i] = gfxColorComp1;
+ devnCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
+ color.c[i] = 0;
+ cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ devnCS->getColorantName(i)->copy());
+ cc->next = customColors;
+ customColors = cc;
+ }
+}
+
void PSOutputDev::updateFillOverprint(GfxState *state) {
- if (level >= psLevel2) {
+ if (level == psLevel2 || level == psLevel2Sep ||
+ level == psLevel3 || level == psLevel3Sep) {
writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
+ noStateChanges = gFalse;
}
}
void PSOutputDev::updateStrokeOverprint(GfxState *state) {
- if (level >= psLevel2) {
+ if (level == psLevel2 || level == psLevel2Sep ||
+ level == psLevel3 || level == psLevel3Sep) {
writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
+ noStateChanges = gFalse;
+ }
+}
+
+void PSOutputDev::updateOverprintMode(GfxState *state) {
+ if (level == psLevel3 || level == psLevel3Sep) {
+ writePSFmt("{0:s} opm\n", state->getOverprintMode() ? "true" : "false");
+ noStateChanges = gFalse;
}
}
@@ -3995,7 +4816,8 @@ void PSOutputDev::updateTransfer(GfxState *state) {
funcs = state->getTransfer();
if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
- if (level >= psLevel2) {
+ if (level == psLevel2 || level == psLevel2Sep ||
+ level == psLevel3 || level == psLevel3Sep) {
for (i = 0; i < 4; ++i) {
cvtFunction(funcs[i]);
}
@@ -4010,6 +4832,7 @@ void PSOutputDev::updateTransfer(GfxState *state) {
} else {
writePS("{} settransfer\n");
}
+ noStateChanges = gFalse;
}
void PSOutputDev::updateFont(GfxState *state) {
@@ -4018,6 +4841,7 @@ void PSOutputDev::updateFont(GfxState *state) {
state->getFont()->getID()->num, state->getFont()->getID()->gen,
fabs(state->getFontSize()) < 0.0001 ? 0.0001
: state->getFontSize());
+ noStateChanges = gFalse;
}
}
@@ -4025,17 +4849,19 @@ void PSOutputDev::updateTextMat(GfxState *state) {
double *mat;
mat = state->getTextMat();
- if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
+ if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 1e-10) {
// avoid a singular (or close-to-singular) matrix
writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]);
} else {
writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n",
mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
}
+ noStateChanges = gFalse;
}
void PSOutputDev::updateCharSpace(GfxState *state) {
writePSFmt("{0:.6g} Tc\n", state->getCharSpace());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateRender(GfxState *state) {
@@ -4047,14 +4873,17 @@ void PSOutputDev::updateRender(GfxState *state) {
if (rm != 0 && rm != 3) {
t3Cacheable = gFalse;
}
+ noStateChanges = gFalse;
}
void PSOutputDev::updateRise(GfxState *state) {
writePSFmt("{0:.6g} Ts\n", state->getRise());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateWordSpace(GfxState *state) {
writePSFmt("{0:.6g} Tw\n", state->getWordSpace());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateHorizScaling(GfxState *state) {
@@ -4065,10 +4894,12 @@ void PSOutputDev::updateHorizScaling(GfxState *state) {
h = 0.01;
}
writePSFmt("{0:.6g} Tz\n", h);
+ noStateChanges = gFalse;
}
void PSOutputDev::updateTextPos(GfxState *state) {
writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY());
+ noStateChanges = gFalse;
}
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
@@ -4077,14 +4908,17 @@ void PSOutputDev::updateTextShift(GfxState *state, double shift) {
} else {
writePSFmt("{0:.6g} TJm\n", shift);
}
+ noStateChanges = gFalse;
}
void PSOutputDev::saveTextPos(GfxState *state) {
writePS("currentpoint\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::restoreTextPos(GfxState *state) {
writePS("m\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::stroke(GfxState *state) {
@@ -4096,23 +4930,43 @@ void PSOutputDev::stroke(GfxState *state) {
} else {
writePS("S\n");
}
+ noStateChanges = gFalse;
}
void PSOutputDev::fill(GfxState *state) {
doPath(state->getPath());
writePS("f\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::eoFill(GfxState *state) {
doPath(state->getPath());
writePS("f*\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *strRef,
- int paintType, Dict *resDict,
+ int paintType, int tilingType,
+ Dict *resDict,
double *mat, double *bbox,
int x0, int y0, int x1, int y1,
double xStep, double yStep) {
+ if (level <= psLevel1Sep) {
+ tilingPatternFillL1(state, gfx, strRef, paintType, tilingType,
+ resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
+ } else {
+ tilingPatternFillL2(state, gfx, strRef, paintType, tilingType,
+ resDict, mat, bbox, x0, y0, x1, y1, xStep, yStep);
+ }
+}
+
+void PSOutputDev::tilingPatternFillL1(GfxState *state, Gfx *gfx,
+ Object *strRef,
+ int paintType, int tilingType,
+ Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
PDFRectangle box;
Gfx *gfx2;
@@ -4174,6 +5028,65 @@ void PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *strRef,
writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
writePS("grestore\n");
+ noStateChanges = gFalse;
+}
+
+void PSOutputDev::tilingPatternFillL2(GfxState *state, Gfx *gfx,
+ Object *strRef,
+ int paintType, int tilingType,
+ Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ PDFRectangle box;
+ Gfx *gfx2;
+
+ // switch to pattern space
+ writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+
+ // define a pattern
+ writePSFmt("/xpdfTile{0:d}\n", numTilingPatterns);
+ writePS("<<\n");
+ writePS(" /PatternType 1\n");
+ writePSFmt(" /PaintType {0:d}\n", paintType);
+ writePSFmt(" /TilingType {0:d}\n", tilingType);
+ writePSFmt(" /BBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}]\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ writePSFmt(" /XStep {0:.6g}\n", xStep);
+ writePSFmt(" /YStep {0:.6g}\n", yStep);
+ writePS(" /PaintProc {\n");
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx2 = new Gfx(doc, this, resDict, &box, NULL);
+ gfx2->takeContentStreamStack(gfx);
+ t3FillColorOnly = paintType == 2;
+ inType3Char = gTrue;
+ ++numTilingPatterns;
+ gfx2->display(strRef);
+ --numTilingPatterns;
+ inType3Char = gFalse;
+ delete gfx2;
+ writePS(" }\n");
+ writePS(">> matrix makepattern def\n");
+
+ // set the pattern
+ if (paintType == 2) {
+ writePS("currentcolor ");
+ }
+ writePSFmt("xpdfTile{0:d} setpattern\n", numTilingPatterns);
+
+ // fill with the pattern
+ writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} rectfill\n",
+ x0 * xStep + bbox[0],
+ y0 * yStep + bbox[1],
+ (x1 - x0) * xStep + bbox[2],
+ (y1 - y0) * yStep + bbox[3]);
+
+ writePS("grestore\n");
+ noStateChanges = gFalse;
}
GBool PSOutputDev::functionShadedFill(GfxState *state,
@@ -4214,6 +5127,7 @@ GBool PSOutputDev::functionShadedFill(GfxState *state,
}
writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1);
+ noStateChanges = gFalse;
return gTrue;
}
@@ -4308,6 +5222,7 @@ GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) {
}
writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax);
+ noStateChanges = gFalse;
return gTrue;
}
@@ -4555,22 +5470,26 @@ GBool PSOutputDev::radialShadedFill(GfxState *state,
}
}
+ noStateChanges = gFalse;
return gTrue;
}
void PSOutputDev::clip(GfxState *state) {
doPath(state->getPath());
writePS("W\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::eoClip(GfxState *state) {
doPath(state->getPath());
writePS("W*\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::clipToStrokePath(GfxState *state) {
doPath(state->getPath());
writePS("Ws\n");
+ noStateChanges = gFalse;
}
void PSOutputDev::doPath(GfxPath *path) {
@@ -4784,7 +5703,11 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
}
writePSFmt("{0:.6g}", dxdy[i]);
}
- writePS("] Tj\n");
+ if (font->getType() == fontType3) {
+ writePS("] Tj3\n");
+ } else {
+ writePS("] Tj\n");
+ }
if (wMode) {
writePSFmt("{0:.6g} {1:.6g} rmoveto\n", tOriginX0, tOriginY0);
}
@@ -4792,15 +5715,18 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
gfree(dxdy);
delete s2;
- if (state->getRender() & 4) {
+ if ((state->getRender() & 4) && font->getType() != fontType3) {
haveTextClip = gTrue;
}
+
+ noStateChanges = gFalse;
}
void PSOutputDev::endTextObject(GfxState *state) {
if (haveTextClip) {
writePS("Tclip\n");
haveTextClip = gFalse;
+ noStateChanges = gFalse;
}
}
@@ -4813,19 +5739,22 @@ void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
switch (level) {
case psLevel1:
case psLevel1Sep:
- doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
+ doImageL1(ref, state, NULL, invert, inlineImg, str, width, height, len);
break;
case psLevel2:
+ case psLevel2Gray:
case psLevel2Sep:
- doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
+ doImageL2(ref, state, NULL, invert, inlineImg, str, width, height, len,
NULL, NULL, 0, 0, gFalse);
break;
case psLevel3:
+ case psLevel3Gray:
case psLevel3Sep:
- doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
+ doImageL3(ref, state, NULL, invert, inlineImg, str, width, height, len,
NULL, NULL, 0, 0, gFalse);
break;
}
+ noStateChanges = gFalse;
}
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
@@ -4838,24 +5767,28 @@ void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
colorMap->getBits() + 7) / 8);
switch (level) {
case psLevel1:
- doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ doImageL1(ref, state, colorMap, gFalse, inlineImg, str,
+ width, height, len);
break;
case psLevel1Sep:
//~ handle indexed, separation, ... color spaces
- doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
+ doImageL1Sep(state, colorMap, gFalse, inlineImg, str, width, height, len);
break;
case psLevel2:
+ case psLevel2Gray:
case psLevel2Sep:
- doImageL2(ref, colorMap, gFalse, inlineImg, str,
+ doImageL2(ref, state, colorMap, gFalse, inlineImg, str,
width, height, len, maskColors, NULL, 0, 0, gFalse);
break;
case psLevel3:
+ case psLevel3Gray:
case psLevel3Sep:
- doImageL3(ref, colorMap, gFalse, inlineImg, str,
+ doImageL3(ref, state, colorMap, gFalse, inlineImg, str,
width, height, len, maskColors, NULL, 0, 0, gFalse);
break;
}
t3Cacheable = gFalse;
+ noStateChanges = gFalse;
}
void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
@@ -4870,27 +5803,31 @@ void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
colorMap->getBits() + 7) / 8);
switch (level) {
case psLevel1:
- doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len);
+ doImageL1(ref, state, colorMap, gFalse, gFalse, str, width, height, len);
break;
case psLevel1Sep:
//~ handle indexed, separation, ... color spaces
- doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len);
+ doImageL1Sep(state, colorMap, gFalse, gFalse, str, width, height, len);
break;
case psLevel2:
+ case psLevel2Gray:
case psLevel2Sep:
- doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ doImageL2(ref, state, colorMap, gFalse, gFalse, str, width, height, len,
NULL, maskStr, maskWidth, maskHeight, maskInvert);
break;
case psLevel3:
+ case psLevel3Gray:
case psLevel3Sep:
- doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ doImageL3(ref, state, colorMap, gFalse, gFalse, str, width, height, len,
NULL, maskStr, maskWidth, maskHeight, maskInvert);
break;
}
t3Cacheable = gFalse;
+ noStateChanges = gFalse;
}
-void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL1(Object *ref, GfxState *state,
+ GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len) {
ImageStream *imgStr;
@@ -4966,7 +5903,7 @@ void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
// write the line
for (x = 0; x < width; ++x) {
imgStr->getPixel(pixBuf);
- colorMap->getGray(pixBuf, &gray);
+ colorMap->getGray(pixBuf, &gray, state->getRenderingIntent());
writePSFmt("{0:02x}", colToByte(gray));
if (++i == 32) {
writePSChar('\n');
@@ -5001,7 +5938,7 @@ void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
}
}
-void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL1Sep(GfxState *state, GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len) {
ImageStream *imgStr;
@@ -5030,7 +5967,7 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
// read the line
for (x = 0; x < width; ++x) {
imgStr->getPixel(pixBuf);
- colorMap->getCMYK(pixBuf, &cmyk);
+ colorMap->getCMYK(pixBuf, &cmyk, state->getRenderingIntent());
lineBuf[4*x+0] = colToByte(cmyk.c);
lineBuf[4*x+1] = colToByte(cmyk.m);
lineBuf[4*x+2] = colToByte(cmyk.y);
@@ -5060,17 +5997,13 @@ void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
gfree(lineBuf);
}
-void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL2(Object *ref, GfxState *state,
+ GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len,
int *maskColors, Stream *maskStr,
int maskWidth, int maskHeight, GBool maskInvert) {
Stream *str2;
- ImageStream *imgStr;
- Guchar *line;
- PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
- int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
- GBool emitRect, addRect, extendRect;
GString *s;
int n, numComps;
GBool useLZW, useRLE, useASCII, useASCIIHex, useCompressed;
@@ -5078,259 +6011,22 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
GfxColor color;
GfxCMYK cmyk;
char buf[4096];
- int c;
- int col, i, j, x0, x1, y, maskXor;
+ int c, col, i;
// color key masking
if (maskColors && colorMap && !inlineImg) {
// can't read the stream twice for inline images -- but masking
// isn't allowed with inline images anyway
- numComps = colorMap->getNumPixelComps();
- imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
- imgStr->reset();
- rects0Len = rects1Len = rectsOutLen = 0;
- rectsSize = rectsOutSize = 64;
- rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
- rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
- rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
- sizeof(PSOutImgClipRect));
- for (y = 0; y < height; ++y) {
- if (!(line = imgStr->getLine())) {
- break;
- }
- i = 0;
- rects1Len = 0;
- for (x0 = 0; x0 < width; ++x0) {
- for (j = 0; j < numComps; ++j) {
- if (line[x0*numComps+j] < maskColors[2*j] ||
- line[x0*numComps+j] > maskColors[2*j+1]) {
- break;
- }
- }
- if (j < numComps) {
- break;
- }
- }
- for (x1 = x0; x1 < width; ++x1) {
- for (j = 0; j < numComps; ++j) {
- if (line[x1*numComps+j] < maskColors[2*j] ||
- line[x1*numComps+j] > maskColors[2*j+1]) {
- break;
- }
- }
- if (j == numComps) {
- break;
- }
- }
- while (x0 < width || i < rects0Len) {
- emitRect = addRect = extendRect = gFalse;
- if (x0 >= width) {
- emitRect = gTrue;
- } else if (i >= rects0Len) {
- addRect = gTrue;
- } else if (rects0[i].x0 < x0) {
- emitRect = gTrue;
- } else if (x0 < rects0[i].x0) {
- addRect = gTrue;
- } else if (rects0[i].x1 == x1) {
- extendRect = gTrue;
- } else {
- emitRect = addRect = gTrue;
- }
- if (emitRect) {
- if (rectsOutLen == rectsOutSize) {
- rectsOutSize *= 2;
- rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
- sizeof(PSOutImgClipRect));
- }
- rectsOut[rectsOutLen].x0 = rects0[i].x0;
- rectsOut[rectsOutLen].x1 = rects0[i].x1;
- rectsOut[rectsOutLen].y0 = height - y - 1;
- rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
- ++rectsOutLen;
- ++i;
- }
- if (addRect || extendRect) {
- if (rects1Len == rectsSize) {
- rectsSize *= 2;
- rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
- sizeof(PSOutImgClipRect));
- rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
- sizeof(PSOutImgClipRect));
- }
- rects1[rects1Len].x0 = x0;
- rects1[rects1Len].x1 = x1;
- if (addRect) {
- rects1[rects1Len].y0 = y;
- }
- if (extendRect) {
- rects1[rects1Len].y0 = rects0[i].y0;
- ++i;
- }
- ++rects1Len;
- for (x0 = x1; x0 < width; ++x0) {
- for (j = 0; j < numComps; ++j) {
- if (line[x0*numComps+j] < maskColors[2*j] ||
- line[x0*numComps+j] > maskColors[2*j+1]) {
- break;
- }
- }
- if (j < numComps) {
- break;
- }
- }
- for (x1 = x0; x1 < width; ++x1) {
- for (j = 0; j < numComps; ++j) {
- if (line[x1*numComps+j] < maskColors[2*j] ||
- line[x1*numComps+j] > maskColors[2*j+1]) {
- break;
- }
- }
- if (j == numComps) {
- break;
- }
- }
- }
- }
- rectsTmp = rects0;
- rects0 = rects1;
- rects1 = rectsTmp;
- i = rects0Len;
- rects0Len = rects1Len;
- rects1Len = i;
- }
- for (i = 0; i < rects0Len; ++i) {
- if (rectsOutLen == rectsOutSize) {
- rectsOutSize *= 2;
- rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
- sizeof(PSOutImgClipRect));
- }
- rectsOut[rectsOutLen].x0 = rects0[i].x0;
- rectsOut[rectsOutLen].x1 = rects0[i].x1;
- rectsOut[rectsOutLen].y0 = height - y - 1;
- rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
- ++rectsOutLen;
- }
- writePSFmt("{0:d} {1:d}\n", maskWidth, maskHeight);
- for (i = 0; i < rectsOutLen; ++i) {
- writePSFmt("{0:d} {1:d} {2:d} {3:d} pr\n",
- rectsOut[i].x0, rectsOut[i].y0,
- rectsOut[i].x1 - rectsOut[i].x0,
- rectsOut[i].y1 - rectsOut[i].y0);
- }
- writePS("pop pop pdfImClip\n");
- gfree(rectsOut);
- gfree(rects0);
- gfree(rects1);
- delete imgStr;
- str->close();
+ convertColorKeyMaskToClipRects(colorMap, str, width, height, maskColors);
// explicit masking
} else if (maskStr) {
- imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
- imgStr->reset();
- rects0Len = rects1Len = rectsOutLen = 0;
- rectsSize = rectsOutSize = 64;
- rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
- rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
- rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
- sizeof(PSOutImgClipRect));
- maskXor = maskInvert ? 1 : 0;
- for (y = 0; y < maskHeight; ++y) {
- if (!(line = imgStr->getLine())) {
- break;
- }
- i = 0;
- rects1Len = 0;
- for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
- for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
- while (x0 < maskWidth || i < rects0Len) {
- emitRect = addRect = extendRect = gFalse;
- if (x0 >= maskWidth) {
- emitRect = gTrue;
- } else if (i >= rects0Len) {
- addRect = gTrue;
- } else if (rects0[i].x0 < x0) {
- emitRect = gTrue;
- } else if (x0 < rects0[i].x0) {
- addRect = gTrue;
- } else if (rects0[i].x1 == x1) {
- extendRect = gTrue;
- } else {
- emitRect = addRect = gTrue;
- }
- if (emitRect) {
- if (rectsOutLen == rectsOutSize) {
- rectsOutSize *= 2;
- rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
- sizeof(PSOutImgClipRect));
- }
- rectsOut[rectsOutLen].x0 = rects0[i].x0;
- rectsOut[rectsOutLen].x1 = rects0[i].x1;
- rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
- rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
- ++rectsOutLen;
- ++i;
- }
- if (addRect || extendRect) {
- if (rects1Len == rectsSize) {
- rectsSize *= 2;
- rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
- sizeof(PSOutImgClipRect));
- rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
- sizeof(PSOutImgClipRect));
- }
- rects1[rects1Len].x0 = x0;
- rects1[rects1Len].x1 = x1;
- if (addRect) {
- rects1[rects1Len].y0 = y;
- }
- if (extendRect) {
- rects1[rects1Len].y0 = rects0[i].y0;
- ++i;
- }
- ++rects1Len;
- for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
- for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
- }
- }
- rectsTmp = rects0;
- rects0 = rects1;
- rects1 = rectsTmp;
- i = rects0Len;
- rects0Len = rects1Len;
- rects1Len = i;
- }
- for (i = 0; i < rects0Len; ++i) {
- if (rectsOutLen == rectsOutSize) {
- rectsOutSize *= 2;
- rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
- sizeof(PSOutImgClipRect));
- }
- rectsOut[rectsOutLen].x0 = rects0[i].x0;
- rectsOut[rectsOutLen].x1 = rects0[i].x1;
- rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
- rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
- ++rectsOutLen;
- }
- writePSFmt("{0:d} {1:d}\n", maskWidth, maskHeight);
- for (i = 0; i < rectsOutLen; ++i) {
- writePSFmt("{0:d} {1:d} {2:d} {3:d} pr\n",
- rectsOut[i].x0, rectsOut[i].y0,
- rectsOut[i].x1 - rectsOut[i].x0,
- rectsOut[i].y1 - rectsOut[i].y0);
- }
- writePS("pop pop pdfImClip\n");
- gfree(rectsOut);
- gfree(rects0);
- gfree(rects1);
- delete imgStr;
- maskStr->close();
+ convertExplicitMaskToClipRects(maskStr, maskWidth, maskHeight, maskInvert);
}
// color space
- if (colorMap) {
- dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ if (colorMap && !(level == psLevel2Gray || level == psLevel3Gray)) {
+ dumpColorSpaceL2(state, colorMap->getColorSpace(), gFalse, gTrue, gFalse);
writePS(" setcolorspace\n");
}
@@ -5341,6 +6037,9 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
if (inlineImg) {
// create an array
str2 = new FixedLengthEncoder(str, len);
+ if (colorMap && (level == psLevel2Gray || level == psLevel3Gray)) {
+ str2 = new GrayRecoder(str2, width, height, colorMap);
+ }
if (globalParams->getPSLZW()) {
str2 = new LZWEncoder(str2);
} else {
@@ -5408,7 +6107,8 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
writePSFmt(" /Height {0:d}\n", height);
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
width, -height, height);
- if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ if (colorMap && (colorMap->getColorSpace()->getMode() == csDeviceN ||
+ level == psLevel2Gray || level == psLevel3Gray)) {
writePS(" /BitsPerComponent 8\n");
} else {
writePSFmt(" /BitsPerComponent {0:d}\n",
@@ -5424,6 +6124,8 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
n = (1 << colorMap->getBits()) - 1;
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
colorMap->getDecodeHigh(0) * n);
+ } else if (level == psLevel2Gray || level == psLevel3Gray) {
+ writePS("0 1");
} else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
getAlt()->getNComps();
@@ -5465,7 +6167,8 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
} else {
s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
" ");
- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ if ((colorMap && (colorMap->getColorSpace()->getMode() == csDeviceN ||
+ level == psLevel2Gray || level == psLevel3Gray)) ||
inlineImg || !s) {
if (globalParams->getPSLZW()) {
useLZW = gTrue;
@@ -5516,8 +6219,12 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
str = str->getUndecodedStream();
}
+ // recode to grayscale
+ if (colorMap && (level == psLevel2Gray || level == psLevel3Gray)) {
+ str = new GrayRecoder(str, width, height, colorMap);
+
// recode DeviceN data
- if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ } else if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
str = new DeviceNRecoder(str, width, height, colorMap);
}
@@ -5565,7 +6272,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
colorMap->getColorSpace()->getMode() == csSeparation) {
color.c[0] = gfxColorComp1;
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
- sepCS->getCMYK(&color, &cmyk);
+ sepCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
colToDbl(cmyk.c), colToDbl(cmyk.m),
colToDbl(cmyk.y), colToDbl(cmyk.k),
@@ -5601,8 +6308,276 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
}
}
+// Convert color key masking to a clipping region consisting of a
+// sequence of clip rectangles.
+void PSOutputDev::convertColorKeyMaskToClipRects(GfxImageColorMap *colorMap,
+ Stream *str,
+ int width, int height,
+ int *maskColors) {
+ ImageStream *imgStr;
+ Guchar *line;
+ PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+ int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+ GBool emitRect, addRect, extendRect;
+ int numComps, i, j, x0, x1, y;
+
+ numComps = colorMap->getNumPixelComps();
+ imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
+ imgStr->reset();
+ rects0Len = rects1Len = rectsOutLen = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ for (y = 0; y < height; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ while (x0 < width || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= width) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
+ sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ writePSFmt("{0:d} {1:d}\n", width, height);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("{0:d} {1:d} {2:d} {3:d} pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePS("pop pop pdfImClip\n");
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ str->close();
+}
+
+// Convert an explicit mask image to a clipping region consisting of a
+// sequence of clip rectangles.
+void PSOutputDev::convertExplicitMaskToClipRects(Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert) {
+ ImageStream *imgStr;
+ Guchar *line;
+ PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+ int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+ GBool emitRect, addRect, extendRect;
+ int i, x0, x1, y, maskXor;
+
+ imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ imgStr->reset();
+ rects0Len = rects1Len = rectsOutLen = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ maskXor = maskInvert ? 1 : 0;
+ for (y = 0; y < maskHeight; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ while (x0 < maskWidth || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= maskWidth) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
+ sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ writePSFmt("{0:d} {1:d}\n", maskWidth, maskHeight);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("{0:d} {1:d} {2:d} {3:d} pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePS("pop pop pdfImClip\n");
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ maskStr->close();
+}
+
//~ this doesn't currently support OPI
-void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL3(Object *ref, GfxState *state,
+ GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len,
int *maskColors, Stream *maskStr,
@@ -5627,11 +6602,26 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
maskFilters = NULL; // make gcc happy
// explicit masking
- if (maskStr) {
+ // -- this also converts color key masking in grayscale mode
+ if (maskStr || (maskColors && colorMap && level == psLevel3Gray)) {
// mask data source
- if ((mode == psModeForm || inType3Char || preload) &&
- globalParams->getPSUncompressPreloadedImages()) {
+ if (maskColors && colorMap && level == psLevel3Gray) {
+ s = NULL;
+ if (globalParams->getPSLZW()) {
+ maskUseLZW = gTrue;
+ maskUseRLE = gFalse;
+ } else {
+ maskUseRLE = gTrue;
+ maskUseLZW = gFalse;
+ }
+ maskUseASCII = gTrue;
+ maskUseCompressed = gFalse;
+ maskWidth = width;
+ maskHeight = height;
+ maskInvert = gFalse;
+ } else if ((mode == psModeForm || inType3Char || preload) &&
+ globalParams->getPSUncompressPreloadedImages()) {
s = NULL;
maskUseLZW = maskUseRLE = gFalse;
maskUseCompressed = gFalse;
@@ -5671,7 +6661,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
if (s) {
delete s;
}
- if (mode == psModeForm || inType3Char || preload) {
+ if ((mode == psModeForm || inType3Char || preload) &&
+ !(maskColors && colorMap && level == psLevel3Gray)) {
writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n",
ref->getRefNum(), ref->getRefGen());
} else {
@@ -5679,6 +6670,12 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
writePS(maskFilters->getCString());
writePS("pdfMask\n");
+ // add the ColorKeyToMask filter
+ if (maskColors && colorMap && level == psLevel3Gray) {
+ maskStr = new ColorKeyToMaskEncoder(str, width, height, colorMap,
+ maskColors);
+ }
+
// add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
if (maskUseCompressed) {
maskStr = maskStr->getUndecodedStream();
@@ -5713,8 +6710,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
}
// color space
- if (colorMap) {
- dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ if (colorMap && level != psLevel3Gray) {
+ dumpColorSpaceL2(state, colorMap->getColorSpace(), gFalse, gTrue, gFalse);
writePS(" setcolorspace\n");
}
@@ -5723,6 +6720,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
if (inlineImg) {
// create an array
str2 = new FixedLengthEncoder(str, len);
+ if (colorMap && level == psLevel3Gray) {
+ str2 = new GrayRecoder(str2, width, height, colorMap);
+ }
if (globalParams->getPSLZW()) {
str2 = new LZWEncoder(str2);
} else {
@@ -5783,17 +6783,18 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
}
// explicit masking
- if (maskStr) {
+ if (maskStr || (maskColors && colorMap && level == psLevel3Gray)) {
writePS("<<\n /ImageType 3\n");
writePS(" /InterleaveType 3\n");
writePS(" /DataDict\n");
}
// image (data) dictionary
- writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
+ writePSFmt("<<\n /ImageType {0:d}\n",
+ (maskColors && colorMap && level != psLevel3Gray) ? 4 : 1);
// color key masking
- if (maskColors && colorMap) {
+ if (maskColors && colorMap && level != psLevel3Gray) {
writePS(" /MaskColor [\n");
numComps = colorMap->getNumPixelComps();
for (i = 0; i < 2 * numComps; i += 2) {
@@ -5807,7 +6808,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
writePSFmt(" /Height {0:d}\n", height);
writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
width, -height, height);
- if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ if (colorMap && level == psLevel3Gray) {
writePS(" /BitsPerComponent 8\n");
} else {
writePSFmt(" /BitsPerComponent {0:d}\n",
@@ -5817,21 +6818,14 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
// decode
if (colorMap) {
writePS(" /Decode [");
- if ((level == psLevel2Sep || level == psLevel3Sep) &&
+ if (level == psLevel3Sep &&
colorMap->getColorSpace()->getMode() == csSeparation) {
// this matches up with the code in the pdfImSep operator
n = (1 << colorMap->getBits()) - 1;
writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
colorMap->getDecodeHigh(0) * n);
- } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
- numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
- getAlt()->getNComps();
- for (i = 0; i < numComps; ++i) {
- if (i > 0) {
- writePS(" ");
- }
- writePS("0 1");
- }
+ } else if (level == psLevel3Gray) {
+ writePS("0 1");
} else {
numComps = colorMap->getNumPixelComps();
for (i = 0; i < numComps; ++i) {
@@ -5862,10 +6856,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
useCompressed = gFalse;
useASCII = gFalse;
} else {
- s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
- " ");
- if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
- inlineImg || !s) {
+ s = str->getPSFilter(3, " ");
+ if ((colorMap && level == psLevel3Gray) || inlineImg || !s) {
if (globalParams->getPSLZW()) {
useLZW = gTrue;
useRLE = gFalse;
@@ -5902,7 +6894,7 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
writePS(">>\n");
// explicit masking
- if (maskStr) {
+ if (maskStr || (maskColors && colorMap && level == psLevel3Gray)) {
writePS(" /MaskDict\n");
writePS("<<\n");
writePS(" /ImageType 1\n");
@@ -5915,7 +6907,8 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
maskInvert ? 1 : 0, maskInvert ? 0 : 1);
// mask data source
- if (mode == psModeForm || inType3Char || preload) {
+ if ((mode == psModeForm || inType3Char || preload) &&
+ !(maskColors && colorMap && level == psLevel3Gray)) {
writePS(" /DataSource {pdfMaskSrc}\n");
writePS(maskFilters->getCString());
} else {
@@ -5934,11 +6927,11 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
} else {
- if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ if (level == psLevel3Sep && colorMap &&
colorMap->getColorSpace()->getMode() == csSeparation) {
color.c[0] = gfxColorComp1;
sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
- sepCS->getCMYK(&color, &cmyk);
+ sepCS->getCMYK(&color, &cmyk, state->getRenderingIntent());
writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
colToDbl(cmyk.c), colToDbl(cmyk.m),
colToDbl(cmyk.y), colToDbl(cmyk.k),
@@ -5963,9 +6956,9 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
str = str->getUndecodedStream();
}
- // recode DeviceN data
- if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
- str = new DeviceNRecoder(str, width, height, colorMap);
+ // recode to grayscale
+ if (colorMap && level == psLevel3Gray) {
+ str = new GrayRecoder(str, width, height, colorMap);
}
// add LZWEncode/RunLengthEncode and ASCIIHex/85 encode filters
@@ -6000,266 +6993,453 @@ void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
}
// close the mask stream
- if (maskStr) {
+ if (maskStr || (maskColors && colorMap && level == psLevel3Gray)) {
if (!(mode == psModeForm || inType3Char || preload)) {
writePS("pdfMaskEnd\n");
}
}
}
-void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
+void PSOutputDev::dumpColorSpaceL2(GfxState *state, GfxColorSpace *colorSpace,
GBool genXform, GBool updateColors,
GBool map01) {
- GfxCalGrayColorSpace *calGrayCS;
- GfxCalRGBColorSpace *calRGBCS;
- GfxLabColorSpace *labCS;
- GfxIndexedColorSpace *indexedCS;
- GfxSeparationColorSpace *separationCS;
- GfxDeviceNColorSpace *deviceNCS;
- GfxColorSpace *baseCS;
- Guchar *lookup, *p;
- double x[gfxColorMaxComps], y[gfxColorMaxComps];
- double low[gfxColorMaxComps], range[gfxColorMaxComps];
- GfxColor color;
- GfxCMYK cmyk;
- Function *func;
- int n, numComps, numAltComps;
- int byte;
- int i, j, k;
-
switch (colorSpace->getMode()) {
-
case csDeviceGray:
- writePS("/DeviceGray");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessBlack;
- }
+ dumpDeviceGrayColorSpace((GfxDeviceGrayColorSpace *)colorSpace,
+ genXform, updateColors, map01);
break;
-
case csCalGray:
- calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
- writePS("[/CIEBasedA <<\n");
- writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
- writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
- calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
- calGrayCS->getWhiteZ());
- writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
- calGrayCS->getWhiteZ());
- writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- calGrayCS->getBlackX(), calGrayCS->getBlackY(),
- calGrayCS->getBlackZ());
- writePS(">>]");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessBlack;
- }
+ dumpCalGrayColorSpace((GfxCalGrayColorSpace *)colorSpace,
+ genXform, updateColors, map01);
break;
-
case csDeviceRGB:
- writePS("/DeviceRGB");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessCMYK;
- }
+ dumpDeviceRGBColorSpace((GfxDeviceRGBColorSpace *)colorSpace,
+ genXform, updateColors, map01);
break;
-
case csCalRGB:
- calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
- writePS("[/CIEBasedABC <<\n");
- writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
- calRGBCS->getGammaR(), calRGBCS->getGammaG(),
- calRGBCS->getGammaB());
- writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
- calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
- calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
- calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
- calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
- calRGBCS->getMatrix()[8]);
- writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
- calRGBCS->getWhiteZ());
- writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- calRGBCS->getBlackX(), calRGBCS->getBlackY(),
- calRGBCS->getBlackZ());
- writePS(">>]");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessCMYK;
- }
+ dumpCalRGBColorSpace((GfxCalRGBColorSpace *)colorSpace,
+ genXform, updateColors, map01);
break;
-
case csDeviceCMYK:
- writePS("/DeviceCMYK");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessCMYK;
- }
+ dumpDeviceCMYKColorSpace((GfxDeviceCMYKColorSpace *)colorSpace,
+ genXform, updateColors, map01);
break;
-
case csLab:
- labCS = (GfxLabColorSpace *)colorSpace;
- writePS("[/CIEBasedABC <<\n");
- if (map01) {
- writePS(" /RangeABC [0 1 0 1 0 1]\n");
- writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
- (labCS->getAMax() - labCS->getAMin()) / 500.0,
- labCS->getAMin() / 500.0,
- (labCS->getBMax() - labCS->getBMin()) / 200.0,
- labCS->getBMin() / 200.0);
+ dumpLabColorSpace((GfxLabColorSpace *)colorSpace,
+ genXform, updateColors, map01);
+ break;
+ case csICCBased:
+ dumpICCBasedColorSpace(state, (GfxICCBasedColorSpace *)colorSpace,
+ genXform, updateColors, map01);
+ break;
+ case csIndexed:
+ dumpIndexedColorSpace(state, (GfxIndexedColorSpace *)colorSpace,
+ genXform, updateColors, map01);
+ break;
+ case csSeparation:
+ dumpSeparationColorSpace(state, (GfxSeparationColorSpace *)colorSpace,
+ genXform, updateColors, map01);
+ break;
+ case csDeviceN:
+ if (level >= psLevel3) {
+ dumpDeviceNColorSpaceL3(state, (GfxDeviceNColorSpace *)colorSpace,
+ genXform, updateColors, map01);
} else {
- writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
- labCS->getAMin(), labCS->getAMax(),
- labCS->getBMin(), labCS->getBMax());
- writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
- }
- writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
- writePS(" /DecodeLMN\n");
- writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
- writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
- labCS->getWhiteX());
- writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
- writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
- labCS->getWhiteY());
- writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
- writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
- labCS->getWhiteZ());
- writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
- writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
- labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
- writePS(">>]");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- processColors |= psProcessCMYK;
+ dumpDeviceNColorSpaceL2(state, (GfxDeviceNColorSpace *)colorSpace,
+ genXform, updateColors, map01);
}
break;
-
- case csICCBased:
- // there is no transform function to the alternate color space, so
- // we can use it directly
- dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
- genXform, updateColors, gFalse);
+ case csPattern:
+ //~ unimplemented
break;
+ }
+}
- case csIndexed:
- indexedCS = (GfxIndexedColorSpace *)colorSpace;
- baseCS = indexedCS->getBase();
- writePS("[/Indexed ");
- dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
- n = indexedCS->getIndexHigh();
- numComps = baseCS->getNComps();
- lookup = indexedCS->getLookup();
- writePSFmt(" {0:d} <\n", n);
- if (baseCS->getMode() == csDeviceN) {
- func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
- baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
- if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
- labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
- } else {
- labCS = NULL;
- }
- numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
- p = lookup;
- for (i = 0; i <= n; i += 8) {
- writePS(" ");
- for (j = i; j < i+8 && j <= n; ++j) {
- for (k = 0; k < numComps; ++k) {
- x[k] = low[k] + (*p++ / 255.0) * range[k];
- }
- func->transform(x, y);
- if (labCS) {
- y[0] /= 100.0;
- y[1] = (y[1] - labCS->getAMin()) /
- (labCS->getAMax() - labCS->getAMin());
- y[2] = (y[2] - labCS->getBMin()) /
- (labCS->getBMax() - labCS->getBMin());
- }
- for (k = 0; k < numAltComps; ++k) {
- byte = (int)(y[k] * 255 + 0.5);
- if (byte < 0) {
- byte = 0;
- } else if (byte > 255) {
- byte = 255;
- }
- writePSFmt("{0:02x}", byte);
- }
- if (updateColors) {
- color.c[0] = dblToCol(j);
- indexedCS->getCMYK(&color, &cmyk);
- addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
- colToDbl(cmyk.y), colToDbl(cmyk.k));
- }
- }
- writePS("\n");
- }
+void PSOutputDev::dumpDeviceGrayColorSpace(GfxDeviceGrayColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("/DeviceGray");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::dumpCalGrayColorSpace(GfxCalGrayColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("[/CIEBasedA <<\n");
+ writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", cs->getGamma());
+ writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getWhiteX(), cs->getWhiteY(), cs->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getWhiteX(), cs->getWhiteY(), cs->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getBlackX(), cs->getBlackY(), cs->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::dumpDeviceRGBColorSpace(GfxDeviceRGBColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("/DeviceRGB");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+}
+
+void PSOutputDev::dumpCalRGBColorSpace(GfxCalRGBColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("[/CIEBasedABC <<\n");
+ writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
+ cs->getGammaR(), cs->getGammaG(), cs->getGammaB());
+ writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
+ cs->getMatrix()[0], cs->getMatrix()[1], cs->getMatrix()[2],
+ cs->getMatrix()[3], cs->getMatrix()[4], cs->getMatrix()[5],
+ cs->getMatrix()[6], cs->getMatrix()[7], cs->getMatrix()[8]);
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getWhiteX(), cs->getWhiteY(), cs->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getBlackX(), cs->getBlackY(), cs->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+}
+
+void PSOutputDev::dumpDeviceCMYKColorSpace(GfxDeviceCMYKColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("/DeviceCMYK");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+}
+
+void PSOutputDev::dumpLabColorSpace(GfxLabColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("[/CIEBasedABC <<\n");
+ if (map01) {
+ writePS(" /RangeABC [0 1 0 1 0 1]\n");
+ writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
+ (cs->getAMax() - cs->getAMin()) / 500.0,
+ cs->getAMin() / 500.0,
+ (cs->getBMax() - cs->getBMin()) / 200.0,
+ cs->getBMin() / 200.0);
+ } else {
+ writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
+ cs->getAMin(), cs->getAMax(),
+ cs->getBMin(), cs->getBMax());
+ writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
+ }
+ writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
+ writePS(" /DecodeLMN\n");
+ writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ cs->getWhiteX());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ cs->getWhiteY());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
+ cs->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getWhiteX(), cs->getWhiteY(), cs->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ cs->getBlackX(), cs->getBlackY(), cs->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+}
+
+void PSOutputDev::dumpICCBasedColorSpace(GfxState *state,
+ GfxICCBasedColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ // there is no transform function to the alternate color space, so
+ // we can use it directly
+ dumpColorSpaceL2(state, cs->getAlt(), genXform, updateColors, gFalse);
+}
+
+
+void PSOutputDev::dumpIndexedColorSpace(GfxState *state,
+ GfxIndexedColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ GfxColorSpace *baseCS;
+ GfxLabColorSpace *labCS;
+ Guchar *lookup, *p;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
+ Function *func;
+ int n, numComps, numAltComps;
+ int byte;
+ int i, j, k;
+
+ baseCS = cs->getBase();
+ writePS("[/Indexed ");
+ dumpColorSpaceL2(state, baseCS, gFalse, updateColors, gTrue);
+ n = cs->getIndexHigh();
+ numComps = baseCS->getNComps();
+ lookup = cs->getLookup();
+ writePSFmt(" {0:d} <\n", n);
+ if (baseCS->getMode() == csDeviceN && level < psLevel3) {
+ func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
+ baseCS->getDefaultRanges(low, range, cs->getIndexHigh());
+ if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
+ labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
} else {
- for (i = 0; i <= n; i += 8) {
- writePS(" ");
- for (j = i; j < i+8 && j <= n; ++j) {
- for (k = 0; k < numComps; ++k) {
- writePSFmt("{0:02x}", lookup[j * numComps + k]);
- }
- if (updateColors) {
- color.c[0] = dblToCol(j);
- indexedCS->getCMYK(&color, &cmyk);
- addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
- colToDbl(cmyk.y), colToDbl(cmyk.k));
+ labCS = NULL;
+ }
+ numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
+ p = lookup;
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ x[k] = low[k] + (*p++ / 255.0) * range[k];
+ }
+ func->transform(x, y);
+ if (labCS) {
+ y[0] /= 100.0;
+ y[1] = (y[1] - labCS->getAMin()) /
+ (labCS->getAMax() - labCS->getAMin());
+ y[2] = (y[2] - labCS->getBMin()) /
+ (labCS->getBMax() - labCS->getBMin());
+ }
+ for (k = 0; k < numAltComps; ++k) {
+ byte = (int)(y[k] * 255 + 0.5);
+ if (byte < 0) {
+ byte = 0;
+ } else if (byte > 255) {
+ byte = 255;
}
+ writePSFmt("{0:02x}", byte);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ cs->getCMYK(&color, &cmyk, state->getRenderingIntent());
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
}
- writePS("\n");
}
+ writePS("\n");
}
- writePS(">]");
- if (genXform) {
- writePS(" {}");
+ } else {
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ writePSFmt("{0:02x}", lookup[j * numComps + k]);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ cs->getCMYK(&color, &cmyk, state->getRenderingIntent());
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ }
+ writePS("\n");
}
- break;
+ }
+ writePS(">]");
+ if (genXform) {
+ writePS(" {}");
+ }
+}
- case csSeparation:
- separationCS = (GfxSeparationColorSpace *)colorSpace;
- writePS("[/Separation ");
- writePSString(separationCS->getName());
+void PSOutputDev::dumpSeparationColorSpace(GfxState *state,
+ GfxSeparationColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ writePS("[/Separation ");
+ writePSString(cs->getName());
+ writePS(" ");
+ dumpColorSpaceL2(state, cs->getAlt(), gFalse, gFalse, gFalse);
+ writePS("\n");
+ cvtFunction(cs->getFunc());
+ writePS("]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ addCustomColor(state, cs);
+ }
+}
+
+void PSOutputDev::dumpDeviceNColorSpaceL2(GfxState *state,
+ GfxDeviceNColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ dumpColorSpaceL2(state, cs->getAlt(), gFalse, updateColors, map01);
+ if (genXform) {
writePS(" ");
- dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
+ cvtFunction(cs->getTintTransformFunc());
+ }
+}
+
+void PSOutputDev::dumpDeviceNColorSpaceL3(GfxState *state,
+ GfxDeviceNColorSpace *cs,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ GString *tint;
+ int i;
+
+ writePS("[/DeviceN [\n");
+ for (i = 0; i < cs->getNComps(); ++i) {
+ writePSString(cs->getColorantName(i));
writePS("\n");
- cvtFunction(separationCS->getFunc());
- writePS("]");
- if (genXform) {
- writePS(" {}");
- }
- if (updateColors) {
- addCustomColor(separationCS);
- }
- break;
+ }
+ writePS("]\n");
+ if ((tint = createDeviceNTintFunc(cs))) {
+ writePS("/DeviceCMYK\n");
+ writePS(tint->getCString());
+ delete tint;
+ } else {
+ dumpColorSpaceL2(state, cs->getAlt(), gFalse, gFalse, gFalse);
+ writePS("\n");
+ cvtFunction(cs->getTintTransformFunc());
+ }
+ writePS("]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ addCustomColors(state, cs);
+ }
+}
- case csDeviceN:
- // DeviceN color spaces are a Level 3 PostScript feature.
- deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
- dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
- if (genXform) {
- writePS(" ");
- cvtFunction(deviceNCS->getTintTransformFunc());
+// If the DeviceN color space has a Colorants dictionary, and all of
+// the colorants are one of: "None", "Cyan", "Magenta", "Yellow",
+// "Black", or have an entry in the Colorants dict that maps to
+// DeviceCMYK, then build a new tint function; else use the existing
+// tint function.
+GString *PSOutputDev::createDeviceNTintFunc(GfxDeviceNColorSpace *cs) {
+ Object *attrs;
+ Object colorants, sepCSObj, funcObj, obj1;
+ GString *name;
+ Function *func;
+ double sepIn;
+ double cmyk[gfxColorMaxComps][4];
+ GString *tint;
+ GBool first;
+ int i, j;
+
+ attrs = cs->getAttrs();
+ if (!attrs->isDict()) {
+ return NULL;
+ }
+ if (!attrs->dictLookup("Colorants", &colorants)->isDict()) {
+ colorants.free();
+ return NULL;
+ }
+ for (i = 0; i < cs->getNComps(); ++i) {
+ name = cs->getColorantName(i);
+ if (!name->cmp("None")) {
+ cmyk[i][0] = cmyk[i][1] = cmyk[i][2] = cmyk[i][3] = 0;
+ } else if (!name->cmp("Cyan")) {
+ cmyk[i][1] = cmyk[i][2] = cmyk[i][3] = 0;
+ cmyk[i][0] = 1;
+ } else if (!name->cmp("Magenta")) {
+ cmyk[i][0] = cmyk[i][2] = cmyk[i][3] = 0;
+ cmyk[i][1] = 1;
+ } else if (!name->cmp("Yellow")) {
+ cmyk[i][0] = cmyk[i][1] = cmyk[i][3] = 0;
+ cmyk[i][2] = 1;
+ } else if (!name->cmp("Black")) {
+ cmyk[i][0] = cmyk[i][1] = cmyk[i][2] = 0;
+ cmyk[i][3] = 1;
+ } else {
+ colorants.dictLookup(name->getCString(), &sepCSObj);
+ if (!sepCSObj.isArray() || sepCSObj.arrayGetLength() != 4) {
+ sepCSObj.free();
+ colorants.free();
+ return NULL;
+ }
+ if (!sepCSObj.arrayGet(0, &obj1)->isName("Separation")) {
+ obj1.free();
+ sepCSObj.free();
+ colorants.free();
+ return NULL;
+ }
+ obj1.free();
+ if (!sepCSObj.arrayGet(2, &obj1)->isName("DeviceCMYK")) {
+ obj1.free();
+ sepCSObj.free();
+ colorants.free();
+ return NULL;
+ }
+ obj1.free();
+ sepCSObj.arrayGet(3, &funcObj);
+ if (!(func = Function::parse(&funcObj))) {
+ funcObj.free();
+ sepCSObj.free();
+ colorants.free();
+ return NULL;
+ }
+ funcObj.free();
+ if (func->getInputSize() != 1 || func->getOutputSize() != 4) {
+ delete func;
+ sepCSObj.free();
+ colorants.free();
+ return NULL;
+ }
+ sepIn = 1;
+ func->transform(&sepIn, cmyk[i]);
+ delete func;
+ sepCSObj.free();
}
- break;
+ }
+ colorants.free();
- case csPattern:
- //~ unimplemented
- break;
+ tint = new GString();
+ tint->append("{\n");
+ for (j = 0; j < 4; ++j) { // C, M, Y, K
+ first = gTrue;
+ for (i = 0; i < cs->getNComps(); ++i) {
+ if (cmyk[i][j] != 0) {
+ tint->appendf("{0:d} index {1:.4f} mul{2:s}\n",
+ j + cs->getNComps() - 1 - i, cmyk[i][j],
+ first ? "" : " add");
+ first = gFalse;
+ }
+ }
+ if (first) {
+ tint->append("0\n");
+ }
+ }
+ tint->appendf("{0:d} 4 roll\n", cs->getNComps() + 4);
+ for (i = 0; i < cs->getNComps(); ++i) {
+ tint->append("pop\n");
}
+ tint->append("}\n");
+
+ return tint;
}
#if OPI_SUPPORT
@@ -6695,6 +7875,7 @@ void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy);
writePS("q\n");
t3NeedsRestore = gTrue;
+ noStateChanges = gFalse;
}
void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
@@ -6714,10 +7895,12 @@ void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
t3FillColorOnly = gTrue;
t3Cacheable = gTrue;
t3NeedsRestore = gTrue;
+ noStateChanges = gFalse;
}
void PSOutputDev::drawForm(Ref id) {
writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
+ noStateChanges = gFalse;
}
void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
@@ -6735,6 +7918,7 @@ void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
writePSBlock(buf, n);
}
str->close();
+ noStateChanges = gFalse;
}
//~ can nextFunc be reset to 0 -- maybe at the start of each page?