Rev 9642 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka* Copyright (C) 1998--2000 Robert Gentleman, Ross Ihaka and the* R Development Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <ctype.h>#include "Defn.h"#include "Graphics.h"#include "Error.h"#include "Fileio.h"#define PS_minus_default 45/* wrongly was 177 (plusminus);hyphen = 45 or 173; (n-dash not available as code!)175 = "¯" (= "overline" (= high 'negative' sign))*/static char PS_minus = PS_minus_default;/*-> TODO: make this a ps.option() !*//* Part 0. AFM File Names *//* This structure gives the set of font names for each type face. *//* They also give the official Adobe abbreviated name which is used *//* for files such as those which contain the font metrics. */static struct {char *family;struct {char *name;char *abbr;} font[5];}Family[] = {{ "AvantGarde",{{ "AvantGarde-Book", "agw_____" },{ "AvantGarde-Demi", "agd_____" },{ "AvantGarde-BookOblique", "agwo____" },{ "AvantGarde-DemiOblique", "agdo____" },{ "Symbol", "sy______" }}},{ "Bookman",{{ "Bookman-Light", "bkl_____" },{ "Bookman-Demi", "bkd_____" },{ "Bookman-LightItalic", "bkli____" },{ "Bookman-DemiItalic", "bkdi____" },{ "Symbol", "sy______" }}},{ "Courier",{{ "Courier", "com_____" },{ "Courier-Bold", "cob_____" },{ "Courier-Oblique", "coo_____" },{ "Courier-BoldOblique", "cobo____" },{ "Symbol", "sy______" }}},{ "Helvetica",{{ "Helvetica", "hv______" },{ "Helvetica-Bold", "hvb_____" },{ "Helvetica-Oblique", "hvo_____" },{ "Helvetica-BoldOblique", "hvbo____" },{ "Symbol", "sy______" }}},#ifdef NOTYET{ "Helvetica-Condensed",{{ "Helvetica-Condensed", "hvc_____" },{ "Helvetica-Condensed-Bold", "hvcb____" },{ "Helvetica-Condensed-Oblique", "hvcdo___" },{ "Helvetica-Condensed-BoldObl", "hvnbo___" },{ "Symbol", "sy______" }}},#endif{ "Helvetica-Narrow",{{ "Helvetica-Narrow", "hvn_____" },{ "Helvetica-Narrow-Bold", "hvnb____" },{ "Helvetica-Narrow-Oblique", "hvno____" },{ "Helvetica-Narrow-BoldOblique", "hvnbo___" },{ "Symbol", "sy______" }}},{ "NewCenturySchoolbook",{{ "NewCenturySchlbk-Roman", "ncr_____" },{ "NewCenturySchlbk-Bold", "ncb_____" },{ "NewCenturySchlbk-Italic", "nci_____" },{ "NewCenturySchlbk-BoldItalic", "ncbi____" },{ "Symbol", "sy______" }}},{ "Palatino",{{ "Palatino-Roman", "por_____" },{ "Palatino-Bold", "pob_____" },{ "Palatino-Italic", "poi_____" },{ "Palatino-BoldItalic", "pobi____" },{ "Symbol", "sy______" }}},{ "Times",{{ "Times-Roman", "tir_____" },{ "Times-Bold", "tib_____" },{ "Times-Italic", "tii_____" },{ "Times-BoldItalic", "tibi____" },{ "Symbol", "sy______" }}},{ NULL }};/* These are the file extensions used on metrics files. */static char *Extension[] = {"afm", /* AdobeStandardEncoding (Unused) */"lt1", /* ISOLatin1Encoding */"lt2", /* ISOLatin2Encoding */0};/* Part 1. AFM File Parsing. *//* These are the basic entities in the AFM file */#define BUFSIZE 512typedef struct {unsigned char c1;unsigned char c2;short kern;} KP;typedef struct {short FontBBox[4];short CapHeight;short XHeight;short Descender;short Ascender;struct {short WX;short BBox[4];} CharInfo[256];KP *KernPairs;short KPstart[256];short KPend[256];short nKP;} FontMetricInfo;enum {Empty,StartFontMetrics,Comment,FontName,EncodingScheme,FullName,FamilyName,Weight,ItalicAngle,IsFixedPitch,UnderlinePosition,UnderlineThickness,Version,Notice,FontBBox,CapHeight,XHeight,Descender,Ascender,StartCharMetrics,C,EndCharMetrics,StartKernData,StartKernPairs,KPX,EndKernPairs,EndKernData,StartComposites,CC,EndComposites,EndFontMetrics,Unknown};static struct {char *keyword;int code;}KeyWordDictionary[] = {{ "StartFontMetrics", StartFontMetrics },{ "Comment", Comment },{ "FontName", FontName },{ "EncodingScheme", EncodingScheme },{ "FullName", FullName },{ "FamilyName", FamilyName },{ "Weight", Weight },{ "ItalicAngle", ItalicAngle },{ "IsFixedPitch", IsFixedPitch },{ "UnderlinePosition", UnderlinePosition },{ "UnderlineThickness", UnderlineThickness },{ "Version", Version },{ "Notice", Notice },{ "FontBBox", FontBBox },{ "CapHeight", CapHeight },{ "XHeight", XHeight },{ "Descender", Descender },{ "Ascender", Ascender },{ "StartCharMetrics", StartCharMetrics },{ "C ", C },{ "EndCharMetrics", EndCharMetrics },{ "StartKernData", StartKernData },{ "StartKernPairs", StartKernPairs },{ "KPX ", KPX },{ "EndKernPairs", EndKernPairs },{ "EndKernData", EndKernData },{ "StartComposites", StartComposites },{ "CC ", CC },{ "EndComposites", EndComposites },{ "EndFontMetrics", EndFontMetrics },{ NULL, Unknown },};static int MatchKey(char *l, char *k){while (*k)if (*k++ != *l++) return 0;return 1;}static int KeyType(char *s){int i;if (*s == '\n')return Empty;for (i = 0; KeyWordDictionary[i].keyword; i++)if (MatchKey(s, KeyWordDictionary[i].keyword))return KeyWordDictionary[i].code;return Unknown;}static char *SkipToNextItem(char *p){while (!isspace((int)*p)) p++;while (isspace((int)*p)) p++;return p;}static char *SkipToNextKey(char *p){while (*p != ';') p++;p++;while (isspace((int)*p)) p++;return p;}static int GetFontBBox(char *buf, FontMetricInfo *metrics){if (sscanf(buf, "FontBBox %hd %hd %hd %hd",&(metrics->FontBBox[0]),&(metrics->FontBBox[1]),&(metrics->FontBBox[2]),&(metrics->FontBBox[3])) != 4) return 0;#ifdef DEBUG_PSRprintf("FontBBox %d %d %d %d\n",(metrics->FontBBox[0]),(metrics->FontBBox[1]),(metrics->FontBBox[2]),(metrics->FontBBox[3]));#endifreturn 1;}static char charnames[256][25];static int GetCharInfo(char *buf, FontMetricInfo *metrics){char *p = buf;int nchar;if (!MatchKey(buf, "C ")) return 0;p = SkipToNextItem(p);sscanf(p, "%d", &nchar);if (nchar < 0) return 1;p = SkipToNextKey(p);if (!MatchKey(p, "WX")) return 0;p = SkipToNextItem(p);sscanf(p, "%hd", &(metrics->CharInfo[nchar].WX));p = SkipToNextKey(p);if (!MatchKey(p, "N ")) return 0;p = SkipToNextItem(p);sscanf(p, "%s", charnames[nchar]);p = SkipToNextKey(p);if (!MatchKey(p, "B ")) return 0;p = SkipToNextItem(p);sscanf(p, "%hd %hd %hd %hd",&(metrics->CharInfo[nchar].BBox[0]),&(metrics->CharInfo[nchar].BBox[1]),&(metrics->CharInfo[nchar].BBox[2]),&(metrics->CharInfo[nchar].BBox[3]));#ifdef DEBUG_PSRprintf("nchar = %d %d %d %d %d %d\n", nchar,metrics->CharInfo[nchar].WX,metrics->CharInfo[nchar].BBox[0],metrics->CharInfo[nchar].BBox[1],metrics->CharInfo[nchar].BBox[2],metrics->CharInfo[nchar].BBox[3]);#endifreturn 1;}static int GetKPX(char *buf, int nkp, FontMetricInfo *metrics){char *p = buf, c1[50], c2[50];int i, done = 0;p = SkipToNextItem(p);sscanf(p, "%s %s %hd", c1, c2, &(metrics->KernPairs[nkp].kern));for(i = 0; i < 256; i++) {if (!strcmp(c1, charnames[i])) {metrics->KernPairs[nkp].c1 = i;done++;break;}}for(i = 0; i < 256; i++)if (!strcmp(c2, charnames[i])) {metrics->KernPairs[nkp].c2 = i;done++;break;}return (done==2);}/* Load Fontmetrics from a File */int PostScriptLoadFontMetrics(char *fontname, FontMetricInfo *metrics){char buf[BUFSIZE], *p;int mode, i = 0, ii, nKPX=0;FILE *fp;if (!(fp = R_fopen(fontname, "r"))) return 0;mode = 0;for (ii = 0; ii < 256; ii++) charnames[ii][0] = '\0';while (fgets(buf, BUFSIZE, fp)) {switch(KeyType(buf)) {case StartFontMetrics:mode = StartFontMetrics;break;case EndFontMetrics:mode = 0;break;case FontBBox:if (!GetFontBBox(buf, metrics)) goto error;break;case C:if (mode != StartFontMetrics) goto error;if (!GetCharInfo(buf, metrics)) goto error;break;case StartKernData:mode = StartKernData;break;case StartKernPairs:if(mode != StartKernData) goto error;p = SkipToNextItem(p=buf);sscanf(p, "%d", &nKPX);metrics->KernPairs = (KP *) malloc(nKPX * sizeof(KP));if (!metrics->KernPairs) goto error;break;case KPX:if(mode != StartKernData || i >= nKPX) goto error;if (GetKPX(buf, i, metrics)) i++;break;case EndKernData:mode = 0;break;case Unknown:printf("Warning: unknown AFM entity encountered");break;case Empty:default:break;}}metrics->nKP = i;fclose(fp);/* Make an index for kern-pair searches: relies on having contiguousblocks by first char for efficiency, but works in all cases. */{int j;short ind, tmp;for (j = 0; j < 256; j++) {metrics->KPstart[j] = i;metrics->KPend[j] = 0;}for (j = 0; j < i; j++) {ind = metrics->KernPairs[j].c1;tmp = metrics->KPstart[ind];if(j < tmp) metrics->KPstart[ind] = j;tmp = metrics->KPend[ind];if(j > tmp) metrics->KPend[ind] = j;}}return 1;error:fclose(fp);return 0;}double PostScriptStringWidth(unsigned char *p, FontMetricInfo *metrics){int sum = 0, i;unsigned char p1, p2;for ( ; *p; p++) {if (*p == '-' && isdigit(p[1]))sum += metrics->CharInfo[(int)PS_minus].WX;elsesum += metrics->CharInfo[*p].WX;/* check for kerning adjustment */p1 = p[0]; p2 = p[1];for (i = metrics->KPstart[p1]; i < metrics->KPend[p1]; i++)/* second test is a safety check: should all start with p1 */if(metrics->KernPairs[i].c2 == p2 &&metrics->KernPairs[i].c1 == p1) {sum += metrics->KernPairs[i].kern;break;}}return 0.001 * sum;}void PostScriptMetricInfo(int c, double *ascent, double *descent,double *width, FontMetricInfo *metrics){if (c == 0) {*ascent = 0.001 * metrics->FontBBox[3];*descent = -0.001 * metrics->FontBBox[1];*width = 0.001 * (metrics->FontBBox[2] - metrics->FontBBox[0]);}else {*ascent = 0.001 * metrics->CharInfo[c].BBox[3];*descent = -0.001 * metrics->CharInfo[c].BBox[1];*width = 0.001 * metrics->CharInfo[c].WX;}}/* Part 2. Graphics Support Code. */static char *TypeFaceDef[] = { "R", "B", "I", "BI", "S" };static void PSEncodeFont(FILE *fp, int index, int encoding){int i;for (i = 0; i < 4 ; i++) {fprintf(fp, "/%s findfont\n", Family[index].font[i].name);fprintf(fp, "dup length dict begin\n");fprintf(fp, " {1 index /FID ne {def} {pop pop} ifelse} forall\n");if (encoding) fprintf(fp, " /Encoding ISOLatin1Encoding def\n");fprintf(fp, " currentdict\n");fprintf(fp, " end\n");fprintf(fp, "/Font%d exch definefont pop\n", i + 1);}fprintf(fp, "/Symbol findfont\n");fprintf(fp, "dup length dict begin\n");fprintf(fp, " {1 index /FID ne {def} {pop pop} ifelse} forall\n");fprintf(fp, " currentdict\n");fprintf(fp, " end\n");fprintf(fp, "/Font5 exch definefont pop\n");}/* The variables "paperwidth" and "paperheight" give the dimensions *//* of the (unrotated) printer page in points whereas the graphics *//* region box is for the rotated page. */static void PSFileHeader(FILE *fp, int font, int encoding, char *papername,double paperwidth, double paperheight, int landscape,int EPSFheader,double left, double bottom, double right, double top){if(EPSFheader)fprintf(fp, "%%!PS-Adobe-3.0 EPSF-3.0\n");elsefprintf(fp, "%%!PS-Adobe-3.0\n");fprintf(fp, "%%%%DocumentFonts: %s %s %s\n%%%%+ %s %s\n",Family[font].font[0].name, Family[font].font[1].name,Family[font].font[2].name, Family[font].font[3].name,Family[font].font[4].name);if(!EPSFheader)fprintf(fp, "%%%%DocumentMedia: %s %.0f %.0f 0 ()\n",papername, paperwidth, paperheight);fprintf(fp, "%%%%Title: R Graphics Output\n");fprintf(fp, "%%%%Creator: R Software\n");fprintf(fp, "%%%%Pages: (atend)\n");if (landscape) {fprintf(fp, "%%%%Orientation: Landscape\n");fprintf(fp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",left, bottom, right, top);/* This appears to be wrong, use *same* BBox as Portraitbottom, left, top, right);*/}else {fprintf(fp, "%%%%Orientation: Portrait\n");fprintf(fp, "%%%%BoundingBox: %.0f %.0f %.0f %.0f\n",left, bottom, right, top);}fprintf(fp, "%%%%EndComments\n");fprintf(fp, "%%%%BeginProlog\n");fprintf(fp, "/gs { gsave } def\n");fprintf(fp, "/gr { grestore } def\n");if (landscape)fprintf(fp, "/bp { gs %.2f 0 translate 90 rotate} def\n", paperwidth);elsefprintf(fp, "/bp { gs } def\n");fprintf(fp, "/ep { showpage gr } def\n");fprintf(fp, "/m { moveto } def\n");fprintf(fp, "/l { lineto } def\n");fprintf(fp, "/np { newpath } def\n");fprintf(fp, "/cp { closepath } def\n");fprintf(fp, "/f { fill } def\n");fprintf(fp, "/o { stroke } def\n");fprintf(fp, "/c { newpath 0 360 arc } def\n");fprintf(fp, "/r { 3 index 3 index moveto 1 index 4 -1 roll\n");fprintf(fp, " lineto exch 1 index lineto lineto closepath } def\n");fprintf(fp, "/p1 { stroke } def\n");fprintf(fp, "/p2 { bg setrgbcolor fill fg setrgbcolor } def\n");fprintf(fp, "/p3 { gsave bg setrgbcolor fill grestore stroke } def\n");fprintf(fp, "/t { 6 -2 roll moveto gsave rotate\n");fprintf(fp, " ps mul neg 0 2 1 roll rmoveto\n");fprintf(fp, " 1 index stringwidth pop\n");fprintf(fp, " mul neg 0 rmoveto show grestore } def\n");fprintf(fp, "/cl { initclip newpath 3 index 3 index moveto 1 index\n");fprintf(fp, " 4 -1 roll lineto exch 1 index lineto lineto\n");fprintf(fp, " closepath clip newpath } def\n");fprintf(fp, "/rgb { setrgbcolor } def\n");fprintf(fp, "/s { scalefont setfont } def\n");fprintf(fp, "/R { /Font1 findfont } def\n");fprintf(fp, "/B { /Font2 findfont } def\n");fprintf(fp, "/I { /Font3 findfont } def\n");fprintf(fp, "/BI { /Font4 findfont } def\n");fprintf(fp, "/S { /Font5 findfont } def\n");PSEncodeFont(fp, font, encoding);fprintf(fp, "1 setlinecap 1 setlinejoin\n");fprintf(fp, "%%%%EndProlog\n");}void PostScriptFileTrailer(FILE *fp, int pageno){fprintf(fp, "ep\n");fprintf(fp, "%%%%Trailer\n");fprintf(fp, "%%%%Pages: %d\n", pageno);fprintf(fp, "%%%%EOF\n");}void PostScriptStartPage(FILE *fp, int pageno){fprintf(fp, "%%%%Page: %d %d\n", pageno, pageno);fprintf(fp, "bp\n");}void PostScriptEndPage(FILE *fp){fprintf(fp, "ep\n");}void PostScriptSetClipRect(FILE *fp, double x0, double x1,double y0, double y1){fprintf(fp, "%.2f %.2f %.2f %.2f cl\n", x0, y0, x1, y1);}void PostScriptSetLineWidth(FILE *fp, double linewidth){fprintf(fp, "%.2f setlinewidth\n", linewidth);}void PostScriptSetFont(FILE *fp, int typeface, double size){fprintf(fp, "/ps %.0f def %s %.0f s\n", size, TypeFaceDef[typeface], size);}void PostScriptSetColor(FILE *fp, double r, double g, double b){fprintf(fp,"%.4f %.4f %.4f rgb\n", r, g, b);}void PostScriptSetLineTexture(FILE *fp, int *lty, int nlty, double lwd){double dash;int i;fprintf(fp,"[");for (i = 0; i < nlty; i++) {dash = (lwd >= 1 ? lwd:1) * ((i % 2) ? lty[i] + 1 : lty[i] - 1);if (dash < 0) dash = 0;fprintf(fp," %.2f", dash);}fprintf(fp,"] 0 setdash\n");}void PostScriptMoveTo(FILE *fp, double x, double y){fprintf(fp, "%.2f %.2f m\n", x, y);}void PostScriptLineTo(FILE *fp, double x, double y){fprintf(fp, "%.2f %.2f l\n", x, y);}void PostScriptStartPath(FILE *fp){fprintf(fp, "np\n");}void PostScriptEndPath(FILE *fp){fprintf(fp, "o\n");}void PostScriptRectangle(FILE *fp, double x0, double y0, double x1, double y1){fprintf(fp, "%.2f %.2f %.2f %.2f r ", x0, y0, x1, y1);}void PostScriptCircle(FILE *fp, double x, double y, double r){fprintf(fp, "%.2f %.2f %.2f c ", x, y, r);}static void PostScriptWriteString(FILE *fp, char *str){fputc('(', fp);for ( ; *str; str++)switch(*str) {case '\n':fprintf(fp, "\\n");break;case '\\':fprintf(fp, "\\\\");break;case '-':if (isdigit((int)str[1]))fputc(PS_minus, fp);elsefputc(*str, fp);break;case '(':case ')':fprintf(fp, "\\%c", *str);break;default:fputc(*str, fp);break;}fputc(')', fp);}void PostScriptText(FILE *fp, double x, double y,char *str, double xc, double yc, double rot){fprintf(fp, "%.2f %.2f ", x, y);PostScriptWriteString(fp, str);fprintf(fp, " %.2f %.2f %.2f t\n", xc, yc, rot);}/* Part 3. Device Driver State. */typedef struct {char filename[PATH_MAX];int open_type;char papername[64]; /* paper name */int paperwidth; /* paper width in big points (1/72 in) */int paperheight; /* paper height in big points */int landscape; /* landscape mode */int pageno; /* page number */int fontfamily; /* font family */int encoding; /* font encoding */int fontstyle; /* font style, R, B, I, BI, S */int fontsize; /* font size in points */int maxpointsize;double width; /* plot width in inches */double height; /* plot height in inches */double pagewidth; /* page width in inches */double pageheight; /* page height in inches */int pagecentre; /* centre image on page? */int printit; /* print page at close? */char command[PATH_MAX];double lwd; /* current line width */int lty; /* current line type */rcolor col; /* current color */rcolor fill; /* current fill color */rcolor bg; /* background color */FILE *psfp; /* output file */int onefile; /* EPSF header etc*/}PostScriptDesc;static FontMetricInfo metrics[5]; /* font metrics *//* Device Driver Actions */static void PS_Activate(DevDesc*);static void PS_Circle(double, double, int, double, int, int, DevDesc*);static void PS_Clip(double, double, double, double, DevDesc*);static void PS_Close(DevDesc*);static void PS_Deactivate(DevDesc*);static void PS_Hold(DevDesc*);static void PS_Line(double, double, double, double, int, DevDesc*);static int PS_Locator(double*, double*, DevDesc*);static void PS_Mode(int, DevDesc*);static void PS_NewPage(DevDesc*);static int PS_Open(DevDesc*, PostScriptDesc*);static void PS_Polygon(int, double*, double*, int, int, int, DevDesc*);static void PS_Polyline(int, double*, double*, int, DevDesc*);static void PS_Rect(double, double, double, double, int, int, int, DevDesc*);static void PS_Resize(DevDesc*);static double PS_StrWidth(char*, DevDesc*);static void PS_MetricInfo(int, double*, double*, double*, DevDesc*);static void PS_Text(double, double, int, char*, double, double, DevDesc*);/* PostScript Support (formally in PostScript.c) */static void PostScriptSetCol(FILE *fp, double r, double g, double b){fprintf(fp,"/fg { %.4f %.4f %.4f } def fg rgb\n", r, g, b);}static void PostScriptSetFill(FILE *fp, double r, double g, double b){fprintf(fp,"/bg { %.4f %.4f %.4f } def\n", r, g, b);}/* Driver Support Routines */static void SetColor(int, DevDesc*);static void SetFill(int, DevDesc*);static void SetFont(int, int, DevDesc*);static void SetLineStyle(int newlty, double newlwd, DevDesc *dd);static int MatchFamily(char *name);int PSDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,char *bg, char *fg,double width, double height,double horizontal, double ps,int onefile, int pagecentre, int printit, char*cmd){/* If we need to bail out with some sort of "error" *//* then we must free(dd) */double xoff, yoff, pointsize;PostScriptDesc *pd;/* Check and extract the device parameters */if(strlen(file) > PATH_MAX - 1) {free(dd);error("filename too long in postscript");}/* allocate new postscript device description */if (!(pd = (PostScriptDesc *) malloc(sizeof(PostScriptDesc))))return 0;/* from here on, if need to bail out with "error", must also *//* free(pd) *//* initialise postscript device description */strcpy(pd->filename, file);strcpy(pd->papername, paper);pd->fontfamily = MatchFamily(family);pd->encoding = 1;pd->bg = str2col(bg);pd->col = str2col(fg);pd->fill = NA_INTEGER;pd->width = width;pd->height = height;pd->landscape = horizontal;pointsize = floor(ps);if(pd->bg == NA_INTEGER && pd->col == NA_INTEGER) {free(dd);free(pd);error("invalid foreground/background color (postscript)");}pd->printit = printit;strcpy(pd->command, cmd);if (printit && strlen(cmd) == 0)error("postscript(prinit.it=T) used with an empty print command");strcpy(pd->command, cmd);/* Deal with paper and plot size and orientation */if(!strcmp(pd->papername, "Default") ||!strcmp(pd->papername, "default")) {SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);if(s != NA_STRING && strlen(CHAR(s)) > 0)strcpy(pd->papername, CHAR(s));else strcpy(pd->papername, "a4");}if(!strcmp(pd->papername, "A4") ||!strcmp(pd->papername, "a4")) {pd->pagewidth = 21.0 / 2.54;pd->pageheight = 29.7 /2.54;}else if(!strcmp(pd->papername, "Letter") ||!strcmp(pd->papername, "letter")) {pd->pagewidth = 8.5;pd->pageheight = 11.0;}else if(!strcmp(pd->papername, "Legal") ||!strcmp(pd->papername, "legal")) {pd->pagewidth = 8.5;pd->pageheight = 14.0;}else if(!strcmp(pd->papername, "Executive") ||!strcmp(pd->papername, "executive")) {pd->pagewidth = 7.25;pd->pageheight = 10.5;}else if(!strcmp(pd->papername, "special")) {if(pd->landscape) {pd->pagewidth = height;pd->pageheight = width;} else {pd->pagewidth = width;pd->pageheight = height;}}else {free(dd);free(pd);error("invalid page type `%s' (postscript)", pd->papername);}pd->pagecentre = pagecentre;pd->paperwidth = 72 * pd->pagewidth;pd->paperheight = 72 * pd->pageheight;pd->onefile = onefile;if(pd->landscape) {double tmp;tmp = pd->pagewidth;pd->pagewidth = pd->pageheight;pd->pageheight = tmp;}if(strcmp(pd->papername, "special")){if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)pd->width = pd->pagewidth-0.5;if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)pd->height = pd->pageheight-0.5;}if(pagecentre){xoff = (pd->pagewidth - pd->width)/2.0;yoff = (pd->pageheight - pd->height)/2.0;} else {xoff = yoff = 0.0;}pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?pd->pageheight : pd->pagewidth);pd->pageno = 0;pd->lty = 1;/* Set graphics parameters that must be set by device driver. *//* Page dimensions in points. */dd->dp.bg = pd->bg;dd->dp.fg = dd->dp.col = pd->col;dd->dp.left = 72 * xoff; /* left */dd->dp.right = 72 * (xoff + pd->width); /* right */dd->dp.bottom = 72 * yoff; /* bottom */dd->dp.top = 72 * (yoff + pd->height); /* top *//* Base Pointsize *//* Nominal Character Sizes in Pixels *//* Only right for 12 point font. *//* Max pointsize suggested by Peter Dalgaard */if(pointsize < 6.0) pointsize = 6.0;if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;dd->dp.ps = pointsize;dd->dp.cra[0] = 0.9 * pointsize;dd->dp.cra[1] = 1.2 * pointsize;/* Character Addressing Offsets *//* These offsets should center a single *//* plotting character over the plotting point. *//* Pure guesswork and eyeballing ... */dd->dp.xCharOffset = 0.4900;dd->dp.yCharOffset = 0.3333;dd->dp.yLineBias = 0.2;/* Inches per Raster Unit *//* We use points (72 dots per inch) */dd->dp.ipr[0] = 1.0/72.0;dd->dp.ipr[1] = 1.0/72.0;/* GREset(.) dd->gp.mkh = dd->gp.cra[0] * dd->gp.ipr[0]; */dd->dp.canResizePlot = 0;dd->dp.canChangeFont = 1;dd->dp.canRotateText = 1;dd->dp.canResizeText = 1;dd->dp.canClip = 1;dd->dp.canHAdj = 2;/* Start the driver */pd->pageno = 0;if(!PS_Open(dd, pd)) {free(pd);return 0;}dd->dp.open = PS_Open;dd->dp.close = PS_Close;dd->dp.activate = PS_Activate;dd->dp.deactivate = PS_Deactivate;dd->dp.resize = PS_Resize;dd->dp.newPage = PS_NewPage;dd->dp.clip = PS_Clip;dd->dp.text = PS_Text;dd->dp.strWidth = PS_StrWidth;dd->dp.metricInfo = PS_MetricInfo;dd->dp.rect = PS_Rect;dd->dp.circle = PS_Circle;dd->dp.line = PS_Line;dd->dp.polygon = PS_Polygon;dd->dp.polyline = PS_Polyline;dd->dp.locator = PS_Locator;dd->dp.mode = PS_Mode;dd->dp.hold = PS_Hold;dd->deviceSpecific = (void *) pd;dd->displayListOn = 0;return 1;}static int MatchFamily(char *name){int i;for(i = 0; Family[i].family != NULL; i++)if(!strcmp(name, Family[i].family)) return i;warning("unknown postscript font family, using %s",Family[3].family);return 3;}static void SetColor(int color, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;if(color != pd->col) {PostScriptSetCol(pd->psfp,R_RED(color)/255.0,R_GREEN(color)/255.0,R_BLUE(color)/255.0);pd->col = color;}}static void SetFill(int color, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;if(color != pd->fill) {PostScriptSetFill(pd->psfp,R_RED(color)/255.0,R_GREEN(color)/255.0,R_BLUE(color)/255.0);pd->fill = color;}}/* Note that the line texture is scaled by the line width. */static void SetLineStyle(int newlty, double newlwd, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;int i, ltyarray[8];if (pd->lty != newlty || pd->lwd != newlwd) {pd->lwd = newlwd;pd->lty = newlty;PostScriptSetLineWidth(pd->psfp, dd->gp.lwd*0.75);/* process lty : */for(i = 0; i < 8 && newlty & 15 ; i++) {ltyarray[i] = newlty & 15;newlty = newlty >> 4;}PostScriptSetLineTexture(pd->psfp, ltyarray, i, dd->gp.lwd * 0.75);}}static void SetFont(int style, int size, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;if(style < 1 || style > 5)style = 1;if(size < 1 || size > pd->maxpointsize)size = 10;if(size != pd->fontsize || style != pd->fontstyle) {PostScriptSetFont(pd->psfp, style-1, size);pd->fontsize = size;pd->fontstyle = style;}}static int PS_Open(DevDesc *dd, PostScriptDesc *pd){char buf[512];int i;for(i = 0; i < 5 ; i++) {sprintf(buf, "%s/afm/%s.%s", R_Home,Family[pd->fontfamily].font[i].abbr,(i == 4) ? "afm" : Extension[pd->encoding]);if(!PostScriptLoadFontMetrics(buf, &(metrics[i])))return 0;}if (strlen(pd->filename) == 0) {#ifndef HAVE_POPENerror("printing via file = \"\" is not implemented in this version");return 0;#elseif(strlen(pd->command) == 0) return 0;pd->psfp = popen(pd->command, "w");pd->open_type = 1;#endif} else if (pd->filename[0] == '|') {#ifndef HAVE_POPENerror("file = \"|cmd\" is not implemented in this version");return 0;#elsepd->psfp = popen(pd->filename + 1, "w");pd->open_type = 1;#endif} else {sprintf(buf, pd->filename, pd->pageno + 1); /* page 1 to start */pd->psfp = R_fopen(R_ExpandFileName(buf), "w");pd->open_type = 0;}if (!pd->psfp) return 0;if(pd->landscape)PSFileHeader(pd->psfp,pd->fontfamily,pd->encoding,pd->papername,pd->paperwidth,pd->paperheight,pd->landscape,!(pd->onefile),dd->dp.bottom,dd->dp.left,dd->dp.top,dd->dp.right);elsePSFileHeader(pd->psfp,pd->fontfamily,pd->encoding,pd->papername,pd->paperwidth,pd->paperheight,pd->landscape,!(pd->onefile),dd->dp.left,dd->dp.bottom,dd->dp.right,dd->dp.top);pd->fontstyle = 1;pd->fontsize = 10;return 1;}static void PS_Clip(double x0, double x1, double y0, double y1, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;PostScriptSetClipRect(pd->psfp, x0, x1, y0, y1);}static void PS_Resize(DevDesc *dd){}static void PostScriptClose(DevDesc *dd);static void PS_NewPage(DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;if(pd->onefile) {if(++pd->pageno > 1) PostScriptEndPage(pd->psfp);} else if(pd->pageno > 0) {PostScriptClose(dd);PS_Open(dd, pd);pd->pageno++;pd->fill = NA_INTEGER;} else pd->pageno++;PostScriptStartPage(pd->psfp, pd->pageno);PostScriptSetFont(pd->psfp, pd->fontstyle-1, pd->fontsize);PostScriptSetLineWidth(pd->psfp, 0.75);PostScriptSetCol(pd->psfp,R_RED(pd->col)/255.0,R_GREEN(pd->col)/255.0,R_BLUE(pd->col)/255.0);if(dd->dp.bg != R_RGB(255,255,255)) {SetFill(dd->dp.bg, dd);PostScriptRectangle(pd->psfp,0, 0, 72.0 * pd->pagewidth, 72.0 * pd->pageheight);fprintf(pd->psfp, "p2\n");}}#ifdef Win32int runcmd(char *cmd, int wait, int visible, char *finput);#endifstatic void PostScriptClose(DevDesc *dd){char buff[PATH_MAX];int err = 0;PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;PostScriptFileTrailer(pd->psfp, pd->pageno);if(pd->open_type == 1)pclose(pd->psfp);else {fclose(pd->psfp);if (pd->printit) {strcpy(buff, pd->command);strcat(buff, " ");strcat(buff, pd->filename);/* Rprintf("buff is %s\n", buff); */#ifdef Unixerr = system(buff);#endif#ifdef Win32err = runcmd(buff, 0, 0, NULL);#endifif (err)warning("error from postscript() in running:\n %s", buff);}}}static void PS_Close(DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;PostScriptClose(dd);free(pd);}static void PS_Activate(DevDesc *dd) {}static void PS_Deactivate(DevDesc *dd) {}static double PS_StrWidth(char *str, DevDesc *dd){return floor(dd->gp.cex * dd->gp.ps + 0.5) *PostScriptStringWidth((unsigned char *)str, &(metrics[dd->gp.font-1]));}static void PS_MetricInfo(int c, double *ascent, double *descent,double *width, DevDesc *dd){PostScriptMetricInfo(c, ascent, descent, width, &(metrics[dd->gp.font-1]));*ascent = floor(dd->gp.cex * dd->gp.ps + 0.5) * *ascent;*descent = floor(dd->gp.cex * dd->gp.ps + 0.5) * *descent;*width = floor(dd->gp.cex * dd->gp.ps + 0.5) * *width;}#ifdef NOT_used_currently/*-- out 'def' (-Wall) --*/static void PS_MoveTo(double x, double y, int coords, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;GConvert(&x, &y, coords, DEVICE, dd);PostScriptMoveTo(pd->psfp, x, y);}static void PS_StartPath(DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;SetColor(dd->gp.col, dd);SetLineStyle(dd->gp.lty, dd->lwd, dd);PostScriptStartPath(pd->psfp);}static void PS_EndPath(DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;PostScriptEndPath(pd->psfp);}#endifstatic void PS_Rect(double x0, double y0, double x1, double y1, int coords,int bg, int fg, DevDesc *dd){int code;PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;/* code is set as follows *//* code == 0, nothing to draw *//* code == 1, outline only *//* code == 2, fill only *//* code == 3, outline and fill */code = 2 * (bg != NA_INTEGER) + (fg != NA_INTEGER);if (code) {if(code & 2)SetFill(bg, dd);if(code & 1) {SetColor(fg, dd);SetLineStyle(dd->gp.lty, dd->gp.lwd, dd);}GConvert(&x0, &y0, coords, DEVICE, dd);GConvert(&x1, &y1, coords, DEVICE, dd);PostScriptRectangle(pd->psfp, x0, y0, x1, y1);fprintf(pd->psfp, "p%d\n", code);}}static void PS_Circle(double x, double y, int coords, double r,int bg, int fg, DevDesc *dd){int code;PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;/* code is set as follows *//* code == 0, nothing to draw *//* code == 1, outline only *//* code == 2, fill only *//* code == 3, outline and fill */code = 2 * (bg != NA_INTEGER) + (fg != NA_INTEGER);if (code) {if(code & 2)SetFill(bg, dd);if(code & 1) {SetColor(fg, dd);SetLineStyle(dd->gp.lty, dd->gp.lwd, dd);}GConvert(&x, &y, coords, DEVICE, dd);PostScriptCircle(pd->psfp, x, y, r);fprintf(pd->psfp, "p%d\n", code);}}static void PS_Line(double x1, double y1, double x2, double y2,int coords, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;GConvert(&x1, &y1, coords, DEVICE, dd);GConvert(&x2, &y2, coords, DEVICE, dd);/* FIXME : clip to the device extents here */SetColor(dd->gp.col, dd);SetLineStyle(dd->gp.lty, dd->gp.lwd, dd);PostScriptStartPath(pd->psfp);PostScriptMoveTo(pd->psfp, x1, y1);PostScriptLineTo(pd->psfp, x2, y2);PostScriptEndPath(pd->psfp);}static void PS_Polygon(int n, double *x, double *y, int coords,int bg, int fg, DevDesc *dd){PostScriptDesc *pd;double xx, yy;int i, code;pd = (PostScriptDesc *) dd->deviceSpecific;/* code is set as follows *//* code == 0, nothing to draw *//* code == 1, outline only *//* code == 2, fill only *//* code == 3, outine and fill */code = 2 * (bg != NA_INTEGER) + (fg != NA_INTEGER);if (code) {if(code & 2)SetFill(bg, dd);if(code & 1) {SetColor(fg, dd);SetLineStyle(dd->gp.lty, dd->gp.lwd, dd);}fprintf(pd->psfp, "np\n");xx = x[0];yy = y[0];GConvert(&xx, &yy, coords, DEVICE, dd);fprintf(pd->psfp, " %.2f %.2f m\n", xx, yy);for(i = 1 ; i < n ; i++) {xx = x[i];yy = y[i];GConvert(&xx, &yy, coords, DEVICE, dd);fprintf(pd->psfp, " %.2f %.2f l\n", xx, yy);}fprintf(pd->psfp, "cp p%d\n", code);}}static void PS_Polyline(int n, double *x, double *y, int coords,DevDesc *dd){PostScriptDesc *pd;double xx, yy;int i;pd = (PostScriptDesc*) dd->deviceSpecific;SetColor(dd->gp.col, dd);SetLineStyle(dd->gp.lty, dd->gp.lwd, dd);fprintf(pd->psfp, "np\n");xx = x[0];yy = y[0];GConvert(&xx, &yy, coords, DEVICE, dd);fprintf(pd->psfp, "%.2f %.2f m\n", xx, yy);for(i = 1 ; i < n ; i++) {xx = x[i];yy = y[i];GConvert(&xx, &yy, coords, DEVICE, dd);fprintf(pd->psfp, "%.2f %.2f l\n", xx, yy);}fprintf(pd->psfp, "o\n");}static void PS_Text(double x, double y, int coords,char *str, double rot, double hadj, DevDesc *dd){PostScriptDesc *pd = (PostScriptDesc *) dd->deviceSpecific;GConvert(&x, &y, coords, DEVICE, dd);SetFont(dd->gp.font, (int)floor(dd->gp.cex * dd->gp.ps + 0.5), dd);SetColor(dd->gp.col, dd);PostScriptText(pd->psfp, x, y, str, hadj, 0.0, rot);}static int PS_Locator(double *x, double *y, DevDesc *dd){return 0;}static void PS_Mode(int mode, DevDesc* dd){}static void PS_Hold(DevDesc *dd){}/***********************************************************************XFig driver shares font handling************************************************************************/typedef struct {char filename[PATH_MAX];char papername[64]; /* paper name */int paperwidth; /* paper width in big points (1/72 in) */int paperheight; /* paper height in big points */int landscape; /* landscape mode */int pageno; /* page number */int fontfamily; /* font family */int fontnum; /* font number in XFig */int encoding; /* font encoding */int fontstyle; /* font style, R, B, I, BI, S */int fontsize; /* font size in points */int maxpointsize;double width; /* plot width in inches */double height; /* plot height in inches */double pagewidth; /* page width in inches */double pageheight; /* page height in inches */int pagecentre; /* centre image on page? */double lwd; /* current line width */int lty; /* current line type */rcolor col; /* current color */rcolor fill; /* current fill color */rcolor bg; /* background color */int XFigColors[534]; int nXFigColors;FILE *psfp; /* output file */FILE *tmpfp; /* temp file */char tmpname[PATH_MAX];int onefile;int ymax; /* used to invert coord system */} XFigDesc;/* TODOline stylesmore accurate text positioning. Ross suggests using XFig justificationif appropriate.*/static voidXF_FileHeader(FILE *fp, char *papername, int landscape, int onefile){fprintf(fp, "#FIG 3.2\n");if(landscape) fprintf(fp, "Landscape\n"); else fprintf(fp, "Portrait\n");fprintf(fp, "Flush Left\nInches\n");/* Fix */fprintf(fp, "%s\n", papername);fprintf(fp, "100.0\n");if(onefile) fprintf(fp, "Multiple\n");else fprintf(fp, "Single\n");fprintf(fp, "-2\n"); /* no background */fprintf(fp, "1200 2\n"); /* coordinate system */fprintf(fp, "# End of XFig header\n");}static void XF_FileTrailer(FILE *fp){fprintf(fp, "# end of XFig file\n");}static void XF_EndPage(FILE *fp){fprintf(fp, "# end of XFig page\n");}static void XF_WriteString(FILE *fp, char *str){unsigned int c;for ( ; *str; str++) {c = (unsigned char)*str;if (c > 127) {fprintf(fp, "\\%o", c);} else {switch(*str) {case '\n':fprintf(fp, "\\n");break;case '\\':fprintf(fp, "\\\\");break;default:fputc(*str, fp);break;}}}}static int XF_SetColor(int color, XFigDesc *pd){int i;if (color <0 || color > 0xffffff) return -1;for (i = 0; i < pd->nXFigColors; i++){if(color == pd->XFigColors[i]) return i;}if(pd->nXFigColors == 534) {error("run out of colors in xfig()");}/* new colour */fprintf(pd->psfp, "0 %d #%02x%02x%02x\n", pd->nXFigColors,R_RED(color), R_GREEN(color), R_BLUE(color));pd->XFigColors[pd->nXFigColors] = color;return pd->nXFigColors++;}static void XFconvert(double *x, double *y, XFigDesc *pd){(*x) *= 16.667;(*y) = pd->ymax - 16.667*(*y);}static int XF_SetLty(int lty){switch(lty) {case LTY_SOLID:case 1: /* "solid" */return 0;case LTY_DASHED:return 1;case LTY_DOTTED:return 2;case LTY_DOTDASH:return 3;default:warning("unimplemented line texture %u: using Dash-double-dotted",lty);return 4;}}/* Device Driver Actions */static void XFig_Activate(DevDesc*);static void XFig_Circle(double, double, int, double, int, int, DevDesc*);static void XFig_Clip(double, double, double, double, DevDesc*);static void XFig_Close(DevDesc*);static void XFig_Deactivate(DevDesc*);static void XFig_Hold(DevDesc*);static void XFig_Line(double, double, double, double, int, DevDesc*);static int XFig_Locator(double*, double*, DevDesc*);static void XFig_Mode(int, DevDesc*);static void XFig_NewPage(DevDesc*);static int XFig_Open(DevDesc*, XFigDesc*);static void XFig_Polygon(int, double*, double*, int, int, int, DevDesc*);static void XFig_Polyline(int, double*, double*, int, DevDesc*);static void XFig_Rect(double, double, double, double, int, int, int, DevDesc*);static void XFig_Resize(DevDesc*);static void XFig_Text(double, double, int, char*, double, double, DevDesc*);static int XFig_basenums[] = {4, 8, 12, 16, 20, 24, 28, 0};/* Driver Support Routines */int XFigDeviceDriver(DevDesc *dd, char *file, char *paper, char *family,char *bg, char *fg,double width, double height,double horizontal, double ps,int onefile, int pagecentre){/* If we need to bail out with some sort of "error" *//* then we must free(dd) */double xoff, yoff, pointsize;XFigDesc *pd;/* Check and extract the device parameters */if(strlen(file) > PATH_MAX - 1) {free(dd);error("filename too long in xfig");}/* allocate new xfig device description */if (!(pd = (XFigDesc *) malloc(sizeof(XFigDesc))))return 0;/* from here on, if need to bail out with "error", must also *//* free(pd) *//* initialize xfig device description */strcpy(pd->filename, file);strcpy(pd->papername, paper);pd->fontfamily = MatchFamily(family);pd->fontnum = XFig_basenums[pd->fontfamily];pd->encoding = 1;pd->bg = str2col(bg);pd->col = str2col(fg);pd->fill = NA_INTEGER;pd->width = width;pd->height = height;pd->landscape = horizontal;pointsize = floor(ps);if(pd->bg == NA_INTEGER && pd->col == NA_INTEGER) {free(dd);free(pd);error("invalid foreground/background color (xfig)");}/* Deal with paper and plot size and orientation */if(!strcmp(pd->papername, "Default") ||!strcmp(pd->papername, "default")) {SEXP s = STRING_ELT(GetOption(install("papersize"), R_NilValue), 0);if(s != NA_STRING && strlen(CHAR(s)) > 0)strcpy(pd->papername, CHAR(s));else strcpy(pd->papername, "A4");}if(!strcmp(pd->papername, "A4") ||!strcmp(pd->papername, "a4")) {strcpy(pd->papername, "A4");pd->pagewidth = 21.0 / 2.54;pd->pageheight = 29.7 / 2.54;}else if(!strcmp(pd->papername, "Letter") ||!strcmp(pd->papername, "letter")) {strcpy(pd->papername, "Letter");pd->pagewidth = 8.5;pd->pageheight = 11.0;}else if(!strcmp(pd->papername, "Legal") ||!strcmp(pd->papername, "legal")) {strcpy(pd->papername, "Legal");pd->pagewidth = 8.5;pd->pageheight = 14.0;}else {free(dd);free(pd);error("invalid page type `%s' (xfig)", pd->papername);}pd->pagecentre = pagecentre;pd->paperwidth = 72 * pd->pagewidth;pd->paperheight = 72 * pd->pageheight;if(!onefile) {char *p = strrchr(pd->filename, '%');if(!p)warning("xfig(%s, onefile=FALSE) will only return the last plot", pd->filename);}if(pd->landscape) {double tmp;tmp = pd->pagewidth;pd->pagewidth = pd->pageheight;pd->pageheight = tmp;}if(pd->width < 0.1 || pd->width > pd->pagewidth-0.5)pd->width = pd->pagewidth-0.5;if(pd->height < 0.1 || pd->height > pd->pageheight-0.5)pd->height = pd->pageheight-0.5;if(pagecentre) {xoff = (pd->pagewidth - pd->width)/2.0;yoff = (pd->pageheight - pd->height)/2.0;} else {xoff = yoff = 0.0;}if(pagecentre)pd->ymax = (int)(1200.0 * pd->pageheight);elsepd->ymax = (int)(1200.0 * pd->height);pd->onefile = onefile;pd->maxpointsize = 72.0 * ((pd->pageheight > pd->pagewidth) ?pd->pageheight : pd->pagewidth);pd->pageno = 0;pd->lty = 1;/* Set graphics parameters that must be set by device driver. *//* Page dimensions in points. */dd->dp.bg = pd->bg;dd->dp.fg = dd->dp.col = pd->col;dd->dp.left = 72 * xoff; /* left */dd->dp.right = 72 * (xoff + pd->width); /* right */dd->dp.bottom = 72 * yoff; /* bottom */dd->dp.top = 72 * (yoff + pd->height); /* top *//* Base Pointsize *//* Nominal Character Sizes in Pixels *//* Only right for 12 point font. *//* Max pointsize suggested by Peter Dalgaard */if(pointsize < 6.0) pointsize = 6.0;if(pointsize > pd->maxpointsize) pointsize = pd->maxpointsize;dd->dp.ps = pointsize;dd->dp.cra[0] = 0.9 * pointsize;dd->dp.cra[1] = 1.2 * pointsize;/* Character Addressing Offsets *//* These offsets should center a single *//* plotting character over the plotting point. *//* Pure guesswork and eyeballing ... */dd->dp.xCharOffset = 0.4900;dd->dp.yCharOffset = 0.3333;dd->dp.yLineBias = 0.2;/* Inches per Raster Unit *//* 1200 dpi */dd->dp.ipr[0] = 1.0/72.0;dd->dp.ipr[1] = 1.0/72.0;dd->dp.canResizePlot = 0;dd->dp.canChangeFont = 1;dd->dp.canRotateText = 1;dd->dp.canResizeText = 1;dd->dp.canClip = 0;dd->dp.canHAdj = 1; /* 0, 0.5, 1 */pd->XFigColors[7] = 0xffffff;pd->nXFigColors = 32;/* Start the driver */if(!XFig_Open(dd, pd)) {free(pd);return 0;}dd->dp.open = XFig_Open;dd->dp.close = XFig_Close;dd->dp.activate = XFig_Activate;dd->dp.deactivate = XFig_Deactivate;dd->dp.resize = XFig_Resize;dd->dp.newPage = XFig_NewPage;dd->dp.clip = XFig_Clip;dd->dp.text = XFig_Text;dd->dp.strWidth = PS_StrWidth;dd->dp.metricInfo = PS_MetricInfo;dd->dp.rect = XFig_Rect;dd->dp.circle = XFig_Circle;dd->dp.line = XFig_Line;dd->dp.polygon = XFig_Polygon;dd->dp.polyline = XFig_Polyline;dd->dp.locator = XFig_Locator;dd->dp.mode = XFig_Mode;dd->dp.hold = XFig_Hold;dd->deviceSpecific = (void *) pd;dd->displayListOn = 0;return 1;}#ifdef Win32char * Rwin32_tmpnam(char * prefix);#endifstatic int XFig_Open(DevDesc *dd, XFigDesc *pd){char buf[512];int i;for(i = 0; i < 5 ; i++) {sprintf(buf, "%s/afm/%s.%s", R_Home,Family[pd->fontfamily].font[i].abbr,(i == 4) ? "afm" : Extension[pd->encoding]);if(!PostScriptLoadFontMetrics(buf, &(metrics[i])))return 0;}if (strlen(pd->filename) == 0) {error("empty file name");return 0;} else {sprintf(buf, pd->filename, pd->pageno + 1); /* page 1 to start */pd->psfp = R_fopen(R_ExpandFileName(buf), "w");}if (!pd->psfp) return 0;#ifdef Win32strcpy(pd->tmpname, Rwin32_tmpnam("Rxfig"));#elsestrcpy(pd->tmpname, tmpnam(NULL));#endifpd->tmpfp = R_fopen(pd->tmpname, "w");if (!pd->tmpfp) {fclose(pd->psfp);return 0;}XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);pd->fontstyle = 1;pd->fontsize = 10;pd->pageno = 0;return 1;}static void XFig_Clip(double x0, double x1, double y0, double y1, DevDesc *dd){}static void XFig_Resize(DevDesc *dd){}#define CHUNK 10000static void XFig_NewPage(DevDesc *dd){char buf[PATH_MAX];XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;pd->pageno++;if(pd->onefile) {fprintf(pd->tmpfp, "#Start of page %d\n", pd->pageno);if(pd->pageno > 1) XF_EndPage(pd->tmpfp);} else {char buffer[CHUNK];size_t nread;if(pd->pageno == 1) return;XF_FileTrailer(pd->tmpfp);fclose(pd->tmpfp);pd->tmpfp = R_fopen(pd->tmpname, "r");while(1) {nread = fread(buffer, 1, CHUNK, pd->tmpfp);if(nread > 0) fwrite(buffer, 1, nread, pd->psfp);if(nread < CHUNK) break;}fclose(pd->tmpfp);fclose(pd->psfp);sprintf(buf, pd->filename, pd->pageno);pd->psfp = R_fopen(R_ExpandFileName(buf), "w");pd->tmpfp = R_fopen(pd->tmpname, "w");XF_FileHeader(pd->psfp, pd->papername, pd->landscape, pd->onefile);pd->XFigColors[7] = 0xffffff;pd->nXFigColors = 32;}if(dd->dp.bg != R_RGB(255,255,255)) {int cbg = XF_SetColor(dd->dp.bg, pd);int ix0, iy0, ix1, iy1;double x0 = 0.0, y0 = 0.0, x1 = 72.0 * pd->pagewidth,y1 = 72.0 * pd->pageheight;XFconvert(&x0, &y0, pd); XFconvert(&x1, &y1, pd);ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;fprintf(fp, "2 2 "); /* Polyline */fprintf(fp, "%d %d ", 0, 0); /* style, thickness */fprintf(fp, "%d %d ", cbg, cbg); /* pen colour fill colour */fprintf(fp, "200 0 20 4.0 0 0 -1 0 0 ");fprintf(fp, "%d\n", 5); /* number of points */fprintf(fp, "%d %d ", ix0, iy0);fprintf(fp, "%d %d ", ix0, iy1);fprintf(fp, "%d %d ", ix1, iy1);fprintf(fp, "%d %d ", ix1, iy0);fprintf(fp, "%d %d\n", ix0, iy0);}}#ifdef HAVE_UNISTD_H#include <unistd.h>#endifstatic void XFig_Close(DevDesc *dd){char buf[CHUNK];size_t nread;XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;XF_FileTrailer(pd->tmpfp);fclose(pd->tmpfp);pd->tmpfp = R_fopen(pd->tmpname, "r");while(1) {nread = fread(buf, 1, CHUNK, pd->tmpfp);if(nread > 0) fwrite(buf, 1, nread, pd->psfp);if(nread < CHUNK) break;}fclose(pd->tmpfp);unlink(pd->tmpname);fclose(pd->psfp);free(pd);}static void XFig_Activate(DevDesc *dd) {}static void XFig_Deactivate(DevDesc *dd) {}static void XFig_Rect(double x0, double y0, double x1, double y1, int coords,int bg, int fg, DevDesc *dd){XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;int ix0, iy0, ix1, iy1;int cbg = XF_SetColor(bg, pd), cfg = XF_SetColor(fg, pd), cpen,dofill, lty = XF_SetLty(dd->gp.lty), lwd = dd->gp.lwd*0.833 + 0.5;cpen = (fg != NA_INTEGER)? cfg: -1;dofill = (bg != NA_INTEGER)? 20: -1;GConvert(&x0, &y0, coords, DEVICE, dd); XFconvert(&x0, &y0, pd);GConvert(&x1, &y1, coords, DEVICE, dd); XFconvert(&x1, &y1, pd);ix0 = (int)x0; iy0 = (int)y0; ix1 = (int)x1; iy1 = (int)y1;fprintf(fp, "2 2 "); /* Polyline */fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */fprintf(fp, "%d\n", 5); /* number of points */fprintf(fp, " %d %d ", ix0, iy0);fprintf(fp, " %d %d ", ix0, iy1);fprintf(fp, " %d %d ", ix1, iy1);fprintf(fp, " %d %d ", ix1, iy0);fprintf(fp, " %d %d\n", ix0, iy0);}static void XFig_Circle(double x, double y, int coords, double r,int bg, int fg, DevDesc *dd){XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;int ix, iy, ir;int cbg = XF_SetColor(bg, pd), cfg = XF_SetColor(fg, pd), cpen,dofill, lty = XF_SetLty(dd->gp.lty), lwd = dd->gp.lwd*0.833 + 0.5;cpen = (fg != NA_INTEGER)? cfg: -1;dofill = (bg != NA_INTEGER)? 20: -1;GConvert(&x, &y, coords, DEVICE, dd); XFconvert(&x, &y, pd);ix = (int)x; iy = (int)y; ir = (int)(16.667*r);fprintf(fp, "1 3 "); /* Circle + radius */fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */fprintf(fp, "%.2f 1 0 ", 4.0*lwd); /* style value, direction, x, angle */fprintf(fp, " %d %d %d %d %d %d %d %d \n",ix, iy, ir, ir, ix, iy, ix+ir, iy);}static void XFig_Line(double x1, double y1, double x2, double y2,int coords, DevDesc *dd){XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;int lty = XF_SetLty(dd->gp.lty), lwd = dd->gp.lwd*0.833 + 0.5;GConvert(&x1, &y1, coords, DEVICE, dd); XFconvert(&x1, &y1, pd);GConvert(&x2, &y2, coords, DEVICE, dd); XFconvert(&x2, &y2, pd);fprintf(fp, "2 1 "); /* Polyline */fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */fprintf(fp, "%d %d ", XF_SetColor(dd->gp.col, pd), 7);/* pen colour fill colour */fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */fprintf(fp, "%d\n", 2); /* number of points */fprintf(fp, "%d %d %d %d\n", (int)x1, (int)y1, (int)x2, (int)y2);}static void XFig_Polygon(int n, double *x, double *y, int coords,int bg, int fg, DevDesc *dd){XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;double xx, yy;int i;int cbg = XF_SetColor(bg, pd), cfg = XF_SetColor(fg, pd), cpen,dofill, lty = XF_SetLty(dd->gp.lty), lwd = dd->gp.lwd*0.833 + 0.5;cpen = (fg != NA_INTEGER)? cfg: -1;dofill = (bg != NA_INTEGER)? 20: -1;fprintf(fp, "2 3 "); /* Polyline */fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */fprintf(fp, "%d %d ", cpen, cbg); /* pen colour fill colour */fprintf(fp, "100 0 %d ", dofill); /* depth, pen style, area fill */fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */fprintf(fp, "%d\n", n); /* number of points */for(i = 0 ; i < n ; i++) {xx = x[i];yy = y[i];GConvert(&xx, &yy, coords, DEVICE, dd); XFconvert(&xx, &yy, pd);fprintf(fp, " %d %d\n", (int)xx, (int)yy);}}static void XFig_Polyline(int n, double *x, double *y, int coords,DevDesc *dd){XFigDesc *pd = (XFigDesc*) dd->deviceSpecific;FILE *fp = pd->tmpfp;double xx, yy;int i, lty = XF_SetLty(dd->gp.lty), lwd = dd->gp.lwd*0.833 + 0.5;fprintf(fp, "2 1 "); /* Polyline */fprintf(fp, "%d %d ", lty, lwd>0?lwd:1); /* style, thickness */fprintf(fp, "%d %d ", XF_SetColor(dd->gp.col, pd), 7); /* pen colour fill colour */fprintf(fp, "100 0 -1 "); /* depth, pen style, area fill */fprintf(fp, "%.2f 0 0 -1 0 0 ", 4.0*lwd); /* style value, join .... */fprintf(fp, "%d\n", n); /* number of points */for(i = 0 ; i < n ; i++) {xx = x[i];yy = y[i];GConvert(&xx, &yy, coords, DEVICE, dd); XFconvert(&xx, &yy, pd);fprintf(fp, " %d %d\n", (int)xx, (int)yy);}}static int styles[4] = {0,2,1,3};static void XFig_Text(double x, double y, int coords,char *str, double rot, double hadj, DevDesc *dd){XFigDesc *pd = (XFigDesc *) dd->deviceSpecific;FILE *fp = pd->tmpfp;int fontnum, style = dd->gp.font;double size = floor(dd->gp.cex * dd->gp.ps + 0.5);if(style < 1 || style > 5) style = 1;pd->fontsize = size;pd->fontstyle = style;if(style == 5) fontnum = 32;else fontnum = pd->fontnum + styles[style-1];GConvert(&x, &y, coords, DEVICE, dd); XFconvert(&x, &y, pd);fprintf(fp, "4 %d ", (int)floor(2*hadj)); /* Text, how justified */fprintf(fp, "%d 100 0 ", XF_SetColor(dd->gp.col, pd));/* color, depth, pen_style */fprintf(fp, "%d %d %.4f 4 ", fontnum, (int)size, rot * DEG2RAD);/* font pointsize angle flags (Postscript font) */fprintf(fp, "%d %d ", (int)(16.667*GStrHeight(str, DEVICE, dd)+0.5),(int)(16.667*GStrWidth(str, DEVICE, dd)+0.5));fprintf(fp, "%d %d ", (int)x, (int)y);XF_WriteString(fp, str);fprintf(fp, "\\001\n");}static int XFig_Locator(double *x, double *y, DevDesc *dd){return 0;}static void XFig_Mode(int mode, DevDesc* dd){}static void XFig_Hold(DevDesc *dd){}