00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014
00015 #include <stdio.h>
00016 #include <stddef.h>
00017 #include <stdarg.h>
00018 #include <signal.h>
00019 #include <math.h>
00020 #include "GString.h"
00021 #include "config.h"
00022 #include "GlobalParams.h"
00023 #include "Object.h"
00024 #include "Error.h"
00025 #include "Function.h"
00026 #include "Gfx.h"
00027 #include "GfxState.h"
00028 #include "GfxFont.h"
00029 #include "CharCodeToUnicode.h"
00030 #include "UnicodeMap.h"
00031 #include "FontFile.h"
00032 #include "Catalog.h"
00033 #include "Page.h"
00034 #include "Stream.h"
00035 #include "Annot.h"
00036 #include "PSOutputDev.h"
00037
00038 #ifdef MACOS
00039
00040 #include "ICSupport.h"
00041 #endif
00042
00043
00044
00045
00046
00047 static char *prolog[] = {
00048 "/xpdf 75 dict def xpdf begin",
00049 "% PDF special state",
00050 "/pdfDictSize 14 def",
00051 "/pdfSetup {",
00052 " 3 1 roll 2 array astore",
00053 " /setpagedevice where {",
00054 " pop 3 dict begin",
00055 " /PageSize exch def",
00056 " /ImagingBBox null def",
00057 " /Policies 1 dict dup begin /PageSize 3 def end def",
00058 " { /Duplex true def } if",
00059 " currentdict end setpagedevice",
00060 " } {",
00061 " pop pop",
00062 " } ifelse",
00063 "} def",
00064 "/pdfStartPage {",
00065 " pdfDictSize dict begin",
00066 " /pdfFill [0] def",
00067 " /pdfStroke [0] def",
00068 " /pdfLastFill false def",
00069 " /pdfLastStroke false def",
00070 " /pdfTextMat [1 0 0 1 0 0] def",
00071 " /pdfFontSize 0 def",
00072 " /pdfCharSpacing 0 def",
00073 " /pdfTextRender 0 def",
00074 " /pdfTextRise 0 def",
00075 " /pdfWordSpacing 0 def",
00076 " /pdfHorizScaling 1 def",
00077 "} def",
00078 "/pdfEndPage { end } def",
00079 "% separation convention operators",
00080 "/findcmykcustomcolor where {",
00081 " pop",
00082 "}{",
00083 " /findcmykcustomcolor { 5 array astore } def",
00084 "} ifelse",
00085 "/setcustomcolor where {",
00086 " pop",
00087 "}{",
00088 " /setcustomcolor {",
00089 " exch",
00090 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
00091 " 0 4 getinterval cvx",
00092 " [ exch /dup load exch { mul exch dup } /forall load",
00093 " /pop load dup ] cvx",
00094 " ] setcolorspace setcolor",
00095 " } def",
00096 "} ifelse",
00097 "/customcolorimage where {",
00098 " pop",
00099 "}{",
00100 " /customcolorimage {",
00101 " gsave",
00102 " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
00103 " 0 4 getinterval cvx",
00104 " [ exch /dup load exch { mul exch dup } /forall load",
00105 " /pop load dup ] cvx",
00106 " ] setcolorspace",
00107 " 10 dict begin",
00108 " /ImageType 1 def",
00109 " /DataSource exch def",
00110 " /ImageMatrix exch def",
00111 " /BitsPerComponent exch def",
00112 " /Height exch def",
00113 " /Width exch def",
00114 " /Decode [1 0] def",
00115 " currentdict end",
00116 " image",
00117 " grestore",
00118 " } def",
00119 "} ifelse",
00120 "% PDF color state",
00121 "/sCol {",
00122 " pdfLastStroke not {",
00123 " pdfStroke aload length",
00124 " dup 1 eq {",
00125 " pop setgray",
00126 " }{",
00127 " dup 3 eq {",
00128 " pop setrgbcolor",
00129 " }{",
00130 " 4 eq {",
00131 " setcmykcolor",
00132 " }{",
00133 " findcmykcustomcolor exch setcustomcolor",
00134 " } ifelse",
00135 " } ifelse",
00136 " } ifelse",
00137 " /pdfLastStroke true def /pdfLastFill false def",
00138 " } if",
00139 "} def",
00140 "/fCol {",
00141 " pdfLastFill not {",
00142 " pdfFill aload length",
00143 " dup 1 eq {",
00144 " pop setgray",
00145 " }{",
00146 " dup 3 eq {",
00147 " pop setrgbcolor",
00148 " }{",
00149 " 4 eq {",
00150 " setcmykcolor",
00151 " }{",
00152 " findcmykcustomcolor exch setcustomcolor",
00153 " } ifelse",
00154 " } ifelse",
00155 " } ifelse",
00156 " /pdfLastFill true def /pdfLastStroke false def",
00157 " } if",
00158 "} def",
00159 "% build a font",
00160 "/pdfMakeFont {",
00161 " 4 3 roll findfont",
00162 " 4 2 roll matrix scale makefont",
00163 " dup length dict begin",
00164 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
00165 " /Encoding exch def",
00166 " currentdict",
00167 " end",
00168 " definefont pop",
00169 "} def",
00170 "/pdfMakeFont16 {",
00171 " exch findfont",
00172 " dup length dict begin",
00173 " { 1 index /FID ne { def } { pop pop } ifelse } forall",
00174 " /WMode exch def",
00175 " currentdict",
00176 " end",
00177 " definefont pop",
00178 "} def",
00179 "/pdfMakeFont16L3 {",
00180 " 1 index /CIDFont resourcestatus {",
00181 " pop pop 1 index /CIDFont findresource /CIDFontType known",
00182 " } {",
00183 " false",
00184 " } ifelse",
00185 " {",
00186 " 0 eq { /Identity-H } { /Identity-V } ifelse",
00187 " exch 1 array astore composefont pop",
00188 " } {",
00189 " pdfMakeFont16",
00190 " } ifelse",
00191 "} def",
00192 "% graphics state operators",
00193 "/q { gsave pdfDictSize dict begin } def",
00194 "/Q { end grestore } def",
00195 "/cm { concat } def",
00196 "/d { setdash } def",
00197 "/i { setflat } def",
00198 "/j { setlinejoin } def",
00199 "/J { setlinecap } def",
00200 "/M { setmiterlimit } def",
00201 "/w { setlinewidth } def",
00202 "% color operators",
00203 "/g { dup 1 array astore /pdfFill exch def setgray",
00204 " /pdfLastFill true def /pdfLastStroke false def } def",
00205 "/G { dup 1 array astore /pdfStroke exch def setgray",
00206 " /pdfLastStroke true def /pdfLastFill false def } def",
00207 "/rg { 3 copy 3 array astore /pdfFill exch def setrgbcolor",
00208 " /pdfLastFill true def /pdfLastStroke false def } def",
00209 "/RG { 3 copy 3 array astore /pdfStroke exch def setrgbcolor",
00210 " /pdfLastStroke true def /pdfLastFill false def } def",
00211 "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
00212 " /pdfLastFill true def /pdfLastStroke false def } def",
00213 "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
00214 " /pdfLastStroke true def /pdfLastFill false def } def",
00215 "/ck { 6 copy 6 array astore /pdfFill exch def",
00216 " findcmykcustomcolor exch setcustomcolor",
00217 " /pdfLastFill true def /pdfLastStroke false def } def",
00218 "/CK { 6 copy 6 array astore /pdfStroke exch def",
00219 " findcmykcustomcolor exch setcustomcolor",
00220 " /pdfLastStroke true def /pdfLastFill false def } def",
00221 "% path segment operators",
00222 "/m { moveto } def",
00223 "/l { lineto } def",
00224 "/c { curveto } def",
00225 "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
00226 " neg 0 rlineto closepath } def",
00227 "/h { closepath } def",
00228 "% path painting operators",
00229 "/S { sCol stroke } def",
00230 "/Sf { fCol stroke } def",
00231 "/f { fCol fill } def",
00232 "/f* { fCol eofill } def",
00233 "% clipping operators",
00234 "/W { clip newpath } def",
00235 "/W* { eoclip newpath } def",
00236 "% text state operators",
00237 "/Tc { /pdfCharSpacing exch def } def",
00238 "/Tf { dup /pdfFontSize exch def",
00239 " dup pdfHorizScaling mul exch matrix scale",
00240 " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
00241 " exch findfont exch makefont setfont } def",
00242 "/Tr { /pdfTextRender exch def } def",
00243 "/Ts { /pdfTextRise exch def } def",
00244 "/Tw { /pdfWordSpacing exch def } def",
00245 "/Tz { /pdfHorizScaling exch def } def",
00246 "% text positioning operators",
00247 "/Td { pdfTextMat transform moveto } def",
00248 "/Tm { /pdfTextMat exch def } def",
00249 "% text string operators",
00250 "/awcp { % awidthcharpath",
00251 " exch {",
00252 " 1 string dup 0 3 index put 2 index charpath",
00253 " 3 index 3 index rmoveto",
00254 " 4 index eq { 5 index 5 index rmoveto } if",
00255 " } forall",
00256 " 6 {pop} repeat",
00257 "} def",
00258 "/Tj { fCol",
00259 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
00260 " 1 index stringwidth pdfTextMat idtransform pop",
00261 " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
00262 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
00263 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
00264 " pdfTextMat dtransform",
00265 " 6 5 roll",
00266 " currentpoint 8 2 roll",
00267 " pdfTextRender 1 and 0 eq {",
00268 " 6 copy awidthshow",
00269 " } if",
00270 " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
00271 " 8 6 roll moveto",
00272 " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
00273 " false awcp currentpoint stroke moveto",
00274 " } {",
00275 " 8 {pop} repeat",
00276 " } ifelse",
00277 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
00278 "/Tj16 { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
00279 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
00280 " 2 index stringwidth pdfTextMat idtransform pop",
00281 " sub exch div",
00282 " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
00283 " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
00284 " pdfTextMat dtransform",
00285 " 6 5 roll awidthshow",
00286 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
00287 "/Tj16V { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
00288 " 0 pdfTextRise pdfTextMat dtransform rmoveto",
00289 " 2 index stringwidth pdfTextMat idtransform exch pop",
00290 " sub exch div",
00291 " 0 pdfWordSpacing pdfTextMat dtransform 32",
00292 " 4 3 roll pdfCharSpacing add 0 exch",
00293 " pdfTextMat dtransform",
00294 " 6 5 roll awidthshow",
00295 " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
00296 "/TJm { pdfFontSize 0.001 mul mul neg 0",
00297 " pdfTextMat dtransform rmoveto } def",
00298 "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
00299 " pdfTextMat dtransform rmoveto } def",
00300 "% Level 1 image operators",
00301 "/pdfIm1 {",
00302 " /pdfImBuf1 4 index string def",
00303 " { currentfile pdfImBuf1 readhexstring pop } image",
00304 "} def",
00305 "/pdfIm1Sep {",
00306 " /pdfImBuf1 4 index string def",
00307 " /pdfImBuf2 4 index string def",
00308 " /pdfImBuf3 4 index string def",
00309 " /pdfImBuf4 4 index string def",
00310 " { currentfile pdfImBuf1 readhexstring pop }",
00311 " { currentfile pdfImBuf2 readhexstring pop }",
00312 " { currentfile pdfImBuf3 readhexstring pop }",
00313 " { currentfile pdfImBuf4 readhexstring pop }",
00314 " true 4 colorimage",
00315 "} def",
00316 "/pdfImM1 {",
00317 " /pdfImBuf1 4 index 7 add 8 idiv string def",
00318 " { currentfile pdfImBuf1 readhexstring pop } imagemask",
00319 "} def",
00320 "% Level 2 image operators",
00321 "/pdfImBuf 100 string def",
00322 "/pdfIm {",
00323 " image",
00324 " { currentfile pdfImBuf readline",
00325 " not { pop exit } if",
00326 " (%-EOD-) eq { exit } if } loop",
00327 "} def",
00328 "/pdfImSep {",
00329 " findcmykcustomcolor exch",
00330 " dup /Width get /pdfImBuf1 exch string def",
00331 " begin Width Height BitsPerComponent ImageMatrix DataSource end",
00332 " /pdfImData exch def",
00333 " { pdfImData pdfImBuf1 readstring pop",
00334 " 0 1 2 index length 1 sub {",
00335 " 1 index exch 2 copy get 255 exch sub put",
00336 " } for }",
00337 " 6 5 roll customcolorimage",
00338 " { currentfile pdfImBuf readline",
00339 " not { pop exit } if",
00340 " (%-EOD-) eq { exit } if } loop",
00341 "} def",
00342 "/pdfImM {",
00343 " fCol imagemask",
00344 " { currentfile pdfImBuf readline",
00345 " not { pop exit } if",
00346 " (%-EOD-) eq { exit } if } loop",
00347 "} def",
00348 "end",
00349 NULL
00350 };
00351
00352 static char *cmapProlog[] = {
00353 "/CIDInit /ProcSet findresource begin",
00354 "10 dict begin",
00355 " begincmap",
00356 " /CMapType 1 def",
00357 " /CMapName /Identity-H def",
00358 " /CIDSystemInfo 3 dict dup begin",
00359 " /Registry (Adobe) def",
00360 " /Ordering (Identity) def",
00361 " /Supplement 0 def",
00362 " end def",
00363 " 1 begincodespacerange",
00364 " <0000> <ffff>",
00365 " endcodespacerange",
00366 " 0 usefont",
00367 " 1 begincidrange",
00368 " <0000> <ffff> 0",
00369 " endcidrange",
00370 " endcmap",
00371 " currentdict CMapName exch /CMap defineresource pop",
00372 "end",
00373 "10 dict begin",
00374 " begincmap",
00375 " /CMapType 1 def",
00376 " /CMapName /Identity-V def",
00377 " /CIDSystemInfo 3 dict dup begin",
00378 " /Registry (Adobe) def",
00379 " /Ordering (Identity) def",
00380 " /Supplement 0 def",
00381 " end def",
00382 " /WMode 1 def",
00383 " 1 begincodespacerange",
00384 " <0000> <ffff>",
00385 " endcodespacerange",
00386 " 0 usefont",
00387 " 1 begincidrange",
00388 " <0000> <ffff> 0",
00389 " endcidrange",
00390 " endcmap",
00391 " currentdict CMapName exch /CMap defineresource pop",
00392 "end",
00393 "end",
00394 NULL
00395 };
00396
00397
00398
00399
00400
00401 struct PSSubstFont {
00402 char *psName;
00403 double mWidth;
00404 };
00405
00406 static char *psFonts[] = {
00407 "Courier",
00408 "Courier-Bold",
00409 "Courier-Oblique",
00410 "Courier-BoldOblique",
00411 "Helvetica",
00412 "Helvetica-Bold",
00413 "Helvetica-Oblique",
00414 "Helvetica-BoldOblique",
00415 "Symbol",
00416 "Times-Roman",
00417 "Times-Bold",
00418 "Times-Italic",
00419 "Times-BoldItalic",
00420 "ZapfDingbats",
00421 NULL
00422 };
00423
00424 static PSSubstFont psSubstFonts[] = {
00425 {"Helvetica", 0.833},
00426 {"Helvetica-Oblique", 0.833},
00427 {"Helvetica-Bold", 0.889},
00428 {"Helvetica-BoldOblique", 0.889},
00429 {"Times-Roman", 0.788},
00430 {"Times-Italic", 0.722},
00431 {"Times-Bold", 0.833},
00432 {"Times-BoldItalic", 0.778},
00433 {"Courier", 0.600},
00434 {"Courier-Oblique", 0.600},
00435 {"Courier-Bold", 0.600},
00436 {"Courier-BoldOblique", 0.600}
00437 };
00438
00439
00440 struct PSFont16Enc {
00441 Ref fontID;
00442 GString *enc;
00443 };
00444
00445
00446
00447
00448
00449 #define psProcessCyan 1
00450 #define psProcessMagenta 2
00451 #define psProcessYellow 4
00452 #define psProcessBlack 8
00453 #define psProcessCMYK 15
00454
00455
00456
00457
00458
00459 class PSOutCustomColor {
00460 public:
00461
00462 PSOutCustomColor(double cA, double mA,
00463 double yA, double kA, GString *nameA);
00464 ~PSOutCustomColor();
00465
00466 double c, m, y, k;
00467 GString *name;
00468 PSOutCustomColor *next;
00469 };
00470
00471 PSOutCustomColor::PSOutCustomColor(double cA, double mA,
00472 double yA, double kA, GString *nameA) {
00473 c = cA;
00474 m = mA;
00475 y = yA;
00476 k = kA;
00477 name = nameA;
00478 next = NULL;
00479 }
00480
00481 PSOutCustomColor::~PSOutCustomColor() {
00482 delete name;
00483 }
00484
00485
00486
00487
00488
00489 extern "C" {
00490 typedef void (*SignalFunc)(int);
00491 }
00492
00493 static void outputToFile(void *stream, char *data, int len) {
00494 fwrite(data, 1, len, (FILE *)stream);
00495 }
00496
00497 PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
00498 int firstPage, int lastPage, PSOutMode modeA) {
00499 FILE *f;
00500 PSFileType fileTypeA;
00501
00502 fontIDs = NULL;
00503 fontFileIDs = NULL;
00504 fontFileNames = NULL;
00505 font16Enc = NULL;
00506 embFontList = NULL;
00507 customColors = NULL;
00508 t3String = NULL;
00509
00510
00511 if (!strcmp(fileName, "-")) {
00512 fileTypeA = psStdout;
00513 f = stdout;
00514 } else if (fileName[0] == '|') {
00515 fileTypeA = psPipe;
00516 #ifdef HAVE_POPEN
00517 #ifndef WIN32
00518 signal(SIGPIPE, (SignalFunc)SIG_IGN);
00519 #endif
00520 if (!(f = popen(fileName + 1, "w"))) {
00521 error(-1, "Couldn't run print command '%s'", fileName);
00522 ok = gFalse;
00523 return;
00524 }
00525 #else
00526 error(-1, "Print commands are not supported ('%s')", fileName);
00527 ok = gFalse;
00528 return;
00529 #endif
00530 } else {
00531 fileTypeA = psFile;
00532 if (!(f = fopen(fileName, "w"))) {
00533 error(-1, "Couldn't open PostScript file '%s'", fileName);
00534 ok = gFalse;
00535 return;
00536 }
00537 }
00538
00539 init(outputToFile, f, fileTypeA,
00540 xrefA, catalog, firstPage, lastPage, modeA);
00541 }
00542
00543 PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
00544 XRef *xrefA, Catalog *catalog,
00545 int firstPage, int lastPage, PSOutMode modeA) {
00546 fontIDs = NULL;
00547 fontFileIDs = NULL;
00548 fontFileNames = NULL;
00549 font16Enc = NULL;
00550 embFontList = NULL;
00551 customColors = NULL;
00552 t3String = NULL;
00553
00554 init(outputFuncA, outputStreamA, psGeneric,
00555 xrefA, catalog, firstPage, lastPage, modeA);
00556 }
00557
00558 void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
00559 PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
00560 int firstPage, int lastPage, PSOutMode modeA) {
00561 Page *page;
00562 PDFRectangle *box;
00563 Dict *resDict;
00564 Annots *annots;
00565 char **p;
00566 int pg;
00567 Object obj1, obj2;
00568 int i;
00569
00570
00571 ok = gTrue;
00572 outputFunc = outputFuncA;
00573 outputStream = outputStreamA;
00574 fileType = fileTypeA;
00575 xref = xrefA;
00576 level = globalParams->getPSLevel();
00577 mode = modeA;
00578 paperWidth = globalParams->getPSPaperWidth();
00579 paperHeight = globalParams->getPSPaperHeight();
00580 if (mode == psModeForm) {
00581 lastPage = firstPage;
00582 }
00583 processColors = 0;
00584 inType3Char = gFalse;
00585
00586 #if OPI_SUPPORT
00587
00588 opi13Nest = 0;
00589 opi20Nest = 0;
00590 #endif
00591
00592
00593 fontIDSize = 64;
00594 fontIDLen = 0;
00595 fontIDs = (Ref *)gmalloc(fontIDSize * sizeof(Ref));
00596 fontFileIDSize = 64;
00597 fontFileIDLen = 0;
00598 fontFileIDs = (Ref *)gmalloc(fontFileIDSize * sizeof(Ref));
00599 fontFileNameSize = 64;
00600 fontFileNameLen = 0;
00601 fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
00602 font16EncLen = 0;
00603 font16EncSize = 0;
00604
00605
00606 embFontList = new GString();
00607
00608
00609 switch (mode) {
00610 case psModePS:
00611 writePS("%!PS-Adobe-3.0\n");
00612 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
00613 writePSFmt("%%%%LanguageLevel: %d\n",
00614 (level == psLevel1 || level == psLevel1Sep) ? 1 :
00615 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
00616 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
00617 writePS("%%DocumentProcessColors: (atend)\n");
00618 writePS("%%DocumentCustomColors: (atend)\n");
00619 }
00620 writePS("%%DocumentSuppliedResources: (atend)\n");
00621 writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
00622 paperWidth, paperHeight);
00623 writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1);
00624 writePS("%%EndComments\n");
00625 writePS("%%BeginDefaults\n");
00626 writePS("%%PageMedia: plain\n");
00627 writePS("%%EndDefaults\n");
00628 break;
00629 case psModeEPS:
00630 writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
00631 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
00632 writePSFmt("%%%%LanguageLevel: %d\n",
00633 (level == psLevel1 || level == psLevel1Sep) ? 1 :
00634 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
00635 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
00636 writePS("%%DocumentProcessColors: (atend)\n");
00637 writePS("%%DocumentCustomColors: (atend)\n");
00638 }
00639 page = catalog->getPage(firstPage);
00640 box = page->getBox();
00641 writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
00642 (int)floor(box->x1), (int)floor(box->y1),
00643 (int)ceil(box->x2), (int)ceil(box->y2));
00644 if (floor(box->x1) != ceil(box->x1) ||
00645 floor(box->y1) != ceil(box->y1) ||
00646 floor(box->x2) != ceil(box->x2) ||
00647 floor(box->y2) != ceil(box->y2)) {
00648 writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n",
00649 box->x1, box->y1, box->x2, box->y2);
00650 }
00651 writePS("%%DocumentSuppliedResources: (atend)\n");
00652 writePS("%%EndComments\n");
00653 break;
00654 case psModeForm:
00655 writePS("%!PS-Adobe-3.0 Resource-Form\n");
00656 writePSFmt("%%%%Creator: xpdf/pdftops %s\n", xpdfVersion);
00657 writePSFmt("%%%%LanguageLevel: %d\n",
00658 (level == psLevel1 || level == psLevel1Sep) ? 1 :
00659 (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
00660 if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
00661 writePS("%%DocumentProcessColors: (atend)\n");
00662 writePS("%%DocumentCustomColors: (atend)\n");
00663 }
00664 writePS("%%DocumentSuppliedResources: (atend)\n");
00665 writePS("%%EndComments\n");
00666 page = catalog->getPage(firstPage);
00667 box = page->getBox();
00668 writePS("32 dict dup begin\n");
00669 writePSFmt("/BBox [%d %d %d %d] def\n",
00670 (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2);
00671 writePS("/FormType 1 def\n");
00672 writePS("/Matrix [1 0 0 1 0 0] def\n");
00673 break;
00674 }
00675
00676
00677 if (mode != psModeForm) {
00678 writePS("%%BeginProlog\n");
00679 }
00680 writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
00681 for (p = prolog; *p; ++p) {
00682 writePSFmt("%s\n", *p);
00683 }
00684 writePS("%%EndResource\n");
00685 if (level >= psLevel3) {
00686 for (p = cmapProlog; *p; ++p) {
00687 writePSFmt("%s\n", *p);
00688 }
00689 }
00690 if (mode != psModeForm) {
00691 writePS("%%EndProlog\n");
00692 }
00693
00694
00695 if (mode == psModeForm) {
00696
00697 writePS("xpdf end begin dup begin\n");
00698 } else {
00699 writePS("%%BeginSetup\n");
00700 writePS("xpdf begin\n");
00701 }
00702 for (pg = firstPage; pg <= lastPage; ++pg) {
00703 page = catalog->getPage(pg);
00704 if ((resDict = page->getResourceDict())) {
00705 setupResources(resDict);
00706 }
00707 annots = new Annots(xref, page->getAnnots(&obj1));
00708 obj1.free();
00709 for (i = 0; i < annots->getNumAnnots(); ++i) {
00710 if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
00711 obj1.streamGetDict()->lookup("Resources", &obj2);
00712 if (obj2.isDict()) {
00713 setupResources(obj2.getDict());
00714 }
00715 obj2.free();
00716 }
00717 obj1.free();
00718 }
00719 delete annots;
00720 }
00721 if (mode != psModeForm) {
00722 if (mode != psModeEPS) {
00723 writePSFmt("%d %d %s pdfSetup\n",
00724 paperWidth, paperHeight,
00725 globalParams->getPSDuplex() ? "true" : "false");
00726 }
00727 #if OPI_SUPPORT
00728 if (globalParams->getPSOPI()) {
00729 writePS("/opiMatrix matrix currentmatrix def\n");
00730 }
00731 #endif
00732 writePS("%%EndSetup\n");
00733 }
00734
00735
00736 seqPage = 1;
00737 }
00738
00739 PSOutputDev::~PSOutputDev() {
00740 PSOutCustomColor *cc;
00741 int i;
00742
00743 if (ok) {
00744 if (mode == psModeForm) {
00745 writePS("/Foo exch /Form defineresource pop\n");
00746 } else {
00747 writePS("%%Trailer\n");
00748 writePS("end\n");
00749 writePS("%%DocumentSuppliedResources:\n");
00750 writePS(embFontList->getCString());
00751 if (level == psLevel1Sep || level == psLevel2Sep ||
00752 level == psLevel3Sep) {
00753 writePS("%%DocumentProcessColors:");
00754 if (processColors & psProcessCyan) {
00755 writePS(" Cyan");
00756 }
00757 if (processColors & psProcessMagenta) {
00758 writePS(" Magenta");
00759 }
00760 if (processColors & psProcessYellow) {
00761 writePS(" Yellow");
00762 }
00763 if (processColors & psProcessBlack) {
00764 writePS(" Black");
00765 }
00766 writePS("\n");
00767 writePS("%%DocumentCustomColors:");
00768 for (cc = customColors; cc; cc = cc->next) {
00769 writePSFmt(" (%s)", cc->name->getCString());
00770 }
00771 writePS("\n");
00772 writePS("%%CMYKCustomColor:\n");
00773 for (cc = customColors; cc; cc = cc->next) {
00774 writePSFmt("%%%%+ %g %g %g %g (%s)\n",
00775 cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
00776 }
00777 }
00778 writePS("%%EOF\n");
00779 }
00780 if (fileType == psFile) {
00781 #ifdef MACOS
00782 ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
00783 #endif
00784 fclose((FILE *)outputStream);
00785 }
00786 #ifdef HAVE_POPEN
00787 else if (fileType == psPipe) {
00788 pclose((FILE *)outputStream);
00789 #ifndef WIN32
00790 signal(SIGPIPE, (SignalFunc)SIG_DFL);
00791 #endif
00792 }
00793 #endif
00794 }
00795 if (embFontList) {
00796 delete embFontList;
00797 }
00798 if (fontIDs) {
00799 gfree(fontIDs);
00800 }
00801 if (fontFileIDs) {
00802 gfree(fontFileIDs);
00803 }
00804 if (fontFileNames) {
00805 for (i = 0; i < fontFileNameLen; ++i) {
00806 delete fontFileNames[i];
00807 }
00808 gfree(fontFileNames);
00809 }
00810 if (font16Enc) {
00811 for (i = 0; i < font16EncLen; ++i) {
00812 delete font16Enc[i].enc;
00813 }
00814 gfree(font16Enc);
00815 }
00816 while (customColors) {
00817 cc = customColors;
00818 customColors = cc->next;
00819 delete cc;
00820 }
00821 }
00822
00823 void PSOutputDev::setupResources(Dict *resDict) {
00824 Object xObjDict, xObj, resObj;
00825 int i;
00826
00827 setupFonts(resDict);
00828 setupImages(resDict);
00829
00830 resDict->lookup("XObject", &xObjDict);
00831 if (xObjDict.isDict()) {
00832 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
00833 xObjDict.dictGetVal(i, &xObj);
00834 if (xObj.isStream()) {
00835 xObj.streamGetDict()->lookup("Resources", &resObj);
00836 if (resObj.isDict()) {
00837 setupResources(resObj.getDict());
00838 }
00839 resObj.free();
00840 }
00841 xObj.free();
00842 }
00843 }
00844 xObjDict.free();
00845 }
00846
00847 void PSOutputDev::setupFonts(Dict *resDict) {
00848 Object fontDict;
00849 GfxFontDict *gfxFontDict;
00850 GfxFont *font;
00851 int i;
00852
00853 resDict->lookup("Font", &fontDict);
00854 if (fontDict.isDict()) {
00855 gfxFontDict = new GfxFontDict(xref, fontDict.getDict());
00856 for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
00857 font = gfxFontDict->getFont(i);
00858 setupFont(font, resDict);
00859 }
00860 delete gfxFontDict;
00861 }
00862 fontDict.free();
00863 }
00864
00865 void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
00866 Ref fontFileID;
00867 GString *name;
00868 PSFontParam *fontParam;
00869 GString *psNameStr;
00870 char *psName;
00871 char type3Name[64], buf[16];
00872 UnicodeMap *uMap;
00873 char *charName;
00874 double xs, ys;
00875 int code;
00876 double w1, w2;
00877 double *fm;
00878 int i, j;
00879
00880
00881 for (i = 0; i < fontIDLen; ++i) {
00882 if (fontIDs[i].num == font->getID()->num &&
00883 fontIDs[i].gen == font->getID()->gen) {
00884 return;
00885 }
00886 }
00887
00888
00889 if (fontIDLen >= fontIDSize) {
00890 fontIDSize += 64;
00891 fontIDs = (Ref *)grealloc(fontIDs, fontIDSize * sizeof(Ref));
00892 }
00893 fontIDs[fontIDLen++] = *font->getID();
00894
00895 xs = ys = 1;
00896 psNameStr = NULL;
00897
00898
00899 if (font->getName() &&
00900 (fontParam = globalParams->getPSFont(font->getName()))) {
00901 psName = fontParam->psFontName->getCString();
00902
00903
00904 } else if (globalParams->getPSEmbedType1() &&
00905 font->getType() == fontType1 &&
00906 font->getEmbeddedFontID(&fontFileID)) {
00907 psNameStr = filterPSName(font->getEmbeddedFontName());
00908 psName = psNameStr->getCString();
00909 setupEmbeddedType1Font(&fontFileID, psName);
00910
00911
00912 } else if (globalParams->getPSEmbedType1() &&
00913 font->getType() == fontType1C &&
00914 font->getEmbeddedFontID(&fontFileID)) {
00915 psNameStr = filterPSName(font->getEmbeddedFontName());
00916 psName = psNameStr->getCString();
00917 setupEmbeddedType1CFont(font, &fontFileID, psName);
00918
00919
00920 } else if (globalParams->getPSEmbedType1() &&
00921 font->getType() == fontType1 &&
00922 font->getExtFontFile()) {
00923
00924 psName = font->getName()->getCString();
00925 setupExternalType1Font(font->getExtFontFile(), psName);
00926
00927
00928 } else if (globalParams->getPSEmbedTrueType() &&
00929 font->getType() == fontTrueType &&
00930 font->getEmbeddedFontID(&fontFileID)) {
00931 psNameStr = filterPSName(font->getEmbeddedFontName());
00932 psName = psNameStr->getCString();
00933 setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
00934
00935
00936 } else if (globalParams->getPSEmbedTrueType() &&
00937 font->getType() == fontTrueType &&
00938 font->getExtFontFile()) {
00939 psNameStr = filterPSName(font->getName());
00940 psName = psNameStr->getCString();
00941 setupExternalTrueTypeFont(font, psName);
00942
00943
00944 } else if (globalParams->getPSEmbedCIDPostScript() &&
00945 font->getType() == fontCIDType0C &&
00946 font->getEmbeddedFontID(&fontFileID)) {
00947 psNameStr = filterPSName(font->getEmbeddedFontName());
00948 psName = psNameStr->getCString();
00949 setupEmbeddedCIDType0Font(font, &fontFileID, psName);
00950
00951
00952 } else if (globalParams->getPSEmbedCIDTrueType() &&
00953 font->getType() == fontCIDType2 &&
00954 font->getEmbeddedFontID(&fontFileID)) {
00955 psNameStr = filterPSName(font->getEmbeddedFontName());
00956 psName = psNameStr->getCString();
00957 setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName);
00958
00959 } else if (font->getType() == fontType3) {
00960 sprintf(type3Name, "T3_%d_%d",
00961 font->getID()->num, font->getID()->gen);
00962 psName = type3Name;
00963 setupType3Font(font, psName, parentResDict);
00964
00965
00966 } else if (!font->isCIDFont()) {
00967 name = font->getName();
00968 psName = NULL;
00969 if (name) {
00970 for (i = 0; psFonts[i]; ++i) {
00971 if (name->cmp(psFonts[i]) == 0) {
00972 psName = psFonts[i];
00973 break;
00974 }
00975 }
00976 }
00977 if (!psName) {
00978 if (font->isFixedWidth()) {
00979 i = 8;
00980 } else if (font->isSerif()) {
00981 i = 4;
00982 } else {
00983 i = 0;
00984 }
00985 if (font->isBold()) {
00986 i += 2;
00987 }
00988 if (font->isItalic()) {
00989 i += 1;
00990 }
00991 psName = psSubstFonts[i].psName;
00992 for (code = 0; code < 256; ++code) {
00993 if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
00994 charName[0] == 'm' && charName[1] == '\0') {
00995 break;
00996 }
00997 }
00998 if (code < 256) {
00999 w1 = ((Gfx8BitFont *)font)->getWidth(code);
01000 } else {
01001 w1 = 0;
01002 }
01003 w2 = psSubstFonts[i].mWidth;
01004 xs = w1 / w2;
01005 if (xs < 0.1) {
01006 xs = 1;
01007 }
01008 if (font->getType() == fontType3) {
01009
01010
01011
01012
01013 ys = xs;
01014 fm = font->getFontMatrix();
01015 if (fm[0] != 0) {
01016 ys *= fm[3] / fm[0];
01017 }
01018 } else {
01019 ys = 1;
01020 }
01021 }
01022
01023
01024 } else if ((fontParam = globalParams->
01025 getPSFont16(font->getName(),
01026 ((GfxCIDFont *)font)->getCollection(),
01027 font->getWMode()))) {
01028 psName = fontParam->psFontName->getCString();
01029 if (font16EncLen >= font16EncSize) {
01030 font16EncSize += 16;
01031 font16Enc = (PSFont16Enc *)grealloc(font16Enc,
01032 font16EncSize * sizeof(PSFont16Enc));
01033 }
01034 font16Enc[font16EncLen].fontID = *font->getID();
01035 font16Enc[font16EncLen].enc = fontParam->encoding->copy();
01036 if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
01037 uMap->decRefCnt();
01038 ++font16EncLen;
01039 } else {
01040 error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
01041 font16Enc[font16EncLen].enc->getCString());
01042 }
01043
01044
01045 } else {
01046 error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
01047 font->getName() ? font->getName()->getCString() : "(unnamed)",
01048 ((GfxCIDFont *)font)->getCollection()
01049 ? ((GfxCIDFont *)font)->getCollection()->getCString()
01050 : "(unknown)");
01051 return;
01052 }
01053
01054
01055 if (font->isCIDFont()) {
01056 if (level == psLevel3 || level == psLevel3Sep) {
01057 writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
01058 font->getID()->num, font->getID()->gen, psName,
01059 font->getWMode());
01060 } else {
01061 writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
01062 font->getID()->num, font->getID()->gen, psName,
01063 font->getWMode());
01064 }
01065 } else {
01066 writePSFmt("/F%d_%d /%s %g %g\n",
01067 font->getID()->num, font->getID()->gen, psName, xs, ys);
01068 for (i = 0; i < 256; i += 8) {
01069 writePSFmt((i == 0) ? "[ " : " ");
01070 for (j = 0; j < 8; ++j) {
01071 if (font->getType() == fontTrueType &&
01072 !((Gfx8BitFont *)font)->getHasEncoding()) {
01073 sprintf(buf, "c%02x", i+j);
01074 charName = buf;
01075 } else {
01076 charName = ((Gfx8BitFont *)font)->getCharName(i+j);
01077
01078
01079 if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
01080 charName = "space";
01081 }
01082 }
01083 writePS("/");
01084 writePSName(charName ? charName : (char *)".notdef");
01085 }
01086 writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
01087 }
01088 writePS("pdfMakeFont\n");
01089 }
01090
01091 if (psNameStr) {
01092 delete psNameStr;
01093 }
01094 }
01095
01096 void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
01097 static char hexChar[17] = "0123456789abcdef";
01098 Object refObj, strObj, obj1, obj2;
01099 Dict *dict;
01100 int length1, length2;
01101 int c;
01102 int start[4];
01103 GBool binMode;
01104 int i;
01105
01106
01107 for (i = 0; i < fontFileIDLen; ++i) {
01108 if (fontFileIDs[i].num == id->num &&
01109 fontFileIDs[i].gen == id->gen)
01110 return;
01111 }
01112
01113
01114 if (fontFileIDLen >= fontFileIDSize) {
01115 fontFileIDSize += 64;
01116 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
01117 }
01118 fontFileIDs[fontFileIDLen++] = *id;
01119
01120
01121 refObj.initRef(id->num, id->gen);
01122 refObj.fetch(xref, &strObj);
01123 refObj.free();
01124 if (!strObj.isStream()) {
01125 error(-1, "Embedded font file object is not a stream");
01126 goto err1;
01127 }
01128 if (!(dict = strObj.streamGetDict())) {
01129 error(-1, "Embedded font stream is missing its dictionary");
01130 goto err1;
01131 }
01132 dict->lookup("Length1", &obj1);
01133 dict->lookup("Length2", &obj2);
01134 if (!obj1.isInt() || !obj2.isInt()) {
01135 error(-1, "Missing length fields in embedded font stream dictionary");
01136 obj1.free();
01137 obj2.free();
01138 goto err1;
01139 }
01140 length1 = obj1.getInt();
01141 length2 = obj2.getInt();
01142 obj1.free();
01143 obj2.free();
01144
01145
01146 writePSFmt("%%%%BeginResource: font %s\n", psName);
01147 embFontList->append("%%+ font ");
01148 embFontList->append(psName);
01149 embFontList->append("\n");
01150
01151
01152 strObj.streamReset();
01153 for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
01154 writePSChar(c);
01155 }
01156
01157
01158 binMode = gFalse;
01159 for (i = 0; i < 4; ++i) {
01160 start[i] = strObj.streamGetChar();
01161 if (start[i] == EOF) {
01162 error(-1, "Unexpected end of file in embedded font stream");
01163 goto err1;
01164 }
01165 if (!((start[i] >= '0' && start[i] <= '9') ||
01166 (start[i] >= 'A' && start[i] <= 'F') ||
01167 (start[i] >= 'a' && start[i] <= 'f')))
01168 binMode = gTrue;
01169 }
01170
01171
01172 if (binMode) {
01173 for (i = 0; i < 4; ++i) {
01174 writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
01175 writePSChar(hexChar[start[i] & 0x0f]);
01176 }
01177 while (i < length2) {
01178 if ((c = strObj.streamGetChar()) == EOF) {
01179 break;
01180 }
01181 writePSChar(hexChar[(c >> 4) & 0x0f]);
01182 writePSChar(hexChar[c & 0x0f]);
01183 if (++i % 32 == 0) {
01184 writePSChar('\n');
01185 }
01186 }
01187 if (i % 32 > 0) {
01188 writePSChar('\n');
01189 }
01190
01191
01192 } else {
01193 for (i = 0; i < 4; ++i) {
01194 writePSChar(start[i]);
01195 }
01196 for (i = 4; i < length2; ++i) {
01197 if ((c = strObj.streamGetChar()) == EOF) {
01198 break;
01199 }
01200 writePSChar(c);
01201 }
01202 }
01203
01204
01205 for (i = 0; i < 8; ++i) {
01206 writePS("00000000000000000000000000000000"
01207 "00000000000000000000000000000000\n");
01208 }
01209 writePS("cleartomark\n");
01210
01211
01212 writePS("%%EndResource\n");
01213
01214 err1:
01215 strObj.streamClose();
01216 strObj.free();
01217 }
01218
01219
01220
01221 void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
01222 FILE *fontFile;
01223 int c;
01224 int i;
01225
01226
01227 for (i = 0; i < fontFileNameLen; ++i) {
01228 if (!fontFileNames[i]->cmp(fileName)) {
01229 return;
01230 }
01231 }
01232
01233
01234 if (fontFileNameLen >= fontFileNameSize) {
01235 fontFileNameSize += 64;
01236 fontFileNames = (GString **)grealloc(fontFileNames,
01237 fontFileNameSize * sizeof(GString *));
01238 }
01239 fontFileNames[fontFileNameLen++] = fileName->copy();
01240
01241
01242 writePSFmt("%%%%BeginResource: font %s\n", psName);
01243 embFontList->append("%%+ font ");
01244 embFontList->append(psName);
01245 embFontList->append("\n");
01246
01247
01248 if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
01249 error(-1, "Couldn't open external font file");
01250 return;
01251 }
01252 while ((c = fgetc(fontFile)) != EOF) {
01253 writePSChar(c);
01254 }
01255 fclose(fontFile);
01256
01257
01258 writePS("%%EndResource\n");
01259 }
01260
01261 void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
01262 char *psName) {
01263 char *fontBuf;
01264 int fontLen;
01265 Type1CFontFile *t1cFile;
01266 int i;
01267
01268
01269 for (i = 0; i < fontFileIDLen; ++i) {
01270 if (fontFileIDs[i].num == id->num &&
01271 fontFileIDs[i].gen == id->gen)
01272 return;
01273 }
01274
01275
01276 if (fontFileIDLen >= fontFileIDSize) {
01277 fontFileIDSize += 64;
01278 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
01279 }
01280 fontFileIDs[fontFileIDLen++] = *id;
01281
01282
01283 writePSFmt("%%%%BeginResource: font %s\n", psName);
01284 embFontList->append("%%+ font ");
01285 embFontList->append(psName);
01286 embFontList->append("\n");
01287
01288
01289 fontBuf = font->readEmbFontFile(xref, &fontLen);
01290 t1cFile = new Type1CFontFile(fontBuf, fontLen);
01291 t1cFile->convertToType1(outputFunc, outputStream);
01292 delete t1cFile;
01293 gfree(fontBuf);
01294
01295
01296 writePS("%%EndResource\n");
01297 }
01298
01299 void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
01300 char *psName) {
01301 char *fontBuf;
01302 int fontLen;
01303 TrueTypeFontFile *ttFile;
01304 CharCodeToUnicode *ctu;
01305 int i;
01306
01307
01308 for (i = 0; i < fontFileIDLen; ++i) {
01309 if (fontFileIDs[i].num == id->num &&
01310 fontFileIDs[i].gen == id->gen)
01311 return;
01312 }
01313
01314
01315 if (fontFileIDLen >= fontFileIDSize) {
01316 fontFileIDSize += 64;
01317 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
01318 }
01319 fontFileIDs[fontFileIDLen++] = *id;
01320
01321
01322 writePSFmt("%%%%BeginResource: font %s\n", psName);
01323 embFontList->append("%%+ font ");
01324 embFontList->append(psName);
01325 embFontList->append("\n");
01326
01327
01328 fontBuf = font->readEmbFontFile(xref, &fontLen);
01329 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
01330 ctu = ((Gfx8BitFont *)font)->getToUnicode();
01331 ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
01332 ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
01333 outputFunc, outputStream);
01334 ctu->decRefCnt();
01335 delete ttFile;
01336 gfree(fontBuf);
01337
01338
01339 writePS("%%EndResource\n");
01340 }
01341
01342 void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
01343 GString *fileName;
01344 char *fontBuf;
01345 int fontLen;
01346 TrueTypeFontFile *ttFile;
01347 CharCodeToUnicode *ctu;
01348 int i;
01349
01350
01351 fileName = font->getExtFontFile();
01352 for (i = 0; i < fontFileNameLen; ++i) {
01353 if (!fontFileNames[i]->cmp(fileName)) {
01354 return;
01355 }
01356 }
01357
01358
01359 if (fontFileNameLen >= fontFileNameSize) {
01360 fontFileNameSize += 64;
01361 fontFileNames = (GString **)grealloc(fontFileNames,
01362 fontFileNameSize * sizeof(GString *));
01363 }
01364 fontFileNames[fontFileNameLen++] = fileName->copy();
01365
01366
01367 writePSFmt("%%%%BeginResource: font %s\n", psName);
01368 embFontList->append("%%+ font ");
01369 embFontList->append(psName);
01370 embFontList->append("\n");
01371
01372
01373 fontBuf = font->readExtFontFile(&fontLen);
01374 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
01375 ctu = ((Gfx8BitFont *)font)->getToUnicode();
01376 ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
01377 ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
01378 outputFunc, outputStream);
01379 ctu->decRefCnt();
01380 delete ttFile;
01381 gfree(fontBuf);
01382
01383
01384 writePS("%%EndResource\n");
01385 }
01386
01387 void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
01388 char *psName) {
01389 char *fontBuf;
01390 int fontLen;
01391 Type1CFontFile *t1cFile;
01392 int i;
01393
01394
01395 for (i = 0; i < fontFileIDLen; ++i) {
01396 if (fontFileIDs[i].num == id->num &&
01397 fontFileIDs[i].gen == id->gen)
01398 return;
01399 }
01400
01401
01402 if (fontFileIDLen >= fontFileIDSize) {
01403 fontFileIDSize += 64;
01404 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
01405 }
01406 fontFileIDs[fontFileIDLen++] = *id;
01407
01408
01409 writePSFmt("%%%%BeginResource: font %s\n", psName);
01410 embFontList->append("%%+ font ");
01411 embFontList->append(psName);
01412 embFontList->append("\n");
01413
01414
01415 fontBuf = font->readEmbFontFile(xref, &fontLen);
01416 t1cFile = new Type1CFontFile(fontBuf, fontLen);
01417 if (globalParams->getPSLevel() >= psLevel3) {
01418
01419 t1cFile->convertToCIDType0(psName, outputFunc, outputStream);
01420 } else {
01421
01422 t1cFile->convertToType0(psName, outputFunc, outputStream);
01423 }
01424 delete t1cFile;
01425 gfree(fontBuf);
01426
01427
01428 writePS("%%EndResource\n");
01429 }
01430
01431 void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
01432 char *psName) {
01433 char *fontBuf;
01434 int fontLen;
01435 TrueTypeFontFile *ttFile;
01436 int i;
01437
01438
01439 for (i = 0; i < fontFileIDLen; ++i) {
01440 if (fontFileIDs[i].num == id->num &&
01441 fontFileIDs[i].gen == id->gen)
01442 return;
01443 }
01444
01445
01446 if (fontFileIDLen >= fontFileIDSize) {
01447 fontFileIDSize += 64;
01448 fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
01449 }
01450 fontFileIDs[fontFileIDLen++] = *id;
01451
01452
01453 writePSFmt("%%%%BeginResource: font %s\n", psName);
01454 embFontList->append("%%+ font ");
01455 embFontList->append(psName);
01456 embFontList->append("\n");
01457
01458
01459 fontBuf = font->readEmbFontFile(xref, &fontLen);
01460 ttFile = new TrueTypeFontFile(fontBuf, fontLen);
01461 if (globalParams->getPSLevel() >= psLevel3) {
01462 ttFile->convertToCIDType2(psName,
01463 ((GfxCIDFont *)font)->getCIDToGID(),
01464 ((GfxCIDFont *)font)->getCIDToGIDLen(),
01465 outputFunc, outputStream);
01466 } else {
01467
01468 ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(),
01469 ((GfxCIDFont *)font)->getCIDToGIDLen(),
01470 outputFunc, outputStream);
01471 }
01472 delete ttFile;
01473 gfree(fontBuf);
01474
01475
01476 writePS("%%EndResource\n");
01477 }
01478
01479 void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
01480 Dict *parentResDict) {
01481 Dict *resDict;
01482 Dict *charProcs;
01483 Object charProc;
01484 Gfx *gfx;
01485 PDFRectangle box;
01486 double *m;
01487 char buf[256];
01488 int i;
01489
01490
01491 if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
01492 setupResources(resDict);
01493 } else {
01494 resDict = parentResDict;
01495 }
01496
01497
01498 writePSFmt("%%%%BeginResource: font %s\n", psName);
01499 embFontList->append("%%+ font ");
01500 embFontList->append(psName);
01501 embFontList->append("\n");
01502
01503
01504 writePS("7 dict begin\n");
01505 writePS("/FontType 3 def\n");
01506 m = font->getFontMatrix();
01507 writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n",
01508 m[0], m[1], m[2], m[3], m[4], m[5]);
01509 m = font->getFontBBox();
01510 writePSFmt("/FontBBox [%g %g %g %g] def\n",
01511 m[0], m[1], m[2], m[3]);
01512 writePS("/Encoding 256 array def\n");
01513 writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
01514 writePS("/BuildGlyph {\n");
01515 writePS(" exch /CharProcs get exch\n");
01516 writePS(" 2 copy known not { pop /.notdef } if\n");
01517 writePS(" get exec\n");
01518 writePS("} bind def\n");
01519 writePS("/BuildChar {\n");
01520 writePS(" 1 index /Encoding get exch get\n");
01521 writePS(" 1 index /BuildGlyph get exec\n");
01522 writePS("} bind def\n");
01523 if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
01524 writePSFmt("/CharProcs %d dict def\n", charProcs->getLength());
01525 writePS("CharProcs begin\n");
01526 box.x1 = m[0];
01527 box.y1 = m[1];
01528 box.x2 = m[2];
01529 box.y2 = m[3];
01530 gfx = new Gfx(xref, this, resDict, &box, gFalse, NULL);
01531 inType3Char = gTrue;
01532 t3Cacheable = gFalse;
01533 for (i = 0; i < charProcs->getLength(); ++i) {
01534 writePS("/");
01535 writePSName(charProcs->getKey(i));
01536 writePS(" {\n");
01537 gfx->display(charProcs->getVal(i, &charProc));
01538 charProc.free();
01539 if (t3String) {
01540 if (t3Cacheable) {
01541 sprintf(buf, "%g %g %g %g %g %g setcachedevice\n",
01542 t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
01543 } else {
01544 sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY);
01545 }
01546 (*outputFunc)(outputStream, buf, strlen(buf));
01547 (*outputFunc)(outputStream, t3String->getCString(),
01548 t3String->getLength());
01549 delete t3String;
01550 t3String = NULL;
01551 }
01552 (*outputFunc)(outputStream, "Q\n", 2);
01553 writePS("} def\n");
01554 }
01555 inType3Char = gFalse;
01556 delete gfx;
01557 writePS("end\n");
01558 }
01559 writePS("currentdict end\n");
01560 writePSFmt("/%s exch definefont pop\n", psName);
01561
01562
01563 writePS("%%EndResource\n");
01564 }
01565
01566 void PSOutputDev::setupImages(Dict *resDict) {
01567 Object xObjDict, xObj, xObjRef, subtypeObj;
01568 int i;
01569
01570 if (mode != psModeForm) {
01571 return;
01572 }
01573
01574 resDict->lookup("XObject", &xObjDict);
01575 if (xObjDict.isDict()) {
01576 for (i = 0; i < xObjDict.dictGetLength(); ++i) {
01577 xObjDict.dictGetValNF(i, &xObjRef);
01578 xObjDict.dictGetVal(i, &xObj);
01579 if (xObj.isStream()) {
01580 xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
01581 if (subtypeObj.isName("Image")) {
01582 if (xObjRef.isRef()) {
01583 setupImage(xObjRef.getRef(), xObj.getStream());
01584 } else {
01585 error(-1, "Image in resource dict is not an indirect reference");
01586 }
01587 }
01588 subtypeObj.free();
01589 }
01590 xObj.free();
01591 xObjRef.free();
01592 }
01593 }
01594 xObjDict.free();
01595 }
01596
01597 void PSOutputDev::setupImage(Ref id, Stream *str) {
01598 int c;
01599 int size, line, col, i;
01600
01601
01602 if (globalParams->getPSASCIIHex()) {
01603 str = new ASCIIHexEncoder(str);
01604 } else {
01605 str = new ASCII85Encoder(str);
01606 }
01607
01608
01609 str->reset();
01610 col = size = 0;
01611 do {
01612 do {
01613 c = str->getChar();
01614 } while (c == '\n' || c == '\r');
01615 if (c == '~' || c == EOF) {
01616 break;
01617 }
01618 if (c == 'z') {
01619 ++col;
01620 } else {
01621 ++col;
01622 for (i = 1; i <= 4; ++i) {
01623 do {
01624 c = str->getChar();
01625 } while (c == '\n' || c == '\r');
01626 if (c == '~' || c == EOF) {
01627 break;
01628 }
01629 ++col;
01630 }
01631 }
01632 if (col > 225) {
01633 ++size;
01634 col = 0;
01635 }
01636 } while (c != '~' && c != EOF);
01637 ++size;
01638 writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
01639
01640
01641 str->reset();
01642 line = col = 0;
01643 writePS("dup 0 <~");
01644 do {
01645 do {
01646 c = str->getChar();
01647 } while (c == '\n' || c == '\r');
01648 if (c == '~' || c == EOF) {
01649 break;
01650 }
01651 if (c == 'z') {
01652 writePSChar(c);
01653 ++col;
01654 } else {
01655 writePSChar(c);
01656 ++col;
01657 for (i = 1; i <= 4; ++i) {
01658 do {
01659 c = str->getChar();
01660 } while (c == '\n' || c == '\r');
01661 if (c == '~' || c == EOF) {
01662 break;
01663 }
01664 writePSChar(c);
01665 ++col;
01666 }
01667 }
01668
01669
01670
01671
01672 if (col > 225) {
01673 writePS("~> put\n");
01674 ++line;
01675 writePSFmt("dup %d <~", line);
01676 col = 0;
01677 }
01678 } while (c != '~' && c != EOF);
01679 writePS("~> put\n");
01680 writePS("pop\n");
01681
01682 delete str;
01683 }
01684
01685 void PSOutputDev::startPage(int pageNum, GfxState *state) {
01686 int x1, y1, x2, y2, width, height, t;
01687
01688
01689 switch (mode) {
01690
01691 case psModePS:
01692 writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage);
01693 writePS("%%BeginPageSetup\n");
01694
01695
01696 x1 = (int)(state->getX1() + 0.5);
01697 y1 = (int)(state->getY1() + 0.5);
01698 x2 = (int)(state->getX2() + 0.5);
01699 y2 = (int)(state->getY2() + 0.5);
01700 width = x2 - x1;
01701 height = y2 - y1;
01702 if (width > height && width > paperWidth) {
01703 landscape = gTrue;
01704 writePSFmt("%%%%PageOrientation: %s\n",
01705 state->getCTM()[0] ? "Landscape" : "Portrait");
01706 writePS("pdfStartPage\n");
01707 writePS("90 rotate\n");
01708 tx = -x1;
01709 ty = -(y1 + paperWidth);
01710 t = width;
01711 width = height;
01712 height = t;
01713 } else {
01714 landscape = gFalse;
01715 writePSFmt("%%%%PageOrientation: %s\n",
01716 state->getCTM()[0] ? "Portrait" : "Landscape");
01717 writePS("pdfStartPage\n");
01718 tx = -x1;
01719 ty = -y1;
01720 }
01721 if (width < paperWidth) {
01722 tx += (paperWidth - width) / 2;
01723 }
01724 if (height < paperHeight) {
01725 ty += (paperHeight - height) / 2;
01726 }
01727 if (tx != 0 || ty != 0) {
01728 writePSFmt("%g %g translate\n", tx, ty);
01729 }
01730 if (width > paperWidth || height > paperHeight) {
01731 xScale = (double)paperWidth / (double)width;
01732 yScale = (double)paperHeight / (double)height;
01733 if (yScale < xScale) {
01734 xScale = yScale;
01735 } else {
01736 yScale = xScale;
01737 }
01738 writePSFmt("%0.4f %0.4f scale\n", xScale, xScale);
01739 } else {
01740 xScale = yScale = 1;
01741 }
01742
01743 writePS("%%EndPageSetup\n");
01744 ++seqPage;
01745 break;
01746
01747 case psModeEPS:
01748 writePS("pdfStartPage\n");
01749 tx = ty = 0;
01750 xScale = yScale = 1;
01751 landscape = gFalse;
01752 break;
01753
01754 case psModeForm:
01755 writePS("/PaintProc {\n");
01756 writePS("begin xpdf begin\n");
01757 writePS("pdfStartPage\n");
01758 tx = ty = 0;
01759 xScale = yScale = 1;
01760 landscape = gFalse;
01761 break;
01762 }
01763 }
01764
01765 void PSOutputDev::endPage() {
01766
01767 if (mode == psModeForm) {
01768 writePS("pdfEndPage\n");
01769 writePS("end end\n");
01770 writePS("} def\n");
01771 writePS("end end\n");
01772 } else {
01773 writePS("showpage\n");
01774 writePS("%%PageTrailer\n");
01775 writePS("pdfEndPage\n");
01776 }
01777 }
01778
01779 void PSOutputDev::saveState(GfxState *state) {
01780 writePS("q\n");
01781 }
01782
01783 void PSOutputDev::restoreState(GfxState *state) {
01784 writePS("Q\n");
01785 }
01786
01787 void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
01788 double m21, double m22, double m31, double m32) {
01789 writePSFmt("[%g %g %g %g %g %g] cm\n", m11, m12, m21, m22, m31, m32);
01790 }
01791
01792 void PSOutputDev::updateLineDash(GfxState *state) {
01793 double *dash;
01794 double start;
01795 int length, i;
01796
01797 state->getLineDash(&dash, &length, &start);
01798 writePS("[");
01799 for (i = 0; i < length; ++i)
01800 writePSFmt("%g%s", dash[i], (i == length-1) ? "" : " ");
01801 writePSFmt("] %g d\n", start);
01802 }
01803
01804 void PSOutputDev::updateFlatness(GfxState *state) {
01805 writePSFmt("%d i\n", state->getFlatness());
01806 }
01807
01808 void PSOutputDev::updateLineJoin(GfxState *state) {
01809 writePSFmt("%d j\n", state->getLineJoin());
01810 }
01811
01812 void PSOutputDev::updateLineCap(GfxState *state) {
01813 writePSFmt("%d J\n", state->getLineCap());
01814 }
01815
01816 void PSOutputDev::updateMiterLimit(GfxState *state) {
01817 writePSFmt("%g M\n", state->getMiterLimit());
01818 }
01819
01820 void PSOutputDev::updateLineWidth(GfxState *state) {
01821 writePSFmt("%g w\n", state->getLineWidth());
01822 }
01823
01824 void PSOutputDev::updateFillColor(GfxState *state) {
01825 GfxColor color;
01826 double gray;
01827 GfxRGB rgb;
01828 GfxCMYK cmyk;
01829 GfxSeparationColorSpace *sepCS;
01830
01831 switch (level) {
01832 case psLevel1:
01833 state->getFillGray(&gray);
01834 writePSFmt("%g g\n", gray);
01835 break;
01836 case psLevel1Sep:
01837 state->getFillCMYK(&cmyk);
01838 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01839 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01840 break;
01841 case psLevel2:
01842 case psLevel3:
01843 if (state->getFillColorSpace()->getMode() == csDeviceCMYK) {
01844 state->getFillCMYK(&cmyk);
01845 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01846 } else {
01847 state->getFillRGB(&rgb);
01848 if (rgb.r == rgb.g && rgb.g == rgb.b) {
01849 writePSFmt("%g g\n", rgb.r);
01850 } else {
01851 writePSFmt("%g %g %g rg\n", rgb.r, rgb.g, rgb.b);
01852 }
01853 }
01854 break;
01855 case psLevel2Sep:
01856 case psLevel3Sep:
01857 if (state->getFillColorSpace()->getMode() == csSeparation) {
01858 sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
01859 color.c[0] = 1;
01860 sepCS->getCMYK(&color, &cmyk);
01861 writePSFmt("%g %g %g %g %g (%s) ck\n",
01862 state->getFillColor()->c[0],
01863 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
01864 sepCS->getName()->getCString());
01865 addCustomColor(sepCS);
01866 } else {
01867 state->getFillCMYK(&cmyk);
01868 writePSFmt("%g %g %g %g k\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01869 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01870 }
01871 break;
01872 }
01873 t3Cacheable = gFalse;
01874 }
01875
01876 void PSOutputDev::updateStrokeColor(GfxState *state) {
01877 GfxColor color;
01878 double gray;
01879 GfxRGB rgb;
01880 GfxCMYK cmyk;
01881 GfxSeparationColorSpace *sepCS;
01882
01883 switch (level) {
01884 case psLevel1:
01885 state->getStrokeGray(&gray);
01886 writePSFmt("%g G\n", gray);
01887 break;
01888 case psLevel1Sep:
01889 state->getStrokeCMYK(&cmyk);
01890 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01891 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01892 break;
01893 case psLevel2:
01894 case psLevel3:
01895 if (state->getStrokeColorSpace()->getMode() == csDeviceCMYK) {
01896 state->getStrokeCMYK(&cmyk);
01897 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01898 } else {
01899 state->getStrokeRGB(&rgb);
01900 if (rgb.r == rgb.g && rgb.g == rgb.b) {
01901 writePSFmt("%g G\n", rgb.r);
01902 } else {
01903 writePSFmt("%g %g %g RG\n", rgb.r, rgb.g, rgb.b);
01904 }
01905 }
01906 break;
01907 case psLevel2Sep:
01908 case psLevel3Sep:
01909 if (state->getStrokeColorSpace()->getMode() == csSeparation) {
01910 sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
01911 color.c[0] = 1;
01912 sepCS->getCMYK(&color, &cmyk);
01913 writePSFmt("%g %g %g %g %g (%s) CK\n",
01914 state->getStrokeColor()->c[0],
01915 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
01916 sepCS->getName()->getCString());
01917 addCustomColor(sepCS);
01918 } else {
01919 state->getStrokeCMYK(&cmyk);
01920 writePSFmt("%g %g %g %g K\n", cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01921 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
01922 }
01923 break;
01924 }
01925 t3Cacheable = gFalse;
01926 }
01927
01928 void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
01929 if (c > 0) {
01930 processColors |= psProcessCyan;
01931 }
01932 if (m > 0) {
01933 processColors |= psProcessMagenta;
01934 }
01935 if (y > 0) {
01936 processColors |= psProcessYellow;
01937 }
01938 if (k > 0) {
01939 processColors |= psProcessBlack;
01940 }
01941 }
01942
01943 void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
01944 PSOutCustomColor *cc;
01945 GfxColor color;
01946 GfxCMYK cmyk;
01947
01948 for (cc = customColors; cc; cc = cc->next) {
01949 if (!cc->name->cmp(sepCS->getName())) {
01950 return;
01951 }
01952 }
01953 color.c[0] = 1;
01954 sepCS->getCMYK(&color, &cmyk);
01955 cc = new PSOutCustomColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k,
01956 sepCS->getName()->copy());
01957 cc->next = customColors;
01958 customColors = cc;
01959 }
01960
01961 void PSOutputDev::updateFont(GfxState *state) {
01962 if (state->getFont()) {
01963 writePSFmt("/F%d_%d %g Tf\n",
01964 state->getFont()->getID()->num, state->getFont()->getID()->gen,
01965 state->getFontSize());
01966 }
01967 }
01968
01969 void PSOutputDev::updateTextMat(GfxState *state) {
01970 double *mat;
01971
01972 mat = state->getTextMat();
01973 writePSFmt("[%g %g %g %g %g %g] Tm\n",
01974 mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
01975 }
01976
01977 void PSOutputDev::updateCharSpace(GfxState *state) {
01978 writePSFmt("%g Tc\n", state->getCharSpace());
01979 }
01980
01981 void PSOutputDev::updateRender(GfxState *state) {
01982 int rm;
01983
01984 rm = state->getRender();
01985 writePSFmt("%d Tr\n", rm);
01986 rm &= 3;
01987 if (rm != 0 && rm != 3) {
01988 t3Cacheable = gFalse;
01989 }
01990 }
01991
01992 void PSOutputDev::updateRise(GfxState *state) {
01993 writePSFmt("%g Ts\n", state->getRise());
01994 }
01995
01996 void PSOutputDev::updateWordSpace(GfxState *state) {
01997 writePSFmt("%g Tw\n", state->getWordSpace());
01998 }
01999
02000 void PSOutputDev::updateHorizScaling(GfxState *state) {
02001 writePSFmt("%g Tz\n", state->getHorizScaling());
02002 }
02003
02004 void PSOutputDev::updateTextPos(GfxState *state) {
02005 writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY());
02006 }
02007
02008 void PSOutputDev::updateTextShift(GfxState *state, double shift) {
02009 if (state->getFont()->getWMode()) {
02010 writePSFmt("%g TJmV\n", shift);
02011 } else {
02012 writePSFmt("%g TJm\n", shift);
02013 }
02014 }
02015
02016 void PSOutputDev::stroke(GfxState *state) {
02017 doPath(state->getPath());
02018 if (t3String) {
02019
02020
02021 writePS("Sf\n");
02022 } else {
02023 writePS("S\n");
02024 }
02025 }
02026
02027 void PSOutputDev::fill(GfxState *state) {
02028 doPath(state->getPath());
02029 writePS("f\n");
02030 }
02031
02032 void PSOutputDev::eoFill(GfxState *state) {
02033 doPath(state->getPath());
02034 writePS("f*\n");
02035 }
02036
02037 void PSOutputDev::clip(GfxState *state) {
02038 doPath(state->getPath());
02039 writePS("W\n");
02040 }
02041
02042 void PSOutputDev::eoClip(GfxState *state) {
02043 doPath(state->getPath());
02044 writePS("W*\n");
02045 }
02046
02047 void PSOutputDev::doPath(GfxPath *path) {
02048 GfxSubpath *subpath;
02049 double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
02050 int n, m, i, j;
02051
02052 n = path->getNumSubpaths();
02053
02054 if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
02055 subpath = path->getSubpath(0);
02056 x0 = subpath->getX(0);
02057 y0 = subpath->getY(0);
02058 x4 = subpath->getX(4);
02059 y4 = subpath->getY(4);
02060 if (x4 == x0 && y4 == y0) {
02061 x1 = subpath->getX(1);
02062 y1 = subpath->getY(1);
02063 x2 = subpath->getX(2);
02064 y2 = subpath->getY(2);
02065 x3 = subpath->getX(3);
02066 y3 = subpath->getY(3);
02067 if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
02068 writePSFmt("%g %g %g %g re\n",
02069 x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
02070 fabs(x2 - x0), fabs(y1 - y0));
02071 return;
02072 } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
02073 writePSFmt("%g %g %g %g re\n",
02074 x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
02075 fabs(x1 - x0), fabs(y2 - y0));
02076 return;
02077 }
02078 }
02079 }
02080
02081 for (i = 0; i < n; ++i) {
02082 subpath = path->getSubpath(i);
02083 m = subpath->getNumPoints();
02084 writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0));
02085 j = 1;
02086 while (j < m) {
02087 if (subpath->getCurve(j)) {
02088 writePSFmt("%g %g %g %g %g %g c\n", subpath->getX(j), subpath->getY(j),
02089 subpath->getX(j+1), subpath->getY(j+1),
02090 subpath->getX(j+2), subpath->getY(j+2));
02091 j += 3;
02092 } else {
02093 writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j));
02094 ++j;
02095 }
02096 }
02097 if (subpath->isClosed()) {
02098 writePS("h\n");
02099 }
02100 }
02101 }
02102
02103 void PSOutputDev::drawString(GfxState *state, GString *s) {
02104 GfxFont *font;
02105 int wMode;
02106 GString *s2;
02107 double dx, dy, dx2, dy2, originX, originY;
02108 char *p;
02109 UnicodeMap *uMap;
02110 CharCode code;
02111 Unicode u[8];
02112 char buf[8];
02113 int len, nChars, uLen, n, m, i, j;
02114
02115
02116 if ((state->getRender() & 3) == 3) {
02117 return;
02118 }
02119
02120
02121 if (s->getLength() == 0) {
02122 return;
02123 }
02124
02125
02126 if (!(font = state->getFont())) {
02127 return;
02128 }
02129 wMode = font->getWMode();
02130
02131
02132 uMap = NULL;
02133 if (font->isCIDFont()) {
02134 for (i = 0; i < font16EncLen; ++i) {
02135 if (font->getID()->num == font16Enc[i].fontID.num &&
02136 font->getID()->gen == font16Enc[i].fontID.gen) {
02137 uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
02138 break;
02139 }
02140 }
02141 }
02142
02143
02144
02145
02146 dx = dy = 0;
02147 nChars = 0;
02148 p = s->getCString();
02149 len = s->getLength();
02150 if (font->isCIDFont()) {
02151 s2 = new GString();
02152 } else {
02153 s2 = s;
02154 }
02155 while (len > 0) {
02156 n = font->getNextChar(p, len, &code,
02157 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
02158 &dx2, &dy2, &originX, &originY);
02159 if (font->isCIDFont()) {
02160 if (uMap) {
02161 for (i = 0; i < uLen; ++i) {
02162 m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
02163 for (j = 0; j < m; ++j) {
02164 s2->append(buf[j]);
02165 }
02166 }
02167
02168
02169
02170 nChars += uLen;
02171 } else {
02172 s2->append((char)((code >> 8) & 0xff));
02173 s2->append((char)(code & 0xff));
02174 ++nChars;
02175 }
02176 }
02177 dx += dx2;
02178 dy += dy2;
02179 p += n;
02180 len -= n;
02181 }
02182 dx *= state->getFontSize() * state->getHorizScaling();
02183 dy *= state->getFontSize();
02184 if (uMap) {
02185 uMap->decRefCnt();
02186 }
02187
02188 if (s2->getLength() > 0) {
02189 writePSString(s2);
02190 if (font->isCIDFont()) {
02191 if (wMode) {
02192 writePSFmt(" %d %g Tj16V\n", nChars, dy);
02193 } else {
02194 writePSFmt(" %d %g Tj16\n", nChars, dx);
02195 }
02196 } else {
02197 writePSFmt(" %g Tj\n", dx);
02198 }
02199 }
02200 if (font->isCIDFont()) {
02201 delete s2;
02202 }
02203 }
02204
02205 void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
02206 int width, int height, GBool invert,
02207 GBool inlineImg) {
02208 int len;
02209
02210 len = height * ((width + 7) / 8);
02211 if (level == psLevel1 || level == psLevel1Sep) {
02212 doImageL1(NULL, invert, inlineImg, str, width, height, len);
02213 } else {
02214 doImageL2(ref, NULL, invert, inlineImg, str, width, height, len);
02215 }
02216 }
02217
02218 void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
02219 int width, int height, GfxImageColorMap *colorMap,
02220 int *maskColors, GBool inlineImg) {
02221 int len;
02222
02223 len = height * ((width * colorMap->getNumPixelComps() *
02224 colorMap->getBits() + 7) / 8);
02225 switch (level) {
02226 case psLevel1:
02227 doImageL1(colorMap, gFalse, inlineImg, str, width, height, len);
02228 break;
02229 case psLevel1Sep:
02230
02231 doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
02232 break;
02233 case psLevel2:
02234 case psLevel2Sep:
02235 case psLevel3:
02236 case psLevel3Sep:
02237 doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len);
02238 break;
02239 }
02240 t3Cacheable = gFalse;
02241 }
02242
02243 void PSOutputDev::doImageL1(GfxImageColorMap *colorMap,
02244 GBool invert, GBool inlineImg,
02245 Stream *str, int width, int height, int len) {
02246 ImageStream *imgStr;
02247 Guchar pixBuf[gfxColorMaxComps];
02248 double gray;
02249 int x, y, i;
02250
02251
02252 if (colorMap) {
02253 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n",
02254 width, height,
02255 width, -height, height);
02256 } else {
02257 writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n",
02258 width, height, invert ? "true" : "false",
02259 width, -height, height);
02260 }
02261
02262
02263 if (colorMap) {
02264
02265
02266 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
02267 colorMap->getBits());
02268 imgStr->reset();
02269
02270
02271 i = 0;
02272 for (y = 0; y < height; ++y) {
02273
02274
02275 for (x = 0; x < width; ++x) {
02276 imgStr->getPixel(pixBuf);
02277 colorMap->getGray(pixBuf, &gray);
02278 writePSFmt("%02x", (int)(gray * 255 + 0.5));
02279 if (++i == 32) {
02280 writePSChar('\n');
02281 i = 0;
02282 }
02283 }
02284 }
02285 if (i != 0) {
02286 writePSChar('\n');
02287 }
02288 delete imgStr;
02289
02290
02291 } else {
02292 str->reset();
02293 i = 0;
02294 for (y = 0; y < height; ++y) {
02295 for (x = 0; x < width; x += 8) {
02296 writePSFmt("%02x", str->getChar() & 0xff);
02297 if (++i == 32) {
02298 writePSChar('\n');
02299 i = 0;
02300 }
02301 }
02302 }
02303 if (i != 0) {
02304 writePSChar('\n');
02305 }
02306 str->close();
02307 }
02308 }
02309
02310 void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
02311 GBool invert, GBool inlineImg,
02312 Stream *str, int width, int height, int len) {
02313 ImageStream *imgStr;
02314 Guchar *lineBuf;
02315 Guchar pixBuf[gfxColorMaxComps];
02316 GfxCMYK cmyk;
02317 int x, y, i, comp;
02318
02319
02320 writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1Sep\n",
02321 width, height,
02322 width, -height, height);
02323
02324
02325 lineBuf = (Guchar *)gmalloc(4 * width);
02326
02327
02328 imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
02329 colorMap->getBits());
02330 imgStr->reset();
02331
02332
02333 i = 0;
02334 for (y = 0; y < height; ++y) {
02335
02336
02337 for (x = 0; x < width; ++x) {
02338 imgStr->getPixel(pixBuf);
02339 colorMap->getCMYK(pixBuf, &cmyk);
02340 lineBuf[4*x+0] = (int)(255 * cmyk.c + 0.5);
02341 lineBuf[4*x+1] = (int)(255 * cmyk.m + 0.5);
02342 lineBuf[4*x+2] = (int)(255 * cmyk.y + 0.5);
02343 lineBuf[4*x+3] = (int)(255 * cmyk.k + 0.5);
02344 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
02345 }
02346
02347
02348 for (comp = 0; comp < 4; ++comp) {
02349 for (x = 0; x < width; ++x) {
02350 writePSFmt("%02x", lineBuf[4*x + comp]);
02351 if (++i == 32) {
02352 writePSChar('\n');
02353 i = 0;
02354 }
02355 }
02356 }
02357 }
02358
02359 if (i != 0) {
02360 writePSChar('\n');
02361 }
02362
02363 delete imgStr;
02364 gfree(lineBuf);
02365 }
02366
02367 void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
02368 GBool invert, GBool inlineImg,
02369 Stream *str, int width, int height, int len) {
02370 GString *s;
02371 int n, numComps;
02372 GBool useRLE, useASCII, useCompressed;
02373 GfxSeparationColorSpace *sepCS;
02374 GfxColor color;
02375 GfxCMYK cmyk;
02376 int c;
02377 int line, col, i;
02378
02379
02380 if (colorMap) {
02381 dumpColorSpaceL2(colorMap->getColorSpace());
02382 writePS(" setcolorspace\n");
02383 }
02384
02385
02386 if (mode == psModeForm || inType3Char) {
02387 if (inlineImg) {
02388
02389 str = new FixedLengthEncoder(str, len);
02390 if (globalParams->getPSASCIIHex()) {
02391 str = new ASCIIHexEncoder(str);
02392 } else {
02393 str = new ASCII85Encoder(str);
02394 }
02395 str->reset();
02396 line = col = 0;
02397 writePS("[<~");
02398 do {
02399 do {
02400 c = str->getChar();
02401 } while (c == '\n' || c == '\r');
02402 if (c == '~' || c == EOF) {
02403 break;
02404 }
02405 if (c == 'z') {
02406 writePSChar(c);
02407 ++col;
02408 } else {
02409 writePSChar(c);
02410 ++col;
02411 for (i = 1; i <= 4; ++i) {
02412 do {
02413 c = str->getChar();
02414 } while (c == '\n' || c == '\r');
02415 if (c == '~' || c == EOF) {
02416 break;
02417 }
02418 writePSChar(c);
02419 ++col;
02420 }
02421 }
02422
02423
02424
02425
02426 if (col > 225) {
02427 writePS("~>\n");
02428 ++line;
02429 writePSFmt("<~", line);
02430 col = 0;
02431 }
02432 } while (c != '~' && c != EOF);
02433 writePS("~>]\n");
02434 writePS("0\n");
02435 delete str;
02436 } else {
02437
02438 writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen());
02439 }
02440 }
02441
02442
02443 writePS("<<\n /ImageType 1\n");
02444
02445
02446 writePSFmt(" /Width %d\n", width);
02447 writePSFmt(" /Height %d\n", height);
02448 writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height);
02449 writePSFmt(" /BitsPerComponent %d\n",
02450 colorMap ? colorMap->getBits() : 1);
02451
02452
02453 if (colorMap) {
02454 writePS(" /Decode [");
02455 if (colorMap->getColorSpace()->getMode() == csSeparation) {
02456
02457 n = (1 << colorMap->getBits()) - 1;
02458 writePSFmt("%g %g", colorMap->getDecodeLow(0) * n,
02459 colorMap->getDecodeHigh(0) * n);
02460 } else {
02461 numComps = colorMap->getNumPixelComps();
02462 for (i = 0; i < numComps; ++i) {
02463 if (i > 0) {
02464 writePS(" ");
02465 }
02466 writePSFmt("%g %g", colorMap->getDecodeLow(i),
02467 colorMap->getDecodeHigh(i));
02468 }
02469 }
02470 writePS("]\n");
02471 } else {
02472 writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1);
02473 }
02474
02475 if (mode == psModeForm || inType3Char) {
02476
02477
02478 writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
02479
02480
02481 writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask");
02482
02483
02484 writePS("pop pop\n");
02485
02486 } else {
02487
02488
02489 writePS(" /DataSource currentfile\n");
02490 s = str->getPSFilter(" ");
02491 if (inlineImg || !s) {
02492 useRLE = gTrue;
02493 useASCII = gTrue;
02494 useCompressed = gFalse;
02495 } else {
02496 useRLE = gFalse;
02497 useASCII = str->isBinary();
02498 useCompressed = gTrue;
02499 }
02500 if (useASCII) {
02501 writePSFmt(" /ASCII%sDecode filter\n",
02502 globalParams->getPSASCIIHex() ? "Hex" : "85");
02503 }
02504 if (useRLE) {
02505 writePS(" /RunLengthDecode filter\n");
02506 }
02507 if (useCompressed) {
02508 writePS(s->getCString());
02509 }
02510 if (s) {
02511 delete s;
02512 }
02513
02514
02515 if (inlineImg) {
02516 str = new FixedLengthEncoder(str, len);
02517 } else if (useCompressed) {
02518 str = str->getBaseStream();
02519 }
02520
02521
02522 if (useRLE) {
02523 str = new RunLengthEncoder(str);
02524 }
02525 if (useASCII) {
02526 if (globalParams->getPSASCIIHex()) {
02527 str = new ASCIIHexEncoder(str);
02528 } else {
02529 str = new ASCII85Encoder(str);
02530 }
02531 }
02532
02533
02534 writePS(">>\n");
02535 #if OPI_SUPPORT
02536 if (opi13Nest) {
02537 if (inlineImg) {
02538
02539 error(-1, "Internal: OPI in inline image");
02540 n = 0;
02541 } else {
02542
02543
02544 str->reset();
02545 n = 0;
02546 while ((c = str->getChar()) != EOF) {
02547 ++n;
02548 }
02549 str->close();
02550 }
02551
02552
02553 n += colorMap ? 14 : 15;
02554 writePSFmt("%%%%BeginData: %d Hex Bytes\n", n);
02555 }
02556 #endif
02557 if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
02558 colorMap->getColorSpace()->getMode() == csSeparation) {
02559 color.c[0] = 1;
02560 sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
02561 sepCS->getCMYK(&color, &cmyk);
02562 writePSFmt("%g %g %g %g (%s) pdfImSep\n",
02563 cmyk.c, cmyk.m, cmyk.y, cmyk.k,
02564 sepCS->getName()->getCString());
02565 } else {
02566 writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM");
02567 }
02568
02569
02570 str->reset();
02571 while ((c = str->getChar()) != EOF) {
02572 writePSChar(c);
02573 }
02574 str->close();
02575
02576
02577 writePSChar('\n');
02578 writePS("%-EOD-\n");
02579 #if OPI_SUPPORT
02580 if (opi13Nest) {
02581 writePS("%%EndData\n");
02582 }
02583 #endif
02584
02585
02586 if (useRLE || useASCII || inlineImg) {
02587 delete str;
02588 }
02589 }
02590 }
02591
02592 void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
02593 GfxCalGrayColorSpace *calGrayCS;
02594 GfxCalRGBColorSpace *calRGBCS;
02595 GfxLabColorSpace *labCS;
02596 GfxIndexedColorSpace *indexedCS;
02597 GfxSeparationColorSpace *separationCS;
02598 GfxColorSpace *baseCS;
02599 Guchar *lookup, *p;
02600 double x[gfxColorMaxComps], y[gfxColorMaxComps];
02601 GfxColor color;
02602 GfxCMYK cmyk;
02603 Function *func;
02604 int n, numComps, numAltComps;
02605 int byte;
02606 int i, j, k;
02607
02608 switch (colorSpace->getMode()) {
02609
02610 case csDeviceGray:
02611 writePS("/DeviceGray");
02612 processColors |= psProcessBlack;
02613 break;
02614
02615 case csCalGray:
02616 calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
02617 writePS("[/CIEBasedA <<\n");
02618 writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma());
02619 writePSFmt(" /MatrixA [%g %g %g]\n",
02620 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
02621 calGrayCS->getWhiteZ());
02622 writePSFmt(" /WhitePoint [%g %g %g]\n",
02623 calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
02624 calGrayCS->getWhiteZ());
02625 writePSFmt(" /BlackPoint [%g %g %g]\n",
02626 calGrayCS->getBlackX(), calGrayCS->getBlackY(),
02627 calGrayCS->getBlackZ());
02628 writePS(">>]");
02629 processColors |= psProcessBlack;
02630 break;
02631
02632 case csDeviceRGB:
02633 writePS("/DeviceRGB");
02634 processColors |= psProcessCMYK;
02635 break;
02636
02637 case csCalRGB:
02638 calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
02639 writePS("[/CIEBasedABC <<\n");
02640 writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n",
02641 calRGBCS->getGammaR(), calRGBCS->getGammaG(),
02642 calRGBCS->getGammaB());
02643 writePSFmt(" /MatrixABC [%g %g %g %g %g %g %g %g %g]\n",
02644 calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
02645 calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
02646 calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
02647 calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
02648 calRGBCS->getMatrix()[8]);
02649 writePSFmt(" /WhitePoint [%g %g %g]\n",
02650 calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
02651 calRGBCS->getWhiteZ());
02652 writePSFmt(" /BlackPoint [%g %g %g]\n",
02653 calRGBCS->getBlackX(), calRGBCS->getBlackY(),
02654 calRGBCS->getBlackZ());
02655 writePS(">>]");
02656 processColors |= psProcessCMYK;
02657 break;
02658
02659 case csDeviceCMYK:
02660 writePS("/DeviceCMYK");
02661 processColors |= psProcessCMYK;
02662 break;
02663
02664 case csLab:
02665 labCS = (GfxLabColorSpace *)colorSpace;
02666 writePS("[/CIEBasedABC <<\n");
02667 writePSFmt(" /RangeABC [0 100 %g %g %g %g]\n",
02668 labCS->getAMin(), labCS->getAMax(),
02669 labCS->getBMin(), labCS->getBMax());
02670 writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
02671 writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
02672 writePS(" /DecodeLMN\n");
02673 writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
02674 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
02675 labCS->getWhiteX());
02676 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
02677 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind\n",
02678 labCS->getWhiteY());
02679 writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
02680 writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n",
02681 labCS->getWhiteZ());
02682 writePSFmt(" /WhitePoint [%g %g %g]\n",
02683 labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
02684 writePSFmt(" /BlackPoint [%g %g %g]\n",
02685 labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
02686 writePS(">>]");
02687 processColors |= psProcessCMYK;
02688 break;
02689
02690 case csICCBased:
02691 dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt());
02692 break;
02693
02694 case csIndexed:
02695 indexedCS = (GfxIndexedColorSpace *)colorSpace;
02696 baseCS = indexedCS->getBase();
02697 writePS("[/Indexed ");
02698 dumpColorSpaceL2(baseCS);
02699 n = indexedCS->getIndexHigh();
02700 numComps = baseCS->getNComps();
02701 lookup = indexedCS->getLookup();
02702 writePSFmt(" %d <\n", n);
02703 if (baseCS->getMode() == csDeviceN) {
02704 func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
02705 numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
02706 p = lookup;
02707 for (i = 0; i <= n; i += 8) {
02708 writePS(" ");
02709 for (j = i; j < i+8 && j <= n; ++j) {
02710 for (k = 0; k < numComps; ++k) {
02711 x[k] = *p++ / 255.0;
02712 }
02713 func->transform(x, y);
02714 for (k = 0; k < numAltComps; ++k) {
02715 byte = (int)(y[k] * 255 + 0.5);
02716 if (byte < 0) {
02717 byte = 0;
02718 } else if (byte > 255) {
02719 byte = 255;
02720 }
02721 writePSFmt("%02x", byte);
02722 }
02723 color.c[0] = j;
02724 indexedCS->getCMYK(&color, &cmyk);
02725 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
02726 }
02727 writePS("\n");
02728 }
02729 } else {
02730 for (i = 0; i <= n; i += 8) {
02731 writePS(" ");
02732 for (j = i; j < i+8 && j <= n; ++j) {
02733 for (k = 0; k < numComps; ++k) {
02734 writePSFmt("%02x", lookup[j * numComps + k]);
02735 }
02736 color.c[0] = j;
02737 indexedCS->getCMYK(&color, &cmyk);
02738 addProcessColor(cmyk.c, cmyk.m, cmyk.y, cmyk.k);
02739 }
02740 writePS("\n");
02741 }
02742 }
02743 writePS(">]");
02744 break;
02745
02746 case csSeparation:
02747
02748
02749
02750 separationCS = (GfxSeparationColorSpace *)colorSpace;
02751 writePS("[/Indexed ");
02752 dumpColorSpaceL2(separationCS->getAlt());
02753 writePS(" 255 <\n");
02754 numComps = separationCS->getAlt()->getNComps();
02755 for (i = 0; i <= 255; i += 8) {
02756 writePS(" ");
02757 for (j = i; j < i+8 && j <= 255; ++j) {
02758 x[0] = (double)j / 255.0;
02759 separationCS->getFunc()->transform(x, y);
02760 for (k = 0; k < numComps; ++k) {
02761 writePSFmt("%02x", (int)(255 * y[k] + 0.5));
02762 }
02763 }
02764 writePS("\n");
02765 }
02766 writePS(">]");
02767 addCustomColor(separationCS);
02768 break;
02769
02770 case csDeviceN:
02771
02772 dumpColorSpaceL2(((GfxDeviceNColorSpace *)colorSpace)->getAlt());
02773 break;
02774
02775 case csPattern:
02776
02777 break;
02778
02779 }
02780 }
02781
02782 #if OPI_SUPPORT
02783 void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
02784 Object dict;
02785
02786 if (globalParams->getPSOPI()) {
02787 opiDict->lookup("2.0", &dict);
02788 if (dict.isDict()) {
02789 opiBegin20(state, dict.getDict());
02790 dict.free();
02791 } else {
02792 dict.free();
02793 opiDict->lookup("1.3", &dict);
02794 if (dict.isDict()) {
02795 opiBegin13(state, dict.getDict());
02796 }
02797 dict.free();
02798 }
02799 }
02800 }
02801
02802 void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
02803 Object obj1, obj2, obj3, obj4;
02804 double width, height, left, right, top, bottom;
02805 int w, h;
02806 int i;
02807
02808 writePS("%%BeginOPI: 2.0\n");
02809 writePS("%%Distilled\n");
02810
02811 dict->lookup("F", &obj1);
02812 if (getFileSpec(&obj1, &obj2)) {
02813 writePSFmt("%%%%ImageFileName: %s\n",
02814 obj2.getString()->getCString());
02815 obj2.free();
02816 }
02817 obj1.free();
02818
02819 dict->lookup("MainImage", &obj1);
02820 if (obj1.isString()) {
02821 writePSFmt("%%%%MainImage: %s\n", obj1.getString()->getCString());
02822 }
02823 obj1.free();
02824
02825
02826
02827
02828 dict->lookup("Size", &obj1);
02829 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
02830 obj1.arrayGet(0, &obj2);
02831 width = obj2.getNum();
02832 obj2.free();
02833 obj1.arrayGet(1, &obj2);
02834 height = obj2.getNum();
02835 obj2.free();
02836 writePSFmt("%%%%ImageDimensions: %g %g\n", width, height);
02837 }
02838 obj1.free();
02839
02840 dict->lookup("CropRect", &obj1);
02841 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
02842 obj1.arrayGet(0, &obj2);
02843 left = obj2.getNum();
02844 obj2.free();
02845 obj1.arrayGet(1, &obj2);
02846 top = obj2.getNum();
02847 obj2.free();
02848 obj1.arrayGet(2, &obj2);
02849 right = obj2.getNum();
02850 obj2.free();
02851 obj1.arrayGet(3, &obj2);
02852 bottom = obj2.getNum();
02853 obj2.free();
02854 writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom);
02855 }
02856 obj1.free();
02857
02858 dict->lookup("Overprint", &obj1);
02859 if (obj1.isBool()) {
02860 writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
02861 }
02862 obj1.free();
02863
02864 dict->lookup("Inks", &obj1);
02865 if (obj1.isName()) {
02866 writePSFmt("%%%%ImageInks: %s\n", obj1.getName());
02867 } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
02868 obj1.arrayGet(0, &obj2);
02869 if (obj2.isName()) {
02870 writePSFmt("%%%%ImageInks: %s %d",
02871 obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
02872 for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
02873 obj1.arrayGet(i, &obj3);
02874 obj1.arrayGet(i+1, &obj4);
02875 if (obj3.isString() && obj4.isNum()) {
02876 writePS(" ");
02877 writePSString(obj3.getString());
02878 writePSFmt(" %g", obj4.getNum());
02879 }
02880 obj3.free();
02881 obj4.free();
02882 }
02883 writePS("\n");
02884 }
02885 obj2.free();
02886 }
02887 obj1.free();
02888
02889 writePS("gsave\n");
02890
02891 writePS("%%BeginIncludedImage\n");
02892
02893 dict->lookup("IncludedImageDimensions", &obj1);
02894 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
02895 obj1.arrayGet(0, &obj2);
02896 w = obj2.getInt();
02897 obj2.free();
02898 obj1.arrayGet(1, &obj2);
02899 h = obj2.getInt();
02900 obj2.free();
02901 writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h);
02902 }
02903 obj1.free();
02904
02905 dict->lookup("IncludedImageQuality", &obj1);
02906 if (obj1.isNum()) {
02907 writePSFmt("%%%%IncludedImageQuality: %g\n", obj1.getNum());
02908 }
02909 obj1.free();
02910
02911 ++opi20Nest;
02912 }
02913
02914 void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
02915 Object obj1, obj2;
02916 int left, right, top, bottom, samples, bits, width, height;
02917 double c, m, y, k;
02918 double llx, lly, ulx, uly, urx, ury, lrx, lry;
02919 double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
02920 double horiz, vert;
02921 int i, j;
02922
02923 writePS("save\n");
02924 writePS("/opiMatrix2 matrix currentmatrix def\n");
02925 writePS("opiMatrix setmatrix\n");
02926
02927 dict->lookup("F", &obj1);
02928 if (getFileSpec(&obj1, &obj2)) {
02929 writePSFmt("%%ALDImageFileName: %s\n",
02930 obj2.getString()->getCString());
02931 obj2.free();
02932 }
02933 obj1.free();
02934
02935 dict->lookup("CropRect", &obj1);
02936 if (obj1.isArray() && obj1.arrayGetLength() == 4) {
02937 obj1.arrayGet(0, &obj2);
02938 left = obj2.getInt();
02939 obj2.free();
02940 obj1.arrayGet(1, &obj2);
02941 top = obj2.getInt();
02942 obj2.free();
02943 obj1.arrayGet(2, &obj2);
02944 right = obj2.getInt();
02945 obj2.free();
02946 obj1.arrayGet(3, &obj2);
02947 bottom = obj2.getInt();
02948 obj2.free();
02949 writePSFmt("%%ALDImageCropRect: %d %d %d %d\n", left, top, right, bottom);
02950 }
02951 obj1.free();
02952
02953 dict->lookup("Color", &obj1);
02954 if (obj1.isArray() && obj1.arrayGetLength() == 5) {
02955 obj1.arrayGet(0, &obj2);
02956 c = obj2.getNum();
02957 obj2.free();
02958 obj1.arrayGet(1, &obj2);
02959 m = obj2.getNum();
02960 obj2.free();
02961 obj1.arrayGet(2, &obj2);
02962 y = obj2.getNum();
02963 obj2.free();
02964 obj1.arrayGet(3, &obj2);
02965 k = obj2.getNum();
02966 obj2.free();
02967 obj1.arrayGet(4, &obj2);
02968 if (obj2.isString()) {
02969 writePSFmt("%%ALDImageColor: %g %g %g %g ", c, m, y, k);
02970 writePSString(obj2.getString());
02971 writePS("\n");
02972 }
02973 obj2.free();
02974 }
02975 obj1.free();
02976
02977 dict->lookup("ColorType", &obj1);
02978 if (obj1.isName()) {
02979 writePSFmt("%%ALDImageColorType: %s\n", obj1.getName());
02980 }
02981 obj1.free();
02982
02983
02984
02985
02986 dict->lookup("CropFixed", &obj1);
02987 if (obj1.isArray()) {
02988 obj1.arrayGet(0, &obj2);
02989 ulx = obj2.getNum();
02990 obj2.free();
02991 obj1.arrayGet(1, &obj2);
02992 uly = obj2.getNum();
02993 obj2.free();
02994 obj1.arrayGet(2, &obj2);
02995 lrx = obj2.getNum();
02996 obj2.free();
02997 obj1.arrayGet(3, &obj2);
02998 lry = obj2.getNum();
02999 obj2.free();
03000 writePSFmt("%%ALDImageCropFixed: %g %g %g %g\n", ulx, uly, lrx, lry);
03001 }
03002 obj1.free();
03003
03004 dict->lookup("GrayMap", &obj1);
03005 if (obj1.isArray()) {
03006 writePS("%ALDImageGrayMap:");
03007 for (i = 0; i < obj1.arrayGetLength(); i += 16) {
03008 if (i > 0) {
03009 writePS("\n%%+");
03010 }
03011 for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
03012 obj1.arrayGet(i+j, &obj2);
03013 writePSFmt(" %d", obj2.getInt());
03014 obj2.free();
03015 }
03016 }
03017 writePS("\n");
03018 }
03019 obj1.free();
03020
03021 dict->lookup("ID", &obj1);
03022 if (obj1.isString()) {
03023 writePSFmt("%%ALDImageID: %s\n", obj1.getString()->getCString());
03024 }
03025 obj1.free();
03026
03027 dict->lookup("ImageType", &obj1);
03028 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
03029 obj1.arrayGet(0, &obj2);
03030 samples = obj2.getInt();
03031 obj2.free();
03032 obj1.arrayGet(1, &obj2);
03033 bits = obj2.getInt();
03034 obj2.free();
03035 writePSFmt("%%ALDImageType: %d %d\n", samples, bits);
03036 }
03037 obj1.free();
03038
03039 dict->lookup("Overprint", &obj1);
03040 if (obj1.isBool()) {
03041 writePSFmt("%%ALDImageOverprint: %s\n", obj1.getBool() ? "true" : "false");
03042 }
03043 obj1.free();
03044
03045 dict->lookup("Position", &obj1);
03046 if (obj1.isArray() && obj1.arrayGetLength() == 8) {
03047 obj1.arrayGet(0, &obj2);
03048 llx = obj2.getNum();
03049 obj2.free();
03050 obj1.arrayGet(1, &obj2);
03051 lly = obj2.getNum();
03052 obj2.free();
03053 obj1.arrayGet(2, &obj2);
03054 ulx = obj2.getNum();
03055 obj2.free();
03056 obj1.arrayGet(3, &obj2);
03057 uly = obj2.getNum();
03058 obj2.free();
03059 obj1.arrayGet(4, &obj2);
03060 urx = obj2.getNum();
03061 obj2.free();
03062 obj1.arrayGet(5, &obj2);
03063 ury = obj2.getNum();
03064 obj2.free();
03065 obj1.arrayGet(6, &obj2);
03066 lrx = obj2.getNum();
03067 obj2.free();
03068 obj1.arrayGet(7, &obj2);
03069 lry = obj2.getNum();
03070 obj2.free();
03071 opiTransform(state, llx, lly, &tllx, &tlly);
03072 opiTransform(state, ulx, uly, &tulx, &tuly);
03073 opiTransform(state, urx, ury, &turx, &tury);
03074 opiTransform(state, lrx, lry, &tlrx, &tlry);
03075 writePSFmt("%%ALDImagePosition: %g %g %g %g %g %g %g %g\n",
03076 tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
03077 obj2.free();
03078 }
03079 obj1.free();
03080
03081 dict->lookup("Resolution", &obj1);
03082 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
03083 obj1.arrayGet(0, &obj2);
03084 horiz = obj2.getNum();
03085 obj2.free();
03086 obj1.arrayGet(1, &obj2);
03087 vert = obj2.getNum();
03088 obj2.free();
03089 writePSFmt("%%ALDImageResoution: %g %g\n", horiz, vert);
03090 obj2.free();
03091 }
03092 obj1.free();
03093
03094 dict->lookup("Size", &obj1);
03095 if (obj1.isArray() && obj1.arrayGetLength() == 2) {
03096 obj1.arrayGet(0, &obj2);
03097 width = obj2.getInt();
03098 obj2.free();
03099 obj1.arrayGet(1, &obj2);
03100 height = obj2.getInt();
03101 obj2.free();
03102 writePSFmt("%%ALDImageDimensions: %d %d\n", width, height);
03103 }
03104 obj1.free();
03105
03106
03107
03108
03109 dict->lookup("Tint", &obj1);
03110 if (obj1.isNum()) {
03111 writePSFmt("%%ALDImageTint: %g\n", obj1.getNum());
03112 }
03113 obj1.free();
03114
03115 dict->lookup("Transparency", &obj1);
03116 if (obj1.isBool()) {
03117 writePSFmt("%%ALDImageTransparency: %s\n", obj1.getBool() ? "true" : "false");
03118 }
03119 obj1.free();
03120
03121 writePS("%%BeginObject: image\n");
03122 writePS("opiMatrix2 setmatrix\n");
03123 ++opi13Nest;
03124 }
03125
03126
03127
03128
03129 void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
03130 double *x1, double *y1) {
03131 double t;
03132
03133 state->transform(x0, y0, x1, y1);
03134 *x1 += tx;
03135 *y1 += ty;
03136 if (landscape) {
03137 t = *x1;
03138 *x1 = -*y1;
03139 *y1 = t;
03140 }
03141 *x1 *= xScale;
03142 *y1 *= yScale;
03143 }
03144
03145 void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
03146 Object dict;
03147
03148 if (globalParams->getPSOPI()) {
03149 opiDict->lookup("2.0", &dict);
03150 if (dict.isDict()) {
03151 writePS("%%EndIncludedImage\n");
03152 writePS("%%EndOPI\n");
03153 writePS("grestore\n");
03154 --opi20Nest;
03155 dict.free();
03156 } else {
03157 dict.free();
03158 opiDict->lookup("1.3", &dict);
03159 if (dict.isDict()) {
03160 writePS("%%EndObject\n");
03161 writePS("restore\n");
03162 --opi13Nest;
03163 }
03164 dict.free();
03165 }
03166 }
03167 }
03168
03169 GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
03170 if (fileSpec->isString()) {
03171 fileSpec->copy(fileName);
03172 return gTrue;
03173 }
03174 if (fileSpec->isDict()) {
03175 fileSpec->dictLookup("DOS", fileName);
03176 if (fileName->isString()) {
03177 return gTrue;
03178 }
03179 fileName->free();
03180 fileSpec->dictLookup("Mac", fileName);
03181 if (fileName->isString()) {
03182 return gTrue;
03183 }
03184 fileName->free();
03185 fileSpec->dictLookup("Unix", fileName);
03186 if (fileName->isString()) {
03187 return gTrue;
03188 }
03189 fileName->free();
03190 fileSpec->dictLookup("F", fileName);
03191 if (fileName->isString()) {
03192 return gTrue;
03193 }
03194 fileName->free();
03195 }
03196 return gFalse;
03197 }
03198 #endif // OPI_SUPPORT
03199
03200 void PSOutputDev::type3D0(GfxState *state, double wx, double wy) {
03201 writePSFmt("%g %g setcharwidth\n", wx, wy);
03202 writePS("q\n");
03203 }
03204
03205 void PSOutputDev::type3D1(GfxState *state, double wx, double wy,
03206 double llx, double lly, double urx, double ury) {
03207 t3WX = wx;
03208 t3WY = wy;
03209 t3LLX = llx;
03210 t3LLY = lly;
03211 t3URX = urx;
03212 t3URY = ury;
03213 t3String = new GString();
03214 writePS("q\n");
03215 t3Cacheable = gTrue;
03216 }
03217
03218 void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
03219 Stream *str;
03220 int c;
03221
03222 if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
03223 str = level1Stream;
03224 } else {
03225 str = psStream;
03226 }
03227 str->reset();
03228 while ((c = str->getChar()) != EOF) {
03229 writePSChar(c);
03230 }
03231 str->close();
03232 }
03233
03234 void PSOutputDev::writePSChar(char c) {
03235 if (t3String) {
03236 t3String->append(c);
03237 } else {
03238 (*outputFunc)(outputStream, &c, 1);
03239 }
03240 }
03241
03242 void PSOutputDev::writePS(char *s) {
03243 if (t3String) {
03244 t3String->append(s);
03245 } else {
03246 (*outputFunc)(outputStream, s, strlen(s));
03247 }
03248 }
03249
03250 void PSOutputDev::writePSFmt(const char *fmt, ...) {
03251 va_list args;
03252 char buf[512];
03253
03254 va_start(args, fmt);
03255 vsprintf(buf, fmt, args);
03256 va_end(args);
03257 if (t3String) {
03258 t3String->append(buf);
03259 } else {
03260 (*outputFunc)(outputStream, buf, strlen(buf));
03261 }
03262 }
03263
03264 void PSOutputDev::writePSString(GString *s) {
03265 Guchar *p;
03266 int n;
03267 char buf[8];
03268
03269 writePSChar('(');
03270 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
03271 if (*p == '(' || *p == ')' || *p == '\\') {
03272 writePSChar('\\');
03273 writePSChar((char)*p);
03274 } else if (*p < 0x20 || *p >= 0x80) {
03275 sprintf(buf, "\\%03o", *p);
03276 if (t3String) {
03277 t3String->append(buf);
03278 } else {
03279 (*outputFunc)(outputStream, buf, strlen(buf));
03280 }
03281 } else {
03282 writePSChar((char)*p);
03283 }
03284 }
03285 writePSChar(')');
03286 }
03287
03288 void PSOutputDev::writePSName(char *s) {
03289 char *p;
03290 char c;
03291
03292 p = s;
03293 while ((c = *p++)) {
03294 if (c <= (char)0x20 || c >= (char)0x7f ||
03295 c == '(' || c == ')' || c == '<' || c == '>' ||
03296 c == '[' || c == ']' || c == '{' || c == '}' ||
03297 c == '/' || c == '%') {
03298 writePSFmt("#%02x", c & 0xff);
03299 } else {
03300 writePSChar(c);
03301 }
03302 }
03303 }
03304
03305 GString *PSOutputDev::filterPSName(GString *name) {
03306 GString *name2;
03307 char buf[8];
03308 int i;
03309 char c;
03310
03311 name2 = new GString();
03312 for (i = 0; i < name->getLength(); ++i) {
03313 c = name->getChar(i);
03314 if (c <= (char)0x20 || c >= (char)0x7f ||
03315 c == '(' || c == ')' || c == '<' || c == '>' ||
03316 c == '[' || c == ']' || c == '{' || c == '}' ||
03317 c == '/' || c == '%') {
03318 sprintf(buf, "#%02x", c & 0xff);
03319 name2->append(buf);
03320 } else {
03321 name2->append(c);
03322 }
03323 }
03324 return name2;
03325 }