b8180d9f6d41dc708a2f249ba892cbca311e7a06 jcasper Mon Feb 27 11:38:55 2023 -0800 Adding transparency support for colors refs #30569 diff --git src/lib/psGfx.c src/lib/psGfx.c index bb303bb..734c9a8 100644 --- src/lib/psGfx.c +++ src/lib/psGfx.c @@ -1,74 +1,96 @@ /* PostScript graphics - * This provides a bit of a shell around writing graphics to * a postScript file. Perhaps the most important thing it * does is convert 0,0 from being at the bottom left to * being at the top left. */ /* Copyright (C) 2011 The Regents of the University of California * See kent/LICENSE or http://genome.ucsc.edu/license/ for licensing information. */ #include "common.h" #include "psPoly.h" #include "psGfx.h" #include "linefile.h" #include "pipeline.h" - static void psFloatOut(FILE *f, double x) /* Write out a floating point number, but not in too much * precision. */ { int i = round(x); if (i == x) fprintf(f, "%d ", i); else fprintf(f, "%0.4f ", x); } void psClipRect(struct psGfx *ps, double x, double y, double width, double height) /* Set clipping rectangle. */ { FILE *f = ps->f; fprintf(f, "cliprestore "); psXyOut(ps, x, y+height); psWhOut(ps, width, height); fprintf(f, "rectclip\n"); } -static void psWriteHeader(FILE *f, double width, double height) +static void psWriteHeader(struct psGfx *ps, double width, double height) /* Write postScript header. It's encapsulated PostScript * actually, so you need to supply image width and height * in points. */ { +FILE *f = ps->f; char *s = #include "common.pss" ; fprintf(f, "%%!PS-Adobe-3.1 EPSF-3.0\n"); fprintf(f, "%%%%BoundingBox: 0 0 %d %d\n", (int)ceil(width), (int)ceil(height)); fprintf(f, "%%%%LanguageLevel: 3\n\n"); +if (ps->newTransOps) + fprintf(f, "0 .pushpdf14devicefilter\n"); fprintf(f, "%s", s); } void psSetLineWidth(struct psGfx *ps, double factor) /* Set line width to factor * a single pixel width. */ { fprintf(ps->f, "%f setlinewidth\n", factor * ps->xScale); } +boolean supportNewTrans(void) +/* Check the version of GS and return whether it supports the newer transparency operators */ +{ +boolean support = FALSE; +char *versionCmd[] = { "gs", "--version", NULL }; +struct pipeline *pl = pipelineOpen1(versionCmd, pipelineRead, "/dev/null", NULL, 0); +if (pl) + { + struct lineFile *lf = pipelineLineFile(pl); + char *versionString; + lineFileNext(lf, &versionString, NULL); + char *minorVersion = NULL; + if (strchr(versionString, '.')) + minorVersion = strchr(versionString, '.') + 1; + if ((atoi(versionString) > 9) || (atoi(versionString) == 9 && minorVersion && atoi(minorVersion) > 51)) + support = TRUE; + } +return support; +} + struct psGfx *psOpen(char *fileName, double userWidth, double userHeight, /* Dimension of image in user's units. */ double ptWidth, double ptHeight, /* Dimension of image in points. */ double ptMargin) /* Image margin in points. */ /* Open up a new postscript file. If ptHeight is 0, it will be * calculated to keep pixels square. */ { struct psGfx *ps; /* Allocate structure and open file. */ AllocVar(ps); ps->f = mustOpen(fileName, "w"); /* Save page dimensions and calculate scaling factors. */ ps->userWidth = userWidth; @@ -83,57 +105,60 @@ else { ps->yScale = ps->xScale; ptHeight = ps->ptHeight = userHeight * ps->yScale + 2*ptMargin; } /* 0.5, 0.5 is the center of the pixel in upper-left corner which corresponds to (0,0) */ ps->xOff = ptMargin; ps->yOff = ptMargin; ps->fontHeight = 10; /* Cope with fact y coordinates are bottom to top rather * than top to bottom. */ ps->yScale = -ps->yScale; ps->yOff = ps->ptHeight - ps->yOff; -psWriteHeader(ps->f, ptWidth, ptHeight); +ps->newTransOps = supportNewTrans(); +psWriteHeader(ps, ptWidth, ptHeight); /* adding a gsave here fixes an old ghostview bug with cliprestore */ fprintf(ps->f, "gsave\n"); /* Set initial clipping rectangle. */ psClipRect(ps, 0, 0, ps->userWidth, ps->userHeight); /* Set line width to a single pixel. */ psSetLineWidth(ps,1); return ps; } void psTranslate(struct psGfx *ps, double xTrans, double yTrans) /* add a constant to translate all coordinates */ { ps->xOff += xTrans*ps->xScale; ps->yOff += yTrans*ps->yScale; } void psClose(struct psGfx **pPs) /* Close out postScript file. */ { struct psGfx *ps = *pPs; if (ps != NULL) { + if (ps->newTransOps) + fprintf(ps->f, ".poppdf14devicefilter\n"); carefulClose(&ps->f); freez(pPs); } } void psXyOut(struct psGfx *ps, double x, double y) /* Output x,y position transformed into PostScript space. */ { FILE *f = ps->f; psFloatOut(f, x * ps->xScale + ps->xOff); psFloatOut(f, y * ps->yScale + ps->yOff); } void psWhOut(struct psGfx *ps, double width, double height) /* Output width/height transformed into PostScript space. */ @@ -325,30 +350,42 @@ fprintf(ps->f, ") showMiddle\n"); } void psTextDown(struct psGfx *ps, double x, double y, char *text) /* Output text going downwards rather than across at position. */ { psMoveTo(ps, x, y); fprintf(ps->f, "gsave\n"); fprintf(ps->f, "-90 rotate\n"); fprintf(ps->f, "("); psTextOutEscaped(ps, text); fprintf(ps->f, ") show\n"); fprintf(ps->f, "grestore\n"); } +void psSetColorAlpha(struct psGfx *ps, int a) +/* Sets alpha in the output if transparency is enabled, otherwise does nothing */ +{ +FILE *f = ps->f; +double scale = 1.0/255; +if (ps->newTransOps) + { + fprintf(f, "%f .setfillconstantalpha\n", scale * a); + fprintf(f, "%f .setstrokeconstantalpha\n", scale * a); + } +} + void psSetColor(struct psGfx *ps, int r, int g, int b) /* Set current color. */ { FILE *f = ps->f; double scale = 1.0/255; if (r == g && g == b) { psFloatOut(f, scale * r); fprintf(f, "setgray\n"); } else { psFloatOut(f, scale * r); psFloatOut(f, scale * g); psFloatOut(f, scale * b); @@ -493,24 +530,34 @@ char *words[5]; chopLine(line, words); width = atof(words[3]); height = atof(words[4]); break; } } lineFileClose(&lf); /* Do conversion. */ chopSuffix(pdfTmpName); pdfName = addSuffix(pdfTmpName, ".pdf"); char widthBuff[1024], heightBuff[1024]; safef(widthBuff, sizeof widthBuff, "-dDEVICEWIDTHPOINTS=%d", round(width)); safef(heightBuff, sizeof heightBuff, "-dDEVICEHEIGHTPOINTS=%d", round(height)); +struct pipeline *pl = NULL; +boolean newTrans = supportNewTrans(); +if (newTrans) + { + char *pipeCmd[] = { "ps2pdf", "-dALLOWPSTRANSPARENCY", widthBuff, heightBuff, epsFile, pdfName, NULL } ; + pl = pipelineOpen1(pipeCmd, pipelineWrite, "/dev/null", NULL, 0); + } +else + { char *pipeCmd[] = { "ps2pdf", widthBuff, heightBuff, epsFile, pdfName, NULL } ; -struct pipeline *pl = pipelineOpen1(pipeCmd, pipelineWrite, "/dev/null", NULL, 0); + pl = pipelineOpen1(pipeCmd, pipelineWrite, "/dev/null", NULL, 0); + } sysVal = pipelineWait(pl); if(sysVal != 0) freez(&pdfName); freez(&pdfTmpName); return pdfName; }