#ident "@(#)VOGLE:driver/pcl5.c - VOGLE driver for PCL5 and HPGL2"
#ident "@(#)VOGLE:author - John S. Urban"
#ident "@(#)VOGLE:version - 1.0, Dec 1996"
/*
HPGL2/2 Driver for vogle John S. Urban. Last updated: Wed Dec 11, 1996
This driver generates HPGL2 and PCL5 commands.
It obeys the prefsize() procedure (resolution is assumed to be 1000
rasters per inch as far as addressability is concerned).
Driver names are hpgl2port, hpgl2land, ppcl5port, pcl5land.
I have used PCL5 on a variety of HP LaserJets, LexMark printers, and
HPGL2 on 36" CALCOMP plotters with an HPGL2 mode with good success.
WordPerfect and other PC packages do a reasonable job of importing the
HPGL2 files.
*/
#include
#include
#include
#include "vogle.h"
#define MIN(x,y) ((x) < (y) ? (x) : (y))
extern FILE *_voutfile();
static int drawn = 0;
static int plotlstx, plotlsty; /* position of last draw */
extern FILE *fp;
#define CMAPSIZE 256
#define P_RESET 0
#define P_MOVE 1
#define P_DRAW 2
#define P_TXTSIZE 3
#define P_BEGTXT 4
#define P_ENDTXT 5
#define P_PEN 6
#define P_WIDE 7
#define P_CLEAR 8
#define P_EXIT 9
#define P_FILL 10
#define P_ENDFILL 11
#define P_BREAKFILL 12
/* basic commands for HPGL2 */
static char *HPGL2[] = {
"DF;\n",
"PU%d,%d;\n",
"PD%d,%d;\n",
"SI%.4f,%.4f;\n",
"LB",
"\003\n",
"SP%d;\n",
"PW%.4f;\n",
"PG;\n",
"\033.)\n",
"PM0",
"PM2;FP0;EP", /* exit polygon mode fill polygon using odd-even algorithm; fill polygon; edge-fill polygon */
"PM1"
};
/* basic commands for pcl5 */
static char *pcl5[] = {
"DF;\n",
"PU%d,%d;\n",
"PD%d,%d;\n",
"SI%.4f,%.4f;\n",
"LB",
"\003\n",
"SP%d;\n",
"PW%.4f;\n",
" ", /* "\033%%1A\033E\n\033&l2A\033&l1O\033%%1B\n", */
"\033%%1A\033E\n",
"PM0\n",
"PM2;FP0;EP\n", /* exit polygon mode fill polygon using odd-even algorithm; fill polygon; edge-fill polygon */
"PM1\n"
};
static char **plotcmds;
static int HPGL2_mapcolor(int i,int r,int g,int b);
/******************************************************************************/
/*
CORRECT THESE NOTES:
prefxs and prefys are preferred plotting area size in rasters
prefy is the BOTTOM margin on this - make big note in manual
NON-INTUITIVE for LANDSCAPE: prefx is the LEFT margin
A4 : 10200 x 7320
A3 : 14720 x 10560
A2 : 18734 x 13440
A1 : 29774 x 21360
17 x 11 : 15370 x 10259
8.5 x 11: 7650 x 9540
11 x 8.5: 9540 x 7650
*/
/******************************************************************************/
/* Performs the common parts of HPGL2 initialization. */
static int HPGL2_common_init(int minx,int maxx,int miny,int maxy){
vdevice.depth = 8;
fp = _voutfile();
/* * The next line is for serial lines if you need to set modes */
fprintf(fp, "\033.(;\033.I81;;17;\033.N;19:IN;");
/* * Cause scaling to be 0 to maxX maxY. */
fprintf(fp, "IP%d,%d,%d,%d;", minx, miny, maxx, maxy);
fprintf(fp, "SC0,%d,0,%d;", vdevice.sizeSx, vdevice.sizeSy);
fprintf(fp,"TR0;\n"); /* transparency mode off, white areas are opaque */
fprintf(fp,"NP256;\n"); /* Establish the number of pens in the HPGL/2 palette*/
fprintf(fp,"CR0,255,0,255,0,255;\n"); /* set color range for relative color data in the HPGL/2 palette*/
HPGL2_mapcolor( 0,255,255,255); /* black */
HPGL2_mapcolor( 1,255,0 ,0 ); /* red */
HPGL2_mapcolor( 2,0 ,255,0 ); /* green */
HPGL2_mapcolor( 3,255,255,0 ); /* yellow */
HPGL2_mapcolor( 4,0 ,0 ,255); /* blue */
HPGL2_mapcolor( 5,255,0 ,255); /* magenta */
HPGL2_mapcolor( 6,0 ,255,255); /* cyan */
HPGL2_mapcolor( 7,0 ,0 ,0 ); /* white */
HPGL2_mapcolor( 8,155,0 ,0 ); /* */
HPGL2_mapcolor( 9,0 ,155,0 ); /* */
HPGL2_mapcolor(10,155,255,255); /* */
HPGL2_mapcolor(11,155,155,0 ); /* */
HPGL2_mapcolor(12,0 ,0 ,155); /* */
HPGL2_mapcolor(13,155,0 ,155); /* */
HPGL2_mapcolor(14,0 ,155,155); /* */
HPGL2_mapcolor(15,100,100,100); /* */
plotcmds = HPGL2;
plotlstx = -1111111;
plotlsty = -1111111;
drawn = 0;
return(UNUSED);
}
/******************************************************************************/
/* Performs the common parts of PCL5 initialization. */
static int PCL5_common_init(int minx, int maxx, int miny, int maxy) {
vdevice.depth = 8;
fp = _voutfile();
/* (exit PCL5 mode) Enter HPGL2 mode, cause scaling to be 0 to maxX maxY */
pcl5[P_CLEAR]=malloc(100);
sprintf(pcl5[P_CLEAR], "\033%%%%1A\033E\n\033&l2A\033&l1O\033%%%%1B\nIP%d,%d,%d,%d;SC0,%d,0,%d;",
minx, miny, maxx, maxy, vdevice.sizeSx, vdevice.sizeSy);
fprintf(fp,pcl5[P_CLEAR]);
fprintf(fp,"TR0;\n"); /* transparency mode off, white areas are opaque */
fprintf(fp,"NP256;\n"); /* Establish the number of pens in the HPGL/2 palette*/
fprintf(fp,"CR0,255,0,255,0,255;\n"); /* set color range for relative color data in the HPGL/2 palette*/
plotcmds = pcl5;
plotlstx = -1111111;
plotlsty = -1111111;
drawn = 0;
return(UNUSED);
}
/******************************************************************************/
/* Performs the common parts of HPGL2 initialization in portrait mode */
static int HPGL2_common_initp(int minx, int maxx, int miny, int maxy) {
vdevice.depth = 8;
fp = _voutfile();
/* * The next line is for serial lines if you need to set modes */
fprintf(fp, "\033.(;\033.I81;;17;\033.N;19:IN;");
/* * Cause scaling to be 0 to maxX maxY. */
fprintf(fp, "IP%d,%d,%d,%d;", minx, miny, maxx, maxy);
fprintf(fp, "SC0,%d,0,%d;", vdevice.sizeSx, vdevice.sizeSy);
fprintf(fp, "RO90;"); /* rotate 90 degrees */
fprintf(fp,"TR0;\n"); /* transparency mode off, white areas are opaque */
fprintf(fp,"NP256;\n"); /* Establish the number of pens in the HPGL/2 palette*/
fprintf(fp,"CR0,255,0,255,0,255;\n"); /* set color range for relative color data in the HPGL/2 palette*/
plotcmds = HPGL2;
plotlstx = -1111111;
plotlsty = -1111111;
drawn = 0;
return(UNUSED);
}
/******************************************************************************/
/* Performs the common parts of PCL5 initialization in portrait mode */
static int PCL5_common_initp(int minx,int maxx,int miny,int maxy) {
vdevice.depth = 8;
fp = _voutfile();
/* (exit PCL5 mode) Enter HPGL2 mode, cause scaling to be 0 to maxX maxY , rotate 90 degrees */
pcl5[P_CLEAR]=malloc(100);
sprintf(pcl5[P_CLEAR], "\033%%%%1A\033E\n\033&l2A\033&l1O\033%%%%1B\nIP%d,%d,%d,%d;SC0,%d,0,%d;RO90;",
minx, miny, maxx, maxy, vdevice.sizeSx, vdevice.sizeSy);
fprintf(fp,pcl5[P_CLEAR]);
fprintf(fp,"TR0;\n"); /* transparency mode off, white areas are opaque */
fprintf(fp,"NP256;\n"); /* Establish the number of pens in the HPGL/2 palette*/
fprintf(fp,"CR0,255,0,255,0,255;\n"); /* set color range for relative color data in the HPGL/2 palette*/
plotcmds = pcl5;
plotlstx = -1111111;
plotlsty = -1111111;
drawn = 0;
return(UNUSED);
}
/******************************************************************************/
static int HPGL2_PORT_init(void) {
/* 8.5 x 11 portrait paper Letter size - JSU */
int prefx, prefy, prefxs, prefys;
vogle_getprefposandsize(&prefx, &prefy, &prefxs, &prefys);
if (prefxs != -1 ) {
vdevice.sizeSy = prefys;
vdevice.sizeSx = prefxs;
vdevice.sizeX = vdevice.sizeY = MIN(prefys, prefxs );
}else{
prefx = 0;
prefy = 0;
vdevice.sizeSx = 7650;
vdevice.sizeSy = 9540;
vdevice.sizeX = vdevice.sizeY = 7650;
}
return(HPGL2_common_initp(prefx, vdevice.sizeSx+prefx, prefy, vdevice.sizeSy+prefy));
}
/******************************************************************************/
static int PCL5_PORT_init(void) {
/* 8.5 x 11 portrait paper Letter size - JSU */
int prefx, prefy, prefxs, prefys;
vogle_getprefposandsize(&prefx, &prefy, &prefxs, &prefys);
if (prefxs != -1 ) {
vdevice.sizeSy = prefys;
vdevice.sizeSx = prefxs;
vdevice.sizeX = vdevice.sizeY = MIN(prefys, prefxs );
}else{
prefx = 0;
prefy = 0;
vdevice.sizeSx = 7650;
vdevice.sizeSy = 9540;
vdevice.sizeX = vdevice.sizeY = 7650;
}
return(PCL5_common_initp(prefx, vdevice.sizeSx+prefx, prefy, vdevice.sizeSy+prefy));
}
/******************************************************************************/
static int HPGL2_LAND_init(void) {
/* 8.5 x 11 landscape paper Letter size - JSU */
int prefx, prefy, prefxs, prefys;
vogle_getprefposandsize(&prefx, &prefy, &prefxs, &prefys);
if (prefxs != -1 ) {
vdevice.sizeSy = prefys;
vdevice.sizeSx = prefxs;
vdevice.sizeX = vdevice.sizeY = MIN(prefys, prefxs );
}else{
prefx = 0;
prefy = 0;
vdevice.sizeSy = 7650;
vdevice.sizeSx = 9540;
vdevice.sizeX = vdevice.sizeY = 7650;
}
return(HPGL2_common_init(prefx, vdevice.sizeSx+prefx, prefy, vdevice.sizeSy+prefy));
}
/******************************************************************************/
static int PCL5_LAND_init(void) {
/* 8.5 x 11 landscape paper Letter size - JSU */
int prefx, prefy, prefxs, prefys;
vogle_getprefposandsize(&prefx, &prefy, &prefxs, &prefys);
if (prefxs != -1 ) {
vdevice.sizeSy = prefys;
vdevice.sizeSx = prefxs;
vdevice.sizeX = vdevice.sizeY = MIN(prefys, prefxs );
}else{
prefx = 0;
prefy = 0;
vdevice.sizeSy = 7650;
vdevice.sizeSx = 9540;
vdevice.sizeX = vdevice.sizeY = 7650;
}
return(PCL5_common_init(prefx, vdevice.sizeSx+prefx, prefy, vdevice.sizeSy+prefy));
}
/******************************************************************************/
/*
* HPGL2_draw
*
* print the commands to draw a line from the current graphics position
* to (x, y).
*/
static int HPGL2_draw(int x, int y) {
if (plotlstx != vdevice.cpVx || plotlsty != vdevice.cpVy)
fprintf(fp, plotcmds[P_MOVE], vdevice.cpVx, vdevice.cpVy);
fprintf(fp, plotcmds[P_DRAW], x, y);
plotlstx = x;
plotlsty = y;
drawn = 1;
return(UNUSED);
}
/******************************************************************************/
/* HPGL2_exit
* exit from vogle printing the command to put away the pen and flush the buffer.
*/
static int HPGL2_exit(void) {
fprintf(fp, plotcmds[P_PEN], 0);
fprintf(fp, plotcmds[P_EXIT]);
fflush(fp);
if (fp != stdout && fp != stderr ){
fflush(fp);
if(vdevice.writestoprocess == 2){
pclose(fp);
}else{
fclose(fp);
}
}
drawn = 1;
return(UNUSED);
}
/******************************************************************************/
/* HPGL2_clear flush current page without resetting graphics state of printer
*/
static int HPGL2_clear(void) {
if (drawn){
fprintf(fp, plotcmds[P_CLEAR]);
}
drawn = 0;
return(UNUSED);
}
/******************************************************************************/
static int HPGL2_setlw(int i) {
static float line_width = 0.2;
if ( i <= -1 ) {
line_width=0.0; /* hpgl will draw thinnest line possible */
} else {
line_width=(float)vdevice.sizeX/10000.0*abs(i); /* figure number of rasters */
/*
Assuming pen width is in mm and 300dpi resolution
1 "raster" =1/300 inch
1inch=25.4mm
:= approximately one raster at 300dpi is .085 mm
*/
line_width=line_width*0.0846666/4.0;
}
fprintf(fp,plotcmds[P_WIDE] , line_width);
return(UNUSED);
}
/******************************************************************************/
/*
* HPGL2_color
*
* change the current pen number.
*
* set the current drawing color index if ind >= 0.
* set the line width in raster units if ind < 0.
* use of -1 value implies use thinnest line
*/
static int HPGL2_color(int i) {
static float line_width = 0.2;
if ( i < 0 )
{
HPGL2_setlw(abs(i));
} else {
fprintf(fp, plotcmds[P_PEN], i);
/*
The pen thickness might return to the default each time
a new pen is selected in HPGL2; but vogle expects
these properties to be separate. Newer versions of HPGL2 documentation
indicate that PW stays in effect until a PU or another PW command
is encountered; but an older manual states that the pen thickness
returns to the default value when a new pen is selected. A third
possibility is that each pen retains its last thickness so I think
it is better to force it each time a pen number is selected.
Could reduce redundant calls by checking if same as last call
*/
fprintf(fp,plotcmds[P_WIDE] , line_width);
}
return(UNUSED);
}
/******************************************************************************/
/* change index i in the color map to the appropriate rgb value. */
static int HPGL2_mapcolor(int i,int r,int g,int b) {
/* fprintf(stderr, "mapcolor = %d %d %d %d\n", i,r,g,b); */
if (i >= CMAPSIZE || i < 0 ){
return(-1);
}
if (i >= CMAPSIZE){
return(UNUSED);
}
fprintf(fp, "PC%d,%d,%d,%d\n", i, r, g, b);
return(UNUSED);
}
/******************************************************************************/
/*
* HPGL2_font
*
* load in large or small
*/
static int HPGL2_font(char *font) {
if (strcmp(font, "small") == 0) {
vdevice.hwidth = 97.01; /* Size in plotter resolution units */
vdevice.hheight = vdevice.hwidth * 2.0;
fprintf(fp, plotcmds[P_TXTSIZE], 0.16, 0.32);
} else if (strcmp(font, "large") == 0) {
vdevice.hwidth = 145.5;
vdevice.hheight = vdevice.hwidth * 2.0;
fprintf(fp, plotcmds[P_TXTSIZE], 0.24, 0.48);
} else
return(0);
return(1);
}
/******************************************************************************/
/*
* HPGL2_char
*
* draw a character.
*/
static int HPGL2_char(char c) {
if (plotlstx != vdevice.cpVx || plotlsty != vdevice.cpVy)
fprintf(fp, plotcmds[P_MOVE], vdevice.cpVx, vdevice.cpVy);
fprintf(fp, plotcmds[P_BEGTXT]);
fprintf(fp, "%c", c);
fprintf(fp, plotcmds[P_ENDTXT]);
plotlstx = plotlsty = -1111111;
drawn = 1;
return(UNUSED);
}
/******************************************************************************/
/* output a string. */
static int HPGL2_string(char *s) {
if (plotlstx != vdevice.cpVx || plotlsty != vdevice.cpVy)
fprintf(fp, plotcmds[P_MOVE], vdevice.cpVx, vdevice.cpVy);
fprintf(fp, plotcmds[P_BEGTXT]);
fputs(s, fp);
fprintf(fp, plotcmds[P_ENDTXT]);
plotlstx = plotlsty = -1111111;
drawn = 1;
return(UNUSED);
}
/******************************************************************************/
/* "fill" a polygon */
static int HPGL2_fill(int n, int x[], int y[]) {
int i;
int xclose, yclose, move_draw;
xclose=x[0];
yclose=y[0];
if (plotlstx != x[0] || plotlsty != y[0])
fprintf(fp, plotcmds[P_MOVE], x[0], y[0]); /* update current position if needed */
fprintf(fp, plotcmds[P_FILL]); /* enter polygon mode */
move_draw=P_DRAW;
for (i = 1; i < n; i++){
/* If not last point in list and hit first point close this as a subpolygon */
if (x[i] == xclose && y[i] == yclose && (i != (n-1)) )
{
fprintf(fp, plotcmds[P_DRAW], x[i], y[i]); /* define polygon vertices */
fprintf(fp, plotcmds[P_BREAKFILL]); /* end subpolygon */
move_draw=P_MOVE; /* move to first point in next subpolygon */
}else{
fprintf(fp, plotcmds[move_draw],x[i],y[i]); /* define polygon vertices */
move_draw=P_DRAW; /* if moving because starting a new subpolygon return to drawing */
}
}
fprintf(fp, plotcmds[P_ENDFILL]); /* end polygon and fill it */
fprintf(fp, plotcmds[P_MOVE], x[n-1], y[n-1]); /* current position should be last one moved to, not x0,y0 */
plotlstx = vdevice.cpVx = x[n - 1];
plotlsty = vdevice.cpVy = y[n - 1];
drawn = 1;
return(UNUSED);
}
/******************************************************************************/
/* no operations - do nothing but return -1 */
static int noop(void) { return(-1); }
static int noop2(int *x, int *y) { return(-1); }
/******************************************************************************/
static DevEntry HPGL2dev = {
"HPGL2", /* char *devname -- name of device */
"large", /* char *large -- name of large font */
"small", /* char *small -- name of small font */
noop, /* int (*Vbackb)() -- Set drawing in back buffer */
HPGL2_char, /* int (*Vchar)() -- Draw a hardware character */
noop, /* int (*Vcheckkey)() -- Check if a key was hit */
HPGL2_clear, /* int (*Vclear)() -- Clear screen to current color */
HPGL2_color, /* int (*Vcolor)() -- Set current color */
HPGL2_draw, /* int (*Vdraw)() -- Draw a line */
HPGL2_exit, /* int (*Vexit)() -- Exit graphics */
HPGL2_fill, /* int (*Vfill)() -- Fill a polygon */
HPGL2_font, /* int (*Vfont)() -- Set hardware font */
noop, /* int (*Vfrontb)() -- Set drawing in front buffer */
noop, /* int (*Vgetkey)() -- Wait for and get next key hit */
HPGL2_LAND_init,/* int (*Vinit)() -- Initialise device */
noop2, /* int (*Vlocator)() -- Get mouse/cross hair position */
HPGL2_mapcolor, /* int (*Vmapcolor)() -- Set color indices */
HPGL2_setlw, /* Set line width */
HPGL2_string, /* int (*Vstring)() -- Draw a hardware string */
noop, /* int (*Vswapb)() -- Swap front and back buffers */
noop /* int (*Vsync)() -- Syncronise display */
};
/******************************************************************************/
int _PCL5_LAND_devcpy(void){ /* copy the PCL5 landscape device into vdevice.dev. */
vdevice.dev = HPGL2dev;
vdevice.dev.Vinit = PCL5_LAND_init;
/* if you don't have structure assignment ... this would set Vinit
char *dev, *tdev, *edev;
dev = (char *)&HPGL2dev;
tdev = (char *)&vdevice.dev;
edev = dev + sizeof(Device);
while (dev != edev)
*tdev++ = *dev++;
*/
return(UNUSED);
}
/******************************************************************************/
int _PCL5_PORT_devcpy(void){/* copy the PCL5 portrait device into vdevice.dev. */
vdevice.dev = HPGL2dev;
vdevice.dev.Vinit = PCL5_PORT_init;
return(UNUSED);
}
/******************************************************************************/
int _HPGL2_PORT_devcpy(void){/* copy the HPGL2 portrait device into vdevice.dev. */
vdevice.dev = HPGL2dev;
vdevice.dev.Vinit = HPGL2_PORT_init;
return(UNUSED);
}
/******************************************************************************/
int _HPGL2_LAND_devcpy(void){/* copy the HPGL2 landscape device into vdevice.dev. */
vdevice.dev = HPGL2dev;
vdevice.dev.Vinit = HPGL2_LAND_init;
return(UNUSED);
}
/******************************************************************************/