• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kviewshell

DjVuToPS.cpp

Go to the documentation of this file.
00001 //C-  -*- C++ -*-
00002 //C- -------------------------------------------------------------------
00003 //C- DjVuLibre-3.5
00004 //C- Copyright (c) 2002-2003  Leon Bottou and Yann Le Cun.
00005 //C- Copyright (c) 2001  AT&T
00006 //C-
00007 //C- This software is subject to, and may be distributed under, the
00008 //C- GNU General Public License, Version 2. The license should have
00009 //C- accompanied the software or you may obtain a copy of the license
00010 //C- from the Free Software Foundation at http://www.fsf.org .
00011 //C-
00012 //C- This program is distributed in the hope that it will be useful,
00013 //C- but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //C- GNU General Public License for more details.
00016 //C- 
00017 //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library
00018 //C- distributed by Lizardtech Software.  On July 19th 2002, Lizardtech 
00019 //C- Software authorized us to replace the original DjVu(r) Reference 
00020 //C- Library notice by the following text (see doc/lizard2002.djvu):
00021 //C-
00022 //C-  ------------------------------------------------------------------
00023 //C- | DjVu (r) Reference Library (v. 3.5)
00024 //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
00025 //C- | The DjVu Reference Library is protected by U.S. Pat. No.
00026 //C- | 6,058,214 and patents pending.
00027 //C- |
00028 //C- | This software is subject to, and may be distributed under, the
00029 //C- | GNU General Public License, Version 2. The license should have
00030 //C- | accompanied the software or you may obtain a copy of the license
00031 //C- | from the Free Software Foundation at http://www.fsf.org .
00032 //C- |
00033 //C- | The computer code originally released by LizardTech under this
00034 //C- | license and unmodified by other parties is deemed "the LIZARDTECH
00035 //C- | ORIGINAL CODE."  Subject to any third party intellectual property
00036 //C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
00037 //C- | non-exclusive license to make, use, sell, or otherwise dispose of 
00038 //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
00039 //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
00040 //C- | General Public License.   This grant only confers the right to 
00041 //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
00042 //C- | the extent such infringement is reasonably necessary to enable 
00043 //C- | recipient to make, have made, practice, sell, or otherwise dispose 
00044 //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
00045 //C- | any greater extent that may be necessary to utilize further 
00046 //C- | modifications or combinations.
00047 //C- |
00048 //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
00049 //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
00050 //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
00051 //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00052 //C- +------------------------------------------------------------------
00053 // 
00054 // $Id: DjVuToPS.cpp,v 1.23 2003/11/07 22:08:21 leonb Exp $
00055 // $Name: release_3_5_15 $
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 // ****************************** Options ************************************
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 // ******************************* DjVuToPS **********************************
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   // Creating tables for bin=>text translation
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   /* Will output the formated string to the specified \Ref{ByteStream}
00297      like #fprintf# would do it for a #FILE#. */
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 // ************************* DOCUMENT LEVEL *********************************
00306 
00307 void
00308 DjVuToPS::
00309 store_doc_prolog(ByteStream &str, int pages, int dpi, GRect *grect)
00310 {
00311   /* Will store the {\em document prolog}, which is basically a
00312      block of document-level comments in PS DSC 3.0 format.
00313      @param str Stream where PostScript data should be written
00314      @param pages Total number of pages
00315      @param dpi (EPS mode only) 
00316      @param grect (EPS mode only) */
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   // Date
00333   time_t tm=time(0);
00334   write(str, "%%%%CreationDate: %s", ctime(&tm));
00335   // For
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   // Language
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   // Pages
00357   write(str, "%%%%Pages: %d\n",pages );
00358   write(str, "%%%%PageOrder: Ascend\n");
00359   // Orientation
00360   if (options.get_orientation() != Options::AUTO)
00361     write(str, "%%%%Orientation: %s\n", 
00362           options.get_orientation()==Options::PORTRAIT ?
00363           "Portrait" : "Landscape" );
00364   // Requirements
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   // End
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   /* Will store the {\em document setup}, which is a set of
00393      PostScript commands and functions used to inspect and prepare
00394      the PostScript interpreter environment before displaying images. */
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       // level<2
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     } // level<2
00540   write(str, "%%%%EndSetup\n\n");
00541 }
00542 
00543 void
00544 DjVuToPS::
00545 store_doc_trailer(ByteStream &str)
00546 {
00547   /* Will store the {\em document trailer}, which is a clean-up code
00548      used to return the PostScript interpeter back to the state, in which
00549      it was before displaying this document. */
00550   write(str, 
00551         "%%%%Trailer\n"
00552         "doc-origstate restore\n"
00553         "%%%%EOF\n");
00554 }
00555 
00556 // ***********************************************************************
00557 // ***************************** PAGE LEVEL ******************************
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   /* Will read data between #src_start# and #src_end# pointers (excluding byte
00566      pointed by #src_end#), encode it using {\bf ASCII85} algorithm, and
00567      output the result into the destination buffer pointed by #dst#.  The
00568      function returns pointer to the first unused byte in the destination
00569      buffer. */
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   /* Will read data between #src_start# and #src_end# pointers (excluding byte
00620      pointed by #src_end#), RLE encode it, and output the result into the
00621      destination buffer pointed by #dst#.  #counter# is used to count the
00622      number of output bytes.  The function returns pointer to the first unused
00623      byte in the destination buffer. */
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           // Guess how many non repeating bytes we have
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           // Get the number of repeating bytes
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   /* Will store PostScript code necessary to prepare page for
00668      the coming \Ref{DjVuImage}. This is basically a scaling
00669      code plus initialization of some buffers. */
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   // Access image size
00836   int width = dimg->get_width();
00837   int height = dimg->get_height();
00838   if (width<=0 || height<=0) return 0;
00839   // CASE1: Incremental BG IW44Image
00840   GP<IW44Image> bg44 = dimg->get_bg44();
00841   if (bg44)
00842     {
00843       int w = bg44->get_width();
00844       int h = bg44->get_height();
00845       // Avoid silly cases
00846       if (w==0 || h==0 || width==0 || height==0)
00847         return 0;
00848       return compute_red(width,height,w,h);
00849     }
00850   // CASE 2: Raw background pixmap
00851   GP<GPixmap>  bgpm = dimg->get_bgpm();
00852   if (bgpm)
00853     {
00854       int w = bgpm->columns();
00855       int h = bgpm->rows();
00856       // Avoid silly cases
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   // Access image size
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   // CASE1: Incremental BG IW44Image
00874   GP<IW44Image> bg44 = dimg->get_bg44();
00875   if (bg44)
00876     {
00877       int w = bg44->get_width();
00878       int h = bg44->get_height();
00879       // Avoid silly cases
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   // CASE 2: Raw background pixmap
00886   GP<GPixmap>  bgpm = dimg->get_bgpm();
00887   if (bgpm)
00888     {
00889       int w = bgpm->columns();
00890       int h = bgpm->rows();
00891       // Avoid silly cases
00892       if (w==0 || h==0 || width==0 || height==0)
00893         return 0;
00894       pm->init(*bgpm, rect);
00895       return pm;
00896     }
00897   // FAILURE
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   // Pure-jb2 or color-jb2 case.
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             // Find first intersecting blit
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             // Setup pattern
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             // Keep performing blits
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       // Cleanup
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       // Define font
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)   //max string length
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   // Print the foreground layer
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   // Display image
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     // Start storing image in bands
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         // Compute next band
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                     // Doing R component of current chunk
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                     // Doing G component of current chunk
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                     // Doing B component of current chunk
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                   } //while (y>=0)
01395               } 
01396             else
01397               {
01398                 // Don't use color
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           } // if (pm)
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       } // while(grectBand.yax<grect.ymax)
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   //restore the scaling
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   // Display image
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       // Start storing image in bands
01519       GRect grectBand = prn_rect;
01520       grectBand.ymax = grectBand.ymin;
01521       while(grectBand.ymax < prn_rect.ymax)
01522         {
01523           // Compute next band
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           // Store next band
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   // Display image
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       // Start storing image in bands
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           // Compute next band
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           // Store next band
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                   // Doing R component of current chunk
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                   // Doing G component of current chunk
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                   // Doing B component of current chunk
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                 } //while (y>=0)
01785             } 
01786           else if (pm)
01787             {
01788               // Don't use color
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; // Add EOF marker
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   // Get separator
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   // Zone children
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   /* Just outputs the specified image. The function assumes, that
02003      all add-ons (like {\em document setup}, {\em page setup}) are
02004      already there. It will just output the image. Since
02005      output of this function will generate PostScript errors when
02006      used without output of auxiliary functions, it should be
02007      used carefully. */
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   // Compute information for chosen display mode
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 // ******* PUBLIC FUNCTION FOR PRINTING A SINGLE PAGE ********************
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 // *************************** DOCUMENT LEVEL ****************************
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   // WARNING! This function is called from another thread
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   // WARNING! This function is called from another thread
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   // This is the best place to call info_cb(). Note, that
02323   // get_page() will start decoding if necessary, and will not
02324   // return until the decoding is over in a single threaded
02325   // environment. That's why we call get_djvu_file() first.
02326   if (info_cb)
02327     info_cb(page_num, cnt, todo, DECODING, info_cl_data);
02328   // Do NOT decode the page synchronously here!!!
02329   // The plugin will deadlock otherwise.
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   // -- make a multiple of four
02455   while (pages.size() & 0x3)
02456     pages.append(-1);
02457   // -- copy to array
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   // -- rebuild
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 // ******* PUBLIC FUNCTIONS FOR PRINTING MULTIPLE PAGES ******************
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   // Get page range
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       /* Encapsulated Postscript mode */
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       /* Normal mode */
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       /* Booklet mode */
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       // -- reorder pages
02536       booklet_order(pages_todo, sheets_max*4);
02537       // -- print
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 

kviewshell

Skip menu "kviewshell"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • kviewshell
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal