home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Stars of Shareware: Programmierung
/
SOURCE.mdf
/
programm
/
msdos
/
c
/
xv221src
/
xvps.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-11
|
41KB
|
1,402 lines
/*
* xvps.c - Postscript dialog box, file output functions
*
* callable functions:
*
* CreatePSD(geom) - creates the psW window. Doesn't map it.
* PSDialog() - maps psW
* PSCheckEvent(event) - called by event handler
* PSSaveParams(str,int) - tells PSDialog what to do when 'Ok' clicked
* PSResize() - called whenever ePic changes size
*/
/*
* Copyright 1989, 1990, 1991, 1992 by John Bradley and
* The University of Pennsylvania
*
* Permission to use, copy, and distribute for non-commercial purposes,
* is hereby granted without fee, providing that the above copyright
* notice appear in all copies and that both the copyright notice and this
* permission notice appear in supporting documentation.
*
* The software may be modified for your own purposes, but modified versions
* may not be distributed.
*
* This software is provided "as is" without any expressed or implied warranty.
*
* The author may be contacted via:
* US Mail: John Bradley
* GRASP Lab, Room 301C
* 3401 Walnut St.
* Philadelphia, PA 19104
*
* Phone: (215) 898-8813
* EMail: bradley@cis.upenn.edu
*/
#include "xv.h"
#define PSWIDE 431
#define PSHIGH 350
#define PMAX 200 /* size of square that a 'page' has to fit into */
#define PS_NBUTTS 6
#define PS_BOK 0
#define PS_BCANC 1
#define PS_BCENT 2
#define PS_BMAX 3
#define PS_BPOSX 4
#define PS_BPOSY 5
/* paperRB indicies */
#define PSZ_NORM 0
#define PSZ_A4 1
#define PSZ_B5 2
#define PSZ_LEGAL 3
#define PSZ_BSIZE 4
#define PSZ_4BY5 5
#define PSZ_35MM 6
/* orientRB indicies */
#define ORNT_PORT 0
#define ORNT_LAND 1
#define BUTTH 24
#define IN2CM 2.54
#define PIX2INCH 72.0 /* # of pixels per inch, at 100% scaling */
#ifdef __STDC__
static void drawPSD(int, int, int, int);
static void drawPosStr();
static void drawSizeStr();
static void drawResStr();
static void drawPage();
static void clickPSD(int, int);
static void clickPage(int, int);
static void doCmd(int);
static void changedScale(void);
static void setScale(void);
static void changedPaper(void);
static void setPaper(void);
static void drawIRect(int);
static void centerImage(void);
static void maxImage(void);
static void moveImage(double, double);
static void writePS(void);
static int rle_encode(byte *, byte *, int);
static void psColorImage();
static void psColorMap(FILE *fp, int, int, byte *, byte *, byte *);
static void psRleCmapImage();
static void epsPreview();
static int writeBWStip(FILE *, byte *, char *, int, int);
#else
static void drawPSD(), drawPosStr(), drawSizeStr(), drawResStr();
static void drawPage(), clickPSD(), clickPage(), doCmd(), changedScale();
static void setScale(), changedPaper(), setPaper(), drawIRect();
static void centerImage(), maxImage(), moveImage(), writePS();
static void psColorImage(), psColorMap(), epsPreview();
static void psRleCmapImage();
static int rle_encode(), writeBWStip();
#endif
/* local variables */
static Window pageF;
static DIAL xsDial, ysDial;
static RBUTT *orientRB, *paperRB;
static CBUTT lockCB;
static BUTT psbut[PS_NBUTTS];
static double sz_inx, sz_iny; /* image size, in inches */
static double pos_inx, pos_iny; /* top-left offset of image, in inches */
static int dpix, dpiy; /* # of image pixels per inch */
static int tracking=0; /* used in changedScale */
static int posxType, posyType;
/* sizes of pages in inches */
static double paperSize[7][2] = { { 8.500, 11.000}, /* US NORMAL */
{ 8.267, 11.811}, /* A4 */
{ 7.283, 10.630}, /* B5 */
{ 8.500, 14.000}, /* US LEGAL */
{11.000, 17.000}, /* B-size */
{ 3.875, 4.875}, /* 4 by 5 */
{ 0.945, 1.417}}; /* 35mm (24x36) */
/* size of l+r margin and t+b margin. image is centered */
static double margins[7][2] = { { 1.000, 1.000}, /* US NORMAL */
{ 1.000, 1.000}, /* A4 */
{ 1.000, 1.000}, /* B5 */
{ 1.000, 1.000}, /* US LEGAL */
{ 1.000, 1.000}, /* B-size */
{ 0.275, 0.275}, /* 4 by 5 */
{ 0.078, 0.078}}; /* 35mm (24x36) */
static double psizex, psizey; /* current paper size, in inches */
static double in2pix; /* inch to pixels in 'pageF' */
static XRectangle pageRect; /* bounding rect of page, in screen coords */
static char *filename; /* filename to save to */
static int colorType; /* value of 'Colors' rbutt in dir box */
static int firsttime=1; /* first time PSDialog being opened ? */
/***************************************************/
void CreatePSD(geom)
char *geom;
{
psW = CreateWindow("xv postscript", geom, PSWIDE, PSHIGH, infofg, infobg);
if (!psW) FatalError("can't create postscript window!");
StoreDeleteWindowProp(psW);
pageF = XCreateSimpleWindow(theDisp, psW, 20,30, PMAX+1,PMAX+1,
1,infofg,infobg);
if (!pageF) FatalError("couldn't create frame windows");
XSetWindowBackgroundPixmap(theDisp, pageF, grayTile);
XSelectInput(theDisp, pageF, ExposureMask | ButtonPressMask);
XSelectInput(theDisp, psW, ExposureMask | ButtonPressMask | KeyPressMask);
CBCreate(&encapsCB, psW, 240, 7, "preview", infofg, infobg);
CBCreate(&pscompCB, psW, 331, 7, "compress", infofg, infobg);
DCreate(&xsDial, psW, 240, 30, 80, 100, 10, 800, 100, 5,
infofg, infobg, "Width", "%");
DCreate(&ysDial, psW, 331, 30, 80, 100, 10, 800, 100, 5,
infofg, infobg, "Height", "%");
xsDial.drawobj = changedScale;
ysDial.drawobj = changedScale;
CBCreate(&lockCB, psW, 319, 136, "", infofg, infobg);
lockCB.val = 1;
orientRB = RBCreate(NULL, psW, 36, 240+18, "Portrait", infofg, infobg);
RBCreate(orientRB, psW, 36+80, 240+18, "Landscape", infofg, infobg);
paperRB = RBCreate(NULL, psW,36, 240+18+36, "8.5\"x11\"", infofg, infobg);
RBCreate(paperRB, psW, 36+80, 240+18+36, "A4", infofg, infobg);
RBCreate(paperRB, psW, 36+154, 240+18+36, "B5", infofg, infobg);
RBCreate(paperRB, psW, 36, 240+36+36, "8.5\"x14\"", infofg, infobg);
RBCreate(paperRB, psW, 36+80, 240+36+36, "11\"x17\"", infofg, infobg);
RBCreate(paperRB, psW, 36, 240+54+36, "4\"x5\"", infofg, infobg);
RBCreate(paperRB, psW, 36+80, 240+54+36, "35mm slide", infofg, infobg);
BTCreate(&psbut[PS_BOK], psW, PSWIDE-160, PSHIGH-10-BUTTH, 60, BUTTH,
"Ok", infofg, infobg);
BTCreate(&psbut[PS_BCANC], psW, PSWIDE-80, PSHIGH-10-BUTTH, 60, BUTTH,
"Cancel", infofg, infobg);
BTCreate(&psbut[PS_BCENT], psW, 240, 153, 88, BUTTH,
"Center", infofg, infobg);
BTCreate(&psbut[PS_BMAX], psW, 240+88+5, 153, 87, BUTTH,
"Maxpect", infofg, infobg);
BTCreate(&psbut[PS_BPOSX], psW, 256-14, 190+13-8, 8,8, "", infofg, infobg);
BTCreate(&psbut[PS_BPOSY], psW, 256-14, 190+26-8, 8,8, "", infofg, infobg);
posxType = posyType = 0;
pos_inx = 1.0; pos_iny = 1.0; /* temporary bootstrapping... */
setPaper();
setScale();
XMapSubwindows(theDisp, psW);
}
/***************************************************/
void PSDialog(vis)
int vis;
{
if (vis) {
setScale();
if (firsttime) centerImage();
firsttime = 0;
CenterMapWindow(psW, psbut[PS_BOK].x + psbut[PS_BOK].w/2,
psbut[PS_BOK].y + psbut[PS_BOK].h/2, PSWIDE, PSHIGH);
}
else XUnmapWindow(theDisp, psW);
psUp = vis;
}
/***************************************************/
int PSCheckEvent(xev)
XEvent *xev;
{
/* check event to see if it's for one of our subwindows. If it is,
deal accordingly, and return '1'. Otherwise, return '0' */
int rv;
rv = 1;
if (!psUp) return 0;
if (xev->type == Expose) {
int x,y,w,h;
XExposeEvent *e = (XExposeEvent *) xev;
x = e->x; y = e->y; w = e->width; h = e->height;
/* throw away excess expose events for 'dumb' windows */
if (e->count > 0 &&
(e->window == xsDial.win || e->window == ysDial.win ||
e->window == pageF)) {}
else if (e->window == psW) drawPSD(x, y, w, h);
else if (e->window == xsDial.win) DRedraw(&xsDial);
else if (e->window == ysDial.win) DRedraw(&ysDial);
else if (e->window == pageF) drawPage();
else rv = 0;
}
else if (xev->type == ButtonPress) {
XButtonEvent *e = (XButtonEvent *) xev;
int x,y;
x = e->x; y = e->y;
if (e->button == Button1) {
if (e->window == psW) clickPSD(x,y);
else if (e->window == pageF) clickPage(x,y);
else if (e->window == xsDial.win || e->window == ysDial.win) {
if (e->window == xsDial.win) {
tracking = 1;
DTrack(&xsDial, x,y);
tracking = 0;
}
else if (e->window == ysDial.win) {
tracking = 2;
DTrack(&ysDial, x,y);
tracking = 0;
}
}
else rv = 0;
} /* button1 */
else rv = 0;
} /* button press */
else if (xev->type == KeyPress) {
XKeyEvent *e = (XKeyEvent *) xev;
char buf[128]; KeySym ks;
int stlen;
stlen = XLookupString(e,buf,128,&ks,(XComposeStatus *) NULL);
buf[stlen] = '\0';
if (e->window == psW) {
double dx, dy;
int movekey;
movekey = 0; dx = dy = 0.0;
if (ks==XK_Left || ks==XK_KP_4) { dx = -0.001; movekey = 1; }
else if (ks==XK_Right || ks==XK_KP_6) { dx = 0.001; movekey = 1; }
else if (ks==XK_Up || ks==XK_KP_8) { dy = -0.001; movekey = 1; }
else if (ks==XK_Down || ks==XK_KP_2) { dy = 0.001; movekey = 1; }
else if (stlen) {
if (buf[0] == '\r' || buf[0] == '\n') { /* enter */
FakeButtonPress(&psbut[PS_BOK]);
}
else if (buf[0] == '\033') { /* ESC */
FakeButtonPress(&psbut[PS_BCANC]);
}
}
if (movekey) {
if (e->state & ShiftMask) { dx *= 10.0; dy *= 10.0; }
moveImage(pos_inx+dx, pos_iny+dy);
}
}
else rv = 0;
}
else rv = 0;
if (rv==0 && (xev->type == ButtonPress || xev->type == KeyPress)) {
XBell(theDisp, 50);
rv = 1; /* eat it */
}
return rv;
}
/***************************************************/
void PSSaveParams(fname, col)
char *fname;
int col;
{
filename = fname;
colorType = col;
}
/***************************************************/
void PSResize()
{
if (!savenormCB.val) changedScale();
}
/***************************************************/
static void drawPSD(x,y,w,h)
int x,y,w,h;
{
char *title = "Save PostScript File...";
int i,cx;
XRectangle xr;
xr.x = x; xr.y = y; xr.width = w; xr.height = h;
XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
XSetForeground(theDisp, theGC, infofg);
XSetBackground(theDisp, theGC, infobg);
RBRedraw(orientRB,-1);
RBRedraw(paperRB,-1);
for (i=0; i<PS_NBUTTS; i++) BTRedraw(&psbut[i]);
CBRedraw(&encapsCB);
if (colorType != F_BWDITHER) CBRedraw(&pscompCB);
CBRedraw(&lockCB);
ULineString(psW, "Orientation", orientRB->x-16, orientRB->y-3-DESCENT);
ULineString(psW, "Paper Size", paperRB->x-16, paperRB->y-3-DESCENT);
/* draw 'lock' arrows */
cx = 240 + 40; /* center of xsDial */
XDrawLine(theDisp, psW, theGC, lockCB.x, lockCB.y+5, cx+2, lockCB.y+5);
XDrawLine(theDisp, psW, theGC, cx+2, lockCB.y+5, cx+2, lockCB.y-2);
XDrawLine(theDisp, psW, theGC, lockCB.x, lockCB.y+9, cx-2, lockCB.y+9);
XDrawLine(theDisp, psW, theGC, cx-2, lockCB.y+9, cx-2, lockCB.y-2);
XDrawLine(theDisp, psW, theGC, cx-2-3, lockCB.y-2+3, cx, lockCB.y-2-2);
XDrawLine(theDisp, psW, theGC, cx+2+3, lockCB.y-2+3, cx, lockCB.y-2-2);
cx = 330 + 40; /* center of ysDial */
XDrawLine(theDisp, psW, theGC, lockCB.x+15, lockCB.y+5, cx-2, lockCB.y+5);
XDrawLine(theDisp, psW, theGC, cx-2, lockCB.y+5, cx-2, lockCB.y-2);
XDrawLine(theDisp, psW, theGC, lockCB.x+15, lockCB.y+9, cx+2, lockCB.y+9);
XDrawLine(theDisp, psW, theGC, cx+2, lockCB.y+9, cx+2, lockCB.y-2);
XDrawLine(theDisp, psW, theGC, cx-2-3, lockCB.y-2+3, cx, lockCB.y-2-2);
XDrawLine(theDisp, psW, theGC, cx+2+3, lockCB.y-2+3, cx, lockCB.y-2-2);
XDrawString(theDisp, psW, theGC, 10, 19, title, strlen(title));
ULineString(psW, "Position:", 240, 190);
drawPosStr();
ULineString(psW, "Size:", 240, 190+45);
drawSizeStr();
ULineString(psW, "Resolution:", 240, 190+90);
drawResStr();
XSetClipMask(theDisp, theGC, None);
}
/***************************************************/
static void drawPosStr()
{
int x,y;
double cmx, cmy, inx, iny;
char str[64], str1[64], *xst, *yst;
x = 256; y = 190 + 13;
switch (posxType) {
case 0: xst = "Left: "; inx = pos_inx; break;
case 1: xst = "Right:"; inx = psizex - (pos_inx + sz_inx); break;
case 2: xst = "X Mid:"; inx = pos_inx + sz_inx/2; break;
}
switch (posyType) {
case 0: yst = "Top: "; iny = pos_iny; break;
case 1: yst = "Bot: "; iny = psizey - (pos_iny + sz_iny); break;
case 2: yst = "Y Mid:"; iny = pos_iny + sz_iny/2; break;
}
cmx = inx * IN2CM;
cmy = iny * IN2CM;
sprintf(str, "%s %.3f\" (%.2fcm) ", xst, inx, cmx);
sprintf(str1, "%s %.3f\" (%.2fcm) ", yst, iny, cmy);
XSetForeground(theDisp, theGC, infofg);
XSetBackground(theDisp, theGC, infobg);
XSetFont(theDisp, theGC, monofont);
XDrawImageString(theDisp, psW, theGC, x, y, str, strlen(str));
XDrawImageString(theDisp, psW, theGC, x, y+13, str1, strlen(str1));
XSetFont(theDisp, theGC, mfont);
}
/***************************************************/
static void drawSizeStr()
{
int x,y;
double cmx, cmy;
char str[64], str1[64];
x = 256; y = 190+13+45;
cmx = sz_inx * IN2CM;
cmy = sz_iny * IN2CM;
sprintf(str, "%.3f\" x %.3f\" ", sz_inx, sz_iny);
sprintf(str1, "%.2fcm x %.2fcm ", cmx, cmy);
XSetForeground(theDisp, theGC, infofg);
XSetBackground(theDisp, theGC, infobg);
XSetFont(theDisp, theGC, monofont);
XDrawImageString(theDisp, psW, theGC, x, y, str, strlen(str));
XDrawImageString(theDisp, psW, theGC, x, y+13, str1, strlen(str1));
XSetFont(theDisp, theGC, mfont);
}
/***************************************************/
static void drawResStr()
{
int x,y;
char str[64];
x = 256; y = 190 + 13 + 90;
sprintf(str, "%ddpi x %ddpi ", dpix, dpiy);
XSetForeground(theDisp, theGC, infofg);
XSetBackground(theDisp, theGC, infobg);
XSetFont(theDisp, theGC, monofont);
XDrawImageString(theDisp, psW, theGC, x, y, str, strlen(str));
XSetFont(theDisp, theGC, mfont);
}
/***************************************************/
static void drawPage()
{
/* draw page */
XSetForeground(theDisp, theGC, infobg);
XFillRectangle(theDisp, pageF, theGC, pageRect.x+1, pageRect.y+1,
pageRect.width-1, pageRect.height-1);
XSetForeground(theDisp, theGC, infofg);
XDrawRectangle(theDisp, pageF, theGC, pageRect.x, pageRect.y,
pageRect.width, pageRect.height);
drawIRect(1);
}
/***************************************************/
static void clickPSD(x,y)
int x,y;
{
int i;
BUTT *bp;
/* check BUTTs */
for (i=0; i<PS_NBUTTS; i++) {
bp = &psbut[i];
if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
}
if (i<PS_NBUTTS) { /* found one */
if (BTTrack(bp)) doCmd(i);
}
/* check RBUTTs */
else if ((i=RBClick(orientRB,x,y)) >= 0) {
if (RBTrack(orientRB, i)) changedPaper();
}
else if ((i=RBClick(paperRB,x,y)) >= 0) {
if (RBTrack(paperRB, i)) changedPaper();
}
/* check CBUTTs */
else if (CBClick(&lockCB,x,y)) {
if (CBTrack(&lockCB) && lockCB.val) { /* turned on lock */
DSetVal(&ysDial, xsDial.val); /* copy xsDial.val to ysDial */
changedScale();
}
}
else if (CBClick(&encapsCB,x,y)) CBTrack(&encapsCB);
else if (CBClick(&pscompCB,x,y)) CBTrack(&pscompCB);
}
/***************************************************/
static void clickPage(mx,my)
int mx,my;
{
Window rW,cW;
int rx,ry,x,y;
unsigned int mask;
double offx, offy, newx, newy;
/* compute offset (in inches) between 'drag point' and
the top-left corner of the image */
offx = ((mx - pageRect.x) / in2pix) - pos_inx;
offy = ((my - pageRect.y) / in2pix) - pos_iny;
/* if clicked outside of image rectangle, ignore */
if (offx<0.0 || offy < 0.0 || offx>=sz_inx || offy >= sz_iny) return;
while (1) {
if (XQueryPointer(theDisp,pageF,&rW,&cW,&rx,&ry,&x,&y,&mask)) {
if (!(mask & Button1Mask)) break; /* button released */
/* compute new pos_inx, pos_iny based on x,y coords */
newx = ((x-pageRect.x) / in2pix) - offx;
newy = ((y-pageRect.y) / in2pix) - offy;
moveImage(newx, newy);
}
}
}
/***************************************************/
static void doCmd(cmd)
int cmd;
{
switch (cmd) {
case PS_BOK: writePS(); PSDialog(0); break;
case PS_BCANC: PSDialog(0); break;
case PS_BCENT: drawIRect(0);
centerImage();
drawIRect(1);
drawPosStr();
break;
case PS_BMAX: drawIRect(0);
maxImage();
drawIRect(1);
drawPosStr();
drawSizeStr();
drawResStr();
break;
case PS_BPOSX: posxType = (posxType + 1) % 3;
drawPosStr();
break;
case PS_BPOSY: posyType = (posyType + 1) % 3;
drawPosStr();
break;
default: break;
}
}
/***************************************************/
static void changedScale()
{
double oldx,oldy;
drawIRect(0);
if (lockCB.val) {
if (tracking == 1) DSetVal(&ysDial, xsDial.val);
else if (tracking == 2) DSetVal(&xsDial, ysDial.val);
}
oldx = pos_inx; oldy = pos_iny;
setScale();
drawIRect(1);
if (pos_inx != oldx || pos_iny != oldy ||
posxType != 0 || posyType != 0) drawPosStr();
drawSizeStr();
drawResStr();
XFlush(theDisp);
}
/***************************************************/
static void setScale()
{
double hsx, hsy;
int w,h;
if (savenormCB.val) { w = cWIDE; h = cHIGH; }
else { w = eWIDE; h = eHIGH; }
sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);
sz_iny = (double) h / PIX2INCH * (ysDial.val / 100.0);
/* round to integer .001ths of an inch */
sz_inx = floor(sz_inx * 1000.0 + 0.5) / 1000.0;
sz_iny = floor(sz_iny * 1000.0 + 0.5) / 1000.0;
dpix = (int) (PIX2INCH / (xsDial.val / 100.0));
dpiy = (int) (PIX2INCH / (ysDial.val / 100.0));
/* make sure 'center' of image is still on page */
hsx = sz_inx/2; hsy = sz_iny/2;
RANGE(pos_inx, -hsx, psizex-hsx);
RANGE(pos_iny, -hsy, psizey-hsy);
/* round to integer .001ths of an inch */
pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
}
/***************************************************/
static void changedPaper()
{
setPaper();
XClearWindow(theDisp, pageF);
centerImage();
drawPosStr();
drawPage();
}
/***************************************************/
static void setPaper()
{
double tmp;
psizex = paperSize[RBWhich(paperRB)][0];
psizey = paperSize[RBWhich(paperRB)][1];
in2pix = (double) PMAX / psizey;
if (RBWhich(orientRB)==ORNT_LAND) {
tmp = psizex; psizex = psizey; psizey = tmp;
}
pageRect.x = (int) ((PMAX/2) - ((psizex/2.0) * in2pix));
pageRect.y = (int) ((PMAX/2) - ((psizey/2.0) * in2pix));
pageRect.width = (int) (psizex * in2pix);
pageRect.height = (int) (psizey * in2pix);
}
/***************************************************/
static void drawIRect(draw)
int draw;
{
int x,y,w,h;
XRectangle xr;
x = pageRect.x + (int) (pos_inx * in2pix);
y = pageRect.y + (int) (pos_iny * in2pix);
w = sz_inx * in2pix;
h = sz_iny * in2pix;
xr.x = pageRect.x + 1;
xr.y = pageRect.y + 1;
xr.width = pageRect.width - 1;
xr.height = pageRect.height - 1;
if (draw) XSetForeground(theDisp, theGC, infofg);
else XSetForeground(theDisp, theGC, infobg);
XSetClipRectangles(theDisp, theGC, 0,0, &xr, 1, Unsorted);
XDrawRectangle(theDisp, pageF, theGC, x, y, w, h);
XDrawLine(theDisp, pageF, theGC, x, y, x+w, y+h);
XDrawLine(theDisp, pageF, theGC, x, y+h, x+w, y);
XSetClipMask(theDisp, theGC, None);
}
/***************************************************/
static void centerImage()
{
pos_inx = psizex/2 - sz_inx/2;
pos_iny = psizey/2 - sz_iny/2;
/* round to integer .001ths of an inch */
pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
}
/***************************************************/
static void maxImage()
{
double scx, scy;
int w,h;
if (savenormCB.val) { w = cWIDE; h = cHIGH; }
else { w = eWIDE; h = eHIGH; }
sz_inx = psizex - margins[RBWhich(paperRB)][0];
sz_iny = psizey - margins[RBWhich(paperRB)][1];
/* choose the smaller scaling factor */
scx = sz_inx / w;
scy = sz_iny / h;
if (scx < scy) { sz_iny = w * scx; }
else { sz_inx = h * scy; }
DSetVal(&xsDial, (int) ((100 * (sz_inx * PIX2INCH) / w) + .5));
DSetVal(&ysDial, xsDial.val);
sz_inx = (double) w / PIX2INCH * (xsDial.val / 100.0);
sz_iny = (double) h / PIX2INCH * (ysDial.val / 100.0);
/* round to integer .001ths of an inch */
sz_inx = floor(sz_inx * 1000.0 + 0.5) / 1000.0;
sz_iny = floor(sz_iny * 1000.0 + 0.5) / 1000.0;
dpix = (int) (PIX2INCH / (xsDial.val / 100.0));
dpiy = (int) (PIX2INCH / (ysDial.val / 100.0));
pos_inx = psizex/2 - sz_inx/2;
pos_iny = psizey/2 - sz_iny/2;
/* round to integer .001ths of an inch */
pos_inx = floor(pos_inx * 1000.0 + 0.5) / 1000.0;
pos_iny = floor(pos_iny * 1000.0 + 0.5) / 1000.0;
}
/***************************************************/
static void moveImage(newx,newy)
double newx, newy;
{
double hsx, hsy;
hsx = sz_inx/2; hsy = sz_iny/2;
/* round to integer .001ths of an inch */
newx = floor(newx * 1000.0 + 0.5) / 1000.0;
newy = floor(newy * 1000.0 + 0.5) / 1000.0;
/* keep center of image within page limits */
RANGE(newx, -hsx, psizex-hsx);
RANGE(newy, -hsy, psizey-hsy);
if (newx != pos_inx || newy != pos_iny) { /* moved */
drawIRect(0);
pos_inx = newx;
pos_iny = newy;
drawIRect(1);
drawPosStr();
}
}
/***************************************************/
static void writePS()
{
FILE *fp;
int i, j, q, err, rpix, gpix, bpix, nc;
int iw, ih, ox, oy, slen, lwidth, bits, colorps, w, h;
byte *inpix, *bwpic, *rmap, *gmap, *bmap;
if (savenormCB.val) { inpix = cpic; w = cWIDE; h = cHIGH; }
else { inpix = epic; w = eWIDE; h = eHIGH; }
bwpic = NULL; rmap = r; gmap = g; bmap = b;
nc = numcols;
fp = OpenOutFile(filename);
if (!fp) return;
WaitCursor();
bwpic = HandleBWandReduced(colorType, &nc, &rmap, &gmap, &bmap);
if (bwpic) inpix = bwpic;
/* printed image will have size iw,ih (in picas) */
iw = (int) (sz_inx * 72.0 + 0.5);
ih = (int) (sz_iny * 72.0 + 0.5);
/* compute offset to bottom-left of image (in picas) */
ox = (int) (pos_inx * 72.0 + 0.5);
oy = (int) ((psizey - (pos_iny + sz_iny)) * 72.0 + 0.5);
/*** write PostScript header ***/
fprintf(fp,"%%!PS-Adobe-2.0 EPSF-2.0\n");
fprintf(fp,"%%%%Title: %s\n",filename);
fprintf(fp,"%%%%Creator: XV %s - by John Bradley\n",REVDATE);
if (RBWhich(orientRB)==ORNT_LAND) /* Landscape mode */
fprintf(fp,"%%%%BoundingBox: %d %d %d %d\n",
(int) (pos_iny * 72.0 + 0.5),
(int) (pos_inx * 72.0 + 0.5),
(int) (pos_iny * 72.0 + 0.5) + iw,
(int) (pos_inx * 72.0 + 0.5) + ih);
else
fprintf(fp,"%%%%BoundingBox: %d %d %d %d\n", ox, oy, ox+iw, oy+ih);
fprintf(fp,"%%%%Pages: 1\n");
fprintf(fp,"%%%%DocumentFonts:\n");
fprintf(fp,"%%%%EndComments\n");
switch (colorType) {
case F_FULLCOLOR:
case F_REDUCED: slen = w*3; bits = 8; colorps = 1; break;
case F_GREYSCALE: slen = w; bits = 8; colorps = 0; break;
case F_BWDITHER: slen = (w+7)/8; bits = 1; colorps = 0; break;
default: FatalError("unknown colorType in writePS()"); break;
}
if (encapsCB.val) epsPreview(fp, inpix, colorType, w, h);
fprintf(fp,"%%%%EndProlog\n\n");
fprintf(fp,"%%%%Page: 1 1\n\n");
fprintf(fp,"%% remember original state\n");
fprintf(fp,"/origstate save def\n\n");
fprintf(fp,"%% build a temporary dictionary\n");
fprintf(fp,"20 dict begin\n\n");
if (colorType == F_BWDITHER || !pscompCB.val) {
fprintf(fp,"%% define string to hold a scanline's worth of data\n");
fprintf(fp,"/pix %d string def\n\n", slen);
}
if (RBWhich(orientRB)==ORNT_LAND) { /* Landscape mode */
fprintf(fp,"%% print in landscape mode\n");
fprintf(fp,"90 rotate 0 %d translate\n\n",(int) (-psizey*72.0));
}
if (RBWhich(paperRB) == PSZ_4BY5 ||
RBWhich(paperRB) == PSZ_35MM) {
fprintf(fp,"%% we're going to a 4x5 or a 35mm film recorder.\n");
fprintf(fp,"%% clear page to black to avoid registration problems\n");
fprintf(fp,"newpath\n");
fprintf(fp," 0 0 moveto\n");
fprintf(fp," 0 %d rlineto\n", (int) (psizey * 72.0));
fprintf(fp," %d 0 rlineto\n", (int) (psizex * 72.0));
fprintf(fp," 0 %d rlineto\n", (int) (-psizey * 72.0));
fprintf(fp," closepath\n");
fprintf(fp," 0 setgray\n");
fprintf(fp," fill\n\n");
}
fprintf(fp,"%% lower left corner\n");
fprintf(fp,"%d %d translate\n\n",ox,oy);
fprintf(fp,"%% size of image (on paper, in 1/72inch coords)\n");
fprintf(fp,"%d %d scale\n\n",iw,ih);
if (colorType == F_BWDITHER) { /* 1-bit dither code uses 'image' */
fprintf(fp,"%% dimensions of data\n");
fprintf(fp,"%d %d %d\n\n",w,h,bits);
fprintf(fp,"%% mapping matrix\n");
fprintf(fp,"[%d 0 0 %d 0 %d]\n\n", w, -h, h);
fprintf(fp,"{currentfile pix readhexstring pop}\n");
fprintf(fp,"image\n");
/* write the actual image data */
err = writeBWStip(fp, inpix, "", w, h);
}
else { /* all other formats */
byte *rleline;
unsigned long outbytes = 0;
/* if we're using color, make sure 'colorimage' is defined */
if (colorps) psColorImage(fp);
if (pscompCB.val) { /* write colormap and rle-colormapped image funct */
psColorMap(fp, colorps, nc, rmap, gmap, bmap);
psRleCmapImage(fp);
}
fprintf(fp,"%d %d %d\t\t\t%% dimensions of data\n",w,h,bits);
fprintf(fp,"[%d 0 0 %d 0 %d]\t\t%% mapping matrix\n", w, -h, h);
if (pscompCB.val) fprintf(fp,"rlecmapimage\n");
else {
fprintf(fp,"{currentfile pix readhexstring pop}\n");
if (colorps) fprintf(fp,"false 3 colorimage\n");
else fprintf(fp,"image\n");
}
/* dump the image data to the file */
err = 0;
if (pscompCB.val) {
rleline = (byte *) malloc(w * 2); /* much worse than possible */
if (!rleline) FatalError("unable to malloc rleline in writePS()\n");
}
for (i=0; i<h && err != EOF; i++) {
int rlen;
lwidth = 0;
putc('\n',fp);
if ((i&0x1f) == 0) WaitCursor();
if (pscompCB.val) { /* write rle-encoded colormapped image data */
rlen = rle_encode(inpix, rleline, w);
inpix += w;
outbytes += rlen;
for (j=0; j<rlen && err != EOF; j++) {
err = fprintf(fp,"%02x", rleline[j]);
lwidth += 2;
if (lwidth>70) { putc('\n',fp); lwidth = 0; }
}
}
else { /* write non-rle raw (gray/rgb) image data */
for (j=0; j<w && err != EOF; j++) {
rpix = rmap[*inpix];
gpix = gmap[*inpix];
bpix = bmap[*inpix];
if (colorps) {
err = fprintf(fp,"%02x%02x%02x",rpix,gpix,bpix);
lwidth+=6;
}
else { /* greyscale */
q = (rpix*21 + gpix*32 + bpix*11) / 64;
err = fprintf(fp,"%02x", q);
lwidth+=2;
}
if (lwidth>70) { putc('\n',fp); lwidth = 0; }
inpix++;
}
}
}
if (pscompCB.val) {
free(rleline);
fprintf(fp,"\n\n");
fprintf(fp,"%%\n");
fprintf(fp,"%% Compression made this file %.2lf%% %s\n",
100.0 * ((double) outbytes) /
((double) eWIDE * eHIGH * ((colorps) ? 3 : 1)),
"of the uncompressed size.");
fprintf(fp,"%%\n");
}
}
fprintf(fp,"\n\nshowpage\n\n");
fprintf(fp,"%% stop using temporary dictionary\n");
fprintf(fp,"end\n\n");
fprintf(fp,"%% restore original state\n");
fprintf(fp,"origstate restore\n\n");
fprintf(fp,"%%%%Trailer\n");
if (bwpic) free(bwpic);
if (CloseOutFile(fp, filename, (err==EOF)) == 0) {
DirBox(0);
LoadCurrentDirectory(); /* wrote file: rescan directory */
}
SetCursors(-1);
}
/**********************************************/
static int rle_encode(scanline, rleline, wide)
byte *scanline, *rleline;
int wide;
{
/* generates a rle-compressed version of the scan line.
* rle is encoded as such:
* <count> <value> # 'run' of count+1 equal pixels
* <count | 0x80> <count+1 data bytes> # count+1 non-equal pixels
*
* count can range between 0 and 127
*
* returns length of the rleline vector
*/
int i, j, blocklen, isrun, rlen;
byte block[256], pix;
blocklen = isrun = rlen = 0;
for (i=0; i<wide; i++) {
/* there are 5 possible states:
* 0: block empty.
* 1: block not empty, block is a run, current pix == previous pix
* 2: block not empty, block is a run, current pix != previous pix
* 3: block not empty, block not a run, current pix == previous pix
* 4: block not empty, block not a run, current pix != previous pix
*/
pix = scanline[i];
if (!blocklen) { /* case 0: empty */
block[blocklen++] = pix;
isrun = 1;
}
else if (isrun) {
if (pix == block[blocklen-1]) { /* case 1: isrun, prev==cur */
block[blocklen++] = pix;
}
else { /* case 2: isrun, prev!=cur */
if (blocklen>1) { /* we have a run block to flush */
rleline[rlen++] = blocklen-1;
rleline[rlen++] = block[0];
block[0] = pix; /* start new run block with pix */
blocklen = 1;
}
else {
isrun = 0; /* blocklen<=1, turn into non-run */
block[blocklen++] = pix;
}
}
}
else { /* not a run */
if (pix == block[blocklen-1]) { /* case 3: non-run, prev==cur */
if (blocklen>1) { /* have a non-run block to flush */
rleline[rlen++] = (blocklen-1) | 0x80;
for (j=0; j<blocklen; j++)
rleline[rlen++] = block[j];
block[0] = pix; /* start new run block with pix */
blocklen = isrun = 1;
}
else {
isrun = 1; /* blocklen<=1 turn into a run */
block[blocklen++] = pix;
}
}
else { /* case 4: non-run, prev!=cur */
block[blocklen++] = pix;
}
}
if (blocklen == 128) { /* max block length. flush */
if (isrun) {
rleline[rlen++] = blocklen-1;
rleline[rlen++] = block[0];
}
else {
rleline[rlen++] = (blocklen-1) | 0x80;
for (j=0; j<blocklen; j++)
rleline[rlen++] = block[j];
}
blocklen = 0;
}
}
/* flush last block */
if (isrun) {
rleline[rlen++] = blocklen-1;
rleline[rlen++] = block[0];
}
else {
rleline[rlen++] = (blocklen-1) | 0x80;
for (j=0; j<blocklen; j++)
rleline[rlen++] = block[j];
}
return rlen;
}
/**********************************************/
static void psColorImage(fp)
FILE *fp;
{
/* spits out code that checks if the PostScript device in question
knows about the 'colorimage' operator. If it doesn't, it defines
'colorimage' in terms of image (ie, generates a greyscale image from
RGB data) */
fprintf(fp,"%% define 'colorimage' if it isn't defined\n");
fprintf(fp,"%% ('colortogray' and 'mergeprocs' come from xwd2ps\n");
fprintf(fp,"%% via xgrab)\n");
fprintf(fp,"/colorimage where %% do we know about 'colorimage'?\n");
fprintf(fp," { pop } %% yes: pop off the 'dict' returned\n");
fprintf(fp," { %% no: define one\n");
fprintf(fp," /colortogray { %% define an RGB->I function\n");
fprintf(fp," /rgbdata exch store %% call input 'rgbdata'\n");
fprintf(fp," rgbdata length 3 idiv\n");
fprintf(fp," /npixls exch store\n");
fprintf(fp," /rgbindx 0 store\n");
fprintf(fp," /grays npixls string store %% str to hold the result\n");
fprintf(fp," 0 1 npixls 1 sub {\n");
fprintf(fp," grays exch\n");
fprintf(fp," rgbdata rgbindx get 20 mul %% Red\n");
fprintf(fp," rgbdata rgbindx 1 add get 32 mul %% Green\n");
fprintf(fp," rgbdata rgbindx 2 add get 12 mul %% Blue\n");
fprintf(fp," add add 64 idiv %% I = .5G + .31R + .18B\n");
fprintf(fp," put\n");
fprintf(fp," /rgbindx rgbindx 3 add store\n");
fprintf(fp," } for\n");
fprintf(fp," grays\n");
fprintf(fp," } bind def\n\n");
fprintf(fp," %% Utility procedure for colorimage operator.\n");
fprintf(fp," %% This procedure takes two procedures off the\n");
fprintf(fp," %% stack and merges them into a single procedure.\n\n");
fprintf(fp," /mergeprocs { %% def\n");
fprintf(fp," dup length\n");
fprintf(fp," 3 -1 roll\n");
fprintf(fp," dup\n");
fprintf(fp," length\n");
fprintf(fp," dup\n");
fprintf(fp," 5 1 roll\n");
fprintf(fp," 3 -1 roll\n");
fprintf(fp," add\n");
fprintf(fp," array cvx\n");
fprintf(fp," dup\n");
fprintf(fp," 3 -1 roll\n");
fprintf(fp," 0 exch\n");
fprintf(fp," putinterval\n");
fprintf(fp," dup\n");
fprintf(fp," 4 2 roll\n");
fprintf(fp," putinterval\n");
fprintf(fp," } bind def\n\n");
fprintf(fp," /colorimage { %% def\n");
fprintf(fp," pop pop %% remove 'false 3' operands\n");
fprintf(fp," {colortogray} mergeprocs\n");
fprintf(fp," image\n");
fprintf(fp," } bind def\n");
fprintf(fp," } ifelse %% end of 'false' case\n");
fprintf(fp,"\n\n\n");
}
/**********************************************/
static void psColorMap(fp, color, nc, rmap, gmap, bmap)
FILE *fp;
int color, nc;
byte *rmap, *gmap, *bmap;
{
/* spits out code for the colormap of the following image
if !color, it spits out a mono-ized graymap */
int i;
fprintf(fp,"%% define the colormap\n");
fprintf(fp,"/cmap %d string def\n\n\n", nc * ((color) ? 3 : 1));
fprintf(fp,"%% load up the colormap\n");
fprintf(fp,"currentfile cmap readhexstring\n");
for (i=0; i<nc; i++) {
if (color) fprintf(fp,"%02x%02x%02x ", rmap[i],gmap[i],bmap[i]);
else fprintf(fp,"%02x ", MONO(rmap[i],gmap[i],bmap[i]));
if ((i%10) == 9) fprintf(fp,"\n");
}
if (i%10) fprintf(fp,"\n");
fprintf(fp,"pop pop %% lose return values from readhexstring\n\n\n");
}
/**********************************************/
static void psRleCmapImage(fp, color)
FILE *fp;
{
/* spits out code that defines the 'rlecmapimage' operator */
fprintf(fp,"%% rlecmapimage expects to have 'w h bits matrix' on stack\n");
fprintf(fp,"/rlecmapimage {\n");
fprintf(fp," /buffer 1 string def\n");
fprintf(fp," /rgbval 3 string def\n");
fprintf(fp," /block 384 string def\n\n");
fprintf(fp," %% proc to read a block from file, and return RGB data\n");
fprintf(fp," { currentfile buffer readhexstring pop\n");
fprintf(fp," /bcount exch 0 get store\n");
fprintf(fp," bcount 128 ge\n");
fprintf(fp," { %% it's a non-run block\n");
fprintf(fp," 0 1 bcount 128 sub\n");
fprintf(fp," { currentfile buffer readhexstring pop pop\n\n");
if (color) {
fprintf(fp," %% look up value in color map\n");
fprintf(fp,"%s/rgbval cmap buffer 0 get 3 mul 3 getinterval store\n\n",
" ");
fprintf(fp," %% and put it in position i*3 in block\n");
fprintf(fp," block exch 3 mul rgbval putinterval\n");
fprintf(fp," } for\n");
fprintf(fp," block 0 bcount 127 sub 3 mul getinterval\n");
fprintf(fp," }\n\n");
}
else {
fprintf(fp," %% look up value in gray map\n");
fprintf(fp,"%s/rgbval cmap buffer 0 get 1 getinterval store\n\n",
" ");
fprintf(fp," %% and put it in position i in block\n");
fprintf(fp," block exch rgbval putinterval\n");
fprintf(fp," } for\n");
fprintf(fp," block 0 bcount 127 sub getinterval\n");
fprintf(fp," }\n\n");
}
fprintf(fp," { %% else it's a run block\n");
fprintf(fp," currentfile buffer readhexstring pop pop\n\n");
if (color) {
fprintf(fp," %% look up value in colormap\n");
fprintf(fp,"%s/rgbval cmap buffer 0 get 3 mul 3 getinterval store\n\n",
" ");
fprintf(fp,"%s0 1 bcount { block exch 3 mul rgbval putinterval } for\n\n",
" ");
fprintf(fp," block 0 bcount 1 add 3 mul getinterval\n");
}
else {
fprintf(fp," %% look up value in graymap\n");
fprintf(fp," /rgbval cmap buffer 0 get 1 getinterval store\n\n");
fprintf(fp," 0 1 bcount { block exch rgbval putinterval } for\n\n");
fprintf(fp," block 0 bcount 1 add getinterval\n");
}
fprintf(fp," } ifelse\n");
fprintf(fp," } %% end of proc\n");
if (color) fprintf(fp," false 3 colorimage\n");
else fprintf(fp," image\n");
fprintf(fp,"} bind def\n\n\n");
}
/**********************************************/
static void epsPreview(fp, pic, colorType, w, h)
FILE *fp;
byte *pic;
int colorType;
int w, h;
{
byte *prev;
/* put in an EPSI preview */
if (colorType != F_BWDITHER) { /* have to generate a preview */
prev = (byte *) malloc(w * h);
if (!prev) {
fprintf(stderr,"Unable to malloc in epsPreview\n");
return;
}
FSDither(pic, w, h, prev);
}
else prev = pic;
fprintf(fp,"%%%%BeginPreview: %d %d %d %d\n", w, h, 1,
(w/(72*4) + 1) * h);
writeBWStip(fp, prev, "% ", w, h);
fprintf(fp,"%%%%EndPreview\n");
if (colorType == F_BWDITHER) free(prev);
}
/***********************************/
static int writeBWStip(fp, pic, prompt, w, h)
FILE *fp;
byte *pic;
char *prompt;
int w, h;
{
/* write the given 'pic' (B/W stippled, 1 byte per pixel, 0=blk,1=wht)
out as hexadecimal, max of 72 hex chars per line.
returns '0' if everythings fine, 'EOF' if writing failed */
int err, i, j, lwidth;
byte outbyte, bitnum, bit;
err = 0;
for (i=0; i<h && err != EOF; i++) {
fprintf(fp, "%s", prompt);
outbyte = bitnum = lwidth = 0;
if ((i&0x3f) == 0) WaitCursor();
for (j=0; j<w && err != EOF; j++) {
bit = *pic;
outbyte = (outbyte<<1) | ((bit)&0x01);
bitnum++;
if (bitnum==8) {
err = fprintf(fp,"%02x",outbyte);
lwidth+=2;
outbyte = bitnum = 0;
}
if (lwidth>=72 && j+1<w) { fprintf(fp, "\n%s", prompt); lwidth = 0; }
pic++;
}
if (bitnum) { /* few bits left over... */
for ( ; bitnum<8; bitnum++) outbyte <<= 1;
err = fprintf(fp,"%02x",outbyte);
lwidth+=2;
}
fprintf(fp, "\n");
}
return err;
}