#ident "@(#)VOGLE:driver/hpgl2.c - VOGLE driver for HPGL2/2" #ident "@(#)VOGLE:author - John S. Urban" #ident "@(#)VOGLE:version - 1.0," #include <stdio.h> #include <stdlib.h> #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 static char P_REESTABLISH[80]; /* 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 char CLEAR_DEVICE[100]; /******************************************************************************/ /* 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 */ /******************************************************************************/ static int HPGL2_PORT_init() { /* 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() { /* 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() { /* 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() { /* 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)); } /******************************************************************************/ /* Performs the common parts of HPGL2 initialization. */ static int HPGL2_common_init(minx, maxx, miny, maxy) int minx, maxx, miny, maxy; { vdevice.depth = 3; 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*/ plotcmds = HPGL2; strncpy(CLEAR_DEVICE,plotcmds[P_CLEAR],100); /* this has parameters sometimes so it is treated differently */ plotlstx = -1111111; plotlsty = -1111111; drawn = 0; return(1); } /******************************************************************************/ /* Performs the common parts of PCL5 initialization. */ static int PCL5_common_init(minx, maxx, miny, maxy) int minx, maxx, miny, maxy; { vdevice.depth = 3; fp = _voutfile(); /* (exit PCL5 mode) Enter HPGL2 mode, cause scaling to be 0 to maxX maxY */ sprintf(CLEAR_DEVICE, "\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,CLEAR_DEVICE); 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(1); } /******************************************************************************/ /* Performs the common parts of HPGL2 initialization in portrait mode */ static int HPGL2_common_initp(minx, maxx, miny, maxy) int minx, maxx, miny, maxy; { vdevice.depth = 3; 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; strncpy(CLEAR_DEVICE,plotcmds[P_CLEAR],100); /* this has parameters sometimes so it is treated differently */ plotlstx = -1111111; plotlsty = -1111111; drawn = 0; return(1); } /******************************************************************************/ /* Performs the common parts of PCL5 initialization in portrait mode */ static int PCL5_common_initp(minx, maxx, miny, maxy) int minx, maxx, miny, maxy; { vdevice.depth = 3; fp = _voutfile(); /* (exit PCL5 mode) Enter HPGL2 mode, cause scaling to be 0 to maxX maxY , rotate 90 degrees */ sprintf(CLEAR_DEVICE, "\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,CLEAR_DEVICE); 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(1); } /******************************************************************************/ /* * PLOT_draw * * print the commands to draw a line from the current graphics position * to (x, y). */ static PLOT_draw(x, y) int x, 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; } /******************************************************************************/ /* PLOT_exit * exit from vogle printing the command to put away the pen and flush the buffer. */ static PLOT_exit() { 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; } /******************************************************************************/ /* PLOT_clear flush current page without resetting graphics state of printer */ static PLOT_clear() { if (drawn){ /* CLEAR_DEVICE is plotcmds[P_CLEAR]) expanded to a fixed string for this device format */ fprintf(fp, CLEAR_DEVICE); } drawn = 0; } /******************************************************************************/ /* * PLOT_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 PLOT_color(i) int i; { static float line_width = 0.2; if ( i < 0 ) { if ( i == -1 ) { line_width=0.0; /* HPGL2 will draw thinnest line possible */ } else { line_width=abs(i)*.085; /* approximately one raster at 300dpi is .085 mm */ } fprintf(fp,plotcmds[P_WIDE] , line_width); } 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); } } /******************************************************************************/ /* * PLOT_setlw * * set the line width in raster units * use of -1 value implies use thinnest line */ static PLOT_setlw(int i) { static float line_width = 0.2; if ( i <= -1 ) { line_width=0.0; /* HPGL2 will draw thinnest line possible */ } else { line_width=(float)vdevice.sizeX/10000.0*abs(i); /* figure number of rasters */ /* approximately one raster at 300dpi is .085 mm */ line_width=line_width*3.333*0.085; } fprintf(fp,plotcmds[P_WIDE] , line_width); } /******************************************************************************/ /* change index i in the color map to the appropriate rgb value. */ PLOT_mapcolor(i, r, g, b) int i; int r, g, b; { /* fprintf(stderr, "mapcolor = %d %d %d %d\n", i,r,g,b); */ if (i >= CMAPSIZE || i < 0 ){ return(-1); } if (i >= CMAPSIZE) return(0); fprintf(fp, "PC%d,%d,%d,%d\n", i, r, g, b); return(0); } /******************************************************************************/ /* * HPGL2_font * * load in large or small */ static int HPGL2_font(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); } /******************************************************************************/ /* * PLOT_char * * draw a character. */ static int PLOT_char(char c) { int dy, dx; 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; } /******************************************************************************/ /* output a string. */ static PLOT_string(s) char *s; { int dy, dx; 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; } /******************************************************************************/ /* "fill" a polygon */ static PLOT_fill(n, x, y) int n, x[], 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; } /******************************************************************************/ static DevEntry HPGL2dev = { "HPGL2", "large", "small", noop, PLOT_char, noop, PLOT_clear, PLOT_color, PLOT_draw, PLOT_exit, PLOT_fill, HPGL2_font, noop, noop, HPGL2_LAND_init, noop, PLOT_mapcolor, PLOT_setlw, PLOT_string, noop, noop }; /******************************************************************************/ /* * _HPGL2_devcpy * * copy the HPGL2 device into vdevice.dev. */ _HPGL2_A2_devcpy() { /* if you don't have structure assignment ... char *dev, *tdev, *edev; dev = (char *)&HPGL2dev; tdev = (char *)&vdevice.dev; edev = dev + sizeof(Device); while (dev != edev) *tdev++ = *dev++; */ vdevice.dev = HPGL2dev; } /******************************************************************************/ _PCL5_LAND_devcpy() { vdevice.dev = HPGL2dev; vdevice.dev.Vinit = PCL5_LAND_init; } /******************************************************************************/ _PCL5_PORT_devcpy() { vdevice.dev = HPGL2dev; vdevice.dev.Vinit = PCL5_PORT_init; } /******************************************************************************/ _HPGL2_PORT_devcpy() { vdevice.dev = HPGL2dev; vdevice.dev.Vinit = HPGL2_PORT_init; } /******************************************************************************/ _HPGL2_LAND_devcpy() { vdevice.dev = HPGL2dev; vdevice.dev.Vinit = HPGL2_LAND_init; } /******************************************************************************/