home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / c / xv221src / xvps.c < prev    next >
C/C++ Source or Header  |  1992-04-11  |  41KB  |  1,402 lines

  1. /* 
  2.  * xvps.c - Postscript dialog box, file output functions
  3.  *
  4.  * callable functions:
  5.  *
  6.  *   CreatePSD(geom)           -  creates the psW window.  Doesn't map it.
  7.  *   PSDialog()                -  maps psW
  8.  *   PSCheckEvent(event)       -  called by event handler
  9.  *   PSSaveParams(str,int)     -  tells PSDialog what to do when 'Ok' clicked
  10.  *   PSResize()                -  called whenever ePic changes size
  11.  */
  12.  
  13. /*
  14.  * Copyright 1989, 1990, 1991, 1992 by John Bradley and
  15.  *                       The University of Pennsylvania
  16.  *
  17.  * Permission to use, copy, and distribute for non-commercial purposes,
  18.  * is hereby granted without fee, providing that the above copyright
  19.  * notice appear in all copies and that both the copyright notice and this
  20.  * permission notice appear in supporting documentation.
  21.  *
  22.  * The software may be modified for your own purposes, but modified versions
  23.  * may not be distributed.
  24.  *
  25.  * This software is provided "as is" without any expressed or implied warranty.
  26.  *
  27.  * The author may be contacted via:
  28.  *    US Mail:   John Bradley
  29.  *               GRASP Lab, Room 301C
  30.  *               3401 Walnut St.
  31.  *               Philadelphia, PA  19104
  32.  *
  33.  *    Phone:     (215) 898-8813
  34.  *    EMail:     bradley@cis.upenn.edu
  35.  */
  36.  
  37.  
  38. #include "xv.h"
  39.  
  40. #define PSWIDE 431
  41. #define PSHIGH 350
  42. #define PMAX   200    /* size of square that a 'page' has to fit into */
  43.  
  44. #define PS_NBUTTS 6
  45. #define PS_BOK    0
  46. #define PS_BCANC  1
  47. #define PS_BCENT  2
  48. #define PS_BMAX   3
  49. #define PS_BPOSX  4
  50. #define PS_BPOSY  5
  51.  
  52. /* paperRB indicies */
  53. #define PSZ_NORM  0
  54. #define PSZ_A4    1
  55. #define PSZ_B5    2
  56. #define PSZ_LEGAL 3
  57. #define PSZ_BSIZE 4
  58. #define PSZ_4BY5  5
  59. #define PSZ_35MM  6
  60.  
  61. /* orientRB indicies */
  62. #define ORNT_PORT 0
  63. #define ORNT_LAND 1
  64.  
  65. #define BUTTH 24
  66.  
  67. #define IN2CM 2.54
  68.  
  69. #define PIX2INCH 72.0   /* # of pixels per inch, at 100% scaling */
  70.  
  71. #ifdef __STDC__
  72. static void drawPSD(int, int, int, int);
  73. static void drawPosStr();
  74. static void drawSizeStr();
  75. static void drawResStr();
  76. static void drawPage();
  77. static void clickPSD(int, int);
  78. static void clickPage(int, int);
  79. static void doCmd(int);
  80. static void changedScale(void);
  81. static void setScale(void);
  82. static void changedPaper(void);
  83. static void setPaper(void);
  84. static void drawIRect(int);
  85. static void centerImage(void);
  86. static void maxImage(void);
  87. static void moveImage(double, double);
  88. static void writePS(void);
  89. static int  rle_encode(byte *, byte *, int);
  90. static void psColorImage();
  91. static void psColorMap(FILE *fp, int, int, byte *, byte *, byte *);
  92. static void psRleCmapImage();
  93. static void epsPreview();
  94. static int  writeBWStip(FILE *, byte *, char *, int, int);
  95. #else
  96. static void drawPSD(), drawPosStr(), drawSizeStr(), drawResStr();
  97. static void drawPage(), clickPSD(), clickPage(), doCmd(), changedScale();
  98. static void setScale(), changedPaper(), setPaper(), drawIRect();
  99. static void centerImage(), maxImage(), moveImage(), writePS();
  100. static void psColorImage(), psColorMap(), epsPreview();
  101. static void psRleCmapImage();
  102. static int  rle_encode(), writeBWStip();
  103. #endif
  104.  
  105.  
  106. /* local variables */
  107. static Window pageF;
  108. static DIAL   xsDial, ysDial;
  109. static RBUTT *orientRB, *paperRB;
  110. static CBUTT  lockCB;
  111. static BUTT   psbut[PS_NBUTTS];
  112. static double sz_inx, sz_iny;     /* image size, in inches */
  113. static double pos_inx, pos_iny;   /* top-left offset of image, in inches */
  114. static int    dpix, dpiy;         /* # of image pixels per inch */
  115. static int    tracking=0;         /* used in changedScale */
  116. static int    posxType, posyType;
  117.  
  118. /* sizes of pages in inches */
  119. static double paperSize[7][2] = { { 8.500, 11.000},   /* US NORMAL */
  120.                   { 8.267, 11.811},   /* A4 */
  121.                   { 7.283, 10.630},   /* B5 */
  122.                   { 8.500, 14.000},   /* US LEGAL */
  123.                   {11.000, 17.000},   /* B-size */
  124.                   { 3.875,  4.875},   /* 4 by 5 */
  125.                   { 0.945,  1.417}};  /* 35mm (24x36) */
  126.  
  127. /* size of l+r margin and t+b margin.  image is centered */
  128. static double margins[7][2] = { { 1.000, 1.000},   /* US NORMAL */
  129.                 { 1.000, 1.000},   /* A4 */
  130.                 { 1.000, 1.000},   /* B5 */
  131.                 { 1.000, 1.000},   /* US LEGAL */
  132.                 { 1.000, 1.000},   /* B-size */
  133.                 { 0.275, 0.275},   /* 4 by 5 */
  134.                 { 0.078, 0.078}};  /* 35mm (24x36) */
  135.  
  136.  
  137. static double psizex, psizey;   /* current paper size, in inches */
  138. static double in2pix;           /* inch to pixels in 'pageF' */
  139. static XRectangle pageRect;     /* bounding rect of page, in screen coords */
  140.  
  141. static char *filename;          /* filename to save to */
  142. static int   colorType;         /* value of 'Colors' rbutt in dir box */
  143. static int   firsttime=1;       /* first time PSDialog being opened ? */
  144.  
  145.  
  146. /***************************************************/
  147. void CreatePSD(geom)
  148. char *geom;
  149. {
  150.   psW = CreateWindow("xv postscript", geom, PSWIDE, PSHIGH, infofg, infobg);
  151.   if (!psW) FatalError("can't create postscript window!");
  152.   StoreDeleteWindowProp(psW);
  153.   
  154.   pageF = XCreateSimpleWindow(theDisp, psW, 20,30, PMAX+1,PMAX+1,
  155.                   1,infofg,infobg);
  156.   if (!pageF) FatalError("couldn't create frame windows");
  157.  
  158.   XSetWindowBackgroundPixmap(theDisp, pageF, grayTile);
  159.  
  160.   XSelectInput(theDisp, pageF, ExposureMask | ButtonPressMask);
  161.   XSelectInput(theDisp, psW,   ExposureMask | ButtonPressMask | KeyPressMask);
  162.  
  163.   CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg);
  164.   CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg);
  165.  
  166.   DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5, 
  167.       infofg, infobg, "Width", "%");
  168.   DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5, 
  169.       infofg, infobg, "Height", "%");
  170.   xsDial.drawobj = changedScale;
  171.   ysDial.drawobj = changedScale;
  172.  
  173.   CBCreate(&lockCB, psW, 319, 136, "", infofg, infobg);
  174.   lockCB.val = 1;
  175.  
  176.   orientRB = RBCreate(NULL, psW, 36, 240+18, "Portrait", infofg, infobg);
  177.   RBCreate(orientRB, psW, 36+80, 240+18, "Landscape", infofg, infobg);
  178.  
  179.   paperRB = RBCreate(NULL, psW,36, 240+18+36, "8.5\"x11\"", infofg, infobg);
  180.   RBCreate(paperRB, psW, 36+80,    240+18+36, "A4",         infofg, infobg);
  181.   RBCreate(paperRB, psW, 36+154,   240+18+36, "B5",         infofg, infobg);
  182.   RBCreate(paperRB, psW, 36,       240+36+36, "8.5\"x14\"", infofg, infobg);
  183.   RBCreate(paperRB, psW, 36+80,    240+36+36, "11\"x17\"",  infofg, infobg);
  184.   RBCreate(paperRB, psW, 36,       240+54+36, "4\"x5\"",    infofg, infobg);
  185.   RBCreate(paperRB, psW, 36+80,    240+54+36, "35mm slide", infofg, infobg);
  186.  
  187.   BTCreate(&psbut[PS_BOK], psW, PSWIDE-160, PSHIGH-10-BUTTH, 60, BUTTH, 
  188.        "Ok", infofg, infobg);
  189.  
  190.   BTCreate(&psbut[PS_BCANC], psW, PSWIDE-80, PSHIGH-10-BUTTH, 60, BUTTH, 
  191.        "Cancel", infofg, infobg);
  192.  
  193.   BTCreate(&psbut[PS_BCENT], psW, 240, 153, 88, BUTTH, 
  194.        "Center", infofg, infobg);
  195.  
  196.   BTCreate(&psbut[PS_BMAX], psW, 240+88+5, 153, 87, BUTTH, 
  197.        "Maxpect", infofg, infobg);
  198.  
  199.   BTCreate(&psbut[PS_BPOSX], psW, 256-14, 190+13-8, 8,8, "", infofg, infobg);
  200.   BTCreate(&psbut[PS_BPOSY], psW, 256-14, 190+26-8, 8,8, "", infofg, infobg);
  201.  
  202.   posxType = posyType = 0;
  203.   pos_inx = 1.0;  pos_iny = 1.0;   /* temporary bootstrapping... */
  204.   setPaper();
  205.   setScale();
  206.  
  207.   XMapSubwindows(theDisp, psW);
  208. }
  209.   
  210.  
  211. /***************************************************/
  212. void PSDialog(vis)
  213. int vis;
  214. {
  215.   if (vis) {
  216.     setScale();
  217.     if (firsttime) centerImage();
  218.     firsttime = 0;
  219.     CenterMapWindow(psW, psbut[PS_BOK].x + psbut[PS_BOK].w/2,
  220.             psbut[PS_BOK].y + psbut[PS_BOK].h/2, PSWIDE, PSHIGH);
  221.   }
  222.   else     XUnmapWindow(theDisp, psW);
  223.   psUp = vis;
  224. }
  225.  
  226.  
  227. /***************************************************/
  228. int PSCheckEvent(xev)
  229. XEvent *xev;
  230. {
  231.   /* check event to see if it's for one of our subwindows.  If it is,
  232.      deal accordingly, and return '1'.  Otherwise, return '0' */
  233.  
  234.   int rv;
  235.   rv = 1;
  236.  
  237.   if (!psUp) return 0;
  238.  
  239.   if (xev->type == Expose) {
  240.     int x,y,w,h;
  241.     XExposeEvent *e = (XExposeEvent *) xev;
  242.     x = e->x;  y = e->y;  w = e->width;  h = e->height;
  243.  
  244.     /* throw away excess expose events for 'dumb' windows */
  245.     if (e->count > 0 && 
  246.     (e->window == xsDial.win || e->window == ysDial.win ||
  247.      e->window == pageF)) {}
  248.  
  249.     else if (e->window == psW)         drawPSD(x, y, w, h);
  250.     else if (e->window == xsDial.win)  DRedraw(&xsDial);
  251.     else if (e->window == ysDial.win)  DRedraw(&ysDial);
  252.     else if (e->window == pageF)       drawPage();
  253.     else rv = 0;
  254.   }
  255.  
  256.   else if (xev->type == ButtonPress) {
  257.     XButtonEvent *e = (XButtonEvent *) xev;
  258.     int x,y;
  259.     x = e->x;  y = e->y;
  260.  
  261.     if (e->button == Button1) {
  262.       if      (e->window == psW)   clickPSD(x,y);
  263.       else if (e->window == pageF) clickPage(x,y);
  264.  
  265.       else if (e->window == xsDial.win || e->window == ysDial.win) {
  266.     if (e->window == xsDial.win) {
  267.       tracking = 1;
  268.       DTrack(&xsDial, x,y);
  269.       tracking = 0;
  270.     }
  271.  
  272.     else if (e->window == ysDial.win) {
  273.       tracking = 2;
  274.       DTrack(&ysDial, x,y);
  275.       tracking = 0;
  276.     }
  277.       }
  278.       else rv = 0;
  279.     }  /* button1 */
  280.     else rv = 0;
  281.   }  /* button press */
  282.  
  283.  
  284.   else if (xev->type == KeyPress) {
  285.     XKeyEvent *e = (XKeyEvent *) xev;
  286.     char buf[128];  KeySym ks;
  287.     int stlen;
  288.     
  289.     stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
  290.     buf[stlen] = '\0';
  291.  
  292.     if (e->window == psW) {
  293.       double dx, dy;
  294.       int movekey;
  295.  
  296.       movekey = 0;  dx = dy = 0.0;
  297.  
  298.       if      (ks==XK_Left  || ks==XK_KP_4) { dx = -0.001;  movekey = 1; }
  299.       else if (ks==XK_Right || ks==XK_KP_6) { dx =  0.001;  movekey = 1; }
  300.       else if (ks==XK_Up    || ks==XK_KP_8) { dy = -0.001;  movekey = 1; }
  301.       else if (ks==XK_Down  || ks==XK_KP_2) { dy =  0.001;  movekey = 1; }
  302.  
  303.       else if (stlen) {
  304.     if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
  305.       FakeButtonPress(&psbut[PS_BOK]);
  306.     }
  307.     else if (buf[0] == '\033') {            /* ESC */
  308.       FakeButtonPress(&psbut[PS_BCANC]);
  309.     }
  310.       }
  311.  
  312.       if (movekey) {
  313.     if (e->state & ShiftMask) { dx *= 10.0;  dy *= 10.0; }
  314.     moveImage(pos_inx+dx, pos_iny+dy);
  315.       }
  316.     }
  317.     else rv = 0;
  318.   }
  319.   else rv = 0;
  320.  
  321.   if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
  322.     XBell(theDisp, 50);
  323.     rv = 1;   /* eat it */
  324.   }
  325.  
  326.   return rv;
  327. }
  328.  
  329.  
  330. /***************************************************/
  331. void PSSaveParams(fname, col)
  332. char *fname;
  333. int col;
  334. {
  335.   filename = fname;
  336.   colorType = col;
  337. }
  338.  
  339.  
  340. /***************************************************/
  341. void PSResize()
  342. {
  343.   if (!savenormCB.val) changedScale();
  344. }
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351. /***************************************************/
  352. static void drawPSD(x,y,w,h)
  353. int x,y,w,h;
  354. {
  355.   char *title = "Save PostScript File...";
  356.   int  i,cx;
  357.   XRectangle xr;
  358.  
  359.   xr.x = x;  xr.y = y;  xr.width = w;  xr.height = h;
  360.   XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
  361.  
  362.   XSetForeground(theDisp, theGC, infofg);
  363.   XSetBackground(theDisp, theGC, infobg);
  364.  
  365.   RBRedraw(orientRB,-1);
  366.   RBRedraw(paperRB,-1);
  367.  
  368.   for (i=0; i<PS_NBUTTS; i++) BTRedraw(&psbut[i]);
  369.  
  370.   CBRedraw(&encapsCB);
  371.   if (colorType != F_BWDITHER) CBRedraw(&pscompCB);
  372.   CBRedraw(&lockCB);
  373.  
  374.   ULineString(psW, "Orientation", orientRB->x-16, orientRB->y-3-DESCENT);
  375.   ULineString(psW, "Paper Size",  paperRB->x-16,   paperRB->y-3-DESCENT);
  376.  
  377.   /* draw 'lock' arrows */
  378.   cx = 240 + 40;  /* center of xsDial */
  379.   XDrawLine(theDisp, psW, theGC, lockCB.x, lockCB.y+5,  cx+2, lockCB.y+5);
  380.   XDrawLine(theDisp, psW, theGC, cx+2, lockCB.y+5, cx+2, lockCB.y-2);
  381.  
  382.   XDrawLine(theDisp, psW, theGC, lockCB.x, lockCB.y+9,  cx-2, lockCB.y+9);
  383.   XDrawLine(theDisp, psW, theGC, cx-2, lockCB.y+9, cx-2, lockCB.y-2);
  384.  
  385.   XDrawLine(theDisp, psW, theGC, cx-2-3, lockCB.y-2+3, cx, lockCB.y-2-2);
  386.   XDrawLine(theDisp, psW, theGC, cx+2+3, lockCB.y-2+3, cx, lockCB.y-2-2);
  387.  
  388.   cx = 330 + 40;  /* center of ysDial */
  389.   XDrawLine(theDisp, psW, theGC, lockCB.x+15, lockCB.y+5,  cx-2, lockCB.y+5);
  390.   XDrawLine(theDisp, psW, theGC, cx-2, lockCB.y+5, cx-2, lockCB.y-2);
  391.  
  392.   XDrawLine(theDisp, psW, theGC, lockCB.x+15, lockCB.y+9,  cx+2, lockCB.y+9);
  393.   XDrawLine(theDisp, psW, theGC, cx+2, lockCB.y+9, cx+2, lockCB.y-2);
  394.  
  395.   XDrawLine(theDisp, psW, theGC, cx-2-3, lockCB.y-2+3, cx, lockCB.y-2-2);
  396.   XDrawLine(theDisp, psW, theGC, cx+2+3, lockCB.y-2+3, cx, lockCB.y-2-2);
  397.  
  398.   XDrawString(theDisp, psW, theGC, 10, 19, title, strlen(title));
  399.  
  400.   ULineString(psW, "Position:",   240, 190);
  401.   drawPosStr();
  402.   ULineString(psW, "Size:",       240, 190+45);
  403.   drawSizeStr();
  404.   ULineString(psW, "Resolution:", 240, 190+90);
  405.   drawResStr();
  406.  
  407.  
  408.   XSetClipMask(theDisp, theGC, None);
  409. }
  410.  
  411.  
  412. /***************************************************/
  413. static void drawPosStr()
  414. {
  415.   int x,y;
  416.   double cmx, cmy, inx, iny;
  417.   char   str[64], str1[64], *xst, *yst;
  418.  
  419.   x = 256;  y = 190 + 13;
  420.  
  421.   switch (posxType) {
  422.   case 0:  xst = "Left: ";  inx = pos_inx;                      break;
  423.   case 1:  xst = "Right:";  inx = psizex - (pos_inx + sz_inx);  break;
  424.   case 2:  xst = "X Mid:";  inx = pos_inx + sz_inx/2;           break;
  425.   }
  426.  
  427.   switch (posyType) {
  428.   case 0:  yst = "Top:  ";  iny = pos_iny;                      break;
  429.   case 1:  yst = "Bot:  ";  iny = psizey - (pos_iny + sz_iny);  break;
  430.   case 2:  yst = "Y Mid:";  iny = pos_iny + sz_iny/2;           break;
  431.   }
  432.  
  433.   cmx = inx * IN2CM;
  434.   cmy = iny * IN2CM;
  435.  
  436.   sprintf(str,  "%s %.3f\" (%.2fcm)       ", xst, inx, cmx);
  437.   sprintf(str1, "%s %.3f\" (%.2fcm)       ", yst, iny, cmy);
  438.  
  439.   XSetForeground(theDisp, theGC, infofg);
  440.   XSetBackground(theDisp, theGC, infobg);
  441.  
  442.   XSetFont(theDisp, theGC, monofont);
  443.   XDrawImageString(theDisp, psW, theGC, x, y,    str,  strlen(str));
  444.   XDrawImageString(theDisp, psW, theGC, x, y+13, str1, strlen(str1));
  445.   XSetFont(theDisp, theGC, mfont);
  446. }
  447.  
  448.   
  449. /***************************************************/
  450. static void drawSizeStr()
  451. {
  452.   int x,y;
  453.   double cmx, cmy;
  454.   char   str[64], str1[64];
  455.  
  456.   x = 256;  y = 190+13+45;
  457.  
  458.   cmx = sz_inx * IN2CM;
  459.   cmy = sz_iny * IN2CM;
  460.  
  461.   sprintf(str,  "%.3f\" x %.3f\"        ", sz_inx, sz_iny);
  462.   sprintf(str1, "%.2fcm x %.2fcm        ", cmx, cmy);
  463.  
  464.   XSetForeground(theDisp, theGC, infofg);
  465.   XSetBackground(theDisp, theGC, infobg);
  466.   XSetFont(theDisp, theGC, monofont);
  467.  
  468.   XDrawImageString(theDisp, psW, theGC, x, y,    str, strlen(str));
  469.   XDrawImageString(theDisp, psW, theGC, x, y+13, str1, strlen(str1));
  470.   XSetFont(theDisp, theGC, mfont);
  471. }
  472.  
  473.   
  474. /***************************************************/
  475. static void drawResStr()
  476. {
  477.   int x,y;
  478.   char   str[64];
  479.  
  480.   x = 256;  y = 190 + 13 + 90;
  481.  
  482.   sprintf(str,  "%ddpi x %ddpi        ", dpix, dpiy);
  483.  
  484.   XSetForeground(theDisp, theGC, infofg);
  485.   XSetBackground(theDisp, theGC, infobg);
  486.   XSetFont(theDisp, theGC, monofont);
  487.   XDrawImageString(theDisp, psW, theGC, x, y, str, strlen(str));
  488.   XSetFont(theDisp, theGC, mfont);
  489. }
  490.  
  491.   
  492.   
  493.   
  494. /***************************************************/
  495. static void drawPage()
  496. {
  497.   /* draw page */
  498.   XSetForeground(theDisp, theGC, infobg);
  499.   XFillRectangle(theDisp, pageF, theGC, pageRect.x+1, pageRect.y+1,
  500.          pageRect.width-1, pageRect.height-1);
  501.  
  502.   XSetForeground(theDisp, theGC, infofg);
  503.   XDrawRectangle(theDisp, pageF, theGC, pageRect.x, pageRect.y,
  504.          pageRect.width, pageRect.height);
  505.  
  506.   drawIRect(1);
  507. }
  508.  
  509.  
  510. /***************************************************/
  511. static void clickPSD(x,y)
  512. int x,y;
  513. {
  514.   int i;
  515.   BUTT *bp;
  516.  
  517.   /* check BUTTs */
  518.  
  519.   for (i=0; i<PS_NBUTTS; i++) {
  520.     bp = &psbut[i];
  521.     if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
  522.   }
  523.  
  524.   if (i<PS_NBUTTS) {  /* found one */
  525.     if (BTTrack(bp)) doCmd(i);
  526.   }
  527.  
  528.   /* check RBUTTs */
  529.  
  530.   else if ((i=RBClick(orientRB,x,y)) >= 0) {
  531.     if (RBTrack(orientRB, i)) changedPaper();
  532.   }
  533.  
  534.   else if ((i=RBClick(paperRB,x,y)) >= 0) {
  535.     if (RBTrack(paperRB, i)) changedPaper();
  536.   }
  537.  
  538.   /* check CBUTTs */
  539.  
  540.   else if (CBClick(&lockCB,x,y)) {
  541.     if (CBTrack(&lockCB) && lockCB.val) {  /* turned on lock */
  542.       DSetVal(&ysDial, xsDial.val);        /* copy xsDial.val to ysDial */
  543.       changedScale();
  544.     }
  545.   }
  546.  
  547.   else if (CBClick(&encapsCB,x,y)) CBTrack(&encapsCB);
  548.   else if (CBClick(&pscompCB,x,y)) CBTrack(&pscompCB);
  549. }
  550.  
  551.  
  552.  
  553. /***************************************************/
  554. static void clickPage(mx,my)
  555. int mx,my;
  556. {
  557.   Window       rW,cW;
  558.   int          rx,ry,x,y;
  559.   unsigned int mask;
  560.   double       offx, offy, newx, newy;
  561.  
  562.   /* compute offset (in inches) between 'drag point' and 
  563.      the top-left corner of the image */
  564.  
  565.   offx = ((mx - pageRect.x) / in2pix) - pos_inx;
  566.   offy = ((my - pageRect.y) / in2pix) - pos_iny;
  567.  
  568.   /* if clicked outside of image rectangle, ignore */
  569.   if (offx<0.0 || offy < 0.0 || offx>=sz_inx || offy >= sz_iny) return;
  570.  
  571.   while (1) {
  572.     if (XQueryPointer(theDisp,pageF,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
  573.       if (!(mask & Button1Mask)) break;    /* button released */
  574.  
  575.       /* compute new pos_inx, pos_iny based on x,y coords */
  576.       newx = ((x-pageRect.x) / in2pix) - offx;
  577.       newy = ((y-pageRect.y) / in2pix) - offy;
  578.  
  579.       moveImage(newx, newy);
  580.     }
  581.   }
  582. }
  583.  
  584.  
  585.  
  586. /***************************************************/
  587. static void doCmd(cmd)
  588. int cmd;
  589. {
  590.   switch (cmd) {
  591.   case PS_BOK:    writePS();    PSDialog(0);  break;
  592.  
  593.   case PS_BCANC:  PSDialog(0);  break;
  594.  
  595.   case PS_BCENT:  drawIRect(0);
  596.                   centerImage();
  597.                   drawIRect(1);
  598.                   drawPosStr();
  599.                   break;
  600.  
  601.   case PS_BMAX:   drawIRect(0);
  602.                   maxImage();
  603.                   drawIRect(1);
  604.                   drawPosStr();
  605.                   drawSizeStr();
  606.                   drawResStr();
  607.                   break;
  608.  
  609.   case PS_BPOSX:  posxType = (posxType + 1) % 3;
  610.                   drawPosStr();
  611.                   break;
  612.  
  613.   case PS_BPOSY:  posyType = (posyType + 1) % 3;
  614.                   drawPosStr();
  615.                   break;
  616.  
  617.   default:        break;
  618.   }
  619. }
  620.  
  621.  
  622. /***************************************************/
  623. static void changedScale()
  624. {
  625.   double oldx,oldy;
  626.  
  627.   drawIRect(0);
  628.  
  629.   if (lockCB.val) {
  630.     if      (tracking == 1) DSetVal(&ysDial, xsDial.val);
  631.     else if (tracking == 2) DSetVal(&xsDial, ysDial.val);
  632.   }
  633.  
  634.   oldx = pos_inx;  oldy = pos_iny;
  635.   setScale();
  636.  
  637.   drawIRect(1);
  638.  
  639.   if (pos_inx != oldx || pos_iny != oldy ||
  640.       posxType != 0 || posyType != 0) drawPosStr();
  641.   drawSizeStr();
  642.   drawResStr();
  643.   XFlush(theDisp);
  644. }
  645.  
  646.  
  647. /***************************************************/
  648. static void setScale()
  649. {
  650.   double hsx, hsy;
  651.  
  652.   int w,h;
  653.  
  654.   if (savenormCB.val) { w = cWIDE;  h = cHIGH; }
  655.                  else { w = eWIDE;  h = eHIGH; }
  656.  
  657.   sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);  
  658.   sz_iny = (double) h / PIX2INCH * (ysDial.val / 100.0);  
  659.  
  660.   /* round to integer .001ths of an inch */
  661.   sz_inx = floor(sz_inx * 1000.0 + 0.5) / 1000.0;
  662.   sz_iny = floor(sz_iny * 1000.0 + 0.5) / 1000.0;
  663.  
  664.   dpix = (int) (PIX2INCH / (xsDial.val / 100.0));  
  665.   dpiy = (int) (PIX2INCH / (ysDial.val / 100.0));  
  666.  
  667.   /* make sure 'center' of image is still on page */
  668.   hsx = sz_inx/2;  hsy = sz_iny/2;
  669.   RANGE(pos_inx, -hsx, psizex-hsx);
  670.   RANGE(pos_iny, -hsy, psizey-hsy);
  671.  
  672.   /* round to integer .001ths of an inch */
  673.   pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
  674.   pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
  675.  
  676. }
  677.  
  678.  
  679. /***************************************************/
  680. static void changedPaper()
  681. {
  682.   setPaper();
  683.   XClearWindow(theDisp, pageF);
  684.   centerImage();
  685.   drawPosStr();
  686.   drawPage();
  687. }
  688.  
  689.  
  690. /***************************************************/
  691. static void setPaper()
  692. {
  693.   double tmp;
  694.  
  695.   psizex = paperSize[RBWhich(paperRB)][0];
  696.   psizey = paperSize[RBWhich(paperRB)][1];
  697.  
  698.   in2pix = (double) PMAX / psizey;
  699.  
  700.   if (RBWhich(orientRB)==ORNT_LAND) {
  701.     tmp = psizex;  psizex = psizey;  psizey = tmp;
  702.   }
  703.  
  704.   pageRect.x = (int) ((PMAX/2) - ((psizex/2.0) * in2pix));
  705.   pageRect.y = (int) ((PMAX/2) - ((psizey/2.0) * in2pix));
  706.   pageRect.width  = (int) (psizex * in2pix);
  707.   pageRect.height = (int) (psizey * in2pix);
  708. }
  709.  
  710.  
  711. /***************************************************/
  712. static void drawIRect(draw)
  713. int draw;
  714. {
  715.   int x,y,w,h;
  716.   XRectangle xr;
  717.  
  718.   x = pageRect.x + (int) (pos_inx * in2pix);
  719.   y = pageRect.y + (int) (pos_iny * in2pix);
  720.   w = sz_inx * in2pix;
  721.   h = sz_iny * in2pix;
  722.  
  723.   xr.x = pageRect.x + 1;
  724.   xr.y = pageRect.y + 1;
  725.   xr.width  = pageRect.width - 1;
  726.   xr.height = pageRect.height - 1;
  727.  
  728.   if (draw) XSetForeground(theDisp, theGC, infofg);
  729.        else XSetForeground(theDisp, theGC, infobg);
  730.  
  731.   XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
  732.   XDrawRectangle(theDisp, pageF, theGC, x, y, w, h);
  733.   XDrawLine(theDisp, pageF, theGC, x, y, x+w, y+h);
  734.   XDrawLine(theDisp, pageF, theGC, x, y+h, x+w, y);
  735.   XSetClipMask(theDisp, theGC, None);
  736. }
  737.  
  738.  
  739.  
  740. /***************************************************/
  741. static void centerImage()
  742. {
  743.   pos_inx = psizex/2 - sz_inx/2;
  744.   pos_iny = psizey/2 - sz_iny/2;
  745.  
  746.   /* round to integer .001ths of an inch */
  747.   pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
  748.   pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
  749. }
  750.  
  751.  
  752. /***************************************************/
  753. static void maxImage()
  754. {
  755.   double scx, scy;
  756.   int w,h;
  757.  
  758.   if (savenormCB.val) { w = cWIDE;  h = cHIGH; }
  759.                  else { w = eWIDE;  h = eHIGH; }
  760.  
  761.   sz_inx = psizex - margins[RBWhich(paperRB)][0];
  762.   sz_iny = psizey - margins[RBWhich(paperRB)][1];
  763.  
  764.   /* choose the smaller scaling factor */
  765.   scx = sz_inx / w;
  766.   scy = sz_iny / h;
  767.  
  768.   if (scx < scy) { sz_iny = w * scx; }
  769.             else { sz_inx = h * scy; }
  770.  
  771.   DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5));
  772.   DSetVal(&ysDial, xsDial.val);
  773.  
  774.   sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);  
  775.   sz_iny = (double) h / PIX2INCH * (ysDial.val / 100.0);  
  776.  
  777.   /* round to integer .001ths of an inch */
  778.   sz_inx = floor(sz_inx * 1000.0 + 0.5) / 1000.0;
  779.   sz_iny = floor(sz_iny * 1000.0 + 0.5) / 1000.0;
  780.  
  781.   dpix = (int) (PIX2INCH / (xsDial.val / 100.0));  
  782.   dpiy = (int) (PIX2INCH / (ysDial.val / 100.0));  
  783.  
  784.   pos_inx = psizex/2 - sz_inx/2;
  785.   pos_iny = psizey/2 - sz_iny/2;
  786.  
  787.   /* round to integer .001ths of an inch */
  788.   pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
  789.   pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
  790. }
  791.  
  792.  
  793. /***************************************************/
  794. static void moveImage(newx,newy)
  795. double newx, newy;
  796. {
  797.   double hsx, hsy;
  798.  
  799.   hsx = sz_inx/2;  hsy = sz_iny/2;
  800.  
  801.   /* round to integer .001ths of an inch */
  802.   newx = floor(newx * 1000.0 + 0.5) / 1000.0;
  803.   newy = floor(newy * 1000.0 + 0.5) / 1000.0;
  804.  
  805.   /* keep center of image within page limits */
  806.   RANGE(newx, -hsx, psizex-hsx);
  807.   RANGE(newy, -hsy, psizey-hsy);
  808.  
  809.   if (newx != pos_inx || newy != pos_iny) {  /* moved */
  810.     drawIRect(0);
  811.     pos_inx = newx;
  812.     pos_iny = newy;
  813.     drawIRect(1);
  814.     drawPosStr();
  815.   }
  816. }
  817.  
  818.  
  819. /***************************************************/
  820. static void writePS()
  821. {
  822.   FILE *fp;
  823.   int   i, j, q, err, rpix, gpix, bpix, nc;
  824.   int   iw, ih, ox, oy, slen, lwidth, bits, colorps, w, h;
  825.   byte *inpix, *bwpic, *rmap, *gmap, *bmap;
  826.   
  827.   if (savenormCB.val) { inpix = cpic;  w = cWIDE;  h = cHIGH; }
  828.                  else { inpix = epic;  w = eWIDE;  h = eHIGH; }
  829.  
  830.   bwpic = NULL;  rmap = r;  gmap = g;  bmap = b;
  831.   nc = numcols;
  832.  
  833.   fp = OpenOutFile(filename);
  834.   if (!fp) return;
  835.  
  836.   WaitCursor();
  837.   
  838.  
  839.   bwpic = HandleBWandReduced(colorType, &nc, &rmap, &gmap, &bmap);
  840.   if (bwpic) inpix = bwpic;
  841.  
  842.     
  843.  
  844.   /* printed image will have size iw,ih (in picas) */
  845.   iw = (int) (sz_inx * 72.0 + 0.5);
  846.   ih = (int) (sz_iny * 72.0 + 0.5);   
  847.  
  848.   /* compute offset to bottom-left of image (in picas) */
  849.   ox = (int) (pos_inx * 72.0 + 0.5);
  850.   oy = (int) ((psizey - (pos_iny + sz_iny)) * 72.0 + 0.5);
  851.  
  852.  
  853.   /*** write PostScript header ***/
  854.  
  855.  
  856.   fprintf(fp,"%%!PS-Adobe-2.0 EPSF-2.0\n");
  857.   fprintf(fp,"%%%%Title: %s\n",filename);
  858.   fprintf(fp,"%%%%Creator: XV %s  -  by John Bradley\n",REVDATE);
  859.  
  860.   if (RBWhich(orientRB)==ORNT_LAND)   /* Landscape mode */
  861.     fprintf(fp,"%%%%BoundingBox: %d %d %d %d\n", 
  862.         (int) (pos_iny * 72.0 + 0.5),
  863.         (int) (pos_inx * 72.0 + 0.5),
  864.         (int) (pos_iny * 72.0 + 0.5) + iw,
  865.         (int) (pos_inx * 72.0 + 0.5) + ih);
  866.   else 
  867.     fprintf(fp,"%%%%BoundingBox: %d %d %d %d\n", ox, oy, ox+iw, oy+ih);
  868.  
  869.   fprintf(fp,"%%%%Pages: 1\n");
  870.   fprintf(fp,"%%%%DocumentFonts:\n");
  871.   fprintf(fp,"%%%%EndComments\n");
  872.  
  873.  
  874.   switch (colorType) {
  875.   case F_FULLCOLOR:
  876.   case F_REDUCED:   slen = w*3;      bits = 8;  colorps = 1;  break;
  877.   case F_GREYSCALE: slen = w;        bits = 8;  colorps = 0;  break;
  878.   case F_BWDITHER:  slen = (w+7)/8;  bits = 1;  colorps = 0;  break;
  879.   default:  FatalError("unknown colorType in writePS()");   break;
  880.   }
  881.   
  882.   if (encapsCB.val) epsPreview(fp, inpix, colorType, w, h);
  883.  
  884.   fprintf(fp,"%%%%EndProlog\n\n");
  885.  
  886.   fprintf(fp,"%%%%Page: 1 1\n\n");
  887.  
  888.   fprintf(fp,"%% remember original state\n");
  889.   fprintf(fp,"/origstate save def\n\n");
  890.  
  891.   fprintf(fp,"%% build a temporary dictionary\n");
  892.   fprintf(fp,"20 dict begin\n\n");
  893.  
  894.   if (colorType == F_BWDITHER || !pscompCB.val) {
  895.     fprintf(fp,"%% define string to hold a scanline's worth of data\n");
  896.     fprintf(fp,"/pix %d string def\n\n", slen);
  897.   }
  898.  
  899.   if (RBWhich(orientRB)==ORNT_LAND) {   /* Landscape mode */
  900.     fprintf(fp,"%% print in landscape mode\n");
  901.     fprintf(fp,"90 rotate 0 %d translate\n\n",(int) (-psizey*72.0));
  902.   }
  903.     
  904.   if (RBWhich(paperRB) == PSZ_4BY5 ||
  905.       RBWhich(paperRB) == PSZ_35MM) {
  906.     fprintf(fp,"%% we're going to a 4x5 or a 35mm film recorder.\n");
  907.     fprintf(fp,"%% clear page to black to avoid registration problems\n");
  908.     fprintf(fp,"newpath\n");
  909.     fprintf(fp,"  0 0 moveto\n");
  910.     fprintf(fp,"  0 %d rlineto\n", (int) (psizey * 72.0));
  911.     fprintf(fp,"  %d 0 rlineto\n", (int) (psizex * 72.0));
  912.     fprintf(fp,"  0 %d rlineto\n", (int) (-psizey * 72.0));
  913.     fprintf(fp,"  closepath\n");
  914.     fprintf(fp,"  0 setgray\n");
  915.     fprintf(fp,"  fill\n\n");
  916.   }
  917.  
  918.  
  919.   fprintf(fp,"%% lower left corner\n");
  920.   fprintf(fp,"%d %d translate\n\n",ox,oy);
  921.  
  922.   fprintf(fp,"%% size of image (on paper, in 1/72inch coords)\n");
  923.   fprintf(fp,"%d %d scale\n\n",iw,ih);
  924.  
  925.   if (colorType == F_BWDITHER) {   /* 1-bit dither code uses 'image' */
  926.     fprintf(fp,"%% dimensions of data\n");
  927.     fprintf(fp,"%d %d %d\n\n",w,h,bits);
  928.  
  929.     fprintf(fp,"%% mapping matrix\n");
  930.     fprintf(fp,"[%d 0 0 %d 0 %d]\n\n", w, -h, h);
  931.  
  932.     fprintf(fp,"{currentfile pix readhexstring pop}\n");
  933.     fprintf(fp,"image\n");
  934.  
  935.     /* write the actual image data */
  936.  
  937.     err = writeBWStip(fp, inpix, "", w, h);
  938.   }
  939.  
  940.   else {      /* all other formats */
  941.     byte *rleline;
  942.     unsigned long outbytes = 0;
  943.  
  944.     /* if we're using color, make sure 'colorimage' is defined */
  945.     if (colorps) psColorImage(fp);
  946.  
  947.     if (pscompCB.val) {   /* write colormap and rle-colormapped image funct */
  948.       psColorMap(fp, colorps, nc, rmap, gmap, bmap);
  949.       psRleCmapImage(fp);
  950.     }
  951.  
  952.     fprintf(fp,"%d %d %d\t\t\t%% dimensions of data\n",w,h,bits);
  953.     fprintf(fp,"[%d 0 0 %d 0 %d]\t\t%% mapping matrix\n", w, -h, h);
  954.  
  955.     if (pscompCB.val) fprintf(fp,"rlecmapimage\n");
  956.     else {
  957.       fprintf(fp,"{currentfile pix readhexstring pop}\n");
  958.       if (colorps) fprintf(fp,"false 3 colorimage\n");
  959.               else fprintf(fp,"image\n");
  960.     }
  961.  
  962.     /* dump the image data to the file */
  963.     err = 0;
  964.  
  965.     if (pscompCB.val) {
  966.       rleline  = (byte *) malloc(w * 2);  /* much worse than possible */
  967.       if (!rleline) FatalError("unable to malloc rleline in writePS()\n");
  968.     }
  969.  
  970.     for (i=0; i<h && err != EOF; i++) {
  971.       int rlen;
  972.       lwidth = 0;
  973.       putc('\n',fp);
  974.  
  975.       if ((i&0x1f) == 0) WaitCursor();
  976.  
  977.       if (pscompCB.val) {  /* write rle-encoded colormapped image data */
  978.     rlen = rle_encode(inpix, rleline, w);
  979.     inpix += w;
  980.     outbytes += rlen;
  981.  
  982.     for (j=0; j<rlen && err != EOF; j++) {
  983.       err = fprintf(fp,"%02x", rleline[j]);
  984.       lwidth += 2;
  985.  
  986.       if (lwidth>70) { putc('\n',fp); lwidth = 0; }
  987.     }
  988.       }
  989.       else {  /* write non-rle raw (gray/rgb) image data */
  990.     for (j=0; j<w && err != EOF; j++) {
  991.       rpix = rmap[*inpix];
  992.       gpix = gmap[*inpix];
  993.       bpix = bmap[*inpix];
  994.       
  995.       if (colorps) { 
  996.         err = fprintf(fp,"%02x%02x%02x",rpix,gpix,bpix);
  997.         lwidth+=6;
  998.       }
  999.       
  1000.       else {  /* greyscale */
  1001.         q = (rpix*21 + gpix*32 + bpix*11) / 64;
  1002.         err = fprintf(fp,"%02x", q);
  1003.         lwidth+=2;
  1004.       }
  1005.  
  1006.       if (lwidth>70) { putc('\n',fp); lwidth = 0; }
  1007.       inpix++;
  1008.     }
  1009.       }
  1010.     }
  1011.  
  1012.     if (pscompCB.val) {
  1013.       free(rleline);
  1014.       fprintf(fp,"\n\n");
  1015.       fprintf(fp,"%%\n");
  1016.       fprintf(fp,"%% Compression made this file %.2lf%% %s\n",
  1017.           100.0 * ((double) outbytes) / 
  1018.           ((double) eWIDE * eHIGH * ((colorps) ? 3 : 1)),
  1019.           "of the uncompressed size.");
  1020.       fprintf(fp,"%%\n");
  1021.     }
  1022.   }
  1023.  
  1024.  
  1025.   fprintf(fp,"\n\nshowpage\n\n");
  1026.  
  1027.   fprintf(fp,"%% stop using temporary dictionary\n");
  1028.   fprintf(fp,"end\n\n");
  1029.  
  1030.   fprintf(fp,"%% restore original state\n");
  1031.   fprintf(fp,"origstate restore\n\n");
  1032.   fprintf(fp,"%%%%Trailer\n");
  1033.  
  1034.   if (bwpic) free(bwpic);
  1035.  
  1036.   if (CloseOutFile(fp, filename, (err==EOF)) == 0) {
  1037.     DirBox(0);
  1038.     LoadCurrentDirectory();   /* wrote file: rescan directory */
  1039.   }
  1040.  
  1041.   SetCursors(-1);
  1042. }
  1043.  
  1044.  
  1045. /**********************************************/
  1046. static int rle_encode(scanline, rleline, wide)
  1047.      byte *scanline, *rleline;
  1048.      int wide;
  1049. {
  1050.   /* generates a rle-compressed version of the scan line.
  1051.    * rle is encoded as such:
  1052.    *    <count> <value>                      # 'run' of count+1 equal pixels
  1053.    *    <count | 0x80> <count+1 data bytes>  # count+1 non-equal pixels
  1054.    *
  1055.    * count can range between 0 and 127
  1056.    *
  1057.    * returns length of the rleline vector
  1058.    */
  1059.   
  1060.   int  i, j, blocklen, isrun, rlen;
  1061.   byte block[256], pix;
  1062.   
  1063.   blocklen = isrun = rlen = 0;
  1064.  
  1065.   for (i=0; i<wide; i++) {
  1066.     /* there are 5 possible states:
  1067.      *   0: block empty.
  1068.      *   1: block not empty, block is  a run, current pix == previous pix
  1069.      *   2: block not empty, block is  a run, current pix != previous pix
  1070.      *   3: block not empty, block not a run, current pix == previous pix
  1071.      *   4: block not empty, block not a run, current pix != previous pix
  1072.      */
  1073.  
  1074.     pix = scanline[i];
  1075.  
  1076.     if (!blocklen) {                    /* case 0:  empty */
  1077.       block[blocklen++] = pix;
  1078.       isrun = 1;
  1079.     }
  1080.  
  1081.     else if (isrun) {
  1082.       if (pix == block[blocklen-1]) {   /* case 1:  isrun, prev==cur */
  1083.     block[blocklen++] = pix;
  1084.       }
  1085.       else {                            /* case 2:  isrun, prev!=cur */
  1086.     if (blocklen>1) {               /*   we have a run block to flush */
  1087.       rleline[rlen++] = blocklen-1;
  1088.       rleline[rlen++] = block[0];
  1089.       block[0] = pix;               /*   start new run block with pix */
  1090.       blocklen = 1;
  1091.     }
  1092.     else {
  1093.       isrun = 0;                    /*   blocklen<=1, turn into non-run */
  1094.       block[blocklen++] = pix;
  1095.     }
  1096.       }
  1097.     }
  1098.     
  1099.     else {   /* not a run */
  1100.       if (pix == block[blocklen-1]) {   /* case 3:  non-run, prev==cur */
  1101.     if (blocklen>1) {               /*  have a non-run block to flush */
  1102.       rleline[rlen++] = (blocklen-1) | 0x80;
  1103.       for (j=0; j<blocklen; j++)
  1104.         rleline[rlen++] = block[j];
  1105.  
  1106.       block[0] = pix;               /*  start new run block with pix */
  1107.       blocklen = isrun = 1;
  1108.     }
  1109.     else {
  1110.       isrun = 1;                    /*  blocklen<=1 turn into a run */
  1111.       block[blocklen++] = pix;
  1112.     }
  1113.       }
  1114.       else {                            /* case 4:  non-run, prev!=cur */
  1115.     block[blocklen++] = pix;
  1116.       }
  1117.     }
  1118.  
  1119.     if (blocklen == 128) {   /* max block length.  flush */
  1120.       if (isrun) {
  1121.     rleline[rlen++] = blocklen-1;
  1122.     rleline[rlen++] = block[0];
  1123.       }
  1124.  
  1125.       else {
  1126.     rleline[rlen++] = (blocklen-1) | 0x80;
  1127.     for (j=0; j<blocklen; j++) 
  1128.       rleline[rlen++] = block[j];
  1129.       }
  1130.  
  1131.       blocklen = 0;
  1132.     }
  1133.   }
  1134.  
  1135.   /* flush last block */
  1136.   if (isrun) {
  1137.     rleline[rlen++] = blocklen-1;
  1138.     rleline[rlen++] = block[0];
  1139.   }
  1140.  
  1141.   else {
  1142.     rleline[rlen++] = (blocklen-1) | 0x80;
  1143.     for (j=0; j<blocklen; j++) 
  1144.       rleline[rlen++] = block[j];
  1145.   }
  1146.  
  1147.   return rlen;
  1148. }
  1149.       
  1150.         
  1151. /**********************************************/
  1152. static void psColorImage(fp)
  1153. FILE *fp;
  1154. {
  1155.   /* spits out code that checks if the PostScript device in question
  1156.      knows about the 'colorimage' operator.  If it doesn't, it defines
  1157.      'colorimage' in terms of image (ie, generates a greyscale image from
  1158.      RGB data) */
  1159.  
  1160.  
  1161.   fprintf(fp,"%% define 'colorimage' if it isn't defined\n");
  1162.   fprintf(fp,"%%   ('colortogray' and 'mergeprocs' come from xwd2ps\n");
  1163.   fprintf(fp,"%%     via xgrab)\n");
  1164.   fprintf(fp,"/colorimage where   %% do we know about 'colorimage'?\n");
  1165.   fprintf(fp,"  { pop }           %% yes: pop off the 'dict' returned\n");
  1166.   fprintf(fp,"  {                 %% no:  define one\n");
  1167.   fprintf(fp,"    /colortogray {  %% define an RGB->I function\n");
  1168.   fprintf(fp,"      /rgbdata exch store    %% call input 'rgbdata'\n");
  1169.   fprintf(fp,"      rgbdata length 3 idiv\n");
  1170.   fprintf(fp,"      /npixls exch store\n");
  1171.   fprintf(fp,"      /rgbindx 0 store\n");
  1172.   fprintf(fp,"      /grays npixls string store  %% str to hold the result\n");
  1173.   fprintf(fp,"      0 1 npixls 1 sub {\n");
  1174.   fprintf(fp,"        grays exch\n");
  1175.   fprintf(fp,"        rgbdata rgbindx       get 20 mul    %% Red\n");
  1176.   fprintf(fp,"        rgbdata rgbindx 1 add get 32 mul    %% Green\n");
  1177.   fprintf(fp,"        rgbdata rgbindx 2 add get 12 mul    %% Blue\n");
  1178.   fprintf(fp,"        add add 64 idiv      %% I = .5G + .31R + .18B\n");
  1179.   fprintf(fp,"        put\n");
  1180.   fprintf(fp,"        /rgbindx rgbindx 3 add store\n");
  1181.   fprintf(fp,"      } for\n");
  1182.   fprintf(fp,"      grays\n");
  1183.   fprintf(fp,"    } bind def\n\n");
  1184.  
  1185.   fprintf(fp,"    %% Utility procedure for colorimage operator.\n");
  1186.   fprintf(fp,"    %% This procedure takes two procedures off the\n");
  1187.   fprintf(fp,"    %% stack and merges them into a single procedure.\n\n");
  1188.   
  1189.   fprintf(fp,"    /mergeprocs { %% def\n");
  1190.   fprintf(fp,"      dup length\n");
  1191.   fprintf(fp,"      3 -1 roll\n");
  1192.   fprintf(fp,"      dup\n");
  1193.   fprintf(fp,"      length\n");
  1194.   fprintf(fp,"      dup\n");
  1195.   fprintf(fp,"      5 1 roll\n");
  1196.   fprintf(fp,"      3 -1 roll\n");
  1197.   fprintf(fp,"      add\n");
  1198.   fprintf(fp,"      array cvx\n");
  1199.   fprintf(fp,"      dup\n");
  1200.   fprintf(fp,"      3 -1 roll\n");
  1201.   fprintf(fp,"      0 exch\n");
  1202.   fprintf(fp,"      putinterval\n");
  1203.   fprintf(fp,"      dup\n");
  1204.   fprintf(fp,"      4 2 roll\n");
  1205.   fprintf(fp,"      putinterval\n");
  1206.   fprintf(fp,"    } bind def\n\n");
  1207.  
  1208.   fprintf(fp,"    /colorimage { %% def\n");
  1209.   fprintf(fp,"      pop pop     %% remove 'false 3' operands\n");
  1210.   fprintf(fp,"      {colortogray} mergeprocs\n");
  1211.   fprintf(fp,"      image\n");
  1212.   fprintf(fp,"    } bind def\n");
  1213.   fprintf(fp,"  } ifelse          %% end of 'false' case\n");
  1214.   fprintf(fp,"\n\n\n");
  1215. }
  1216.  
  1217.  
  1218. /**********************************************/
  1219. static void psColorMap(fp, color, nc, rmap, gmap, bmap)
  1220.      FILE *fp;
  1221.      int color, nc;
  1222.      byte *rmap, *gmap, *bmap;
  1223. {
  1224.   /* spits out code for the colormap of the following image
  1225.      if !color, it spits out a mono-ized graymap */
  1226.  
  1227.   int i;
  1228.  
  1229.   fprintf(fp,"%% define the colormap\n");
  1230.   fprintf(fp,"/cmap %d string def\n\n\n", nc * ((color) ? 3 : 1));
  1231.  
  1232.   fprintf(fp,"%% load up the colormap\n");
  1233.   fprintf(fp,"currentfile cmap readhexstring\n");
  1234.  
  1235.   for (i=0; i<nc; i++) {
  1236.     if (color) fprintf(fp,"%02x%02x%02x ", rmap[i],gmap[i],bmap[i]);
  1237.     else fprintf(fp,"%02x ", MONO(rmap[i],gmap[i],bmap[i]));
  1238.     
  1239.     if ((i%10) == 9) fprintf(fp,"\n");
  1240.   }
  1241.   if (i%10) fprintf(fp,"\n");
  1242.   fprintf(fp,"pop pop   %% lose return values from readhexstring\n\n\n");
  1243.          
  1244. }
  1245.  
  1246.  
  1247. /**********************************************/
  1248. static void psRleCmapImage(fp, color)
  1249. FILE *fp;
  1250. {
  1251.   /* spits out code that defines the 'rlecmapimage' operator */
  1252.  
  1253.   fprintf(fp,"%% rlecmapimage expects to have 'w h bits matrix' on stack\n");
  1254.   fprintf(fp,"/rlecmapimage {\n");
  1255.   fprintf(fp,"  /buffer 1 string def\n");
  1256.   fprintf(fp,"  /rgbval 3 string def\n");
  1257.   fprintf(fp,"  /block  384 string def\n\n");
  1258.  
  1259.   fprintf(fp,"  %% proc to read a block from file, and return RGB data\n");
  1260.   fprintf(fp,"  { currentfile buffer readhexstring pop\n");
  1261.   fprintf(fp,"    /bcount exch 0 get store\n");
  1262.   fprintf(fp,"    bcount 128 ge\n");
  1263.   fprintf(fp,"    {  %% it's a non-run block\n");
  1264.   fprintf(fp,"      0 1 bcount 128 sub\n");
  1265.   fprintf(fp,"      { currentfile buffer readhexstring pop pop\n\n");
  1266.  
  1267.   if (color) {
  1268.     fprintf(fp,"        %% look up value in color map\n");
  1269.     fprintf(fp,"%s/rgbval cmap buffer 0 get 3 mul 3 getinterval store\n\n",
  1270.         "        ");
  1271.     fprintf(fp,"        %% and put it in position i*3 in block\n");
  1272.     fprintf(fp,"        block exch 3 mul rgbval putinterval\n");
  1273.     fprintf(fp,"      } for\n");
  1274.     fprintf(fp,"      block  0  bcount 127 sub 3 mul  getinterval\n");
  1275.     fprintf(fp,"    }\n\n");
  1276.   }
  1277.   else {
  1278.     fprintf(fp,"        %% look up value in gray map\n");
  1279.     fprintf(fp,"%s/rgbval cmap buffer 0 get 1 getinterval store\n\n",
  1280.         "        ");
  1281.     fprintf(fp,"        %% and put it in position i in block\n");
  1282.     fprintf(fp,"        block exch rgbval putinterval\n");
  1283.     fprintf(fp,"      } for\n");
  1284.     fprintf(fp,"      block  0  bcount 127 sub  getinterval\n");
  1285.     fprintf(fp,"    }\n\n");
  1286.   }
  1287.  
  1288.   fprintf(fp,"    { %% else it's a run block\n");
  1289.   fprintf(fp,"      currentfile buffer readhexstring pop pop\n\n");
  1290.  
  1291.   if (color) {
  1292.     fprintf(fp,"      %% look up value in colormap\n");
  1293.     fprintf(fp,"%s/rgbval cmap buffer 0 get 3 mul 3 getinterval store\n\n",
  1294.         "      ");
  1295.     fprintf(fp,"%s0 1 bcount { block exch 3 mul rgbval putinterval } for\n\n",
  1296.         "      ");
  1297.     fprintf(fp,"      block 0 bcount 1 add 3 mul getinterval\n");
  1298.   }
  1299.   else {
  1300.     fprintf(fp,"      %% look up value in graymap\n");
  1301.     fprintf(fp,"      /rgbval cmap buffer 0 get 1 getinterval store\n\n");
  1302.     fprintf(fp,"      0 1 bcount { block exch rgbval putinterval } for\n\n");
  1303.     fprintf(fp,"      block 0 bcount 1 add getinterval\n");
  1304.   }
  1305.  
  1306.   fprintf(fp,"    } ifelse\n");
  1307.   fprintf(fp,"  } %% end of proc\n");
  1308.  
  1309.   if (color) fprintf(fp,"  false 3 colorimage\n");
  1310.         else fprintf(fp,"  image\n");
  1311.  
  1312.   fprintf(fp,"} bind def\n\n\n");
  1313. }
  1314.  
  1315.  
  1316.  
  1317. /**********************************************/
  1318. static void epsPreview(fp, pic, colorType, w, h)
  1319.      FILE *fp;
  1320.      byte *pic;
  1321.      int   colorType;
  1322.      int   w, h;
  1323. {
  1324.   byte *prev;
  1325.  
  1326.   /* put in an EPSI preview */
  1327.   
  1328.   if (colorType != F_BWDITHER) { /* have to generate a preview */
  1329.     prev = (byte *) malloc(w * h);
  1330.     if (!prev) {
  1331.       fprintf(stderr,"Unable to malloc in epsPreview\n");
  1332.       return;
  1333.     }
  1334.     FSDither(pic, w, h, prev);
  1335.   }
  1336.   else prev = pic;
  1337.   
  1338.   fprintf(fp,"%%%%BeginPreview: %d %d %d %d\n", w, h, 1, 
  1339.       (w/(72*4) + 1) * h);
  1340.  
  1341.   writeBWStip(fp, prev, "% ", w, h);
  1342.  
  1343.   fprintf(fp,"%%%%EndPreview\n");
  1344.  
  1345.   if (colorType == F_BWDITHER) free(prev);
  1346. }
  1347.  
  1348.  
  1349. /***********************************/
  1350. static int writeBWStip(fp, pic, prompt, w, h)
  1351.      FILE *fp;
  1352.      byte *pic;
  1353.      char *prompt;
  1354.      int  w, h;
  1355. {
  1356.   /* write the given 'pic' (B/W stippled, 1 byte per pixel, 0=blk,1=wht) 
  1357.      out as hexadecimal, max of 72 hex chars per line.
  1358.  
  1359.      returns '0' if everythings fine, 'EOF' if writing failed */
  1360.  
  1361.   int err, i, j, lwidth;
  1362.   byte outbyte, bitnum, bit;
  1363.  
  1364.   err = 0;
  1365.  
  1366.   for (i=0; i<h && err != EOF; i++) {
  1367.     fprintf(fp, "%s", prompt);
  1368.  
  1369.     outbyte = bitnum = lwidth = 0;
  1370.  
  1371.     if ((i&0x3f) == 0) WaitCursor();
  1372.  
  1373.     for (j=0; j<w && err != EOF; j++) {
  1374.       bit = *pic;
  1375.       outbyte = (outbyte<<1) | ((bit)&0x01);
  1376.       bitnum++;
  1377.  
  1378.       if (bitnum==8) {
  1379.     err = fprintf(fp,"%02x",outbyte);
  1380.     lwidth+=2;
  1381.     outbyte = bitnum = 0;
  1382.       }
  1383.  
  1384.       if (lwidth>=72 && j+1<w) { fprintf(fp, "\n%s", prompt); lwidth = 0; }
  1385.       pic++;
  1386.     }
  1387.  
  1388.     if (bitnum) {   /* few bits left over... */
  1389.       for ( ; bitnum<8; bitnum++) outbyte <<= 1;
  1390.       err = fprintf(fp,"%02x",outbyte);
  1391.       lwidth+=2;
  1392.     }
  1393.  
  1394.     fprintf(fp, "\n");
  1395.   }
  1396.  
  1397.   return err;
  1398. }
  1399.  
  1400.  
  1401.  
  1402.