//
// PSOutputDev.cc
//
-// Copyright 1996 Derek B. Noonburg
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
#include <signal.h>
#include <math.h>
#include "GString.h"
-#include "config.h"
+#include "GList.h"
+#include "xpdfconfig.h"
+#include "GlobalParams.h"
#include "Object.h"
#include "Error.h"
+#include "Function.h"
+#include "Gfx.h"
#include "GfxState.h"
#include "GfxFont.h"
-#include "FontFile.h"
+#include "UnicodeMap.h"
+#include "FoFiType1C.h"
+#include "FoFiTrueType.h"
#include "Catalog.h"
#include "Page.h"
#include "Stream.h"
-#include "FormWidget.h"
+#include "Annot.h"
#include "PSOutputDev.h"
-#if JAPANESE_SUPPORT
-#include "Japan12ToRKSJ.h"
-#endif
-
#ifdef MACOS
// needed for setting type/creator of MacOS files
#include "ICSupport.h"
#endif
-//------------------------------------------------------------------------
-// Parameters
-//------------------------------------------------------------------------
-
-// Generate Level 1 PostScript?
-GBool psOutLevel1 = gFalse;
-
-// Generate Level 1 separable PostScript?
-GBool psOutLevel1Sep = gFalse;
-
-// Generate Encapsulated PostScript?
-GBool psOutEPS = gFalse;
-
-#if OPI_SUPPORT
-// Generate OPI comments?
-GBool psOutOPI = gFalse;
-#endif
-
-int paperWidth = defPaperWidth;
-int paperHeight = defPaperHeight;
-
//------------------------------------------------------------------------
// PostScript prolog and setup
//------------------------------------------------------------------------
static char *prolog[] = {
"/xpdf 75 dict def xpdf begin",
"% PDF special state",
- "/pdfDictSize 14 def",
+ "/pdfDictSize 15 def",
+ "~1",
+ "/pdfStates 64 array def",
+ " 0 1 63 {",
+ " pdfStates exch pdfDictSize dict",
+ " dup /pdfStateIdx 3 index put",
+ " put",
+ " } for",
+ "~a",
"/pdfSetup {",
- " 2 array astore",
+ " 3 1 roll 2 array astore",
" /setpagedevice where {",
- " pop 3 dict dup begin",
- " exch /PageSize exch def",
+ " pop 3 dict begin",
+ " /PageSize exch def",
" /ImagingBBox null def",
" /Policies 1 dict dup begin /PageSize 3 def end def",
- " end setpagedevice",
+ " { /Duplex true def } if",
+ " currentdict end setpagedevice",
" } {",
- " pop",
+ " pop pop",
" } ifelse",
"} def",
+ "~1",
+ "/pdfOpNames [",
+ " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
+ " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
+ " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
+ "] def",
+ "~a",
"/pdfStartPage {",
+ "~1",
+ " pdfStates 0 get begin",
+ "~2",
" pdfDictSize dict begin",
+ "~a",
" /pdfFill [0] def",
" /pdfStroke [0] def",
" /pdfLastFill false def",
" /pdfTextRise 0 def",
" /pdfWordSpacing 0 def",
" /pdfHorizScaling 1 def",
+ " /pdfTextClipPath [] def",
"} def",
"/pdfEndPage { end } def",
+ "% separation convention operators",
+ "/findcmykcustomcolor where {",
+ " pop",
+ "}{",
+ " /findcmykcustomcolor { 5 array astore } def",
+ "} ifelse",
+ "/setcustomcolor where {",
+ " pop",
+ "}{",
+ " /setcustomcolor {",
+ " exch",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace setcolor",
+ " } def",
+ "} ifelse",
+ "/customcolorimage where {",
+ " pop",
+ "}{",
+ " /customcolorimage {",
+ " gsave",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace",
+ " 10 dict begin",
+ " /ImageType 1 def",
+ " /DataSource exch def",
+ " /ImageMatrix exch def",
+ " /BitsPerComponent exch def",
+ " /Height exch def",
+ " /Width exch def",
+ " /Decode [1 0] def",
+ " currentdict end",
+ " image",
+ " grestore",
+ " } def",
+ "} ifelse",
+ "% PDF color state",
"/sCol {",
" pdfLastStroke not {",
" pdfStroke aload length",
- " dup 1 eq { pop setgray }",
- " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
" /pdfLastStroke true def /pdfLastFill false def",
" } if",
"} def",
"/fCol {",
" pdfLastFill not {",
" pdfFill aload length",
- " dup 1 eq { pop setgray }",
- " { 3 eq { setrgbcolor } { setcmykcolor } ifelse } ifelse",
+ " dup 1 eq {",
+ " pop setgray",
+ " }{",
+ " dup 3 eq {",
+ " pop setrgbcolor",
+ " }{",
+ " 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " } ifelse",
+ " } ifelse",
" /pdfLastFill true def /pdfLastStroke false def",
" } if",
"} def",
" end",
" definefont pop",
"} def",
- "/pdfMakeFont16 { findfont definefont pop } def",
+ "/pdfMakeFont16 {",
+ " exch findfont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /WMode exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "/pdfMakeFont16L3 {",
+ " 1 index /CIDFont resourcestatus {",
+ " pop pop 1 index /CIDFont findresource /CIDFontType known",
+ " } {",
+ " false",
+ " } ifelse",
+ " {",
+ " 0 eq { /Identity-H } { /Identity-V } ifelse",
+ " exch 1 array astore composefont pop",
+ " } {",
+ " pdfMakeFont16",
+ " } ifelse",
+ "} def",
"% graphics state operators",
+ "~1",
+ "/q {",
+ " gsave",
+ " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
+ " pdfStates pdfStateIdx 1 add get begin",
+ " pdfOpNames { exch def } forall",
+ "} def",
+ "~2",
"/q { gsave pdfDictSize dict begin } def",
+ "~a",
"/Q { end grestore } def",
"/cm { concat } def",
"/d { setdash } def",
" /pdfLastFill true def /pdfLastStroke false def } def",
"/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
" /pdfLastStroke true def /pdfLastFill false def } def",
+ "/ck { 6 copy 6 array astore /pdfFill exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/CK { 6 copy 6 array astore /pdfStroke exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
"% path segment operators",
"/m { moveto } def",
"/l { lineto } def",
"/h { closepath } def",
"% path painting operators",
"/S { sCol stroke } def",
+ "/Sf { fCol stroke } def",
"/f { fCol fill } def",
"/f* { fCol eofill } def",
"% clipping operators",
"/Td { pdfTextMat transform moveto } def",
"/Tm { /pdfTextMat exch def } def",
"% text string operators",
- "/Tj { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
- " 0 pdfTextRise pdfTextMat dtransform rmoveto",
- " pdfFontSize mul pdfHorizScaling mul",
- " 1 index stringwidth pdfTextMat idtransform pop",
- " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
- " pdfWordSpacing 0 pdfTextMat dtransform 32",
- " 4 3 roll pdfCharSpacing add 0 pdfTextMat dtransform",
- " 6 5 roll awidthshow",
- " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
+ "/cshow where {",
+ " pop",
+ " /cshow2 {",
+ " dup {",
+ " pop pop",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } exch cshow",
+ " pop pop",
+ " } def",
+ "}{",
+ " /cshow2 {",
+ " currentfont /FontType get 0 eq {",
+ " 0 2 2 index length 1 sub {",
+ " 2 copy get exch 1 add 2 index exch get",
+ " 2 copy exch 256 mul add",
+ " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
+ " 3 index exec",
+ " } for",
+ " } {",
+ " dup {",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } forall",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+ "/awcp {", // awidthcharpath
+ " exch {",
+ " false charpath",
+ " 5 index 5 index rmoveto",
+ " 6 index eq { 7 index 7 index rmoveto } if",
+ " } exch cshow2",
+ " 6 {pop} repeat",
+ "} def",
+ "/Tj {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 1 index stringwidth pdfTextMat idtransform pop",
+ " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16 {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform pop",
+ " sub exch div",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16V {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform exch pop",
+ " sub exch div",
+ " 0 pdfWordSpacing pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing add 0 exch",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj1 {",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " currentpoint 8 2 roll",
+ " pdfTextRender 1 and 0 eq {",
+ " 6 copy awidthshow",
+ " } if",
+ " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
+ " 7 index 7 index moveto",
+ " 6 copy",
+ " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+ " false awcp currentpoint stroke moveto",
+ " } if",
+ " pdfTextRender 4 and 0 ne {",
+ " 8 6 roll moveto",
+ " false awcp",
+ " /pdfTextClipPath [ pdfTextClipPath aload pop",
+ " {/moveto cvx}",
+ " {/lineto cvx}",
+ " {/curveto cvx}",
+ " {/closepath cvx}",
+ " pathforall ] def",
+ " currentpoint newpath moveto",
+ " } {",
+ " 8 {pop} repeat",
+ " } ifelse",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ "} def",
"/TJm { pdfFontSize 0.001 mul mul neg 0",
" pdfTextMat dtransform rmoveto } def",
+ "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
+ " pdfTextMat dtransform rmoveto } def",
+ "/Tclip { pdfTextClipPath cvx exec clip newpath",
+ " /pdfTextClipPath [] def } def",
+ "~1",
"% Level 1 image operators",
"/pdfIm1 {",
" /pdfImBuf1 4 index string def",
" /pdfImBuf1 4 index 7 add 8 idiv string def",
" { currentfile pdfImBuf1 readhexstring pop } imagemask",
"} def",
+ "/pdfImM1a {",
+ " { 2 copy get exch 1 add exch } imagemask",
+ " pop pop",
+ "} def",
+ "~2",
"% Level 2 image operators",
"/pdfImBuf 100 string def",
"/pdfIm {",
" not { pop exit } if",
" (%-EOD-) eq { exit } if } loop",
"} def",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+ " dup /Width get /pdfImBuf1 exch string def",
+ " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
+ " /pdfImDecodeLow exch def",
+ " begin Width Height BitsPerComponent ImageMatrix DataSource end",
+ " /pdfImData exch def",
+ " { pdfImData pdfImBuf1 readstring pop",
+ " 0 1 2 index length 1 sub {",
+ " 1 index exch 2 copy get",
+ " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
+ " 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
"/pdfImM {",
" fCol imagemask",
" { currentfile pdfImBuf readline",
" not { pop exit } if",
" (%-EOD-) eq { exit } if } loop",
"} def",
+ "~a",
+ "end",
+ NULL
+};
+
+static char *cmapProlog[] = {
+ "/CIDInit /ProcSet findresource begin",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-H def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-V def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " /WMode 1 def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
"end",
NULL
};
// Fonts
//------------------------------------------------------------------------
-struct PSFont {
- char *name; // PDF name
- char *psName; // PostScript name
-};
-
struct PSSubstFont {
char *psName; // PostScript name
double mWidth; // width of 'm' character
};
-static PSFont psFonts[] = {
- {"Courier", "Courier"},
- {"Courier-Bold", "Courier-Bold"},
- {"Courier-Oblique", "Courier-Bold"},
- {"Courier-BoldOblique", "Courier-BoldOblique"},
- {"Helvetica", "Helvetica"},
- {"Helvetica-Bold", "Helvetica-Bold"},
- {"Helvetica-Oblique", "Helvetica-Oblique"},
- {"Helvetica-BoldOblique", "Helvetica-BoldOblique"},
- {"Symbol", "Symbol"},
- {"Times-Roman", "Times-Roman"},
- {"Times-Bold", "Times-Bold"},
- {"Times-Italic", "Times-Italic"},
- {"Times-BoldItalic", "Times-BoldItalic"},
- {"ZapfDingbats", "ZapfDingbats"},
- {NULL}
+static char *psFonts[] = {
+ "Courier",
+ "Courier-Bold",
+ "Courier-Oblique",
+ "Courier-BoldOblique",
+ "Helvetica",
+ "Helvetica-Bold",
+ "Helvetica-Oblique",
+ "Helvetica-BoldOblique",
+ "Symbol",
+ "Times-Roman",
+ "Times-Bold",
+ "Times-Italic",
+ "Times-BoldItalic",
+ "ZapfDingbats",
+ NULL
};
static PSSubstFont psSubstFonts[] = {
{"Courier-BoldOblique", 0.600}
};
+// Encoding info for substitute 16-bit font
+struct PSFont16Enc {
+ Ref fontID;
+ GString *enc;
+};
+
//------------------------------------------------------------------------
-// PSOutputDev
+// process colors
//------------------------------------------------------------------------
-PSOutputDev::PSOutputDev(char *fileName, Catalog *catalog,
- int firstPage, int lastPage,
- GBool embedType11, GBool doForm1) {
- Page *page;
- Dict *resDict;
- FormWidgets *formWidgets;
- char **p;
- int pg;
- Object obj1, obj2;
+#define psProcessCyan 1
+#define psProcessMagenta 2
+#define psProcessYellow 4
+#define psProcessBlack 8
+#define psProcessCMYK 15
+
+//------------------------------------------------------------------------
+// PSOutCustomColor
+//------------------------------------------------------------------------
+
+class PSOutCustomColor {
+public:
+
+ PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA);
+ ~PSOutCustomColor();
+
+ double c, m, y, k;
+ GString *name;
+ PSOutCustomColor *next;
+};
+
+PSOutCustomColor::PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA) {
+ c = cA;
+ m = mA;
+ y = yA;
+ k = kA;
+ name = nameA;
+ next = NULL;
+}
+
+PSOutCustomColor::~PSOutCustomColor() {
+ delete name;
+}
+
+//------------------------------------------------------------------------
+// DeviceNRecoder
+//------------------------------------------------------------------------
+
+class DeviceNRecoder: public FilterStream {
+public:
+
+ DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA);
+ virtual ~DeviceNRecoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ 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 GBool isBinary(GBool last = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ GBool fillBuf();
+
+ int width, height;
+ GfxImageColorMap *colorMap;
+ Function *func;
+ ImageStream *imgStr;
+ int buf[gfxColorMaxComps];
+ int pixelIdx;
+ int bufIdx;
+ int bufSize;
+};
+
+DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA):
+ FilterStream(strA) {
+ width = widthA;
+ height = heightA;
+ colorMap = colorMapA;
+ imgStr = NULL;
+ pixelIdx = 0;
+ bufIdx = gfxColorMaxComps;
+ bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getTintTransformFunc();
+}
+
+DeviceNRecoder::~DeviceNRecoder() {
+ if (imgStr) {
+ delete imgStr;
+ }
+}
+
+void DeviceNRecoder::reset() {
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+}
+
+GBool DeviceNRecoder::fillBuf() {
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxColor color;
+ double y[gfxColorMaxComps];
int i;
- // initialize
- embedType1 = embedType11;
- doForm = doForm1;
+ if (pixelIdx >= width * height) {
+ return gFalse;
+ }
+ imgStr->getPixel(pixBuf);
+ colorMap->getColor(pixBuf, &color);
+ func->transform(color.c, y);
+ for (i = 0; i < bufSize; ++i) {
+ buf[i] = (int)(y[i] * 255 + 0.5);
+ }
+ bufIdx = 0;
+ ++pixelIdx;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+extern "C" {
+typedef void (*SignalFunc)(int);
+}
+
+static void outputToFile(void *stream, char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+
+PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA) {
+ FILE *f;
+ PSFileType fileTypeA;
+
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+
fontIDs = NULL;
fontFileIDs = NULL;
fontFileNames = NULL;
+ font16Enc = NULL;
+ xobjStack = NULL;
embFontList = NULL;
- f = NULL;
- if (doForm)
- lastPage = firstPage;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
// open file or pipe
- ok = gTrue;
if (!strcmp(fileName, "-")) {
- fileType = psStdout;
+ fileTypeA = psStdout;
f = stdout;
} else if (fileName[0] == '|') {
- fileType = psPipe;
+ fileTypeA = psPipe;
#ifdef HAVE_POPEN
#ifndef WIN32
- signal(SIGPIPE, (void (*)(int))SIG_IGN);
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
#endif
if (!(f = popen(fileName + 1, "w"))) {
error(-1, "Couldn't run print command '%s'", fileName);
return;
#endif
} else {
- fileType = psFile;
+ fileTypeA = psFile;
if (!(f = fopen(fileName, "w"))) {
error(-1, "Couldn't open PostScript file '%s'", fileName);
ok = gFalse;
}
}
+ init(outputToFile, f, fileTypeA,
+ xrefA, catalog, firstPage, lastPage, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+}
+
+PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
+ XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA) {
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+
+ fontIDs = NULL;
+ fontFileIDs = NULL;
+ fontFileNames = NULL;
+ font16Enc = NULL;
+ xobjStack = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
+
+ init(outputFuncA, outputStreamA, psGeneric,
+ xrefA, catalog, firstPage, lastPage, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+}
+
+void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA) {
+ Page *page;
+ PDFRectangle *box;
+
+ // initialize
+ ok = gTrue;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
+ fileType = fileTypeA;
+ xref = xrefA;
+ level = globalParams->getPSLevel();
+ mode = modeA;
+ paperWidth = globalParams->getPSPaperWidth();
+ paperHeight = globalParams->getPSPaperHeight();
+ imgLLX = imgLLXA;
+ imgLLY = imgLLYA;
+ imgURX = imgURXA;
+ imgURY = imgURYA;
+ if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
+ globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY);
+ }
+ if (paperWidth < 0 || paperHeight < 0) {
+ // this check is needed in case the document has zero pages
+ if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
+ page = catalog->getPage(firstPage);
+ paperWidth = (int)(page->getWidth() + 0.5);
+ paperHeight = (int)(page->getHeight() + 0.5);
+ } else {
+ paperWidth = 1;
+ paperHeight = 1;
+ }
+ imgLLX = imgLLY = 0;
+ imgURX = paperWidth;
+ imgURY = paperHeight;
+ }
+ manualCtrl = manualCtrlA;
+ if (mode == psModeForm) {
+ lastPage = firstPage;
+ }
+ processColors = 0;
+ inType3Char = gFalse;
+
+#if OPI_SUPPORT
+ // initialize OPI nesting levels
+ opi13Nest = 0;
+ opi20Nest = 0;
+#endif
+
+ tx0 = ty0 = 0;
+ xScale0 = yScale0 = 1;
+ rotate0 = 0;
+ clipLLX0 = clipLLY0 = 0;
+ clipURX0 = clipURY0 = -1;
+
// initialize fontIDs, fontFileIDs, and fontFileNames lists
fontIDSize = 64;
fontIDLen = 0;
fontFileNameSize = 64;
fontFileNameLen = 0;
fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
+ nextTrueTypeNum = 0;
+ font16EncLen = 0;
+ font16EncSize = 0;
+
+ xobjStack = new GList();
+ numSaves = 0;
// initialize embedded font resource comment list
embFontList = new GString();
- // write header
- if (doForm) {
- writePS("%%!PS-Adobe-3.0 Resource-Form\n");
- writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
- writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
- }
- writePS("%%%%EndComments\n");
- page = catalog->getPage(firstPage);
- writePS("32 dict dup begin\n");
- writePS("/BBox [%d %d %d %d] def\n",
- (int)page->getX1(), (int)page->getY1(),
- (int)page->getX2(), (int)page->getY2());
- writePS("/FormType 1 def\n");
- writePS("/Matrix [1 0 0 1 0 0] def\n");
- } else if (psOutEPS) {
- writePS("%%!PS-Adobe-3.0 EPSF-3.0\n");
- writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
- writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
- }
- page = catalog->getPage(firstPage);
- writePS("%%%%BoundingBox: %d %d %d %d\n",
- (int)floor(page->getX1()), (int)floor(page->getY1()),
- (int)ceil(page->getX2()), (int)ceil(page->getY2()));
- if (floor(page->getX1()) != ceil(page->getX1()) ||
- floor(page->getY1()) != ceil(page->getY1()) ||
- floor(page->getX2()) != ceil(page->getX2()) ||
- floor(page->getY2()) != ceil(page->getY2())) {
- writePS("%%%%HiResBoundingBox: %g %g %g %g\n",
- page->getX1(), page->getY1(),
- page->getX2(), page->getY2());
- }
- writePS("%%%%DocumentSuppliedResources: (atend)\n");
- writePS("%%%%EndComments\n");
- } else {
- writePS("%%!PS-Adobe-3.0\n");
- writePS("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
- writePS("%%%%LanguageLevel: %d\n",
- (psOutLevel1 || psOutLevel1Sep) ? 1 : 2);
- if (psOutLevel1Sep) {
- writePS("%%%%DocumentProcessColors: Cyan Magenta Yellow Black\n");
- }
- writePS("%%%%DocumentMedia: plain %d %d 0 () ()\n",
- paperWidth, paperHeight);
- writePS("%%%%Pages: %d\n", lastPage - firstPage + 1);
- writePS("%%%%EndComments\n");
- writePS("%%%%BeginDefaults\n");
- writePS("%%%%PageMedia: plain\n");
- writePS("%%%%EndDefaults\n");
- }
-
- // write prolog
- if (!doForm) {
- writePS("%%%%BeginProlog\n");
- }
- writePS("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
- for (p = prolog; *p; ++p) {
- writePS("%s\n", *p);
- }
- writePS("%%%%EndResource\n");
- if (!doForm) {
- writePS("%%%%EndProlog\n");
- }
-
- // set up fonts and images
- type3Warning = gFalse;
- if (doForm) {
- // swap the form and xpdf dicts
- writePS("xpdf end begin dup begin\n");
- } else {
- writePS("%%%%BeginSetup\n");
- writePS("xpdf begin\n");
- }
- for (pg = firstPage; pg <= lastPage; ++pg) {
- page = catalog->getPage(pg);
- if ((resDict = page->getResourceDict())) {
- setupResources(resDict);
+ 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)->getBox(),
+ catalog->getPage(firstPage)->getCropBox());
+ } else {
+ box = new PDFRectangle(0, 0, 1, 1);
+ writeHeader(firstPage, lastPage, box, box);
+ delete box;
}
- formWidgets = new FormWidgets(page->getAnnots(&obj1));
- obj1.free();
- for (i = 0; i < formWidgets->getNumWidgets(); ++i) {
- if (formWidgets->getWidget(i)->getAppearance(&obj1)->isStream()) {
- obj1.streamGetDict()->lookup("Resources", &obj2);
- if (obj2.isDict()) {
- setupResources(obj2.getDict());
- }
- obj2.free();
- }
- obj1.free();
+ if (mode != psModeForm) {
+ writePS("%%BeginProlog\n");
}
- delete formWidgets;
- }
- if (!doForm) {
-#if OPI_SUPPORT
- if (psOutOPI) {
- writePS("/opiMatrix matrix currentmatrix def\n");
+ writeXpdfProcset();
+ if (mode != psModeForm) {
+ writePS("%%EndProlog\n");
+ writePS("%%BeginSetup\n");
}
-#endif
- if (!psOutEPS) {
- writePS("%d %d pdfSetup\n", paperWidth, paperHeight);
+ writeDocSetup(catalog, firstPage, lastPage);
+ if (mode != psModeForm) {
+ writePS("%%EndSetup\n");
}
- writePS("%%%%EndSetup\n");
}
// initialize sequential page number
seqPage = 1;
-
-#if OPI_SUPPORT
- // initialize OPI nesting levels
- opi13Nest = 0;
- opi20Nest = 0;
-#endif
}
PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
int i;
- if (f) {
- if (doForm) {
- writePS("/Foo exch /Form defineresource pop\n");
- } else if (psOutEPS) {
- writePS("%%%%Trailer\n");
- writePS("end\n");
- writePS("%%%%DocumentSuppliedResources:\n");
- writePS("%s", embFontList->getCString());
- writePS("%%%%EOF\n");
- } else {
- writePS("%%%%Trailer\n");
- writePS("end\n");
- writePS("%%%%EOF\n");
+ if (ok) {
+ if (!manualCtrl) {
+ writePS("%%Trailer\n");
+ writeTrailer();
+ if (mode != psModeForm) {
+ writePS("%%EOF\n");
+ }
}
if (fileType == psFile) {
#ifdef MACOS
- ICS_MapRefNumAndAssign((short)f->handle);
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
#endif
- fclose(f);
+ fclose((FILE *)outputStream);
}
#ifdef HAVE_POPEN
else if (fileType == psPipe) {
- pclose(f);
+ pclose((FILE *)outputStream);
#ifndef WIN32
- signal(SIGPIPE, (void (*)(int))SIG_DFL);
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
#endif
}
#endif
}
gfree(fontFileNames);
}
+ if (font16Enc) {
+ for (i = 0; i < font16EncLen; ++i) {
+ delete font16Enc[i].enc;
+ }
+ gfree(font16Enc);
+ }
+ if (xobjStack) {
+ delete xobjStack;
+ }
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
+}
+
+void PSOutputDev::writeHeader(int firstPage, int lastPage,
+ PDFRectangle *mediaBox, PDFRectangle *cropBox) {
+ switch (mode) {
+ case psModePS:
+ writePS("%!PS-Adobe-3.0\n");
+ writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePSFmt("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 :
+ (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors: (atend)\n");
+ writePS("%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+ writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
+ paperWidth, paperHeight);
+ writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth, paperHeight);
+ writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1);
+ writePS("%%EndComments\n");
+ writePS("%%BeginDefaults\n");
+ writePS("%%PageMedia: plain\n");
+ writePS("%%EndDefaults\n");
+ break;
+ case psModeEPS:
+ writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
+ writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePSFmt("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 :
+ (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors: (atend)\n");
+ writePS("%%DocumentCustomColors: (atend)\n");
+ }
+ writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
+ (int)floor(cropBox->x1), (int)floor(cropBox->y1),
+ (int)ceil(cropBox->x2), (int)ceil(cropBox->y2));
+ if (floor(cropBox->x1) != ceil(cropBox->x1) ||
+ floor(cropBox->y1) != ceil(cropBox->y1) ||
+ floor(cropBox->x2) != ceil(cropBox->x2) ||
+ floor(cropBox->y2) != ceil(cropBox->y2)) {
+ writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n",
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
+ }
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+ writePS("%%EndComments\n");
+ break;
+ case psModeForm:
+ writePS("%!PS-Adobe-3.0 Resource-Form\n");
+ writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
+ writePSFmt("%%%%LanguageLevel: %d\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 :
+ (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors: (atend)\n");
+ writePS("%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+ writePS("%%EndComments\n");
+ writePS("32 dict dup begin\n");
+ writePSFmt("/BBox [%d %d %d %d] def\n",
+ (int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
+ (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ break;
+ }
+}
+
+void PSOutputDev::writeXpdfProcset() {
+ char prologLevel;
+ char **p;
+
+ writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
+ prologLevel = 'a';
+ for (p = prolog; *p; ++p) {
+ if ((*p)[0] == '~' && (*p)[1] == '1') {
+ prologLevel = '1';
+ } else if ((*p)[0] == '~' && (*p)[1] == '2') {
+ prologLevel = '2';
+ } else if ((*p)[0] == '~' && (*p)[1] == 'a') {
+ prologLevel = 'a';
+ } else if (prologLevel == 'a' ||
+ (prologLevel == '1' && level < psLevel2) ||
+ (prologLevel == '2' && level >= psLevel2)) {
+ writePSFmt("%s\n", *p);
+ }
+ }
+ writePS("%%EndResource\n");
+
+ if (level >= psLevel3) {
+ for (p = cmapProlog; *p; ++p) {
+ writePSFmt("%s\n", *p);
+ }
+ }
+}
+
+void PSOutputDev::writeDocSetup(Catalog *catalog,
+ int firstPage, int lastPage) {
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object obj1, obj2;
+ int pg, i;
+
+ if (mode == psModeForm) {
+ // swap the form and xpdf dicts
+ writePS("xpdf end begin dup begin\n");
+ } else {
+ writePS("xpdf begin\n");
+ }
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ page = catalog->getPage(pg);
+ if ((resDict = page->getResourceDict())) {
+ setupResources(resDict);
+ }
+ annots = new Annots(xref, page->getAnnots(&obj1));
+ obj1.free();
+ for (i = 0; i < annots->getNumAnnots(); ++i) {
+ if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
+ obj1.streamGetDict()->lookup("Resources", &obj2);
+ if (obj2.isDict()) {
+ setupResources(obj2.getDict());
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ delete annots;
+ }
+ if (mode != psModeForm) {
+ if (mode != psModeEPS && !manualCtrl) {
+ writePSFmt("%d %d %s pdfSetup\n",
+ paperWidth, paperHeight,
+ globalParams->getPSDuplex() ? "true" : "false");
+ }
+#if OPI_SUPPORT
+ if (globalParams->getPSOPI()) {
+ writePS("/opiMatrix matrix currentmatrix def\n");
+ }
+#endif
+ }
+}
+
+void PSOutputDev::writePageTrailer() {
+ if (mode != psModeForm) {
+ writePS("pdfEndPage\n");
+ }
+}
+
+void PSOutputDev::writeTrailer() {
+ PSOutCustomColor *cc;
+
+ if (mode == psModeForm) {
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("end\n");
+ writePS("%%DocumentSuppliedResources:\n");
+ writePS(embFontList->getCString());
+ if (level == psLevel1Sep || level == psLevel2Sep ||
+ level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
+ }
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt(" (%s)", cc->name->getCString());
+ }
+ writePS("\n");
+ writePS("%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt("%%%%+ %g %g %g %g (%s)\n",
+ cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
+ }
+ }
+ }
}
void PSOutputDev::setupResources(Dict *resDict) {
- Object xObjDict, xObj, resObj;
- int i;
+ Object xObjDict, xObjRef, xObj, resObj;
+ Ref ref0, ref1;
+ GBool skip;
+ int i, j;
setupFonts(resDict);
setupImages(resDict);
resDict->lookup("XObject", &xObjDict);
if (xObjDict.isDict()) {
for (i = 0; i < xObjDict.dictGetLength(); ++i) {
- xObjDict.dictGetVal(i, &xObj);
- if (xObj.isStream()) {
- xObj.streamGetDict()->lookup("Resources", &resObj);
- if (resObj.isDict()) {
- setupResources(resObj.getDict());
+
+ // avoid infinite recursion on XObjects
+ skip = gFalse;
+ if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
+ ref0 = xObjRef.getRef();
+ for (j = 0; j < xobjStack->getLength(); ++j) {
+ ref1 = *(Ref *)xobjStack->get(j);
+ if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
+ skip = gTrue;
+ break;
+ }
+ }
+ if (!skip) {
+ xobjStack->append(&ref0);
}
- resObj.free();
}
- xObj.free();
+ if (!skip) {
+
+ // process the XObject's resource dictionary
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ xObj.free();
+ }
+
+ if (xObjRef.isRef() && !skip) {
+ xobjStack->del(xobjStack->getLength() - 1);
+ }
+ xObjRef.free();
}
}
xObjDict.free();
}
void PSOutputDev::setupFonts(Dict *resDict) {
- Object fontDict;
+ Object obj1, obj2;
+ Ref r;
GfxFontDict *gfxFontDict;
GfxFont *font;
int i;
- resDict->lookup("Font", &fontDict);
- if (fontDict.isDict()) {
- gfxFontDict = new GfxFontDict(fontDict.getDict());
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
- font = gfxFontDict->getFont(i);
- setupFont(font);
+ if ((font = gfxFontDict->getFont(i))) {
+ setupFont(font, resDict);
+ }
}
delete gfxFontDict;
}
- fontDict.free();
+ obj1.free();
}
-void PSOutputDev::setupFont(GfxFont *font) {
+void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
Ref fontFileID;
GString *name;
- char *psName;
+ PSFontParam *fontParam;
+ GString *psName;
+ char type3Name[64], buf[16];
+ GBool subst;
+ UnicodeMap *uMap;
char *charName;
double xs, ys;
- GBool do16Bit;
int code;
double w1, w2;
double *fm;
// check if font is already set up
for (i = 0; i < fontIDLen; ++i) {
- if (fontIDs[i].num == font->getID().num &&
- fontIDs[i].gen == font->getID().gen)
+ if (fontIDs[i].num == font->getID()->num &&
+ fontIDs[i].gen == font->getID()->gen) {
return;
+ }
}
// add entry to fontIDs list
fontIDSize += 64;
fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
}
- fontIDs[fontIDLen++] = font->getID();
+ fontIDs[fontIDLen++] = *font->getID();
xs = ys = 1;
- do16Bit = gFalse;
+ subst = gFalse;
+
+ // check for resident 8-bit font
+ if (font->getName() &&
+ (fontParam = globalParams->getPSFont(font->getName()))) {
+ psName = new GString(fontParam->psFontName->getCString());
// check for embedded Type 1 font
- if (embedType1 && font->getType() == fontType1 &&
- font->getEmbeddedFontID(&fontFileID)) {
- psName = font->getEmbeddedFontName();
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1 &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedType1Font(&fontFileID, psName);
+ // check for embedded Type 1C font
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1C &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedType1CFont(font, &fontFileID, psName);
+
// check for external Type 1 font file
- } else if (embedType1 && font->getType() == fontType1 &&
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1 &&
font->getExtFontFile()) {
// this assumes that the PS font name matches the PDF font name
- psName = font->getName()->getCString();
- setupEmbeddedType1Font(font->getExtFontFile(), psName);
+ psName = font->getName()->copy();
+ setupExternalType1Font(font->getExtFontFile(), psName);
- // check for embedded Type 1C font
- } else if (embedType1 && font->getType() == fontType1C &&
+ // check for embedded TrueType font
+ } else if (globalParams->getPSEmbedTrueType() &&
+ font->getType() == fontTrueType &&
font->getEmbeddedFontID(&fontFileID)) {
- psName = font->getEmbeddedFontName();
- setupEmbeddedType1CFont(font, &fontFileID, psName);
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
- } else if (font->is16Bit() && font->getCharSet16() == font16AdobeJapan12) {
- psName = "Ryumin-Light-RKSJ";
- do16Bit = gTrue;
+ // check for external TrueType font file
+ } else if (globalParams->getPSEmbedTrueType() &&
+ font->getType() == fontTrueType &&
+ font->getExtFontFile()) {
+ psName = filterPSName(font->getName());
+ setupExternalTrueTypeFont(font, psName);
- // do font substitution
- } else {
- if (!type3Warning && font->getType() == fontType3) {
- error(-1, "This document uses Type 3 fonts - some text may not be correctly printed");
- type3Warning = gTrue;
- }
+ // check for embedded CID PostScript font
+ } else if (globalParams->getPSEmbedCIDPostScript() &&
+ font->getType() == fontCIDType0C &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedCIDType0Font(font, &fontFileID, psName);
+
+ // check for embedded CID TrueType font
+ } else if (globalParams->getPSEmbedCIDTrueType() &&
+ font->getType() == fontCIDType2 &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName);
+
+ } else if (font->getType() == fontType3) {
+ sprintf(type3Name, "T3_%d_%d",
+ font->getID()->num, font->getID()->gen);
+ psName = new GString(type3Name);
+ setupType3Font(font, psName, parentResDict);
+
+ // do 8-bit font substitution
+ } else if (!font->isCIDFont()) {
+ subst = gTrue;
name = font->getName();
psName = NULL;
if (name) {
- for (i = 0; psFonts[i].name; ++i) {
- if (name->cmp(psFonts[i].name) == 0) {
- psName = psFonts[i].psName;
+ for (i = 0; psFonts[i]; ++i) {
+ if (name->cmp(psFonts[i]) == 0) {
+ psName = new GString(psFonts[i]);
break;
}
}
}
if (!psName) {
- if (font->isFixedWidth())
+ if (font->isFixedWidth()) {
i = 8;
- else if (font->isSerif())
+ } else if (font->isSerif()) {
i = 4;
- else
+ } else {
i = 0;
- if (font->isBold())
+ }
+ if (font->isBold()) {
i += 2;
- if (font->isItalic())
+ }
+ if (font->isItalic()) {
i += 1;
- psName = psSubstFonts[i].psName;
- if ((code = font->getCharCode("m")) >= 0) {
- w1 = font->getWidth(code);
+ }
+ psName = new GString(psSubstFonts[i].psName);
+ for (code = 0; code < 256; ++code) {
+ if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
+ charName[0] == 'm' && charName[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)font)->getWidth(code);
} else {
w1 = 0;
}
ys = 1;
}
}
+
+ // do 16-bit font substitution
+ } else if ((fontParam = globalParams->
+ getPSFont16(font->getName(),
+ ((GfxCIDFont *)font)->getCollection(),
+ font->getWMode()))) {
+ subst = gTrue;
+ psName = fontParam->psFontName->copy();
+ if (font16EncLen >= font16EncSize) {
+ font16EncSize += 16;
+ font16Enc = (PSFont16Enc *)grealloc(font16Enc,
+ font16EncSize * sizeof(PSFont16Enc));
+ }
+ font16Enc[font16EncLen].fontID = *font->getID();
+ font16Enc[font16EncLen].enc = fontParam->encoding->copy();
+ if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
+ uMap->decRefCnt();
+ ++font16EncLen;
+ } else {
+ error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
+ font16Enc[font16EncLen].enc->getCString());
+ }
+
+ // give up - can't do anything with this font
+ } else {
+ error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
+ font->getName() ? font->getName()->getCString() : "(unnamed)",
+ ((GfxCIDFont *)font)->getCollection()
+ ? ((GfxCIDFont *)font)->getCollection()->getCString()
+ : "(unknown)");
+ return;
}
// generate PostScript code to set up the font
- if (do16Bit) {
- writePS("/F%d_%d /%s pdfMakeFont16\n",
- font->getID().num, font->getID().gen, psName);
+ if (font->isCIDFont()) {
+ if (level == psLevel3 || level == psLevel3Sep) {
+ writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
+ font->getID()->num, font->getID()->gen, psName->getCString(),
+ font->getWMode());
+ } else {
+ writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
+ font->getID()->num, font->getID()->gen, psName->getCString(),
+ font->getWMode());
+ }
} else {
- writePS("/F%d_%d /%s %g %g\n",
- font->getID().num, font->getID().gen, psName, xs, ys);
+ writePSFmt("/F%d_%d /%s %g %g\n",
+ font->getID()->num, font->getID()->gen, psName->getCString(),
+ xs, ys);
for (i = 0; i < 256; i += 8) {
- writePS((i == 0) ? "[ " : " ");
+ writePSFmt((i == 0) ? "[ " : " ");
for (j = 0; j < 8; ++j) {
- charName = font->getCharName(i+j);
- writePS("/%s", charName ? charName : ".notdef");
+ if (font->getType() == fontTrueType &&
+ !subst &&
+ !((Gfx8BitFont *)font)->getHasEncoding()) {
+ sprintf(buf, "c%02x", i+j);
+ charName = buf;
+ } else {
+ charName = ((Gfx8BitFont *)font)->getCharName(i+j);
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+ charName = "space";
+ }
+ }
+ writePS("/");
+ writePSName(charName ? charName : (char *)".notdef");
}
- writePS((i == 256-8) ? "]\n" : "\n");
+ writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
}
writePS("pdfMakeFont\n");
}
+
+ delete psName;
}
-void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) {
static char hexChar[17] = "0123456789abcdef";
- Object refObj, strObj, obj1, obj2;
+ Object refObj, strObj, obj1, obj2, obj3;
Dict *dict;
- int length1, length2;
+ int length1, length2, length3;
int c;
int start[4];
GBool binMode;
// get the font stream and info
refObj.initRef(id->num, id->gen);
- refObj.fetch(&strObj);
+ refObj.fetch(xref, &strObj);
refObj.free();
if (!strObj.isStream()) {
error(-1, "Embedded font file object is not a stream");
}
dict->lookup("Length1", &obj1);
dict->lookup("Length2", &obj2);
- if (!obj1.isInt() || !obj2.isInt()) {
+ dict->lookup("Length3", &obj3);
+ if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
error(-1, "Missing length fields in embedded font stream dictionary");
obj1.free();
obj2.free();
+ obj3.free();
goto err1;
}
length1 = obj1.getInt();
length2 = obj2.getInt();
+ length3 = obj3.getInt();
obj1.free();
obj2.free();
+ obj3.free();
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
// copy ASCII portion of font
strObj.streamReset();
- for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i)
- fputc(c, f);
+ for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
+ writePSChar(c);
+ }
// figure out if encrypted portion is binary or ASCII
binMode = gFalse;
// convert binary data to ASCII
if (binMode) {
for (i = 0; i < 4; ++i) {
- fputc(hexChar[(start[i] >> 4) & 0x0f], f);
- fputc(hexChar[start[i] & 0x0f], f);
+ writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
+ writePSChar(hexChar[start[i] & 0x0f]);
}
+ // 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;
while (i < length2) {
- if ((c = strObj.streamGetChar()) == EOF)
+ if ((c = strObj.streamGetChar()) == EOF) {
break;
- fputc(hexChar[(c >> 4) & 0x0f], f);
- fputc(hexChar[c & 0x0f], f);
- if (++i % 32 == 0)
- fputc('\n', f);
+ }
+ writePSChar(hexChar[(c >> 4) & 0x0f]);
+ writePSChar(hexChar[c & 0x0f]);
+ if (++i % 32 == 0) {
+ writePSChar('\n');
+ }
+ }
+ if (i % 32 > 0) {
+ writePSChar('\n');
}
- if (i % 32 > 0)
- fputc('\n', f);
// already in ASCII format -- just copy it
} else {
- for (i = 0; i < 4; ++i)
- fputc(start[i], f);
+ for (i = 0; i < 4; ++i) {
+ writePSChar(start[i]);
+ }
for (i = 4; i < length2; ++i) {
- if ((c = strObj.streamGetChar()) == EOF)
+ if ((c = strObj.streamGetChar()) == EOF) {
break;
- fputc(c, f);
+ }
+ writePSChar(c);
}
}
// write padding and "cleartomark"
- for (i = 0; i < 8; ++i)
+ for (i = 0; i < 8; ++i) {
writePS("00000000000000000000000000000000"
"00000000000000000000000000000000\n");
+ }
writePS("cleartomark\n");
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
- }
+ writePS("%%EndResource\n");
err1:
strObj.streamClose();
//~ This doesn't handle .pfb files or binary eexec data (which only
//~ happens in pfb files?).
-void PSOutputDev::setupEmbeddedType1Font(GString *fileName, char *psName) {
+void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
FILE *fontFile;
int c;
int i;
fontFileNames[fontFileNameLen++] = fileName->copy();
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
// copy the font file
if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
error(-1, "Couldn't open external font file");
return;
}
- while ((c = fgetc(fontFile)) != EOF)
- fputc(c, f);
+ while ((c = fgetc(fontFile)) != EOF) {
+ writePSChar(c);
+ }
fclose(fontFile);
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
- }
+ writePS("%%EndResource\n");
}
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
- char *psName) {
+ GString *psName) {
char *fontBuf;
int fontLen;
- Type1CFontConverter *cvt;
+ FoFiType1C *ffT1C;
int i;
// check if font is already embedded
fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- if (psOutEPS) {
- writePS("%%%%BeginResource: font %s\n", psName);
- embFontList->append("%%+ font ");
- embFontList->append(psName);
- embFontList->append("\n");
- }
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
// convert it to a Type 1 font
- fontBuf = font->readEmbFontFile(&fontLen);
- cvt = new Type1CFontConverter(fontBuf, fontLen, f);
- cvt->convert();
- delete cvt;
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ ffT1C->convertToType1(NULL, gTrue, outputFunc, outputStream);
+ delete ffT1C;
+ }
gfree(fontBuf);
// ending comment
- if (psOutEPS) {
- writePS("%%%%EndResource\n");
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char unique[32];
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ Gushort *codeToGID;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen) {
+ sprintf(unique, "_%d", nextTrueTypeNum++);
+ psName->append(unique);
+ break;
+ }
+ }
+
+ // add entry to fontFileIDs list
+ if (i == fontFileIDLen) {
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
}
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ gfree(codeToGID);
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) {
+ char unique[32];
+ GString *fileName;
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ Gushort *codeToGID;
+ int i;
+
+ // check if font is already embedded
+ fileName = font->getExtFontFile();
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!fontFileNames[i]->cmp(fileName)) {
+ sprintf(unique, "_%d", nextTrueTypeNum++);
+ psName->append(unique);
+ break;
+ }
+ }
+
+ // add entry to fontFileNames list
+ if (i == fontFileNameLen) {
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames =
+ (GString **)grealloc(fontFileNames,
+ fontFileNameSize * sizeof(GString *));
+ }
+ }
+ fontFileNames[fontFileNameLen++] = fileName->copy();
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readExtFontFile(&fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiType1C *ffT1C;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
+ }
+ delete ffT1C;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType2(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ outputFunc, outputStream);
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupType3Font(GfxFont *font, GString *psName,
+ Dict *parentResDict) {
+ Dict *resDict;
+ Dict *charProcs;
+ Object charProc;
+ Gfx *gfx;
+ PDFRectangle box;
+ double *m;
+ char buf[256];
+ int i;
+
+ // set up resources used by font
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ inType3Char = gTrue;
+ setupResources(resDict);
+ inType3Char = gFalse;
+ } else {
+ resDict = parentResDict;
+ }
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // font dictionary
+ writePS("8 dict begin\n");
+ writePS("/FontType 3 def\n");
+ m = font->getFontMatrix();
+ writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+ m = font->getFontBBox();
+ writePSFmt("/FontBBox [%g %g %g %g] def\n",
+ m[0], m[1], m[2], m[3]);
+ writePS("/Encoding 256 array def\n");
+ writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
+ writePS("/BuildGlyph {\n");
+ writePS(" exch /CharProcs get exch\n");
+ writePS(" 2 copy known not { pop /.notdef } if\n");
+ writePS(" get exec\n");
+ writePS("} bind def\n");
+ writePS("/BuildChar {\n");
+ writePS(" 1 index /Encoding get exch get\n");
+ writePS(" 1 index /BuildGlyph get exec\n");
+ writePS("} bind def\n");
+ if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
+ writePSFmt("/CharProcs %d dict def\n", charProcs->getLength());
+ writePS("CharProcs begin\n");
+ box.x1 = m[0];
+ box.y1 = m[1];
+ box.x2 = m[2];
+ box.y2 = m[3];
+ gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL);
+ inType3Char = gTrue;
+ t3Cacheable = gFalse;
+ for (i = 0; i < charProcs->getLength(); ++i) {
+ writePS("/");
+ writePSName(charProcs->getKey(i));
+ writePS(" {\n");
+ gfx->display(charProcs->getVal(i, &charProc));
+ charProc.free();
+ if (t3String) {
+ if (t3Cacheable) {
+ sprintf(buf, "%g %g %g %g %g %g setcachedevice\n",
+ t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
+ } else {
+ sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY);
+ }
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ (*outputFunc)(outputStream, t3String->getCString(),
+ t3String->getLength());
+ delete t3String;
+ t3String = NULL;
+ }
+ (*outputFunc)(outputStream, "Q\n", 2);
+ writePS("} def\n");
+ }
+ inType3Char = gFalse;
+ delete gfx;
+ writePS("end\n");
+ }
+ writePS("currentdict end\n");
+ writePSFmt("/%s exch definefont pop\n", psName->getCString());
+
+ // ending comment
+ writePS("%%EndResource\n");
}
void PSOutputDev::setupImages(Dict *resDict) {
Object xObjDict, xObj, xObjRef, subtypeObj;
int i;
- if (!doForm) {
+ if (!(mode == psModeForm || inType3Char)) {
return;
}
}
void PSOutputDev::setupImage(Ref id, Stream *str) {
+ GBool useASCIIHex;
int c;
int size, line, col, i;
// construct an encoder stream
- str = new ASCII85Encoder(str);
+ useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
+ globalParams->getPSASCIIHex();
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
// compute image data size
str->reset();
do {
c = str->getChar();
} while (c == '\n' || c == '\r');
- if (c == '~' || c == EOF) {
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
break;
}
if (c == 'z') {
++col;
} else {
++col;
- for (i = 1; i <= 4; ++i) {
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
do {
c = str->getChar();
} while (c == '\n' || c == '\r');
- if (c == '~' || c == EOF) {
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
break;
}
++col;
++size;
col = 0;
}
- } while (c != '~' && c != EOF);
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
++size;
- writePS("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
+ writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
+ str->close();
// write the data into the array
str->reset();
line = col = 0;
- writePS("dup 0 <~");
+ writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
do {
do {
c = str->getChar();
} while (c == '\n' || c == '\r');
- if (c == '~' || c == EOF) {
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
break;
}
if (c == 'z') {
- fputc(c, f);
+ writePSChar(c);
++col;
} else {
- fputc(c, f);
+ writePSChar(c);
++col;
- for (i = 1; i <= 4; ++i) {
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
do {
c = str->getChar();
} while (c == '\n' || c == '\r');
- if (c == '~' || c == EOF) {
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
break;
}
- fputc(c, f);
+ writePSChar(c);
++col;
}
}
// chunks are 1 or 4 bytes each, so we have to stop at 232
// but make it 225 just to be safe
if (col > 225) {
- writePS("~> put\n");
+ writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
++line;
- writePS("dup %d <~", line);
+ writePSFmt((char *)(useASCIIHex ? "dup %d <" : "dup %d <~"), line);
col = 0;
}
- } while (c != '~' && c != EOF);
- writePS("~> put\n");
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
writePS("pop\n");
+ str->close();
delete str;
-}
-
-void PSOutputDev::startPage(int pageNum, GfxState *state) {
- int x1, y1, x2, y2, width, height, t;
-
- if (doForm) {
-
- writePS("/PaintProc {\n");
- writePS("begin xpdf begin\n");
- writePS("pdfStartPage\n");
- tx = ty = 0;
- xScale = yScale = 1;
- landscape = gFalse;
+}
- } else if (psOutEPS) {
+void PSOutputDev::startPage(int pageNum, GfxState *state) {
+ int x1, y1, x2, y2, width, height;
+ int imgWidth, imgHeight, imgWidth2, imgHeight2;
- writePS("pdfStartPage\n");
- tx = ty = 0;
- xScale = yScale = 1;
- landscape = gFalse;
- } else {
+ switch (mode) {
- writePS("%%%%Page: %d %d\n", pageNum, seqPage);
- writePS("%%%%BeginPageSetup\n");
+ case psModePS:
+ writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage);
+ writePS("%%BeginPageSetup\n");
// rotate, translate, and scale page
+ imgWidth = imgURX - imgLLX;
+ imgHeight = imgURY - imgLLY;
x1 = (int)(state->getX1() + 0.5);
y1 = (int)(state->getY1() + 0.5);
x2 = (int)(state->getX2() + 0.5);
y2 = (int)(state->getY2() + 0.5);
width = x2 - x1;
height = y2 - y1;
- if (width > height && width > paperWidth) {
- landscape = gTrue;
- writePS("%%%%PageOrientation: Landscape\n");
+ tx = ty = 0;
+ // portrait or landscape
+ if (width > height && width > imgWidth) {
+ rotate = 90;
+ writePSFmt("%%%%PageOrientation: %s\n",
+ state->getCTM()[0] ? "Landscape" : "Portrait");
writePS("pdfStartPage\n");
writePS("90 rotate\n");
- tx = -x1;
- ty = -(y1 + paperWidth);
- t = width;
- width = height;
- height = t;
+ ty = -imgWidth;
+ imgWidth2 = imgHeight;
+ imgHeight2 = imgWidth;
} else {
- landscape = gFalse;
- writePS("%%%%PageOrientation: Portrait\n");
+ rotate = 0;
+ writePSFmt("%%%%PageOrientation: %s\n",
+ state->getCTM()[0] ? "Portrait" : "Landscape");
writePS("pdfStartPage\n");
- tx = -x1;
- ty = -y1;
- }
- if (width < paperWidth) {
- tx += (paperWidth - width) / 2;
- }
- if (height < paperHeight) {
- ty += (paperHeight - height) / 2;
- }
- if (tx != 0 || ty != 0) {
- writePS("%g %g translate\n", tx, ty);
- }
- if (width > paperWidth || height > paperHeight) {
- xScale = (double)paperWidth / (double)width;
- yScale = (double)paperHeight / (double)height;
+ imgWidth2 = imgWidth;
+ imgHeight2 = imgHeight;
+ }
+ // shrink or expand
+ if ((globalParams->getPSShrinkLarger() &&
+ (width > imgWidth2 || height > imgHeight2)) ||
+ (globalParams->getPSExpandSmaller() &&
+ (width < imgWidth2 && height < imgHeight2))) {
+ xScale = (double)imgWidth2 / (double)width;
+ yScale = (double)imgHeight2 / (double)height;
if (yScale < xScale) {
xScale = yScale;
+ } else {
+ yScale = xScale;
}
- writePS("%0.4f %0.4f scale\n", xScale, xScale);
} else {
xScale = yScale = 1;
}
+ // deal with odd bounding boxes
+ tx -= xScale * x1;
+ ty -= yScale * y1;
+ // center
+ if (globalParams->getPSCenter()) {
+ tx += (imgWidth2 - xScale * width) / 2;
+ ty += (imgHeight2 - yScale * height) / 2;
+ }
+ tx += imgLLX + tx0;
+ ty += imgLLY + ty0;
+ xScale *= xScale0;
+ yScale *= yScale0;
+ if (tx != 0 || ty != 0) {
+ writePSFmt("%g %g translate\n", tx, ty);
+ }
+ if (xScale != 1 || yScale != 1) {
+ writePSFmt("%0.4f %0.4f scale\n", xScale, xScale);
+ }
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ writePSFmt("%g %g %g %g re W\n",
+ clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
+ }
- writePS("%%%%EndPageSetup\n");
+ writePS("%%EndPageSetup\n");
++seqPage;
+ break;
+
+ case psModeEPS:
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ rotate = 0;
+ break;
+
+ case psModeForm:
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ rotate = 0;
+ break;
+ }
+
+ if (underlayCbk) {
+ (*underlayCbk)(this, underlayCbkData);
}
}
void PSOutputDev::endPage() {
- if (doForm) {
+ if (overlayCbk) {
+ (*overlayCbk)(this, overlayCbkData);
+ }
+
+
+ if (mode == psModeForm) {
writePS("pdfEndPage\n");
writePS("end end\n");
writePS("} def\n");
writePS("end end\n");
} else {
- writePS("showpage\n");
- writePS("%%%%PageTrailer\n");
- writePS("pdfEndPage\n");
+ if (!manualCtrl) {
+ writePS("showpage\n");
+ writePS("%%PageTrailer\n");
+ writePageTrailer();
+ }
}
}
void PSOutputDev::saveState(GfxState *state) {
writePS("q\n");
+ ++numSaves;
}
void PSOutputDev::restoreState(GfxState *state) {
writePS("Q\n");
+ --numSaves;
}
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
double m21, double m22, double m31, double m32) {
- writePS("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
+ writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
}
void PSOutputDev::updateLineDash(GfxState *state) {
state->getLineDash(&dash, &length, &start);
writePS("[");
for (i = 0; i < length; ++i)
- writePS("%g%s", dash[i], (i == length-1) ? "" : " ");
- writePS("] %g d\n", start);
+ writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " ");
+ writePSFmt("] %g d\n", start);
}
void PSOutputDev::updateFlatness(GfxState *state) {
- writePS("%d i\n", state->getFlatness());
+ writePSFmt("%d i\n", state->getFlatness());
}
void PSOutputDev::updateLineJoin(GfxState *state) {
- writePS("%d j\n", state->getLineJoin());
+ writePSFmt("%d j\n", state->getLineJoin());
}
void PSOutputDev::updateLineCap(GfxState *state) {
- writePS("%d J\n", state->getLineCap());
+ writePSFmt("%d J\n", state->getLineCap());
}
void PSOutputDev::updateMiterLimit(GfxState *state) {
- writePS("%g M\n", state->getMiterLimit());
+ writePSFmt("%g M\n", state->getMiterLimit());
}
void PSOutputDev::updateLineWidth(GfxState *state) {
- writePS("%g w\n", state->getLineWidth());
+ writePSFmt("%g w\n", state->getLineWidth());
}
void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor color;
+ double gray;
GfxRGB rgb;
GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
- if (psOutLevel1Sep) {
+ switch (level) {
+ case psLevel1:
+ state->getFillGray(&gray);
+ writePSFmt("%g g\n", gray);
+ break;
+ case psLevel1Sep:
state->getFillCMYK(&cmyk);
- writePS("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
- } else {
- state->getFillRGB(&rgb);
- if (rgb.r == rgb.g && rgb.g == rgb.b) {
- writePS("%g g\n", rgb.r);
+ writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
+ state->getFillCMYK(&cmyk);
+ writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ } else {
+ state->getFillRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePSFmt("%g g\n", rgb.r);
+ } else {
+ writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getFillColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("%g %g %g %g %g (%s) ck\n",
+ state->getFillColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
} else {
- writePS("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
+ state->getFillCMYK(&cmyk);
+ writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
}
+ break;
}
+ t3Cacheable = gFalse;
}
void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor color;
+ double gray;
GfxRGB rgb;
GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
- if (psOutLevel1Sep) {
+ switch (level) {
+ case psLevel1:
+ state->getStrokeGray(&gray);
+ writePSFmt("%g G\n", gray);
+ break;
+ case psLevel1Sep:
state->getStrokeCMYK(&cmyk);
- writePS("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
- } else {
- state->getStrokeRGB(&rgb);
- if (rgb.r == rgb.g && rgb.g == rgb.b) {
- writePS("%g G\n", rgb.r);
+ writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
+ state->getStrokeCMYK(&cmyk);
+ writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ } else {
+ state->getStrokeRGB(&rgb);
+ if (rgb.r == rgb.g && rgb.g == rgb.b) {
+ writePSFmt("%g G\n", rgb.r);
+ } else {
+ writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+ }
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getStrokeColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("%g %g %g %g %g (%s) CK\n",
+ state->getStrokeColor()->c[0],
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ addCustomColor(sepCS);
} else {
- writePS("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
+ state->getStrokeCMYK(&cmyk);
+ writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
+ if (c > 0) {
+ processColors |= psProcessCyan;
+ }
+ if (m > 0) {
+ processColors |= psProcessMagenta;
+ }
+ if (y > 0) {
+ processColors |= psProcessYellow;
+ }
+ if (k > 0) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(sepCS->getName())) {
+ return;
}
}
+ color.c[0] = 1;
+ sepCS->getCMYK(&color, &cmyk);
+ cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->copy());
+ cc->next = customColors;
+ customColors = cc;
}
void PSOutputDev::updateFont(GfxState *state) {
if (state->getFont()) {
- writePS("/F%d_%d %g Tf\n",
- state->getFont()->getID().num, state->getFont()->getID().gen,
- state->getFontSize());
+ writePSFmt("/F%d_%d %g Tf\n",
+ state->getFont()->getID()->num, state->getFont()->getID()->gen,
+ state->getFontSize());
}
}
double *mat;
mat = state->getTextMat();
- writePS("[%g %g %g %g %g %g] Tm\n",
- mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("[%g %g %g %g %g %g] Tm\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
}
void PSOutputDev::updateCharSpace(GfxState *state) {
- writePS("%g Tc\n", state->getCharSpace());
+ writePSFmt("%g Tc\n", state->getCharSpace());
}
void PSOutputDev::updateRender(GfxState *state) {
- writePS("%d Tr\n", state->getRender());
+ int rm;
+
+ rm = state->getRender();
+ writePSFmt("%d Tr\n", rm);
+ rm &= 3;
+ if (rm != 0 && rm != 3) {
+ t3Cacheable = gFalse;
+ }
}
void PSOutputDev::updateRise(GfxState *state) {
- writePS("%g Ts\n", state->getRise());
+ writePSFmt("%g Ts\n", state->getRise());
}
void PSOutputDev::updateWordSpace(GfxState *state) {
- writePS("%g Tw\n", state->getWordSpace());
+ writePSFmt("%g Tw\n", state->getWordSpace());
}
void PSOutputDev::updateHorizScaling(GfxState *state) {
- writePS("%g Tz\n", state->getHorizScaling());
+ double h;
+
+ if ((h = state->getHorizScaling()) < 0.01) {
+ h = 0.01;
+ }
+ writePSFmt("%g Tz\n", h);
}
void PSOutputDev::updateTextPos(GfxState *state) {
- writePS("%g %g Td\n", state->getLineX(), state->getLineY());
+ writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY());
}
void PSOutputDev::updateTextShift(GfxState *state, double shift) {
- writePS("%g TJm\n", shift);
+ if (state->getFont()->getWMode()) {
+ writePSFmt("%g TJmV\n", shift);
+ } else {
+ writePSFmt("%g TJm\n", shift);
+ }
}
void PSOutputDev::stroke(GfxState *state) {
doPath(state->getPath());
- writePS("S\n");
+ if (t3String) {
+ // if we're construct a cacheable Type 3 glyph, we need to do
+ // everything in the fill color
+ writePS("Sf\n");
+ } else {
+ writePS("S\n");
+ }
}
void PSOutputDev::fill(GfxState *state) {
x3 = subpath->getX(3);
y3 = subpath->getY(3);
if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
- writePS("%g %g %g %g re\n",
- x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
- fabs(x2 - x0), fabs(y1 - y0));
+ writePSFmt("%g %g %g %g re\n",
+ x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+ fabs(x2 - x0), fabs(y1 - y0));
return;
} else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
- writePS("%g %g %g %g re\n",
- x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
- fabs(x1 - x0), fabs(y2 - y0));
+ writePSFmt("%g %g %g %g re\n",
+ x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+ fabs(x1 - x0), fabs(y2 - y0));
return;
}
}
for (i = 0; i < n; ++i) {
subpath = path->getSubpath(i);
m = subpath->getNumPoints();
- writePS("%g %g m\n", subpath->getX(0), subpath->getY(0));
+ writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0));
j = 1;
while (j < m) {
if (subpath->getCurve(j)) {
- writePS("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
- subpath->getX(j+1), subpath->getY(j+1),
- subpath->getX(j+2), subpath->getY(j+2));
+ writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ subpath->getX(j+2), subpath->getY(j+2));
j += 3;
} else {
- writePS("%g %g l\n", subpath->getX(j), subpath->getY(j));
+ writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j));
++j;
}
}
}
void PSOutputDev::drawString(GfxState *state, GString *s) {
+ GfxFont *font;
+ int wMode;
+ GString *s2;
+ double dx, dy, dx2, dy2, originX, originY;
+ char *p;
+ UnicodeMap *uMap;
+ CharCode code;
+ Unicode u[8];
+ char buf[8];
+ int len, nChars, uLen, n, m, i, j;
+
// check for invisible text -- this is used by Acrobat Capture
- if ((state->getRender() & 3) == 3)
+ if (state->getRender() == 3) {
return;
+ }
- writePSString(s);
- writePS(" %g Tj\n", state->getFont()->getWidth(s));
-}
-
-void PSOutputDev::drawString16(GfxState *state, GString *s) {
- int c1, c2;
- double w;
- int i;
+ // ignore empty strings
+ if (s->getLength() == 0) {
+ return;
+ }
- // check for invisible text -- this is used by Acrobat Capture
- if ((state->getRender() & 3) == 3)
+ // get the font
+ if (!(font = state->getFont())) {
return;
+ }
+ wMode = font->getWMode();
- switch (state->getFont()->getCharSet16()) {
+ // check for a subtitute 16-bit font
+ uMap = NULL;
+ if (font->isCIDFont()) {
+ for (i = 0; i < font16EncLen; ++i) {
+ if (font->getID()->num == font16Enc[i].fontID.num &&
+ font->getID()->gen == font16Enc[i].fontID.gen) {
+ uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
+ break;
+ }
+ }
+ }
- case font16AdobeJapan12:
-#if JAPANESE_SUPPORT
- writePS("<");
- w = 0;
- for (i = 0; i < s->getLength(); i += 2) {
- c1 = ((s->getChar(i) & 0xff) << 8) + (s->getChar(i+1) & 0xff);
- if (c1 <= 8285) {
- c2 = japan12ToRKSJ[c1];
+ // compute width of chars in string, ignoring char spacing and word
+ // spacing -- the Tj operator will adjust for the metrics of the
+ // font that's actually used
+ dx = dy = 0;
+ nChars = 0;
+ p = s->getCString();
+ len = s->getLength();
+ if (font->isCIDFont()) {
+ s2 = new GString();
+ } else {
+ s2 = s;
+ }
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx2, &dy2, &originX, &originY);
+ if (font->isCIDFont()) {
+ if (uMap) {
+ for (i = 0; i < uLen; ++i) {
+ m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
+ for (j = 0; j < m; ++j) {
+ s2->append(buf[j]);
+ }
+ }
+ //~ this really needs to get the number of chars in the target
+ //~ encoding - which may be more than the number of Unicode
+ //~ chars
+ nChars += uLen;
} else {
- c2 = 0x20;
+ s2->append((char)((code >> 8) & 0xff));
+ s2->append((char)(code & 0xff));
+ ++nChars;
}
- if (c2 <= 0xff) {
- writePS("%02x", c2);
+ }
+ dx += dx2;
+ dy += dy2;
+ p += n;
+ len -= n;
+ }
+ dx *= state->getFontSize() * state->getHorizScaling();
+ dy *= state->getFontSize();
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+
+ if (s2->getLength() > 0) {
+ writePSString(s2);
+ if (font->isCIDFont()) {
+ if (wMode) {
+ writePSFmt(" %d %g Tj16V\n", nChars, dy);
} else {
- writePS("%02x%02x", c2 >> 8, c2 & 0xff);
+ writePSFmt(" %d %g Tj16\n", nChars, dx);
}
- w += state->getFont()->getWidth16(c1);
+ } else {
+ writePSFmt(" %g Tj\n", dx);
}
- writePS("> %g Tj\n", w);
-#endif
- break;
+ }
+ if (font->isCIDFont()) {
+ delete s2;
+ }
- case font16AdobeGB12:
- break;
+ if (state->getRender() & 4) {
+ haveTextClip = gTrue;
+ }
+}
- case font16AdobeCNS13:
- break;
+void PSOutputDev::endTextObject(GfxState *state) {
+ if (haveTextClip) {
+ writePS("Tclip\n");
+ haveTextClip = gFalse;
}
}
int len;
len = height * ((width + 7) / 8);
- if (psOutLevel1 || psOutLevel1Sep) {
- doImageL1(NULL, invert, inlineImg, str, width, height, len);
+ if (level == psLevel1 || level == psLevel1Sep) {
+ doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
} else {
doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
}
void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int width, int height, GfxImageColorMap *colorMap,
- GBool inlineImg) {
+ int *maskColors, GBool inlineImg) {
int len;
len = height * ((width * colorMap->getNumPixelComps() *
colorMap->getBits() + 7) / 8);
- if (psOutLevel1) {
- doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
- } else if (psOutLevel1Sep) {
+ switch (level) {
+ case psLevel1:
+ doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ case psLevel1Sep:
//~ handle indexed, separation, ... color spaces
doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
- } else {
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ case psLevel3:
+ case psLevel3Sep:
doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
}
+ t3Cacheable = gFalse;
}
-void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
+void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
GBool invert, GBool inlineImg,
Stream *str, int width, int height, int len) {
ImageStream *imgStr;
Guchar pixBuf[gfxColorMaxComps];
double gray;
- int x, y, i;
+ int col, x, y, c, i;
- // width, height, matrix, bits per component
- if (colorMap) {
- writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
- width, height,
- width, -height, height);
+ if (inType3Char && !colorMap) {
+ if (inlineImg) {
+ // create an array
+ str = new FixedLengthEncoder(str, len);
+ str = new ASCIIHexEncoder(str);
+ str->reset();
+ col = 0;
+ writePS("[<");
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '>' || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ // each line is: "<...data...><eol>"
+ // so max data length = 255 - 4 = 251
+ // but make it 240 just to be safe
+ // chunks are 2 bytes each, so we need to stop on an even col number
+ if (col == 240) {
+ writePS(">\n<");
+ col = 0;
+ }
+ } while (c != '>' && c != EOF);
+ writePS(">]\n");
+ writePS("0\n");
+ str->close();
+ delete str;
+ } else {
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // image/imagemask command
+ if (inType3Char && !colorMap) {
+ writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ } else if (colorMap) {
+ writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
+ width, height,
+ width, -height, height);
} else {
- writePS("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
- width, height, invert ? "true" : "false",
- width, -height, height);
+ writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
}
- // image
- if (colorMap) {
+ // image data
+ if (!(inType3Char && !colorMap)) {
- // set up to process the data stream
- imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
- colorMap->getBits());
- imgStr->reset();
+ if (colorMap) {
- // process the data stream
- i = 0;
- for (y = 0; y < height; ++y) {
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
- // write the line
- for (x = 0; x < width; ++x) {
- imgStr->getPixel(pixBuf);
- colorMap->getGray(pixBuf, &gray);
- fprintf(f, "%02x", (int)(gray * 255 + 0.5));
- if (++i == 32) {
- fputc('\n', f);
- i = 0;
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // write the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getGray(pixBuf, &gray);
+ writePSFmt("%02x", (int)(gray * 255 + 0.5));
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
}
}
- }
- if (i != 0)
- fputc('\n', f);
- delete imgStr;
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ delete imgStr;
- // imagemask
- } else {
- str->reset();
- i = 0;
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; x += 8) {
- fprintf(f, "%02x", str->getChar() & 0xff);
- if (++i == 32) {
- fputc('\n', f);
- i = 0;
+ // imagemask
+ } else {
+ str->reset();
+ i = 0;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; x += 8) {
+ writePSFmt("%02x", str->getChar() & 0xff);
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
}
}
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ str->close();
}
- if (i != 0)
- fputc('\n', f);
}
}
int x, y, i, comp;
// width, height, matrix, bits per component
- writePS("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
- width, height,
- width, -height, height);
+ writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
+ width, height,
+ width, -height, height);
// allocate a line buffer
lineBuf = (Guchar *)gmalloc(4 * width);
lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
}
// write one line of each color component
for (comp = 0; comp < 4; ++comp) {
for (x = 0; x < width; ++x) {
- fprintf(f, "%02x", lineBuf[4*x + comp]);
+ writePSFmt("%02x", lineBuf[4*x + comp]);
if (++i == 32) {
- fputc('\n', f);
+ writePSChar('\n');
i = 0;
}
}
}
if (i != 0) {
- fputc('\n', f);
+ writePSChar('\n');
}
delete imgStr;
Stream *str, int width, int height, int len) {
GString *s;
int n, numComps;
- GBool useRLE, useA85;
+ GBool useRLE, useASCII, useASCIIHex, useCompressed;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
int c;
- int i;
+ int col, i;
// color space
if (colorMap) {
writePS(" setcolorspace\n");
}
- // set up to use the array created by setupImages()
- if (doForm && !inlineImg) {
- writePS("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+ useASCIIHex = globalParams->getPSASCIIHex();
+
+ // set up the image data
+ if (mode == psModeForm || inType3Char) {
+ if (inlineImg) {
+ // create an array
+ str = new FixedLengthEncoder(str, len);
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ str->reset();
+ col = 0;
+ writePS((char *)(useASCIIHex ? "[<" : "[<~"));
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "<~...data...~><eol>"
+ // so max data length = 255 - 6 = 249
+ // chunks are 1 or 5 bytes each, so we have to stop at 245
+ // but make it 240 just to be safe
+ if (col > 240) {
+ writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? ">]\n" : "~>]\n"));
+ writePS("0\n");
+ str->close();
+ delete str;
+ } else {
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
+ }
}
// image dictionary
writePS("<<\n /ImageType 1\n");
// width, height, matrix, bits per component
- writePS(" /Width %d\n", width);
- writePS(" /Height %d\n", height);
- writePS(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
- writePS(" /BitsPerComponent %d\n",
- colorMap ? colorMap->getBits() : 1);
+ writePSFmt(" /Width %d\n", width);
+ writePSFmt(" /Height %d\n", height);
+ writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ writePSFmt(" /BitsPerComponent 8\n");
+ } else {
+ writePSFmt(" /BitsPerComponent %d\n",
+ colorMap ? colorMap->getBits() : 1);
+ }
// decode
if (colorMap) {
if (colorMap->getColorSpace()->getMode() == csSeparation) {
//~ this is a kludge -- see comment in dumpColorSpaceL2
n = (1 << colorMap->getBits()) - 1;
- writePS("%g %g", colorMap->getDecodeLow(0) * n,
- colorMap->getDecodeHigh(0) * n);
+ writePSFmt("%g %g", 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(" ");
+ }
+ writePSFmt("0 1", colorMap->getDecodeLow(i),
+ colorMap->getDecodeHigh(i));
+ }
} else {
numComps = colorMap->getNumPixelComps();
for (i = 0; i < numComps; ++i) {
if (i > 0) {
writePS(" ");
}
- writePS("%g %g", colorMap->getDecodeLow(i),
- colorMap->getDecodeHigh(i));
+ writePSFmt("%g %g", colorMap->getDecodeLow(i),
+ colorMap->getDecodeHigh(i));
}
}
writePS("]\n");
} else {
- writePS(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
+ writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
}
- if (doForm) {
-
- if (inlineImg) {
-
- // data source
- writePS(" /DataSource <~\n");
-
- // write image data stream, using ASCII85 encode filter
- str = new FixedLengthEncoder(str, len);
- str = new ASCII85Encoder(str);
- str->reset();
- while ((c = str->getChar()) != EOF) {
- fputc(c, f);
- }
- fputc('\n', f);
- delete str;
+ if (mode == psModeForm || inType3Char) {
- } else {
- writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
- }
+ // data source
+ writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
// end of image dictionary
- writePS(">>\n%s\n", colorMap ? "image" : "imagemask");
+ writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask");
// get rid of the array and index
- if (!inlineImg) {
- writePS("pop pop\n");
- }
+ writePS("pop pop\n");
} else {
// data source
writePS(" /DataSource currentfile\n");
- s = str->getPSFilter(" ");
- if (inlineImg || !s) {
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ inlineImg || !s) {
useRLE = gTrue;
- useA85 = gTrue;
+ useASCII = gTrue;
+ useCompressed = gFalse;
} else {
useRLE = gFalse;
- useA85 = str->isBinary();
+ useASCII = str->isBinary();
+ useCompressed = gTrue;
}
- if (useA85)
- writePS(" /ASCII85Decode filter\n");
- if (useRLE)
+ if (useASCII) {
+ writePSFmt(" /ASCII%sDecode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (useRLE) {
writePS(" /RunLengthDecode filter\n");
- else
- writePS("%s", s->getCString());
- if (s)
+ }
+ if (useCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
delete s;
+ }
// cut off inline image streams at appropriate length
- if (inlineImg)
+ if (inlineImg) {
str = new FixedLengthEncoder(str, len);
- else if (!useRLE)
+ } else if (useCompressed) {
str = str->getBaseStream();
+ }
- // add RunLengthEncode and ASCII85 encode filters
- if (useRLE)
+ // recode DeviceN data
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ str = new DeviceNRecoder(str, width, height, colorMap);
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (useRLE) {
str = new RunLengthEncoder(str);
- if (useA85)
- str = new ASCII85Encoder(str);
+ }
+ if (useASCII) {
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ }
// end of image dictionary
writePS(">>\n");
n = 0;
} else {
// need to read the stream to count characters -- the length
- // is data-dependent (because of A85 and RLE filters)
+ // is data-dependent (because of ASCII and RLE filters)
str->reset();
n = 0;
while ((c = str->getChar()) != EOF) {
++n;
}
+ str->close();
}
// +6/7 for "pdfIm\n" / "pdfImM\n"
// +8 for newline + trailer
n += colorMap ? 14 : 15;
- writePS("%%%%BeginData: %d Hex Bytes\n", n);
+ writePSFmt("%%%%BeginData: %d Hex Bytes\n", n);
}
#endif
- writePS("%s\n", colorMap ? "pdfIm" : "pdfImM");
+ if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ color.c[0] = 1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("%g %g %g %g (%s) pdfImSep\n",
+ cmyk.c, cmyk.m, cmyk.y, cmyk.k,
+ sepCS->getName()->getCString());
+ } else {
+ writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM");
+ }
// copy the stream data
str->reset();
- while ((c = str->getChar()) != EOF)
- fputc(c, f);
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
// add newline and trailer to the end
- fputc('\n', f);
- fputs("%-EOD-\n", f);
+ writePSChar('\n');
+ writePS("%-EOD-\n");
#if OPI_SUPPORT
if (opi13Nest) {
- writePS("%%%%EndData\n");
+ writePS("%%EndData\n");
}
#endif
// delete encoders
- if (useRLE || useA85)
+ if (useRLE || useASCII || inlineImg) {
delete str;
+ }
}
}
GfxLabColorSpace *labCS;
GfxIndexedColorSpace *indexedCS;
GfxSeparationColorSpace *separationCS;
- Guchar *lookup;
- double x[1], y[gfxColorMaxComps];
- int n, numComps;
+ GfxColorSpace *baseCS;
+ Guchar *lookup, *p;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
+ Function *func;
+ int n, numComps, numAltComps;
+ int byte;
int i, j, k;
switch (colorSpace->getMode()) {
case csDeviceGray:
writePS("/DeviceGray");
+ processColors |= psProcessBlack;
break;
case csCalGray:
calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
writePS("[/CIEBasedA <<\n");
- writePS(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
- writePS(" /MatrixA [%g %g %g]\n",
- calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
- calGrayCS->getWhiteZ());
- writePS(" /WhitePoint [%g %g %g]\n",
- calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
- calGrayCS->getWhiteZ());
- writePS(" /BlackPoint [%g %g %g]\n",
- calGrayCS->getBlackX(), calGrayCS->getBlackY(),
- calGrayCS->getBlackZ());
+ writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
+ writePSFmt(" /MatrixA [%g %g %g]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [%g %g %g]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [%g %g %g]\n",
+ calGrayCS->getBlackX(), calGrayCS->getBlackY(),
+ calGrayCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessBlack;
break;
case csDeviceRGB:
writePS("/DeviceRGB");
+ processColors |= psProcessCMYK;
break;
case csCalRGB:
calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
writePS("[/CIEBasedABC <<\n");
- writePS(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
- calRGBCS->getGammaR(), calRGBCS->getGammaG(),
- calRGBCS->getGammaB());
- writePS(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
- calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
- calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
- calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
- calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
- calRGBCS->getMatrix()[8]);
- writePS(" /WhitePoint [%g %g %g]\n",
- calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
- calRGBCS->getWhiteZ());
- writePS(" /BlackPoint [%g %g %g]\n",
- calRGBCS->getBlackX(), calRGBCS->getBlackY(),
- calRGBCS->getBlackZ());
+ writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
+ calRGBCS->getGammaR(), calRGBCS->getGammaG(),
+ calRGBCS->getGammaB());
+ writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
+ calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
+ calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
+ calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
+ calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
+ calRGBCS->getMatrix()[8]);
+ writePSFmt(" /WhitePoint [%g %g %g]\n",
+ calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
+ calRGBCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [%g %g %g]\n",
+ calRGBCS->getBlackX(), calRGBCS->getBlackY(),
+ calRGBCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessCMYK;
break;
case csDeviceCMYK:
writePS("/DeviceCMYK");
+ processColors |= psProcessCMYK;
break;
case csLab:
labCS = (GfxLabColorSpace *)colorSpace;
writePS("[/CIEBasedABC <<\n");
- writePS(" /RangeABC [0 100 %g %g %g %g]\n",
- labCS->getAMin(), labCS->getAMax(),
- labCS->getBMin(), labCS->getBMax());
+ writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
+ labCS->getAMin(), labCS->getAMax(),
+ labCS->getBMin(), labCS->getBMax());
writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
writePS(" /DecodeLMN\n");
writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
- writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
- labCS->getWhiteX());
+ writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+ labCS->getWhiteX());
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
- writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
- labCS->getWhiteY());
+ writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
+ labCS->getWhiteY());
writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
- writePS(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
- labCS->getWhiteZ());
- writePS(" /WhitePoint [%g %g %g]\n",
- labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
- writePS(" /BlackPoint [%g %g %g]\n",
- labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
+ writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
+ labCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [%g %g %g]\n",
+ labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [%g %g %g]\n",
+ labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
writePS(">>]");
+ processColors |= psProcessCMYK;
break;
case csICCBased:
+ // there is no transform function to the alternate color space, so
+ // we can use it directly
dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
break;
case csIndexed:
indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ baseCS = indexedCS->getBase();
writePS("[/Indexed ");
- dumpColorSpaceL2(indexedCS->getBase());
+ dumpColorSpaceL2(baseCS);
n = indexedCS->getIndexHigh();
- numComps = indexedCS->getBase()->getNComps();
+ numComps = baseCS->getNComps();
lookup = indexedCS->getLookup();
- writePS(" %d <\n", n);
- for (i = 0; i <= n; i += 8) {
- writePS(" ");
- for (j = i; j < i+8 && j <= n; ++j) {
- for (k = 0; k < numComps; ++k) {
- writePS("%02x", lookup[j * numComps + k]);
+ writePSFmt(" %d <\n", n);
+ if (baseCS->getMode() == csDeviceN) {
+ func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
+ numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
+ p = lookup;
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ x[k] = *p++ / 255.0;
+ }
+ func->transform(x, y);
+ for (k = 0; k < numAltComps; ++k) {
+ byte = (int)(y[k] * 255 + 0.5);
+ if (byte < 0) {
+ byte = 0;
+ } else if (byte > 255) {
+ byte = 255;
+ }
+ writePSFmt("%02x", byte);
+ }
+ color.c[0] = j;
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
}
+ writePS("\n");
+ }
+ } else {
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ writePSFmt("%02x", lookup[j * numComps + k]);
+ }
+ color.c[0] = j;
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
+ }
+ writePS("\n");
}
- writePS("\n");
}
writePS(">]");
break;
//~ separation color space, with the specified alternate color
//~ space and tint transform
separationCS = (GfxSeparationColorSpace *)colorSpace;
- writePS(" [/Indexed ");
+ writePS("[/Indexed ");
dumpColorSpaceL2(separationCS->getAlt());
writePS(" 255 <\n");
numComps = separationCS->getAlt()->getNComps();
x[0] = (double)j / 255.0;
separationCS->getFunc()->transform(x, y);
for (k = 0; k < numComps; ++k) {
- writePS("%02x", (int)(255 * y[k] + 0.5));
+ writePSFmt("%02x", (int)(255 * y[k] + 0.5));
}
}
writePS("\n");
}
writePS(">]");
+#if 0 //~ this shouldn't be here since the PS file doesn't actually refer
+ //~ to this colorant (it's converted to CMYK instead)
+ addCustomColor(separationCS);
+#endif
break;
case csDeviceN:
void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
Object dict;
- if (psOutOPI) {
+ if (globalParams->getPSOPI()) {
opiDict->lookup("2.0", &dict);
if (dict.isDict()) {
opiBegin20(state, dict.getDict());
int w, h;
int i;
- writePS("%%%%BeginOPI: 2.0\n");
- writePS("%%%%Distilled\n");
+ writePS("%%BeginOPI: 2.0\n");
+ writePS("%%Distilled\n");
dict->lookup("F", &obj1);
if (getFileSpec(&obj1, &obj2)) {
- writePS("%%%%ImageFileName: %s\n",
- obj2.getString()->getCString());
+ writePSFmt("%%%%ImageFileName: %s\n",
+ obj2.getString()->getCString());
obj2.free();
}
obj1.free();
dict->lookup("MainImage", &obj1);
if (obj1.isString()) {
- writePS("%%%%MainImage: %s\n", obj1.getString()->getCString());
+ writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString());
}
obj1.free();
obj1.arrayGet(1, &obj2);
height = obj2.getNum();
obj2.free();
- writePS("%%%%ImageDimensions: %g %g\n", width, height);
+ writePSFmt("%%%%ImageDimensions: %g %g\n", width, height);
}
obj1.free();
obj1.arrayGet(3, &obj2);
bottom = obj2.getNum();
obj2.free();
- writePS("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
+ writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
}
obj1.free();
dict->lookup("Overprint", &obj1);
if (obj1.isBool()) {
- writePS("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+ writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
}
obj1.free();
dict->lookup("Inks", &obj1);
if (obj1.isName()) {
- writePS("%%%%ImageInks: %s\n", obj1.getName());
+ writePSFmt("%%%%ImageInks: %s\n", obj1.getName());
} else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
obj1.arrayGet(0, &obj2);
if (obj2.isName()) {
- writePS("%%%%ImageInks: %s %d",
- obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
+ writePSFmt("%%%%ImageInks: %s %d",
+ obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
obj1.arrayGet(i, &obj3);
obj1.arrayGet(i+1, &obj4);
if (obj3.isString() && obj4.isNum()) {
writePS(" ");
writePSString(obj3.getString());
- writePS(" %g", obj4.getNum());
+ writePSFmt(" %g", obj4.getNum());
}
obj3.free();
obj4.free();
writePS("gsave\n");
- writePS("%%%%BeginIncludedImage\n");
+ writePS("%%BeginIncludedImage\n");
dict->lookup("IncludedImageDimensions", &obj1);
if (obj1.isArray() && obj1.arrayGetLength() == 2) {
obj1.arrayGet(1, &obj2);
h = obj2.getInt();
obj2.free();
- writePS("%%%%IncludedImageDimensions: %d %d\n", w, h);
+ writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h);
}
obj1.free();
dict->lookup("IncludedImageQuality", &obj1);
if (obj1.isNum()) {
- writePS("%%%%IncludedImageQuality: %g\n", obj1.getNum());
+ writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum());
}
obj1.free();
dict->lookup("F", &obj1);
if (getFileSpec(&obj1, &obj2)) {
- writePS("%%ALDImageFileName: %s\n",
- obj2.getString()->getCString());
+ writePSFmt("%%ALDImageFileName: %s\n",
+ obj2.getString()->getCString());
obj2.free();
}
obj1.free();
obj1.arrayGet(3, &obj2);
bottom = obj2.getInt();
obj2.free();
- writePS("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
+ writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
}
obj1.free();
obj2.free();
obj1.arrayGet(4, &obj2);
if (obj2.isString()) {
- writePS("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
+ writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
writePSString(obj2.getString());
writePS("\n");
}
dict->lookup("ColorType", &obj1);
if (obj1.isName()) {
- writePS("%%ALDImageColorType: %s\n", obj1.getName());
+ writePSFmt("%%ALDImageColorType: %s\n", obj1.getName());
}
obj1.free();
obj1.arrayGet(3, &obj2);
lry = obj2.getNum();
obj2.free();
- writePS("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
+ writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
}
obj1.free();
dict->lookup("GrayMap", &obj1);
if (obj1.isArray()) {
- writePS("%%ALDImageGrayMap:");
+ writePS("%ALDImageGrayMap:");
for (i = 0; i < obj1.arrayGetLength(); i += 16) {
if (i > 0) {
- writePS("\n%%%%+");
+ writePS("\n%%+");
}
for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
obj1.arrayGet(i+j, &obj2);
- writePS(" %d", obj2.getInt());
+ writePSFmt(" %d", obj2.getInt());
obj2.free();
}
}
dict->lookup("ID", &obj1);
if (obj1.isString()) {
- writePS("%%ALDImageID: %s\n", obj1.getString()->getCString());
+ writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString());
}
obj1.free();
obj1.arrayGet(1, &obj2);
bits = obj2.getInt();
obj2.free();
- writePS("%%ALDImageType: %d %d\n", samples, bits);
+ writePSFmt("%%ALDImageType: %d %d\n", samples, bits);
}
obj1.free();
dict->lookup("Overprint", &obj1);
if (obj1.isBool()) {
- writePS("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
+ writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
}
obj1.free();
opiTransform(state, ulx, uly, &tulx, &tuly);
opiTransform(state, urx, ury, &turx, &tury);
opiTransform(state, lrx, lry, &tlrx, &tlry);
- writePS("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
- tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
+ writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
+ tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
obj2.free();
}
obj1.free();
obj1.arrayGet(1, &obj2);
vert = obj2.getNum();
obj2.free();
- writePS("%%ALDImageResoution: %g %g\n", horiz, vert);
+ writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert);
obj2.free();
}
obj1.free();
obj1.arrayGet(1, &obj2);
height = obj2.getInt();
obj2.free();
- writePS("%%ALDImageDimensions: %d %d\n", width, height);
+ writePSFmt("%%ALDImageDimensions: %d %d\n", width, height);
}
obj1.free();
dict->lookup("Tint", &obj1);
if (obj1.isNum()) {
- writePS("%%ALDImageTint: %g\n", obj1.getNum());
+ writePSFmt("%%ALDImageTint: %g\n", obj1.getNum());
}
obj1.free();
dict->lookup("Transparency", &obj1);
if (obj1.isBool()) {
- writePS("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
+ writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
}
obj1.free();
- writePS("%%%%BeginObject: image\n");
+ writePS("%%BeginObject: image\n");
writePS("opiMatrix2 setmatrix\n");
++opi13Nest;
}
state->transform(x0, y0, x1, y1);
*x1 += tx;
*y1 += ty;
- if (landscape) {
+ if (rotate == 90) {
t = *x1;
*x1 = -*y1;
*y1 = t;
+ } else if (rotate == 180) {
+ *x1 = -*x1;
+ *y1 = -*y1;
+ } else if (rotate == 270) {
+ t = *x1;
+ *x1 = *y1;
+ *y1 = -t;
}
*x1 *= xScale;
*y1 *= yScale;
void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
Object dict;
- if (psOutOPI) {
+ if (globalParams->getPSOPI()) {
opiDict->lookup("2.0", &dict);
if (dict.isDict()) {
- writePS("%%%%EndIncludedImage\n");
- writePS("%%%%EndOPI\n");
+ writePS("%%EndIncludedImage\n");
+ writePS("%%EndOPI\n");
writePS("grestore\n");
--opi20Nest;
dict.free();
dict.free();
opiDict->lookup("1.3", &dict);
if (dict.isDict()) {
- writePS("%%%%EndObject\n");
+ writePS("%%EndObject\n");
writePS("restore\n");
--opi13Nest;
}
}
#endif // OPI_SUPPORT
-void PSOutputDev::writePS(const char *fmt, ...) {
+void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
+ writePSFmt("%g %g setcharwidth\n", wx, wy);
+ writePS("q\n");
+}
+
+void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury) {
+ t3WX = wx;
+ t3WY = wy;
+ t3LLX = llx;
+ t3LLY = lly;
+ t3URX = urx;
+ t3URY = ury;
+ t3String = new GString();
+ writePS("q\n");
+ t3Cacheable = gTrue;
+}
+
+void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
+ Stream *str;
+ int c;
+
+ if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
+ str = level1Stream;
+ } else {
+ str = psStream;
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+}
+
+void PSOutputDev::writePSChar(char c) {
+ if (t3String) {
+ t3String->append(c);
+ } else {
+ (*outputFunc)(outputStream, &c, 1);
+ }
+}
+
+void PSOutputDev::writePS(char *s) {
+ if (t3String) {
+ t3String->append(s);
+ } else {
+ (*outputFunc)(outputStream, s, strlen(s));
+ }
+}
+
+void PSOutputDev::writePSFmt(const char *fmt, ...) {
va_list args;
+ char buf[512];
va_start(args, fmt);
- vfprintf(f, fmt, args);
+ vsprintf(buf, fmt, args);
va_end(args);
+ if (t3String) {
+ t3String->append(buf);
+ } else {
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
}
void PSOutputDev::writePSString(GString *s) {
Guchar *p;
int n;
+ char buf[8];
- fputc('(', f);
+ writePSChar('(');
for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
- if (*p == '(' || *p == ')' || *p == '\\')
- fprintf(f, "\\%c", *p);
- else if (*p < 0x20 || *p >= 0x80)
- fprintf(f, "\\%03o", *p);
- else
- fputc(*p, f);
- }
- fputc(')', f);
+ if (*p == '(' || *p == ')' || *p == '\\') {
+ writePSChar('\\');
+ writePSChar((char)*p);
+ } else if (*p < 0x20 || *p >= 0x80) {
+ sprintf(buf, "\\%03o", *p);
+ if (t3String) {
+ t3String->append(buf);
+ } else {
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ } else {
+ writePSChar((char)*p);
+ }
+ }
+ writePSChar(')');
+}
+
+void PSOutputDev::writePSName(char *s) {
+ char *p;
+ char c;
+
+ p = s;
+ while ((c = *p++)) {
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%') {
+ writePSFmt("#%02x", c & 0xff);
+ } else {
+ writePSChar(c);
+ }
+ }
+}
+
+GString *PSOutputDev::filterPSName(GString *name) {
+ GString *name2;
+ char buf[8];
+ int i;
+ char c;
+
+ name2 = new GString();
+
+ // ghostscript chokes on names that begin with out-of-limits
+ // numbers, e.g., 1e4foo is handled correctly (as a name), but
+ // 1e999foo generates a limitcheck error
+ c = name->getChar(0);
+ if (c >= '0' && c <= '9') {
+ name2->append('f');
+ }
+
+ for (i = 0; i < name->getLength(); ++i) {
+ c = name->getChar(i);
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%') {
+ sprintf(buf, "#%02x", c & 0xff);
+ name2->append(buf);
+ } else {
+ name2->append(c);
+ }
+ }
+ return name2;
}