00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063
00064 #include "DjVuToPS.h"
00065 #include "IFFByteStream.h"
00066 #include "BSByteStream.h"
00067 #include "DjVuImage.h"
00068 #include "DjVuText.h"
00069 #include "DataPool.h"
00070 #include "IW44Image.h"
00071 #include "JB2Image.h"
00072 #include "GBitmap.h"
00073 #include "GPixmap.h"
00074 #include "debug.h"
00075 #include <stdarg.h>
00076 #include <stdlib.h>
00077 #include <stdio.h>
00078 #include <time.h>
00079 #include <math.h>
00080 #ifdef UNIX
00081 #include <pwd.h>
00082 #include <grp.h>
00083 #include <unistd.h>
00084 #endif
00085
00086
00087 #ifdef HAVE_NAMESPACES
00088 namespace DJVU {
00089 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00090 }
00091 #endif
00092 #endif
00093
00094
00095 static const size_t ps_string_size=15000;
00096
00097
00098
00099
00100
00101 DjVuToPS::Options::
00102 Options(void)
00103 : format(PS),
00104 level(2),
00105 orientation(AUTO),
00106 mode(COLOR),
00107 zoom(0),
00108 color(true),
00109 calibrate(true),
00110 text(false),
00111 gamma((double)2.2),
00112 copies(1),
00113 frame(false),
00114 cropmarks(false),
00115 bookletmode(OFF),
00116 bookletmax(0),
00117 bookletalign(0),
00118 bookletfold(18),
00119 bookletxfold(200)
00120 {}
00121
00122 void
00123 DjVuToPS::Options::
00124 set_format(Format xformat)
00125 {
00126 if (xformat != EPS && xformat != PS)
00127 G_THROW(ERR_MSG("DjVuToPS.bad_format"));
00128 format=xformat;
00129 }
00130
00131 void
00132 DjVuToPS::Options::
00133 set_level(int xlevel)
00134 {
00135 if (xlevel<1 || xlevel>3)
00136 G_THROW(ERR_MSG("DjVuToPS.bad_level")
00137 + GUTF8String("\t") + GUTF8String(xlevel));
00138 level=xlevel;
00139 }
00140
00141 void
00142 DjVuToPS::Options::
00143 set_orientation(Orientation xorientation)
00144 {
00145 if (xorientation!=PORTRAIT &&
00146 xorientation!=LANDSCAPE &&
00147 xorientation!=AUTO )
00148 G_THROW(ERR_MSG("DjVuToPS.bad_orient"));
00149 orientation=xorientation;
00150 }
00151
00152 void
00153 DjVuToPS::Options::
00154 set_mode(Mode xmode)
00155 {
00156 if (xmode!=COLOR && xmode!=FORE && xmode!=BACK && xmode!=BW)
00157 G_THROW(ERR_MSG("DjVuToPS.bad_mode"));
00158 mode=xmode;
00159 }
00160
00161 void
00162 DjVuToPS::Options::
00163 set_zoom(int xzoom)
00164 {
00165 if (xzoom!=0 && !(xzoom>=5 && xzoom<=999))
00166 G_THROW(ERR_MSG("DjVuToPS.bad_zoom"));
00167 zoom=xzoom;
00168 }
00169
00170 void
00171 DjVuToPS::Options::
00172 set_color(bool xcolor)
00173 {
00174 color=xcolor;
00175 }
00176
00177 void
00178 DjVuToPS::Options::
00179 set_sRGB(bool xcalibrate)
00180 {
00181 calibrate=xcalibrate;
00182 }
00183
00184 void
00185 DjVuToPS::Options::
00186 set_gamma(double xgamma)
00187 {
00188 if (xgamma<(double)(0.3-0.0001) || xgamma>(double)(5.0+0.0001))
00189 G_THROW(ERR_MSG("DjVuToPS.bad_gamma"));
00190 gamma=xgamma;
00191 }
00192
00193 void
00194 DjVuToPS::Options::
00195 set_copies(int xcopies)
00196 {
00197 if (xcopies<=0)
00198 G_THROW(ERR_MSG("DjVuToPS.bad_number"));
00199 copies=xcopies;
00200 }
00201
00202 void
00203 DjVuToPS::Options::
00204 set_frame(bool xframe)
00205 {
00206 frame=xframe;
00207 }
00208
00209 void
00210 DjVuToPS::Options::
00211 set_cropmarks(bool xmarks)
00212 {
00213 cropmarks=xmarks;
00214 }
00215
00216 void
00217 DjVuToPS::Options::
00218 set_text(bool xtext)
00219 {
00220 text=xtext;
00221 }
00222
00223 void
00224 DjVuToPS::Options::
00225 set_bookletmode(BookletMode m)
00226 {
00227 bookletmode = m;
00228 }
00229
00230 void
00231 DjVuToPS::Options::
00232 set_bookletmax(int m)
00233 {
00234 bookletmax = 0;
00235 if (m > 0)
00236 bookletmax = (m+3)/4;
00237 bookletmax *= 4;
00238 }
00239
00240 void
00241 DjVuToPS::Options::
00242 set_bookletalign(int m)
00243 {
00244 bookletalign = m;
00245 }
00246
00247 void
00248 DjVuToPS::Options::
00249 set_bookletfold(int fold, int xfold)
00250 {
00251 if (fold >= 0)
00252 bookletfold = fold;
00253 if (xfold >= 0)
00254 bookletxfold = xfold;
00255 }
00256
00257
00258
00259
00260
00261
00262 static char bin2hex[256][2];
00263
00264 DjVuToPS::DjVuToPS(void)
00265 {
00266 DEBUG_MSG("DjVuToPS::DjVuToPS(): initializing...\n");
00267 DEBUG_MAKE_INDENT(3);
00268 DEBUG_MSG("Initializing dig2hex[]\n");
00269
00270 static char * dig2hex="0123456789ABCDEF";
00271 int i;
00272 for(i=0;i<256;i++)
00273 {
00274 bin2hex[i][0]=dig2hex[i/16];
00275 bin2hex[i][1]=dig2hex[i%16];
00276 }
00277 refresh_cb=0;
00278 refresh_cl_data=0;
00279 prn_progress_cb=0;
00280 prn_progress_cl_data=0;
00281 dec_progress_cb=0;
00282 dec_progress_cl_data=0;
00283 info_cb=0;
00284 info_cl_data=0;
00285 }
00286
00287 #ifdef __GNUC__
00288 static void
00289 write(ByteStream &str, const char *format, ...)
00290 __attribute__((format (printf, 2, 3)));
00291 #endif
00292
00293 static void
00294 write(ByteStream &str, const char *format, ...)
00295 {
00296
00297
00298 va_list args;
00299 va_start(args, format);
00300 GUTF8String tmp;
00301 tmp.vformat(format, args);
00302 str.writall((const char *) tmp, tmp.length());
00303 }
00304
00305
00306
00307 void
00308 DjVuToPS::
00309 store_doc_prolog(ByteStream &str, int pages, int dpi, GRect *grect)
00310 {
00311
00312
00313
00314
00315
00316
00317 DEBUG_MSG("storing the document prolog\n");
00318 DEBUG_MAKE_INDENT(3);
00319 if (options.get_format()==Options::EPS)
00320 write(str,
00321 "%%!PS-Adobe-3.0 EPSF 3.0\n"
00322 "%%%%BoundingBox: 0 0 %d %d\n",
00323 (grect->width()*100+dpi-1)/dpi,
00324 (grect->height()*100+dpi-1)/dpi );
00325 else
00326 write(str, "%%!PS-Adobe-3.0\n");
00327 write(str,
00328 "%%%%Title: DjVu PostScript document\n"
00329 "%%%%Copyright: Copyright (c) 1998-1999 AT&T\n"
00330 "%%%%Creator: DjVu (code by Andrei Erofeev)\n"
00331 "%%%%DocumentData: Clean7Bit\n");
00332
00333 time_t tm=time(0);
00334 write(str, "%%%%CreationDate: %s", ctime(&tm));
00335
00336 #ifdef UNIX
00337 passwd *pswd = getpwuid(getuid());
00338 if (pswd)
00339 {
00340 char *s = strchr(pswd->pw_gecos, ',');
00341 if (s)
00342 *s = 0;
00343 s = 0;
00344 if (pswd->pw_gecos && strlen(pswd->pw_gecos))
00345 s = pswd->pw_gecos;
00346 else if (pswd->pw_name && strlen(pswd->pw_name))
00347 s = pswd->pw_name;
00348 if (s)
00349 write(str, "%%%%For: %s\n", s);
00350 }
00351 #endif
00352
00353 write(str, "%%%%LanguageLevel: %d\n", options.get_level());
00354 if (options.get_level()<2 && options.get_color())
00355 write(str, "%%%%Extensions: CMYK\n");
00356
00357 write(str, "%%%%Pages: %d\n",pages );
00358 write(str, "%%%%PageOrder: Ascend\n");
00359
00360 if (options.get_orientation() != Options::AUTO)
00361 write(str, "%%%%Orientation: %s\n",
00362 options.get_orientation()==Options::PORTRAIT ?
00363 "Portrait" : "Landscape" );
00364
00365 if (options.get_format() == Options::PS)
00366 {
00367 write(str, "%%%%Requirements:");
00368 if (options.get_color())
00369 write(str, " color");
00370 if (options.get_copies()>1)
00371 write(str, " numcopies(%d)", options.get_copies());
00372 if (options.get_level()>=2)
00373 {
00374 if (options.get_copies()>1)
00375 write(str, " collate");
00376 if (options.get_bookletmode() == Options::RECTOVERSO)
00377 write(str, " duplex(tumble)");
00378 }
00379 write(str, "\n");
00380 }
00381
00382 write(str,
00383 "%%%%EndComments\n"
00384 "%%%%EndProlog\n"
00385 "\n");
00386 }
00387
00388 void
00389 DjVuToPS::
00390 store_doc_setup(ByteStream &str)
00391 {
00392
00393
00394
00395 write(str,
00396 "%%%%BeginSetup\n"
00397 "/doc-origstate save def\n");
00398 if (options.get_level()>=2)
00399 {
00400 if (options.get_format() == Options::PS)
00401 {
00402 if (options.get_copies()>1)
00403 write(str,
00404 "[{\n"
00405 "%%%%BeginFeature: NumCopies %d\n"
00406 "<< /NumCopies %d >> setpagedevice\n"
00407 "%%%%EndFeature\n"
00408 "} stopped cleartomark\n"
00409 "[{\n"
00410 "%%%%BeginFeature: Collate\n"
00411 "<< /Collate true >> setpagedevice\n"
00412 "%%%%EndFeature\n"
00413 "} stopped cleartomark\n",
00414 options.get_copies(),
00415 options.get_copies() );
00416 if (options.get_bookletmode()==Options::RECTOVERSO)
00417 write(str,
00418 "[{\n"
00419 "%%%%BeginFeature: Duplex DuplexTumble\n"
00420 "<< /Duplex true /Tumble true >> setpagedevice\n"
00421 "%%%%EndFeature\n"
00422 "} stopped cleartomark\n");
00423 }
00424 if (options.get_color())
00425 write(str,
00426 "%% -- procs for reading color image\n"
00427 "/readR () def\n"
00428 "/readG () def\n"
00429 "/readB () def\n"
00430 "/ReadData {\n"
00431 " currentfile /ASCII85Decode filter dup\n"
00432 " /RunLengthDecode filter\n"
00433 " bufferR readstring pop /readR exch def\n"
00434 " dup status { flushfile } { pop } ifelse\n"
00435 " currentfile /ASCII85Decode filter dup\n"
00436 " /RunLengthDecode filter\n"
00437 " bufferG readstring pop /readG exch def\n"
00438 " dup status { flushfile } { pop } ifelse\n"
00439 " currentfile /ASCII85Decode filter dup\n"
00440 " /RunLengthDecode filter\n"
00441 " bufferB readstring pop /readB exch def\n"
00442 " dup status { flushfile } { pop } ifelse\n"
00443 "} bind def\n"
00444 "/ReadR {\n"
00445 " readR length 0 eq { ReadData } if\n"
00446 " readR /readR () def\n"
00447 "} bind def\n"
00448 "/ReadG {\n"
00449 " readG length 0 eq { ReadData } if\n"
00450 " readG /readG () def\n"
00451 "} bind def\n"
00452 "/ReadB {\n"
00453 " readB length 0 eq { ReadData } if\n"
00454 " readB /readB () def\n"
00455 "} bind def\n");
00456 write(str,
00457 "%% -- procs for foreground layer\n"
00458 "/g {gsave 0 0 0 0 5 index 5 index setcachedevice\n"
00459 " true [1 0 0 1 0 0] 5 4 roll imagemask grestore\n"
00460 "} bind def\n"
00461 "/gn {gsave 0 0 0 0 6 index 6 index setcachedevice\n"
00462 " true [1 0 0 1 0 0] 3 2 roll 5 1 roll \n"
00463 " { 1 sub 0 index 2 add 1 index 1 add roll\n"
00464 " } imagemask grestore pop \n"
00465 "} bind def\n"
00466 "/c {setcolor rmoveto glyphshow} bind def\n"
00467 "/s {rmoveto glyphshow} bind def\n"
00468 "/S {rmoveto gsave show grestore} bind def\n"
00469 "/F {(Helvetica) findfont exch scalefont setfont} bind def\n"
00470 "%% -- emulations\n"
00471 "systemdict /rectstroke known not {\n"
00472 " /rectstroke %% stack : x y width height \n"
00473 " { newpath 4 2 roll moveto 1 index 0 rlineto\n"
00474 " 0 exch rlineto neg 0 rlineto closepath stroke\n"
00475 " } bind def } if\n"
00476 "systemdict /rectclip known not {\n"
00477 " /rectclip %% stack : x y width height \n"
00478 " { newpath 4 2 roll moveto 1 index 0 rlineto\n"
00479 " 0 exch rlineto neg 0 rlineto closepath clip\n"
00480 " } bind def } if\n"
00481 "%% -- color space\n" );
00482 if (options.get_sRGB())
00483 write(str,
00484 "/DjVuColorSpace [ %s\n"
00485 "<< /DecodeLMN [ { dup 0.03928 le {\n"
00486 " 12.92321 div\n"
00487 " } {\n"
00488 " 0.055 add 1.055 div 2.4 exp\n"
00489 " } ifelse } bind dup dup ]\n"
00490 " /MatrixLMN [\n"
00491 " 0.412457 0.212673 0.019334\n"
00492 " 0.357576 0.715152 0.119192\n"
00493 " 0.180437 0.072175 0.950301 ]\n"
00494 " /WhitePoint [ 0.9505 1 1.0890 ] %% D65 \n"
00495 " /BlackPoint[0 0 0] >> ] def\n",
00496 (options.get_color()) ? "/CIEBasedABC" : "/CIEBasedA" );
00497 else if (options.get_color())
00498 write(str,"/DjVuColorSpace /DeviceRGB def\n");
00499 else
00500 write(str,"/DjVuColorSpace /DeviceGray def\n");
00501 }
00502 else
00503 {
00504
00505 if (options.get_format() == Options::PS)
00506 if (options.get_copies() > 1)
00507 write(str,"/#copies %d def\n", options.get_copies());
00508 if (options.get_color())
00509 write(str,
00510 "%% -- buffers for reading image\n"
00511 "/buffer8 () def\n"
00512 "/buffer24 () def\n"
00513 "%% -- colorimage emulation\n"
00514 "systemdict /colorimage known {\n"
00515 " /ColorProc {\n"
00516 " currentfile buffer24 readhexstring pop\n"
00517 " } bind def\n"
00518 " /ColorImage {\n"
00519 " colorimage\n"
00520 " } bind def\n"
00521 "} {\n"
00522 " /ColorProc {\n"
00523 " currentfile buffer24 readhexstring pop\n"
00524 " /data exch def /datalen data length def\n"
00525 " /cnt 0 def\n"
00526 " 0 1 datalen 3 idiv 1 sub {\n"
00527 " buffer8 exch\n"
00528 " data cnt get 20 mul /cnt cnt 1 add def\n"
00529 " data cnt get 32 mul /cnt cnt 1 add def\n"
00530 " data cnt get 12 mul /cnt cnt 1 add def\n"
00531 " add add 64 idiv put\n"
00532 " } for\n"
00533 " buffer8 0 datalen 3 idiv getinterval\n"
00534 " } bind def\n"
00535 " /ColorImage {\n"
00536 " pop pop image\n"
00537 " } bind def\n"
00538 "} ifelse\n");
00539 }
00540 write(str, "%%%%EndSetup\n\n");
00541 }
00542
00543 void
00544 DjVuToPS::
00545 store_doc_trailer(ByteStream &str)
00546 {
00547
00548
00549
00550 write(str,
00551 "%%%%Trailer\n"
00552 "doc-origstate restore\n"
00553 "%%%%EOF\n");
00554 }
00555
00556
00557
00558
00559
00560 static unsigned char *
00561 ASCII85_encode(unsigned char * dst,
00562 const unsigned char * src_start,
00563 const unsigned char * src_end)
00564 {
00565
00566
00567
00568
00569
00570 int symbols=0;
00571 const unsigned char * ptr;
00572 for(ptr=src_start;ptr<src_end;ptr+=4)
00573 {
00574 unsigned int num=0;
00575 if (ptr+3<src_end)
00576 {
00577 num |= ptr[0] << 24;
00578 num |= ptr[1] << 16;
00579 num |= ptr[2] << 8;
00580 num |= ptr[3];
00581 }
00582 else
00583 {
00584 num |= ptr[0] << 24;
00585 if (ptr+1<src_end)
00586 num |= ptr[1] << 16;
00587 if (ptr+2<src_end)
00588 num |= ptr[2] << 8;
00589 }
00590 int a1, a2, a3, a4, a5;
00591 a5=num % 85; num/=85;
00592 a4=num % 85; num/=85;
00593 a3=num % 85; num/=85;
00594 a2=num % 85;
00595 a1=num / 85;
00596 *dst++ = a1+33;
00597 *dst++ = a2+33;
00598 if (ptr+1<src_end)
00599 *dst++ = a3+33;
00600 if (ptr+2<src_end)
00601 *dst++ = a4+33;
00602 if (ptr+3<src_end)
00603 *dst++ = a5+33;
00604 symbols += 5;
00605 if (symbols > 70 && ptr+4<src_end)
00606 {
00607 *dst++='\n';
00608 symbols=0;
00609 }
00610 }
00611 return dst;
00612 }
00613
00614 static unsigned char *
00615 RLE_encode(unsigned char * dst,
00616 const unsigned char * src_start,
00617 const unsigned char * src_end)
00618 {
00619
00620
00621
00622
00623
00624 const unsigned char * ptr;
00625 for(ptr=src_start;ptr<src_end;ptr++)
00626 {
00627 if (ptr==src_end-1)
00628 {
00629 *dst++=0; *dst++=*ptr;
00630 }
00631 else if (ptr[0]!=ptr[1])
00632 {
00633
00634 const unsigned char * ptr1;
00635 for(ptr1=ptr+1;ptr1<src_end-1;ptr1++)
00636 if (ptr1[0]==ptr1[1] || ptr1-ptr>=128) break;
00637 int pixels=ptr1-ptr;
00638 *dst++=pixels-1;
00639 for(int cnt=0;cnt<pixels;cnt++)
00640 *dst++=*ptr++;
00641 ptr--;
00642 }
00643 else
00644 {
00645
00646 const unsigned char * ptr1;
00647 for(ptr1=ptr+1;ptr1<src_end-1;ptr1++)
00648 if (ptr1[0]!=ptr1[1] || ptr1-ptr+1>=128) break;
00649 int pixels=ptr1-ptr+1;
00650 *dst++=257-pixels;
00651 *dst++=*ptr;
00652 ptr=ptr1;
00653 }
00654 }
00655 return dst;
00656 }
00657
00658 #define GRAY(r,g,b) (((r)*20+(g)*32+(b)*12)/64)
00659
00660 void
00661 DjVuToPS::
00662 store_page_setup(ByteStream &str,
00663 int dpi,
00664 const GRect &grect,
00665 int align )
00666 {
00667
00668
00669
00670 if (options.get_format() == Options::EPS)
00671 write(str,
00672 "/page-origstate save def\n"
00673 "%% -- coordinate system\n"
00674 "/image-dpi %d def\n"
00675 "/image-x 0 def\n"
00676 "/image-y 0 def\n"
00677 "/image-width %d def\n"
00678 "/image-height %d def\n"
00679 "/coeff 100 image-dpi div def\n"
00680 "/a11 coeff def\n"
00681 "/a12 0 def\n"
00682 "/a13 0 def\n"
00683 "/a21 0 def\n"
00684 "/a22 coeff def\n"
00685 "/a23 0 def\n"
00686 "[a11 a21 a12 a22 a13 a23] concat\n"
00687 "gsave 0 0 image-width image-height rectclip\n"
00688 "%% -- begin printing\n",
00689 dpi, grect.width(), grect.height() );
00690 else
00691 {
00692 int margin = 0;
00693 const char *xauto = "false";
00694 const char *xportrait = "false";
00695 const char *xfit = "false";
00696 if (options.get_orientation()==Options::AUTO)
00697 xauto = "true";
00698 if (options.get_orientation()==Options::PORTRAIT)
00699 xportrait = "true";
00700 if (options.get_zoom()<=0)
00701 xfit = "true";
00702 if (options.get_cropmarks())
00703 margin = 36;
00704 else if (options.get_frame())
00705 margin = 6;
00706 write(str,
00707 "/page-origstate save def\n"
00708 "%% -- coordinate system\n"
00709 "/auto-orient %s def\n"
00710 "/portrait %s def\n"
00711 "/fit-page %s def\n"
00712 "/zoom %d def\n"
00713 "/image-dpi %d def\n"
00714 "clippath pathbbox newpath\n"
00715 "2 index sub exch 3 index sub\n"
00716 "/page-width exch def\n"
00717 "/page-height exch def\n"
00718 "/page-y exch def\n"
00719 "/page-x exch def\n"
00720 "/image-x 0 def\n"
00721 "/image-y 0 def\n"
00722 "/image-width %d def\n"
00723 "/image-height %d def\n"
00724 "/margin %d def\n"
00725 "/halign %d def\n"
00726 "/valign 0 def\n",
00727 xauto, xportrait, xfit, options.get_zoom(),
00728 dpi, grect.width(), grect.height(),
00729 margin, align );
00730 write(str,
00731 "%% -- position page\n"
00732 "auto-orient {\n"
00733 " image-height image-width sub\n"
00734 " page-height page-width sub\n"
00735 " mul 0 ge /portrait exch def\n"
00736 "} if\n"
00737 "fit-page {\n"
00738 " /page-width page-width margin sub\n"
00739 " halign 0 eq { margin sub } if def\n"
00740 " /page-height page-height margin sub\n"
00741 " valign 0 eq { margin sub } if def\n"
00742 " /page-x page-x halign 0 ge { margin add } if def\n"
00743 " /page-y page-y valign 0 ge { margin add } if def\n"
00744 "} if\n"
00745 "portrait {\n"
00746 " fit-page {\n"
00747 " image-height page-height div\n"
00748 " image-width page-width div\n"
00749 " gt {\n"
00750 " page-height image-height div /coeff exch def\n"
00751 " } {\n"
00752 " page-width image-width div /coeff exch def\n"
00753 " } ifelse\n"
00754 " } {\n"
00755 " /coeff 72 image-dpi div zoom mul 100 div def\n"
00756 " } ifelse\n"
00757 " /start-x page-x page-width image-width\n"
00758 " coeff mul sub 2 div halign 1 add mul add def\n"
00759 " /start-y page-y page-height image-height\n"
00760 " coeff mul sub 2 div valign 1 add mul add def\n"
00761 " /a11 coeff def\n"
00762 " /a12 0 def\n"
00763 " /a13 start-x def\n"
00764 " /a21 0 def\n"
00765 " /a22 coeff def\n"
00766 " /a23 start-y def\n"
00767 "} { %% landscape\n"
00768 " fit-page {\n"
00769 " image-height page-width div\n"
00770 " image-width page-height div\n"
00771 " gt {\n"
00772 " page-width image-height div /coeff exch def\n"
00773 " } {\n"
00774 " page-height image-width div /coeff exch def\n"
00775 " } ifelse\n"
00776 " } {\n"
00777 " /coeff 72 image-dpi div zoom mul 100 div def\n"
00778 " } ifelse\n"
00779 " /start-x page-x page-width add page-width image-height\n"
00780 " coeff mul sub 2 div valign 1 add mul sub def\n"
00781 " /start-y page-y page-height image-width\n"
00782 " coeff mul sub 2 div halign 1 add mul add def\n"
00783 " /a11 0 def\n"
00784 " /a12 coeff neg def\n"
00785 " /a13 start-x image-y coeff neg mul sub def\n"
00786 " /a21 coeff def\n"
00787 " /a22 0 def\n"
00788 " /a23 start-y image-x coeff mul add def \n"
00789 "} ifelse\n"
00790 "[a11 a21 a12 a22 a13 a23] concat\n"
00791 "gsave 0 0 image-width image-height rectclip\n"
00792 "%% -- begin print\n");
00793 }
00794 }
00795
00796 void
00797 DjVuToPS::
00798 store_page_trailer(ByteStream &str)
00799 {
00800 write(str,
00801 "%% -- end print\n"
00802 "grestore\n");
00803 if (options.get_frame())
00804 write(str,
00805 "%% Drawing frame\n"
00806 "gsave 0.7 setgray 0.5 coeff div setlinewidth 0 0\n"
00807 "image-width image-height rectstroke\n"
00808 "grestore\n");
00809 if (options.get_cropmarks() &&
00810 options.get_format() != Options::EPS )
00811 write(str,
00812 "%% Drawing crop marks\n"
00813 "/cm { gsave translate rotate 1 coeff div dup scale\n"
00814 " 0 setgray 0.5 setlinewidth -36 0 moveto 0 0 lineto\n"
00815 " 0 -36 lineto stroke grestore } bind def\n"
00816 "0 0 0 cm 180 image-width image-height cm\n"
00817 "90 image-width 0 cm 270 0 image-height cm\n");
00818 write(str,
00819 "page-origstate restore\n");
00820 }
00821
00822 static int
00823 compute_red(int w, int h, int rw, int rh)
00824 {
00825 for (int red=1; red<16; red++)
00826 if (((w+red-1)/red==rw) && ((h+red-1)/red==rh))
00827 return red;
00828 return 16;
00829 }
00830
00831 static int
00832 get_bg_red(GP<DjVuImage> dimg)
00833 {
00834 GP<GPixmap> pm = 0;
00835
00836 int width = dimg->get_width();
00837 int height = dimg->get_height();
00838 if (width<=0 || height<=0) return 0;
00839
00840 GP<IW44Image> bg44 = dimg->get_bg44();
00841 if (bg44)
00842 {
00843 int w = bg44->get_width();
00844 int h = bg44->get_height();
00845
00846 if (w==0 || h==0 || width==0 || height==0)
00847 return 0;
00848 return compute_red(width,height,w,h);
00849 }
00850
00851 GP<GPixmap> bgpm = dimg->get_bgpm();
00852 if (bgpm)
00853 {
00854 int w = bgpm->columns();
00855 int h = bgpm->rows();
00856
00857 if (w==0 || h==0 || width==0 || height==0)
00858 return 0;
00859 return compute_red(width,height,w,h);
00860 }
00861 return 0;
00862 }
00863
00864 static GP<GPixmap>
00865 get_bg_pixmap(GP<DjVuImage> dimg, const GRect &rect)
00866 {
00867 GP<GPixmap> pm = 0;
00868
00869 int width = dimg->get_width();
00870 int height = dimg->get_height();
00871 GP<DjVuInfo> info = dimg->get_info();
00872 if (width<=0 || height<=0 || !info) return 0;
00873
00874 GP<IW44Image> bg44 = dimg->get_bg44();
00875 if (bg44)
00876 {
00877 int w = bg44->get_width();
00878 int h = bg44->get_height();
00879
00880 if (w==0 || h==0 || width==0 || height==0)
00881 return 0;
00882 pm = bg44->get_pixmap(1,rect);
00883 return pm;
00884 }
00885
00886 GP<GPixmap> bgpm = dimg->get_bgpm();
00887 if (bgpm)
00888 {
00889 int w = bgpm->columns();
00890 int h = bgpm->rows();
00891
00892 if (w==0 || h==0 || width==0 || height==0)
00893 return 0;
00894 pm->init(*bgpm, rect);
00895 return pm;
00896 }
00897
00898 return 0;
00899 }
00900
00901 void
00902 DjVuToPS::
00903 make_gamma_ramp(GP<DjVuImage> dimg)
00904 {
00905 double targetgamma = options.get_gamma();
00906 double whitepoint = (options.get_sRGB() ? 255 : 280);
00907 for (int i=0; i<256; i++)
00908 ramp[i] = i;
00909 if (! dimg->get_info())
00910 return;
00911 if (targetgamma < 0.1)
00912 return;
00913 double filegamma = dimg->get_info()->gamma;
00914 double correction = filegamma / targetgamma;
00915 if (correction<0.1 || correction>10)
00916 return;
00917 {
00918 for (int i=0; i<256; i++)
00919 {
00920 double x = (double)(i)/255.0;
00921 if (correction != 1.0)
00922 x = pow(x, correction);
00923 int j = (int) floor(whitepoint * x + 0.5);
00924 ramp[i] = (j>255) ? 255 : (j<0) ? 0 : j;
00925 }
00926 }
00927 }
00928
00929 void
00930 DjVuToPS::
00931 print_fg_2layer(ByteStream &str,
00932 GP<DjVuImage> dimg,
00933 const GRect &prn_rect,
00934 unsigned char *blit_list)
00935 {
00936
00937 GPixel p;
00938 int currentx=0;
00939 int currenty=0;
00940 GP<DjVuPalette> pal = dimg->get_fgbc();
00941 GP<JB2Image> jb2 = dimg->get_fgjb();
00942 if (! jb2) return;
00943 int num_blits = jb2->get_blit_count();
00944 int current_blit;
00945 for(current_blit=0; current_blit<num_blits; current_blit++)
00946 {
00947 if (blit_list[current_blit])
00948 {
00949 JB2Blit *blit = jb2->get_blit(current_blit);
00950 if ((pal) && !(options.get_mode()==Options::BW))
00951 {
00952 pal->index_to_color(pal->colordata[current_blit], p);
00953 if (options.get_color())
00954 {
00955 write(str,"/%d %d %d %f %f %f c\n",
00956 blit->shapeno,
00957 blit->left-currentx, blit->bottom-currenty,
00958 ramp[p.r]/255.0, ramp[p.g]/255.0, ramp[p.b]/255.0);
00959 }
00960 else
00961 {
00962 write(str,"/%d %d %d %f c\n",
00963 blit->shapeno,
00964 blit->left-currentx, blit->bottom-currenty,
00965 ramp[GRAY(p.r, p.g, p.b)]/255.0);
00966 }
00967 }
00968 else
00969 {
00970 write(str,"/%d %d %d s\n",
00971 blit->shapeno,
00972 blit->left-currentx, blit->bottom-currenty);
00973 }
00974 currentx = blit->left;
00975 currenty = blit->bottom;
00976 }
00977 }
00978 }
00979
00980 void
00981 DjVuToPS::
00982 print_fg_3layer(ByteStream &str,
00983 GP<DjVuImage> dimg,
00984 const GRect &cprn_rect,
00985 unsigned char *blit_list )
00986 {
00987 GRect prn_rect;
00988 GP<GPixmap> brush = dimg->get_fgpm();
00989 if (! brush) return;
00990 int br = brush->rows();
00991 int bc = brush->columns();
00992 int red = compute_red(dimg->get_width(),dimg->get_height(),bc,br);
00993 prn_rect.ymin = (cprn_rect.ymin)/red;
00994 prn_rect.xmin = (cprn_rect.xmin)/red;
00995 prn_rect.ymax = (cprn_rect.ymax+red-1)/red;
00996 prn_rect.xmax = (cprn_rect.xmax+red-1)/red;
00997 int color_nb = ((options.get_color()) ? 3 : 1);
00998 GP<JB2Image> jb2 = dimg->get_fgjb();
00999 if (! jb2) return;
01000 int pw = bc;
01001 int ph = 2;
01002
01003 write(str,
01004 "/P {\n"
01005 " 11 dict dup begin 4 1 roll\n"
01006 " /PatternType 1 def\n"
01007 " /PaintType 1 def\n"
01008 " /TilingType 1 def\n"
01009 " /H exch def\n"
01010 " /W exch def\n"
01011 " /Red %d def\n"
01012 " /PatternString exch def\n"
01013 " /XStep W Red mul def\n"
01014 " /YStep H Red mul def\n"
01015 " /BBox [0 0 XStep YStep] def\n"
01016 " /PaintProc { begin\n"
01017 " Red dup scale\n"
01018 " << /ImageType 1 /Width W /Height H\n"
01019 " /BitsPerComponent 8 /Interpolate false\n"
01020 " /Decode [%s] /ImageMatrix [1 0 0 1 0 0]\n"
01021 " /DataSource PatternString >> image\n"
01022 " end } bind def\n"
01023 " 0 0 XStep YStep rectclip\n"
01024 " end matrix makepattern\n"
01025 " /Pattern setcolorspace setpattern\n"
01026 " 0 0 moveto\n"
01027 "} def\n", red, (color_nb == 1) ? "0 1" : "0 1 0 1 0 1" );
01028
01029 unsigned char *s;
01030 GPBuffer<unsigned char> gs(s,pw*ph*color_nb);
01031 unsigned char *s_ascii_encoded;
01032 GPBuffer<unsigned char> gs_ascii_encoded(s_ascii_encoded,pw*ph*2*color_nb);
01033 {
01034 for (int y=prn_rect.ymin; y<prn_rect.ymax; y+=ph)
01035 for (int x=prn_rect.xmin; x<prn_rect.xmax; x+=pw)
01036 {
01037 int w = ((x+pw > prn_rect.xmax) ? prn_rect.xmax-x : pw);
01038 int h = ((y+ph > prn_rect.ymax) ? prn_rect.ymax-y : ph);
01039 int currentx = x * red;
01040 int currenty = y * red;
01041
01042 int current_blit;
01043 int num_blits = jb2->get_blit_count();
01044 GRect rect1(currentx,currenty, w*red, h*red);
01045 for(current_blit=0; current_blit<num_blits; current_blit++)
01046 if (blit_list[current_blit])
01047 {
01048 JB2Blit *blit = jb2->get_blit(current_blit);
01049 GRect rect2(blit->left, blit->bottom,
01050 jb2->get_shape(blit->shapeno).bits->columns(),
01051 jb2->get_shape(blit->shapeno).bits->rows());
01052 if (rect2.intersect(rect1,rect2))
01053 break;
01054 }
01055 if (current_blit >= num_blits)
01056 continue;
01057
01058 write(str,"gsave %d %d translate\n", currentx, currenty);
01059 write(str,"<~");
01060 unsigned char *q = s;
01061 for(int current_row = y; current_row<y+h; current_row++)
01062 {
01063 GPixel *row_pix = (*brush)[current_row];
01064 for(int current_col = x; current_col<x+w; current_col++)
01065 {
01066 GPixel &p = row_pix[current_col];
01067 if (color_nb>1)
01068 {
01069 *q++ = ramp[p.r];
01070 *q++ = ramp[p.g];
01071 *q++ = ramp[p.b];
01072 }
01073 else
01074 {
01075 *q++ = ramp[GRAY(p.r,p.g,p.b)];
01076 }
01077 }
01078 }
01079 unsigned char *stop_ascii =
01080 ASCII85_encode(s_ascii_encoded,s,s+w*h*color_nb);
01081 *stop_ascii++='\0';
01082 write(str,"%s",s_ascii_encoded);
01083 write(str,"~> %d %d P\n", w, h);
01084
01085 for(; current_blit<num_blits; current_blit++)
01086 if (blit_list[current_blit])
01087 {
01088 JB2Blit *blit = jb2->get_blit(current_blit);
01089 GRect rect2(blit->left, blit->bottom,
01090 jb2->get_shape(blit->shapeno).bits->columns(),
01091 jb2->get_shape(blit->shapeno).bits->rows());
01092 if (rect2.intersect(rect1,rect2))
01093 {
01094 write(str,"/%d %d %d s\n",
01095 blit->shapeno,
01096 blit->left-currentx, blit->bottom-currenty);
01097 currentx = blit->left;
01098 currenty = blit->bottom;
01099 }
01100 }
01101 write(str,"grestore\n");
01102 }
01103
01104 }
01105 }
01106
01107 void
01108 DjVuToPS::
01109 print_fg(ByteStream &str,
01110 GP<DjVuImage> dimg,
01111 const GRect &prn_rect )
01112 {
01113 GP<JB2Image> jb2=dimg->get_fgjb();
01114 if (! jb2) return;
01115 int num_blits = jb2->get_blit_count();
01116 int num_shapes = jb2->get_shape_count();
01117 unsigned char *dict_shapes = 0;
01118 unsigned char *blit_list = 0;
01119 GPBuffer<unsigned char> gdict_shapes(dict_shapes,num_shapes);
01120 GPBuffer<unsigned char> gblit_list(blit_list,num_blits);
01121 for(int i=0; i<num_shapes; i++)
01122 {
01123 dict_shapes[i]=0;
01124 }
01125 for(int current_blit=0; current_blit<num_blits; current_blit++)
01126 {
01127 JB2Blit *blit = jb2->get_blit(current_blit);
01128 JB2Shape *shape = & jb2->get_shape(blit->shapeno);
01129 blit_list[current_blit] = 0;
01130 if (! shape->bits)
01131 continue;
01132 GRect rect2(blit->left, blit->bottom,
01133 shape->bits->columns(), shape->bits->rows());
01134 if (rect2.intersect(rect2, prn_rect))
01135 {
01136 dict_shapes[blit->shapeno] = 1;
01137 blit_list[current_blit] = 1;
01138 }
01139 }
01140 write(str,
01141 "%% --- now doing the foreground\n"
01142 "gsave DjVuColorSpace setcolorspace\n" );
01143
01144 write(str,
01145 "/$DjVuLocalFont 7 dict def\n"
01146 "$DjVuLocalFont begin\n"
01147 "/FontType 3 def \n"
01148 "/FontMatrix [1 0 0 1 0 0] def\n"
01149 "/FontBBox [0 0 1 .5] def\n"
01150 "/CharStrings %d dict def\n"
01151 "/Encoding 2 array def\n"
01152 "0 1 1 {Encoding exch /.notdef put} for \n"
01153 "CharStrings begin\n"
01154 "/.notdef {} def\n",
01155 num_shapes+1);
01156 for(int current_shape=0; current_shape<num_shapes; current_shape++)
01157 {
01158 if (dict_shapes[current_shape])
01159 {
01160 JB2Shape *shape = & jb2->get_shape(current_shape);
01161 GP<GBitmap> bitmap = shape->bits;
01162 int rows = bitmap->rows();
01163 int columns = bitmap->columns();
01164 int nbytes = (columns+7)/8*rows+1;
01165 int nrows = rows;
01166 int nstrings=0;
01167 if (nbytes>(int)ps_string_size)
01168 {
01169 nrows=ps_string_size/((columns+7)/8);
01170 nbytes=(columns+7)/8*nrows+1;
01171 }
01172 unsigned char *s_start;
01173 GPBuffer<unsigned char> gs_start(s_start,nbytes);
01174 unsigned char *s_ascii;
01175 GPBuffer<unsigned char> gs_ascii(s_ascii,nbytes*2);
01176 write(str,"/%d {",current_shape);
01177
01178 unsigned char *s = s_start;
01179 for(int current_row=0; current_row<rows; current_row++)
01180 {
01181 unsigned char * row_bits = (*bitmap)[current_row];
01182 unsigned char acc = 0;
01183 unsigned char mask = 0;
01184 for(int current_col=0; current_col<columns; current_col++)
01185 {
01186 if (mask == 0)
01187 mask = 0x80;
01188 if (row_bits[current_col])
01189 acc |= mask;
01190 mask >>= 1;
01191 if (mask == 0)
01192 {
01193 *s=acc;
01194 s++;
01195 acc = mask = 0;
01196 }
01197 }
01198 if (mask != 0)
01199 {
01200 *s=acc;
01201 s++;
01202 }
01203 if (!((current_row+1)%nrows))
01204 {
01205 unsigned char *stop_ascii = ASCII85_encode(s_ascii,s_start,s);
01206 *stop_ascii++='\0';
01207 write(str,"<~%s~> ",s_ascii);
01208 s=s_start;
01209 nstrings++;
01210 }
01211 }
01212 if (s!=s_start)
01213 {
01214 unsigned char *stop_ascii = ASCII85_encode(s_ascii,s_start,s);
01215 *stop_ascii++='\0';
01216 write(str,"<~%s~> ",s_ascii);
01217 nstrings++;
01218 }
01219 if (nstrings==1)
01220 write(str," %d %d g} def\n", columns, rows);
01221 else
01222 write(str," %d %d %d gn} def\n", columns, rows,nstrings);
01223 }
01224 }
01225 write(str,
01226 "end\n"
01227 "/BuildGlyph {\n"
01228 " exch /CharStrings get exch\n"
01229 " 2 copy known not\n"
01230 " {pop /.notdef} if\n"
01231 " get exec \n"
01232 "} bind def\n"
01233 "end\n"
01234 "/LocalDjVuFont $DjVuLocalFont definefont pop\n"
01235 "/LocalDjVuFont findfont setfont\n" );
01236 write(str,
01237 "-%d -%d translate\n"
01238 "0 0 moveto\n",
01239 prn_rect.xmin, prn_rect.ymin);
01240
01241 if (dimg->get_fgpm() && !(options.get_mode()==Options::BW))
01242 print_fg_3layer(str, dimg, prn_rect, blit_list);
01243 else
01244 print_fg_2layer(str, dimg, prn_rect, blit_list);
01245 write(str, "/LocalDjVuFont undefinefont grestore\n");
01246 }
01247
01248
01249 void
01250 DjVuToPS::
01251 print_bg(ByteStream &str,
01252 GP<DjVuImage> dimg,
01253 const GRect &cprn_rect)
01254 {
01255 GP<GPixmap> pm;
01256 GRect prn_rect;
01257 double print_done = 0;
01258 int red = 0;
01259 write(str, "%% --- now doing the background\n");
01260 if (! (red = get_bg_red(dimg)))
01261 return;
01262 write(str,
01263 "gsave -%d -%d translate\n"
01264 "/bgred %d def bgred bgred scale\n",
01265 cprn_rect.xmin % red,
01266 cprn_rect.ymin % red,
01267 red);
01268 prn_rect.ymin = (cprn_rect.ymin)/red;
01269 prn_rect.ymax = (cprn_rect.ymax+red-1)/red;
01270 prn_rect.xmin = (cprn_rect.xmin)/red;
01271 prn_rect.xmax = (cprn_rect.xmax+red-1)/red;
01272
01273 int band_bytes = 125000;
01274 int band_height = band_bytes/prn_rect.width();
01275 int buffer_size = band_height*prn_rect.width();
01276 int ps_chunk_height = 30960/prn_rect.width()+1;
01277 buffer_size = buffer_size*23/10;
01278 bool do_color = options.get_color();
01279 if (!dimg->is_legal_photo() &&
01280 !dimg->is_legal_compound() ||
01281 options.get_mode()==Options::BW)
01282 do_color = false;
01283 if (do_color)
01284 buffer_size *= 3;
01285 if (do_color)
01286 write(str,
01287 "/bufferR %d string def\n"
01288 "/bufferG %d string def\n"
01289 "/bufferB %d string def\n"
01290 "DjVuColorSpace setcolorspace\n"
01291 "<< /ImageType 1\n"
01292 " /Width %d\n"
01293 " /Height %d\n"
01294 " /BitsPerComponent 8\n"
01295 " /Decode [0 1 0 1 0 1]\n"
01296 " /ImageMatrix [1 0 0 1 0 0]\n"
01297 " /MultipleDataSources true\n"
01298 " /DataSource [ { ReadR } { ReadG } { ReadB } ]\n"
01299 " /Interpolate false >> image\n",
01300 ps_chunk_height*prn_rect.width(),
01301 ps_chunk_height*prn_rect.width(),
01302 ps_chunk_height*prn_rect.width(),
01303 prn_rect.width(), prn_rect.height());
01304 else
01305 write(str,
01306 "DjVuColorSpace setcolorspace\n"
01307 "<< /ImageType 1\n"
01308 " /Width %d\n"
01309 " /Height %d\n"
01310 " /BitsPerComponent 8\n"
01311 " /Decode [0 1]\n"
01312 " /ImageMatrix [1 0 0 1 0 0]\n"
01313 " /DataSource currentfile /ASCII85Decode\n"
01314 " filter /RunLengthDecode filter\n"
01315 " /Interpolate false >> image\n",
01316 prn_rect.width(), prn_rect.height());
01317
01318 unsigned char *buffer;
01319 GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
01320 unsigned char *rle_in;
01321 GPBuffer<unsigned char> grle_in(rle_in,ps_chunk_height*prn_rect.width());
01322 unsigned char *rle_out;
01323 GPBuffer<unsigned char> grle_out(rle_out,2*ps_chunk_height*prn_rect.width());
01324 {
01325
01326 unsigned char * rle_out_end = rle_out;
01327 GRect grectBand = prn_rect;
01328 grectBand.ymax = grectBand.ymin;
01329 while(grectBand.ymax < prn_rect.ymax)
01330 {
01331 GP<GPixmap> pm = 0;
01332
01333 grectBand.ymin=grectBand.ymax;
01334 grectBand.ymax=grectBand.ymin+band_bytes/grectBand.width();
01335 if (grectBand.ymax>prn_rect.ymax)
01336 grectBand.ymax=prn_rect.ymax;
01337 pm = get_bg_pixmap(dimg, grectBand);
01338 unsigned char *buf_ptr = buffer;
01339 if (pm)
01340 {
01341 if (do_color)
01342 {
01343 int y=0;
01344 while(y<grectBand.height())
01345 {
01346 int row, y1;
01347 unsigned char *ptr, *ptr1;
01348
01349 for (row=0,ptr=rle_in,y1=y;
01350 row<ps_chunk_height && y1<grectBand.height();
01351 row++,y1++)
01352 {
01353 GPixel *pix = (*pm)[y1];
01354 for (int x=grectBand.width(); x>0; x--,pix++)
01355 *ptr++ = ramp[pix->r];
01356 }
01357 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01358 *ptr1++ = 0x80;
01359 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01360 *buf_ptr++ = '~'; *buf_ptr++ = '>'; *buf_ptr++ = '\n';
01361
01362 for (row=0,ptr=rle_in,y1=y;
01363 row<ps_chunk_height && y1<grectBand.height();
01364 row++,y1++)
01365 {
01366 GPixel *pix = (*pm)[y1];
01367 for (int x=grectBand.width(); x>0; x--,pix++)
01368 *ptr++ = ramp[pix->g];
01369 }
01370 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01371 *ptr1++ = 0x80;
01372 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01373 *buf_ptr++ = '~';
01374 *buf_ptr++ = '>';
01375 *buf_ptr++ = '\n';
01376
01377 for (row=0, ptr=rle_in, y1=y;
01378 row<ps_chunk_height && y1<grectBand.height();
01379 row++,y1++)
01380 {
01381 GPixel *pix = (*pm)[y1];
01382 for (int x=grectBand.width(); x>0; x--,pix++)
01383 *ptr++ = ramp[pix->b];
01384 }
01385 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01386 *ptr1++ = 0x80;
01387 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01388 *buf_ptr++ = '~';
01389 *buf_ptr++ = '>';
01390 *buf_ptr++ = '\n';
01391 y=y1;
01392 if (refresh_cb)
01393 refresh_cb(refresh_cl_data);
01394 }
01395 }
01396 else
01397 {
01398
01399 int y=0;
01400 while(y<grectBand.height())
01401 {
01402 unsigned char *ptr = rle_in;
01403 for(int row=0;
01404 row<ps_chunk_height && y<grectBand.height();
01405 row++,y++)
01406 {
01407 GPixel *pix = (*pm)[y];
01408 for (int x=grectBand.width(); x>0; x--,pix++)
01409 *ptr++ = ramp[GRAY(pix->r,pix->g,pix->b)];
01410 }
01411 rle_out_end = RLE_encode(rle_out_end, rle_in, ptr);
01412 unsigned char *encode_to
01413 = rle_out+(rle_out_end-rle_out)/4*4;
01414 int bytes_left = rle_out_end-encode_to;
01415 buf_ptr = ASCII85_encode(buf_ptr, rle_out, encode_to);
01416 *buf_ptr++ = '\n';
01417 memcpy(rle_out, encode_to, bytes_left);
01418 rle_out_end = rle_out+bytes_left;
01419 if (refresh_cb)
01420 refresh_cb(refresh_cl_data);
01421 }
01422 }
01423 }
01424 str.writall(buffer, buf_ptr-buffer);
01425 if (prn_progress_cb)
01426 {
01427 double done=(double)(grectBand.ymax
01428 - prn_rect.ymin)/prn_rect.height();
01429 if ((int) (20*print_done)!=(int) (20*done))
01430 {
01431 print_done=done;
01432 prn_progress_cb(done, prn_progress_cl_data);
01433 }
01434 }
01435 }
01436 if (! do_color)
01437 {
01438 unsigned char * buf_ptr = buffer;
01439 *rle_out_end++ = 0x80;
01440 buf_ptr = ASCII85_encode(buf_ptr, rle_out, rle_out_end);
01441 *buf_ptr++='~';
01442 *buf_ptr++='>';
01443 *buf_ptr++='\n';
01444 str.writall(buffer, buf_ptr-buffer);
01445 }
01446 }
01447
01448 write(str, "grestore\n");
01449 }
01450
01451 void
01452 DjVuToPS::
01453 print_image_lev1(ByteStream &str,
01454 GP<DjVuImage> dimg,
01455 const GRect &prn_rect)
01456 {
01457 double print_done=0;
01458 GRect all(0,0, dimg->get_width(),dimg->get_height());
01459 GP<GPixmap> pm;
01460 GP<GBitmap> bm;
01461 GRect test(0,0,1,1);
01462 if (options.get_mode() == Options::FORE)
01463 pm = dimg->get_fg_pixmap(test, all);
01464 else if (options.get_mode() == Options::BACK)
01465 pm = dimg->get_bg_pixmap(test, all);
01466 else if (options.get_mode() != Options::BW)
01467 pm = dimg->get_pixmap(test, all);
01468 if (! pm)
01469 bm = dimg->get_bitmap(test,all);
01470 if (! pm && ! bm)
01471 return;
01472 write(str,
01473 "%% --- now doing a level 1 image\n"
01474 "gsave\n");
01475
01476 int band_bytes=125000;
01477 int band_height = band_bytes/prn_rect.width();
01478 int buffer_size = band_height*prn_rect.width();
01479 buffer_size = buffer_size*21/10;
01480 bool do_color = false;
01481 bool do_color_or_gray = false;
01482 if (pm && (options.get_mode() != Options::BW))
01483 do_color_or_gray = true;
01484 if (do_color_or_gray && options.get_color())
01485 do_color = true;
01486 if (do_color)
01487 buffer_size *= 3;
01488 if (do_color)
01489 write(str, "/buffer24 %d string def\n", 3*prn_rect.width());
01490 if (do_color_or_gray)
01491 write(str, "/buffer8 %d string def\n", prn_rect.width());
01492 else
01493 write(str, "/buffer8 %d string def\n", (prn_rect.width()+7)/8);
01494 if (do_color)
01495 {
01496 write(str,
01497 "%d %d 8 [ 1 0 0 1 0 0 ]\n"
01498 "{ ColorProc } false 3 ColorImage\n",
01499 prn_rect.width(), prn_rect.height());
01500 }
01501 else if (do_color_or_gray)
01502 {
01503 write(str,
01504 "%d %d 8 [ 1 0 0 1 0 0 ]\n"
01505 "{ currentfile buffer8 readhexstring pop } image\n",
01506 prn_rect.width(), prn_rect.height());
01507 }
01508 else
01509 {
01510 write(str,
01511 "%d %d 1 [ 1 0 0 1 0 0 ]\n"
01512 "{ currentfile buffer8 readhexstring pop } image\n",
01513 prn_rect.width(), prn_rect.height());
01514 }
01515 unsigned char * buffer;
01516 GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
01517 {
01518
01519 GRect grectBand = prn_rect;
01520 grectBand.ymax = grectBand.ymin;
01521 while(grectBand.ymax < prn_rect.ymax)
01522 {
01523
01524 grectBand.ymin = grectBand.ymax;
01525 grectBand.ymax = grectBand.ymin+band_bytes/grectBand.width();
01526 if (grectBand.ymax > prn_rect.ymax)
01527 grectBand.ymax = prn_rect.ymax;
01528 GRect all(0,0, dimg->get_width(),dimg->get_height());
01529 pm = 0;
01530 bm = 0;
01531 if (do_color_or_gray)
01532 {
01533 if (options.get_mode() == Options::FORE)
01534 pm = dimg->get_fg_pixmap(grectBand, all);
01535 else if (options.get_mode() == Options::BACK)
01536 pm = dimg->get_bg_pixmap(grectBand, all);
01537 else
01538 pm = dimg->get_pixmap(grectBand, all);
01539 }
01540 else
01541 {
01542 bm = dimg->get_bitmap(grectBand, all);
01543 }
01544
01545 unsigned char *buf_ptr = buffer;
01546 int symbols=0;
01547 for (int y=0; y<grectBand.height(); y++)
01548 {
01549 if (pm && do_color_or_gray)
01550 {
01551 GPixel *pix = (*pm)[y];
01552 for (int x=grectBand.width(); x>0; x--, pix++)
01553 {
01554 if (do_color)
01555 {
01556 char *data;
01557 data = bin2hex[ramp[pix->r]];
01558 *buf_ptr++ = data[0];
01559 *buf_ptr++ = data[1];
01560 data = bin2hex[ramp[pix->g]];
01561 *buf_ptr++ = data[0];
01562 *buf_ptr++ = data[1];
01563 data = bin2hex[ramp[pix->b]];
01564 *buf_ptr++ = data[0];
01565 *buf_ptr++ = data[1];
01566 symbols += 6;
01567 }
01568 else
01569 {
01570 char *data;
01571 data = bin2hex[ramp[GRAY(pix->r,pix->g,pix->b)]];
01572 *buf_ptr++ = data[0];
01573 *buf_ptr++ = data[1];
01574 symbols += 2;
01575 }
01576 if (symbols>70)
01577 {
01578 *buf_ptr++ = '\n';
01579 symbols=0;
01580 }
01581 }
01582 }
01583 else if (bm)
01584 {
01585 unsigned char *pix = (*bm)[y];
01586 unsigned char acc = 0;
01587 unsigned char mask = 0;
01588 char *data;
01589 for (int x=grectBand.width(); x>0; x--, pix++)
01590 {
01591 if (mask == 0)
01592 mask = 0x80;
01593 if (! *pix)
01594 acc |= mask;
01595 mask >>= 1;
01596 if (mask == 0)
01597 {
01598 data = bin2hex[acc];
01599 acc = 0;
01600 *buf_ptr++ = data[0];
01601 *buf_ptr++ = data[1];
01602 symbols += 2;
01603 if (symbols>70)
01604 {
01605 *buf_ptr++ = '\n';
01606 symbols = 0;
01607 }
01608 }
01609 }
01610 if (mask != 0)
01611 {
01612 data = bin2hex[acc];
01613 *buf_ptr++ = data[0];
01614 *buf_ptr++ = data[1];
01615 symbols += 2;
01616 }
01617 }
01618 if (refresh_cb)
01619 refresh_cb(refresh_cl_data);
01620 }
01621 str.writall(buffer, buf_ptr-buffer);
01622 if (prn_progress_cb)
01623 {
01624 double done=(double) (grectBand.ymax
01625 - prn_rect.ymin)/prn_rect.height();
01626 if ((int) (20*print_done)!=(int) (20*done))
01627 {
01628 print_done=done;
01629 prn_progress_cb(done, prn_progress_cl_data);
01630 }
01631 }
01632 }
01633 write(str, "\n");
01634 }
01635 write(str, "grestore\n");
01636 }
01637
01638 void
01639 DjVuToPS::
01640 print_image_lev2(ByteStream &str,
01641 GP<DjVuImage> dimg,
01642 const GRect &prn_rect)
01643 {
01644 double print_done=0;
01645 GRect all(0,0, dimg->get_width(),dimg->get_height());
01646 GP<GPixmap> pm;
01647 GRect test(0,0,1,1);
01648 if (options.get_mode() == Options::FORE)
01649 pm = dimg->get_fg_pixmap(test, all);
01650 else if (options.get_mode() == Options::BACK)
01651 pm = dimg->get_bg_pixmap(test, all);
01652 else if (options.get_mode() != Options::BW)
01653 pm = dimg->get_pixmap(test, all);
01654 if (! pm)
01655 return;
01656 write(str,
01657 "%% --- now doing a level 2 image\n"
01658 "gsave\n");
01659
01660 int band_bytes=125000;
01661 int band_height = band_bytes/prn_rect.width();
01662 int buffer_size = band_height*prn_rect.width();
01663 int ps_chunk_height = 30960/prn_rect.width()+1;
01664 buffer_size = buffer_size*21/10 + 32;
01665 bool do_color = options.get_color();
01666 if (do_color)
01667 {
01668 buffer_size *= 3;
01669 write(str,
01670 "/bufferR %d string def\n"
01671 "/bufferG %d string def\n"
01672 "/bufferB %d string def\n"
01673 "DjVuColorSpace setcolorspace\n"
01674 "<< /ImageType 1\n"
01675 " /Width %d\n"
01676 " /Height %d\n"
01677 " /BitsPerComponent 8\n"
01678 " /Decode [0 1 0 1 0 1]\n"
01679 " /ImageMatrix [1 0 0 1 0 0]\n"
01680 " /MultipleDataSources true\n"
01681 " /DataSource [ { ReadR } { ReadG } { ReadB } ]\n"
01682 " /Interpolate false >> image\n",
01683 ps_chunk_height*prn_rect.width(),
01684 ps_chunk_height*prn_rect.width(),
01685 ps_chunk_height*prn_rect.width(),
01686 prn_rect.width(), prn_rect.height());
01687 }
01688 else
01689 {
01690 write(str,
01691 "DjVuColorSpace setcolorspace\n"
01692 "<< /ImageType 1\n"
01693 " /Width %d\n"
01694 " /Height %d\n"
01695 " /BitsPerComponent 8\n"
01696 " /Decode [0 1]\n"
01697 " /ImageMatrix [1 0 0 1 0 0]\n"
01698 " /DataSource currentfile /ASCII85Decode\n"
01699 " filter /RunLengthDecode filter\n"
01700 " /Interpolate false >> image\n",
01701 prn_rect.width(), prn_rect.height());
01702 }
01703 unsigned char *buffer;
01704 GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
01705 unsigned char *rle_in;
01706 GPBuffer<unsigned char> grle_in(rle_in,ps_chunk_height*prn_rect.width());
01707 unsigned char *rle_out;
01708 GPBuffer<unsigned char> grle_out(rle_out,2*ps_chunk_height*prn_rect.width());
01709 {
01710
01711 unsigned char * rle_out_end = rle_out;
01712 GRect grectBand = prn_rect;
01713 grectBand.ymax = grectBand.ymin;
01714 while(grectBand.ymax < prn_rect.ymax)
01715 {
01716
01717 grectBand.ymin = grectBand.ymax;
01718 grectBand.ymax = grectBand.ymin+band_bytes/grectBand.width();
01719 if (grectBand.ymax > prn_rect.ymax)
01720 grectBand.ymax = prn_rect.ymax;
01721 GRect all(0,0, dimg->get_width(),dimg->get_height());
01722 pm = 0;
01723 if (options.get_mode() == Options::FORE)
01724 pm = dimg->get_fg_pixmap(grectBand, all);
01725 else if (options.get_mode() == Options::BACK)
01726 pm = dimg->get_bg_pixmap(grectBand, all);
01727 else
01728 pm = dimg->get_pixmap(grectBand, all);
01729
01730 unsigned char *buf_ptr = buffer;
01731 if (do_color && pm)
01732 {
01733 int y=0;
01734 while(y<grectBand.height())
01735 {
01736 int row, y1;
01737 unsigned char *ptr, *ptr1;
01738
01739 for (row=0,ptr=rle_in,y1=y;
01740 row<ps_chunk_height && y1<grectBand.height();
01741 row++,y1++)
01742 {
01743 GPixel *pix = (*pm)[y1];
01744 for (int x=grectBand.width(); x>0; x--,pix++)
01745 *ptr++ = ramp[pix->r];
01746 }
01747 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01748 *ptr1++ = 0x80;
01749 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01750 *buf_ptr++ = '~'; *buf_ptr++ = '>'; *buf_ptr++ = '\n';
01751
01752 for (row=0,ptr=rle_in,y1=y;
01753 row<ps_chunk_height && y1<grectBand.height();
01754 row++,y1++)
01755 {
01756 GPixel *pix = (*pm)[y1];
01757 for (int x=grectBand.width(); x>0; x--,pix++)
01758 *ptr++ = ramp[pix->g];
01759 }
01760 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01761 *ptr1++ = 0x80;
01762 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01763 *buf_ptr++ = '~';
01764 *buf_ptr++ = '>';
01765 *buf_ptr++ = '\n';
01766
01767 for (row=0, ptr=rle_in, y1=y;
01768 row<ps_chunk_height && y1<grectBand.height();
01769 row++,y1++)
01770 {
01771 GPixel *pix = (*pm)[y1];
01772 for (int x=grectBand.width(); x>0; x--,pix++)
01773 *ptr++ = ramp[pix->b];
01774 }
01775 ptr1 = RLE_encode(rle_out, rle_in, ptr);
01776 *ptr1++ = 0x80;
01777 buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
01778 *buf_ptr++ = '~';
01779 *buf_ptr++ = '>';
01780 *buf_ptr++ = '\n';
01781 y=y1;
01782 if (refresh_cb)
01783 refresh_cb(refresh_cl_data);
01784 }
01785 }
01786 else if (pm)
01787 {
01788
01789 int y=0;
01790 while(y<grectBand.height())
01791 {
01792 unsigned char *ptr = rle_in;
01793 for(int row=0;
01794 row<ps_chunk_height && y<grectBand.height();
01795 row++,y++)
01796 {
01797 GPixel *pix = (*pm)[y];
01798 for (int x=grectBand.width(); x>0; x--,pix++)
01799 *ptr++ = ramp[GRAY(pix->r,pix->g,pix->b)];
01800 }
01801 rle_out_end = RLE_encode(rle_out_end, rle_in, ptr);
01802 unsigned char *encode_to = rle_out
01803 + (rle_out_end-rle_out)/4*4;
01804 int bytes_left = rle_out_end-encode_to;
01805 buf_ptr = ASCII85_encode(buf_ptr, rle_out, encode_to);
01806 *buf_ptr++ = '\n';
01807 memcpy(rle_out, encode_to, bytes_left);
01808 rle_out_end = rle_out+bytes_left;
01809 if (refresh_cb)
01810 refresh_cb(refresh_cl_data);
01811 }
01812 if (grectBand.ymax >= prn_rect.ymax)
01813 {
01814 *rle_out_end++ = 0x80;
01815 buf_ptr = ASCII85_encode(buf_ptr, rle_out, rle_out_end);
01816 *buf_ptr++ = '~';
01817 *buf_ptr++ = '>';
01818 *buf_ptr++ = '\n';
01819 }
01820 }
01821 str.writall(buffer, buf_ptr-buffer);
01822 if (prn_progress_cb)
01823 {
01824 double done=(double) (grectBand.ymax
01825 - prn_rect.ymin)/prn_rect.height();
01826 if ((int) (20*print_done)!=(int) (20*done))
01827 {
01828 print_done=done;
01829 prn_progress_cb(done, prn_progress_cl_data);
01830 }
01831 }
01832 }
01833 write(str, "\n");
01834 }
01835 write(str, "grestore\n");
01836 }
01837
01838 static void
01839 get_anno_sub(IFFByteStream &iff, IFFByteStream &out)
01840 {
01841 GUTF8String chkid;
01842 while (iff.get_chunk(chkid))
01843 {
01844 if (iff.composite())
01845 get_anno_sub(iff, out);
01846 else if (chkid == "ANTa" || chkid == "ANTz" ||
01847 chkid == "TXTa" || chkid == "TXTz" )
01848 {
01849 out.put_chunk(chkid);
01850 out.copy(*iff.get_bytestream());
01851 out.close_chunk();
01852 }
01853 iff.close_chunk();
01854 }
01855 }
01856
01857 static GP<ByteStream>
01858 get_anno(GP<DjVuFile> f)
01859 {
01860 if (! f->anno)
01861 {
01862 GP<ByteStream> bs = f->get_init_data_pool()->get_stream();
01863 GP<ByteStream> anno = ByteStream::create();
01864 GP<IFFByteStream> in = IFFByteStream::create(bs);
01865 GP<IFFByteStream> out = IFFByteStream::create(anno);
01866 get_anno_sub(*in, *out);
01867 f->anno = anno;
01868 }
01869 f->anno->seek(0);
01870 return f->anno;
01871 }
01872
01873 static GP<DjVuTXT>
01874 get_text(GP<DjVuFile> file)
01875 {
01876 GUTF8String chkid;
01877 GP<IFFByteStream> iff = IFFByteStream::create(get_anno(file));
01878 while (iff->get_chunk(chkid))
01879 {
01880 if (chkid == "TXTa")
01881 {
01882 GP<DjVuTXT> txt = DjVuTXT::create();
01883 txt->decode(iff->get_bytestream());
01884 return txt;
01885 }
01886 else if (chkid == "TXTz")
01887 {
01888 GP<DjVuTXT> txt = DjVuTXT::create();
01889 GP<ByteStream> bsiff = BSByteStream::create(iff->get_bytestream());
01890 txt->decode(bsiff);
01891 return txt;
01892 }
01893 iff->close_chunk();
01894 }
01895 return 0;
01896 }
01897
01898 static void
01899 print_ps_string(const char *data, int length, ByteStream &out)
01900 {
01901 while (*data && length>0)
01902 {
01903 int span = 0;
01904 while (span<length && data[span]>=0x20 && data[span]<0x7f
01905 && data[span]!='(' && data[span]!=')' && data[span]!='\\' )
01906 span++;
01907 if (span > 0)
01908 {
01909 out.write(data, span);
01910 data += span;
01911 length -= span;
01912 }
01913 else
01914 {
01915 char buffer[5];
01916 sprintf(buffer,"\\%03o", *data);
01917 out.write(buffer,4);
01918 data += 1;
01919 length -= 1;
01920 }
01921 }
01922 }
01923
01924 static void
01925 print_txt_sub(DjVuTXT &txt, DjVuTXT::Zone &zone,
01926 ByteStream &out,int &lastx,int &lasty)
01927 {
01928
01929 char separator = 0;
01930 switch(zone.ztype)
01931 {
01932 case DjVuTXT::COLUMN:
01933 separator = DjVuTXT::end_of_column; break;
01934 case DjVuTXT::REGION:
01935 separator = DjVuTXT::end_of_region; break;
01936 case DjVuTXT::PARAGRAPH:
01937 separator = DjVuTXT::end_of_paragraph; break;
01938 case DjVuTXT::LINE:
01939 separator = DjVuTXT::end_of_line; break;
01940 case DjVuTXT::WORD:
01941 separator = ' '; break;
01942 default:
01943 separator = 0; break;
01944 }
01945
01946 if (zone.children.isempty())
01947 {
01948 const char *data = (const char*)txt.textUTF8 + zone.text_start;
01949 int length = zone.text_length;
01950 if (data[length-1] == separator)
01951 length -= 1;
01952 out.write("( ",2);
01953 print_ps_string(data,length,out);
01954 out.write(")",1);
01955 GUTF8String message;
01956 int tmpx= zone.rect.xmin-lastx;
01957 int tmpy= zone.rect.ymin-lasty;
01958 message.format(" %d %d S \n", tmpx, tmpy);
01959 lastx=zone.rect.xmin;
01960 lasty=zone.rect.ymin;
01961 out.write((const char*)message, message.length());
01962 }
01963 else
01964 {
01965 if (zone.ztype==DjVuTXT::LINE)
01966 {
01967 GUTF8String message;
01968 message.format("%d F\n",zone.rect.ymax-zone.rect.ymin);
01969 out.write((const char*)message,message.length());
01970 }
01971 for (GPosition pos=zone.children; pos; ++pos)
01972 print_txt_sub(txt, zone.children[pos], out,lastx,lasty);
01973 }
01974 }
01975
01976 static void
01977 print_txt(GP<DjVuTXT> txt,
01978 ByteStream &out )
01979 {
01980 if (txt)
01981 {
01982 int lastx=0;
01983 int lasty=0;
01984 GUTF8String message =
01985 "%% -- now doing hidden text\n"
01986 "gsave -1 -1 0 0 clip 0 0 moveto\n";
01987 out.write((const char*)message,message.length());
01988 print_txt_sub(*txt, txt->page_zone, out,lastx,lasty);
01989 message =
01990 "grestore \n";
01991 out.write((const char*)message,message.length());
01992 }
01993 }
01994
01995 void
01996 DjVuToPS::
01997 print_image(ByteStream &str,
01998 GP<DjVuImage> dimg,
01999 const GRect &prn_rect,
02000 GP<DjVuTXT> txt)
02001 {
02002
02003
02004
02005
02006
02007
02008 DEBUG_MSG("DjVuToPS::print_image(): Printing DjVuImage to a stream\n");
02009 DEBUG_MAKE_INDENT(3);
02010 if (!dimg)
02011 G_THROW(ERR_MSG("DjVuToPS.empty_image"));
02012 if (prn_rect.isempty())
02013 G_THROW(ERR_MSG("DjVuToPS.empty_rect"));
02014 if (prn_progress_cb)
02015 prn_progress_cb(0, prn_progress_cl_data);
02016
02017 print_txt(txt, str);
02018 make_gamma_ramp(dimg);
02019 if (options.get_level() < 2)
02020 {
02021 print_image_lev1(str, dimg, prn_rect);
02022 }
02023 else if (options.get_level() < 3 && dimg->get_fgpm())
02024 {
02025 switch(options.get_mode())
02026 {
02027 case Options::COLOR:
02028 case Options::FORE:
02029 print_image_lev2(str, dimg, prn_rect);
02030 break;
02031 case Options::BW:
02032 print_fg(str, dimg, prn_rect);
02033 break;
02034 case Options::BACK:
02035 print_bg(str, dimg, prn_rect);
02036 break;
02037 }
02038 }
02039 else
02040 {
02041 switch(options.get_mode())
02042 {
02043 case Options::COLOR:
02044 print_bg(str, dimg, prn_rect);
02045 print_fg(str, dimg, prn_rect);
02046 break;
02047 case Options::FORE:
02048 case Options::BW:
02049 print_fg(str, dimg, prn_rect);
02050 break;
02051 case Options::BACK:
02052 print_bg(str, dimg, prn_rect);
02053 break;
02054 }
02055 }
02056 if (prn_progress_cb)
02057 prn_progress_cb(1, prn_progress_cl_data);
02058 }
02059
02060
02061
02062
02063
02064
02065
02066
02067
02068
02069
02070 void
02071 DjVuToPS::
02072 print(ByteStream &str,
02073 GP<DjVuImage> dimg,
02074 const GRect &prn_rect_in,
02075 const GRect &img_rect,
02076 int override_dpi)
02077 {
02078 DEBUG_MSG("DjVuToPS::print(): Printing DjVu page to a stream\n");
02079 DEBUG_MAKE_INDENT(3);
02080 GRect prn_rect;
02081 prn_rect.intersect(prn_rect_in, img_rect);
02082 DEBUG_MSG("prn_rect=(" << prn_rect.xmin << ", " << prn_rect.ymin << ", " <<
02083 prn_rect.width() << ", " << prn_rect.height() << ")\n");
02084 DEBUG_MSG("img_rect=(" << img_rect.xmin << ", " << img_rect.ymin << ", " <<
02085 img_rect.width() << ", " << img_rect.height() << ")\n");
02086 if (!dimg)
02087 G_THROW(ERR_MSG("DjVuToPS.empty_image"));
02088 if (prn_rect.isempty())
02089 G_THROW(ERR_MSG("DjVuToPS.empty_rect"));
02090 if (img_rect.isempty())
02091 G_THROW(ERR_MSG("DjVuToPS.bad_scale"));
02092 GRectMapper mapper;
02093 mapper.set_input(img_rect);
02094 GRect full_rect(0, 0, dimg->get_width(), dimg->get_height());
02095 mapper.set_output(full_rect);
02096 mapper.map(prn_rect);
02097 int image_dpi = dimg->get_dpi();
02098 if (override_dpi>0)
02099 image_dpi = override_dpi;
02100 if (image_dpi <= 0)
02101 image_dpi = 300;
02102 store_doc_prolog(str, 1, (int)(image_dpi), &prn_rect);
02103 store_doc_setup(str);
02104 write(str,"%%%%Page: 1 1\n");
02105 store_page_setup(str, (int)(image_dpi), prn_rect);
02106 print_image(str, dimg, prn_rect, 0);
02107 store_page_trailer(str);
02108 write(str,"showpage\n");
02109 store_doc_trailer(str);
02110 }
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120 void
02121 DjVuToPS::
02122 parse_range(GP<DjVuDocument> doc,
02123 GUTF8String page_range,
02124 GList<int> &pages_todo)
02125 {
02126 int doc_pages = doc->get_pages_num();
02127 if (!page_range.length())
02128 page_range.format("1-%d", doc_pages);
02129 DEBUG_MSG("page_range='" << (const char *)page_range << "'\n");
02130 int spec = 0;
02131 int both = 1;
02132 int start_page = 1;
02133 int end_page = doc_pages;
02134 const char *q = (const char*)page_range;
02135 char *p = (char*)q;
02136 while (*p)
02137 {
02138 while (*p==' ')
02139 p += 1;
02140 if (! *p)
02141 break;
02142 if (*p>='0' && *p<='9')
02143 {
02144 end_page = strtol(p, &p, 10);
02145 spec = 1;
02146 }
02147 else if (*p=='$')
02148 {
02149 spec = 1;
02150 end_page = doc_pages;
02151 p += 1;
02152 }
02153 else if (both)
02154 {
02155 end_page = 1;
02156 }
02157 else
02158 {
02159 end_page = doc_pages;
02160 }
02161 while (*p==' ')
02162 p += 1;
02163 if (both)
02164 {
02165 start_page = end_page;
02166 if (*p == '-')
02167 {
02168 p += 1;
02169 both = 0;
02170 continue;
02171 }
02172 }
02173 both = 1;
02174 while (*p==' ')
02175 p += 1;
02176 if (*p && *p != ',')
02177 G_THROW(ERR_MSG("DjVuToPS.bad_range")
02178 + GUTF8String("\t") + GUTF8String(p) );
02179 if (*p == ',')
02180 p += 1;
02181 if (! spec)
02182 G_THROW(ERR_MSG("DjVuToPS.bad_range")
02183 + GUTF8String("\t") + page_range );
02184 spec = 0;
02185 if (end_page < 0)
02186 end_page = 0;
02187 if (start_page < 0)
02188 start_page = 0;
02189 if (end_page > doc_pages)
02190 end_page = doc_pages;
02191 if (start_page > doc_pages)
02192 start_page = doc_pages;
02193 if (start_page <= end_page)
02194 for(int page_num=start_page; page_num<=end_page; page_num++)
02195 pages_todo.append(page_num-1);
02196 else
02197 for(int page_num=start_page; page_num>=end_page; page_num--)
02198 pages_todo.append(page_num-1);
02199 }
02200 }
02201
02202 class DjVuToPS::DecodePort : public DjVuPort
02203 {
02204 protected:
02205 DecodePort(void);
02206 public:
02207 static GP<DecodePort> create(void);
02208 GEvent decode_event;
02209 bool decode_event_received;
02210 double decode_done;
02211 GURL decode_page_url;
02212 virtual void notify_file_flags_changed(const DjVuFile*,long,long);
02213 virtual void notify_decode_progress(const DjVuPort*,double);
02214 };
02215
02216 DjVuToPS::DecodePort::
02217 DecodePort(void)
02218 : decode_event_received(false),
02219 decode_done((double)0)
02220 {
02221 }
02222
02223 GP<DjVuToPS::DecodePort>
02224 DjVuToPS::DecodePort::
02225 create(void)
02226 {
02227 return new DecodePort;
02228 }
02229
02230 void
02231 DjVuToPS::DecodePort::
02232 notify_file_flags_changed(const DjVuFile *source,
02233 long set_mask, long clr_mask)
02234 {
02235
02236 if (set_mask & (DjVuFile::DECODE_OK |
02237 DjVuFile::DECODE_FAILED |
02238 DjVuFile::DECODE_STOPPED ))
02239 {
02240 if (source->get_url() == decode_page_url)
02241 {
02242 decode_event_received=true;
02243 decode_event.set();
02244 }
02245 }
02246 }
02247
02248 void
02249 DjVuToPS::DecodePort::
02250 notify_decode_progress(const DjVuPort *source, double done)
02251 {
02252
02253 if (source->inherits("DjVuFile"))
02254 {
02255 DjVuFile * file=(DjVuFile *) source;
02256 if (file->get_url()==decode_page_url)
02257 if ((int) (decode_done*20)!=(int) (done*20))
02258 {
02259 decode_done=done;
02260 decode_event_received=true;
02261 decode_event.set();
02262 }
02263 }
02264 }
02265
02266 void
02267 DjVuToPS::
02268 set_refresh_cb(void (*_refresh_cb)(void*), void *_refresh_cl_data)
02269 {
02270 refresh_cb = _refresh_cb;
02271 refresh_cl_data = _refresh_cl_data;
02272 }
02273
02274 void
02275 DjVuToPS::
02276 set_prn_progress_cb(void (*_prn_progress_cb)(double, void *),
02277 void *_prn_progress_cl_data)
02278 {
02279 prn_progress_cb=_prn_progress_cb;
02280 prn_progress_cl_data=_prn_progress_cl_data;
02281 }
02282
02283 void
02284 DjVuToPS::
02285 set_dec_progress_cb(void (*_dec_progress_cb)(double, void *),
02286 void *_dec_progress_cl_data)
02287 {
02288 dec_progress_cb=_dec_progress_cb;
02289 dec_progress_cl_data=_dec_progress_cl_data;
02290 }
02291
02292 void
02293 DjVuToPS::
02294 set_info_cb(void (*_info_cb)(int, int, int, Stage, void*),
02295 void *_info_cl_data)
02296 {
02297 info_cb=_info_cb;
02298 info_cl_data=_info_cl_data;
02299 }
02300
02301 GP<DjVuImage>
02302 DjVuToPS::
02303 decode_page(GP<DjVuDocument> doc,
02304 int page_num, int cnt, int todo)
02305 {
02306 DEBUG_MSG("processing page #" << page_num << "\n");
02307 if (! port)
02308 {
02309 port = DecodePort::create();
02310 DjVuPort::get_portcaster()->add_route((DjVuDocument*)doc, port);
02311 }
02312 port->decode_event_received = false;
02313 port->decode_done = 0;
02314 GP<DjVuFile> djvu_file;
02315 GP<DjVuImage> dimg;
02316 if (page_num >= 0 && page_num < doc->get_pages_num())
02317 djvu_file = doc->get_djvu_file(page_num);
02318 if (! djvu_file )
02319 return 0;
02320 if (djvu_file->is_decode_ok())
02321 return doc->get_page(page_num, false);
02322
02323
02324
02325
02326 if (info_cb)
02327 info_cb(page_num, cnt, todo, DECODING, info_cl_data);
02328
02329
02330 dimg = doc->get_page(page_num, false);
02331 djvu_file = dimg->get_djvu_file();
02332 port->decode_page_url = djvu_file->get_url();
02333 if (djvu_file->is_decode_ok())
02334 return dimg;
02335 DEBUG_MSG("decoding\n");
02336 if (dec_progress_cb)
02337 dec_progress_cb(0, dec_progress_cl_data);
02338 while(! djvu_file->is_decode_ok())
02339 {
02340 while(!port->decode_event_received &&
02341 !djvu_file->is_decode_ok())
02342 {
02343 port->decode_event.wait(250);
02344 if (refresh_cb)
02345 refresh_cb(refresh_cl_data);
02346 }
02347 port->decode_event_received = false;
02348 if (djvu_file->is_decode_failed() ||
02349 djvu_file->is_decode_stopped())
02350 G_THROW(ERR_MSG("DjVuToPS.no_image")
02351 + GUTF8String("\t")
02352 + GUTF8String(page_num));
02353 if (dec_progress_cb)
02354 dec_progress_cb(port->decode_done, dec_progress_cl_data);
02355 }
02356 if (dec_progress_cb)
02357 dec_progress_cb(1, dec_progress_cl_data);
02358 return dimg;
02359 }
02360
02361 void
02362 DjVuToPS::
02363 process_single_page(ByteStream &str,
02364 GP<DjVuDocument> doc,
02365 int page_num, int cnt, int todo,
02366 int magic)
02367 {
02368 GP<DjVuTXT> txt;
02369 GP<DjVuImage> dimg;
02370 dimg = decode_page(doc, page_num, cnt, todo);
02371 if (options.get_text())
02372 txt = get_text(dimg->get_djvu_file());
02373 if (info_cb)
02374 info_cb(page_num, cnt, todo, PRINTING, info_cl_data);
02375 if (!magic)
02376 write(str, "%%%%Page: %d %d\n", page_num+1, cnt+1);
02377 if (dimg)
02378 {
02379 int dpi = dimg->get_dpi();
02380 dpi = ((dpi <= 0) ? 300 : dpi);
02381 GRect img_rect(0, 0, dimg->get_width(), dimg->get_height());
02382 store_page_setup(str, dpi, img_rect, magic);
02383 print_image(str, dimg, img_rect,txt);
02384 store_page_trailer(str);
02385 }
02386 if (!magic)
02387 write(str,"showpage\n");
02388 }
02389
02390
02391 struct pdata {
02392 int page1, page2;
02393 int smax, spos;
02394 int offset;
02395 };
02396
02397 void
02398 DjVuToPS::
02399 process_double_page(ByteStream &str,
02400 GP<DjVuDocument> doc,
02401 void *v, int cnt, int todo)
02402 {
02403 const pdata *inf = (const pdata*)v;
02404 int off = abs(inf->offset);
02405 write(str,
02406 "%%%%Page: (%d,%d) %d\n"
02407 "gsave\n"
02408 "/fold-dict 8 dict dup 3 1 roll def begin\n"
02409 " clippath pathbbox newpath pop pop translate\n"
02410 " clippath pathbbox newpath 4 2 roll pop pop\n"
02411 " /ph exch def\n"
02412 " /pw exch def\n"
02413 " /w ph %d sub 2 div def\n"
02414 " /m1 %d def\n"
02415 " /m2 %d def\n"
02416 "end\n",
02417 inf->page1 + 1, inf->page2 + 1, cnt,
02418 2 * (off + options.get_bookletfold(inf->smax-1)),
02419 inf->offset + options.get_bookletfold(inf->spos),
02420 inf->offset - options.get_bookletfold(inf->spos));
02421 if (options.get_cropmarks())
02422 write(str,
02423 "%% -- folding marks\n"
02424 "fold-dict begin\n"
02425 " 0 setgray 0.5 setlinewidth\n"
02426 " ph m1 m2 add add 2 div dup\n"
02427 " 0 exch moveto 36 0 rlineto stroke\n"
02428 " pw exch moveto -36 0 rlineto stroke\n"
02429 "end\n");
02430 write(str,
02431 "%% -- first page\n"
02432 "gsave fold-dict begin\n"
02433 " 0 ph 2 div w add m1 add translate 270 rotate\n"
02434 " 0 0 w pw rectclip end\n");
02435 if (inf->page1 >= 0)
02436 process_single_page(str, doc, inf->page1, cnt*2, todo*2, +1);
02437 write(str,
02438 "grestore\n"
02439 "%% -- second page\n"
02440 "gsave fold-dict begin\n"
02441 " 0 ph 2 div m2 add translate 270 rotate\n"
02442 " 0 0 w pw rectclip end\n");
02443 if (inf->page2 >= 0)
02444 process_single_page(str, doc, inf->page2, cnt*2+1, todo*2, -1);
02445 write(str,
02446 "grestore\n"
02447 "grestore\n"
02448 "showpage\n");
02449 }
02450
02451 static void
02452 booklet_order(GList<int>& pages, int smax)
02453 {
02454
02455 while (pages.size() & 0x3)
02456 pages.append(-1);
02457
02458 int i = 0;
02459 int n = pages.size();
02460 GTArray<int> p(0,n-1);
02461 for (GPosition pos=pages; pos; ++pos)
02462 p[i++] = pages[pos];
02463
02464 pages.empty();
02465 for (i=0; i<n; i+=smax)
02466 {
02467 int lo = i;
02468 int hi = i+smax-1;
02469 if (hi >= n)
02470 hi = n-1;
02471 while (lo < hi)
02472 {
02473 pages.append(p[hi--]);
02474 pages.append(p[lo++]);
02475 pages.append(p[lo++]);
02476 pages.append(p[hi--]);
02477 }
02478 }
02479 }
02480
02481
02482
02483
02484
02485
02486
02487
02488 void
02489 DjVuToPS::
02490 print(ByteStream &str,
02491 GP<DjVuDocument> doc,
02492 GUTF8String page_range)
02493 {
02494 DEBUG_MSG("DjVuToPS::print(): Printing DjVu document\n");
02495 DEBUG_MAKE_INDENT(3);
02496
02497 GList<int> pages_todo;
02498 parse_range(doc, page_range, pages_todo);
02499 int todo = pages_todo.size();
02500 if (options.get_format()==Options::EPS)
02501 {
02502
02503 if (todo != 1)
02504 G_THROW(ERR_MSG("DjVuToPS.only_one_page"));
02505 GPosition pos = pages_todo;
02506 int page_num = pages_todo[pos];
02507 GP<DjVuImage> dimg = decode_page(doc,page_num,0,todo);
02508 if (! dimg)
02509 G_THROW(ERR_MSG("DjVuToPS.no_image") + GUTF8String("\t1"));
02510 GRect bbox(0, 0, dimg->get_width(), dimg->get_height());
02511 store_doc_prolog(str, 1, dimg->get_dpi(), &bbox);
02512 store_doc_setup(str);
02513 process_single_page(str, doc, page_num, 0, todo, 0);
02514 }
02515 else if (options.get_bookletmode()==Options::OFF)
02516 {
02517
02518 int cnt = 0;
02519 store_doc_prolog(str, todo, 0, 0);
02520 store_doc_setup(str);
02521 for(GPosition pos = pages_todo; pos; ++pos)
02522 process_single_page(str,doc,pages_todo[pos],cnt++,todo,0);
02523 store_doc_trailer(str);
02524 }
02525 else
02526 {
02527
02528 int sheets_left = (todo+3)/4;
02529 int sides_todo = sheets_left;
02530 if (options.get_bookletmode() == Options::RECTOVERSO)
02531 sides_todo *= 2;
02532 int sheets_max = (options.get_bookletmax()+3)/4;
02533 if (! sheets_max)
02534 sheets_max = sheets_left;
02535
02536 booklet_order(pages_todo, sheets_max*4);
02537
02538 int sides = 0;
02539 int sheetpos = sheets_max;
02540 store_doc_prolog(str, sides_todo, 0, 0);
02541 store_doc_setup(str);
02542 for (GPosition p=pages_todo; p; ++p)
02543 {
02544 struct pdata inf;
02545 inf.page1 = pages_todo[p];
02546 inf.page2 = pages_todo[++p];
02547 inf.smax = sheets_max;
02548 inf.spos = --sheetpos;
02549 inf.offset = options.get_bookletalign();
02550 if (options.get_bookletmode() != Options::VERSO)
02551 process_double_page(str,doc,(void*)&inf,sides++,sides_todo);
02552 inf.page1 = pages_todo[++p];
02553 inf.page2 = pages_todo[++p];
02554 inf.offset = -inf.offset;
02555 if (options.get_bookletmode() != Options::RECTO)
02556 process_double_page(str,doc,(void*)&inf,sides++,sides_todo);
02557 sheets_left -= 1;
02558 if (sheetpos <= 0)
02559 sheetpos = ((sheets_max<sheets_left) ? sheets_max : sheets_left);
02560 }
02561 store_doc_trailer(str);
02562 }
02563 }
02564
02565
02566 void
02567 DjVuToPS::
02568 print(ByteStream &str, GP<DjVuDocument> doc)
02569 {
02570 GUTF8String dummy;
02571 print(str,doc,dummy);
02572 }
02573
02574
02575
02576 #ifdef HAVE_NAMESPACES
02577 }
02578 # ifndef NOT_USING_DJVU_NAMESPACE
02579 using namespace DJVU;
02580 # endif
02581 #endif
02582