src/oneShot/rgbaGfxTest/rgbaGfxTest.c 1.3
1.3 2010/05/07 05:37:08 kent
Fiddling with spacing.
Index: src/oneShot/rgbaGfxTest/rgbaGfxTest.c
===================================================================
RCS file: /projects/compbio/cvsroot/kent/src/oneShot/rgbaGfxTest/rgbaGfxTest.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -b -B -U 1000000 -r1.2 -r1.3
--- src/oneShot/rgbaGfxTest/rgbaGfxTest.c 30 Apr 2010 17:08:46 -0000 1.2
+++ src/oneShot/rgbaGfxTest/rgbaGfxTest.c 7 May 2010 05:37:08 -0000 1.3
@@ -1,415 +1,416 @@
/* rgbaGfxTest - Test out rgbaGfx system.. */
#include "png.h"
#include "common.h"
#include "linefile.h"
#include "hash.h"
#include "options.h"
#include "memgfx.h"
#include "bigWig.h"
char *chrom = "chr2";
int chromStart = 74514968;
int chromEnd = 74589245;
int minVal = 0;
int maxVal = 40;
static char const rcsid[] = "$Id$";
void usage()
/* Explain usage and exit. */
{
errAbort(
"rgbaGfxTest - Test out rgbaGfx system.\n"
"usage:\n"
" rgbaGfxTest in1.bw in2.bw in3.bw ... inN.bw out.png\n"
"options:\n"
" -chrom=chr2\n"
" -chromStart=74514968\n"
" -chromEnd=74589245\n"
" -minVal=0\n"
" -maxVal=40\n"
);
}
static struct optionSpec options[] = {
{"chrom", OPTION_STRING},
{"chromStart", OPTION_INT},
{"chromEnd", OPTION_INT},
{"minVal", OPTION_INT},
{"maxVal", OPTION_INT},
{NULL, 0},
};
struct rgbaColor
{
unsigned char r, g, b, a;
};
struct rgbaGfx
/* Structure you can draw on in red/green/blue/alpha (transparency). */
{
struct rgbaColor *pixels;
int width, height;
int clipMinX, clipMaxX;
int clipMinY, clipMaxY;
};
struct rgbaGfx *rgbaGfxNew(int width, int height)
/* Return a new image to draw one. */
{
struct rgbaGfx *rg;
AllocVar(rg);
rg->width = rg->clipMaxX = width;
rg->height = rg->clipMaxY = height;
rg->pixels = needHugeMem(width*height*sizeof(rg->pixels[0]));
return rg;
}
void rgbaGfxSetToSolidWhite(struct rgbaGfx *rg)
/* Set all pixels (quickly) to non-transparent white. */
{
int count = rg->width * rg->height;
bits32 solid = 0xFFFFFFFF;
bits32 *pt = (bits32*)rg->pixels;
int i;
for (i=0; i<count; ++i)
*pt++ = solid;
}
#define _rgBpr(rg) ((rg)->width)
/* Get what to add to get to next line */
#define _rgPixAdr(rg,x,y) ((rg)->pixels + (rg)->width * (y) + (x))
/* Get pixel address */
#define _rgPutDot(rg, x, y, color) (*_rgPixAdr(rg,x,y) = (color))
/* Unclipped plot a dot */
#define _rgGetDot(rg, x, y) (*_rgPixAdr(rg,x,y))
/* Unclipped get a dot, you do not want to use this, this is special for
* verticalText only */
#define rgPutDot(rg,x,y,color) if ((x)>=(rg)->clipMinX && (x) < (rg)->clipMaxX && (y)>=(rg)->clipMinY && (y) < (rg)->clipMaxY) _rgPutDot(rg,x,y,color)
/* Clipped put dot */
#define rgGetDot(rg,x,y) ((x)>=(rg)->clipMinX && (x) < (rg)->clipMaxX && (y)>=(rg)->clipMinY && (y) < (rg)->clipMaxY) ? _rgGetDot(rg,x,y) : 0
/* Clipped get dot, you do not want to use this, this is special for
* verticalText only */
struct rgbaColor rgbaTransparentBlend(struct rgbaColor a, struct rgbaColor b)
/* Return blend of two rgba format colors. Does not actually touch the alpha
* channel. It does blend the colors though, treating them as if they were both
* transparent filters. */
{
struct rgbaColor res;
res.a = (a.a + b.a)>>1;
res.r = (a.r * b.r)/255;
res.g = (a.g * b.g)/255;
res.b = (a.b * b.b)/255;
return res;
}
void rgBlendDot(struct rgbaGfx *rg, int x, int y, struct rgbaColor color)
/* BLend in one dot. */
{
struct rgbaColor *pt = _rgPixAdr(rg, x, y);
*pt = rgbaTransparentBlend(*pt, color);
}
/* Draw a box. */
void rgDrawBox(struct rgbaGfx *rg, int x, int y, int width, int height, struct rgbaColor color)
/* Draw a box. */
{
int i;
struct rgbaColor *pt;
int x2 = x + width;
int y2 = y + height;
int wrapCount;
if (x < rg->clipMinX)
x = rg->clipMinX;
if (y < rg->clipMinY)
y = rg->clipMinY;
if (x2 > rg->clipMaxX)
x2 = rg->clipMaxX;
if (y2 > rg->clipMaxY)
y2 = rg->clipMaxY;
width = x2-x;
height = y2-y;
if (width > 0 && height > 0)
{
pt = _rgPixAdr(rg,x,y);
wrapCount = rg->width - width;
while (--height >= 0)
{
i = width;
while (--i >= 0)
{
*pt = rgbaTransparentBlend(*pt, color);
pt += 1;
}
pt += wrapCount;
}
}
}
static void pngAbort(png_structp png, png_const_charp errorMessage)
/* type png_error wrapper around errAbort */
{
errAbort("%s", (char *)errorMessage);
}
static void pngWarn(png_structp png, png_const_charp warningMessage)
/* type png_error wrapper around warn */
{
warn("%s", (char *)warningMessage);
}
boolean saveToPng(FILE *f, struct rgbaGfx *rg)
/* Save RGBA PNG to an already open file.
* Reference: http://libpng.org/pub/png/libpng-1.2.5-manual.html */
{
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, // don't need pointer to data for err/warn handlers
pngAbort, pngWarn);
if (!png)
{
errAbort("png_write_struct failed");
return FALSE;
}
png_infop info = png_create_info_struct(png);
if (!info)
{
png_destroy_write_struct(&png, NULL);
errAbort("png create_info_struct failed");
return FALSE;
}
// If setjmp returns nonzero, it means png_error is returning control here.
// But that should not happen because png_error should call pngAbort which calls errAbort.
if (setjmp(png_jmpbuf(png)))
{
png_destroy_write_struct(&png, &info);
fclose(f);
errAbort("pngwrite: setjmp nonzero. "
"why didn't png_error..pngAbort..errAbort stop execution before this errAbort?");
return FALSE;
}
// Configure PNG output params:
png_init_io(png, f);
png_set_IHDR(png, info, rg->width, rg->height, 8, // 8=bit_depth
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Write header/params, write pixels, close and clean up.
// PNG wants a 2D array of pointers to byte offsets into palette/colorMap.
// rg has a 1D array of byte offsets. Make row pointers for PNG:
png_byte **row_pointers = needMem(rg->height * sizeof(png_byte *));
int i;
for (i = 0; i < rg->height; i++)
row_pointers[i] = (png_byte*)(&(rg->pixels[i*rg->width]));
png_set_rows(png, info, row_pointers);
png_write_png(png, info, PNG_TRANSFORM_IDENTITY, // no transform
NULL); // unused as of PNG 1.2
png_destroy_write_struct(&png, &info);
return TRUE;
}
void savePng(char *filename, struct rgbaGfx *rg)
{
FILE *pngFile = mustOpen(filename, "wb");
if (!saveToPng(pngFile, rg))
{
remove(filename);
errAbort("Couldn't save %s", filename);
}
if (fclose(pngFile) != 0)
errnoAbort("fclose failed");
}
void rgDrawLine(struct rgbaGfx *rg, int x1, int y1, int x2, int y2, struct rgbaColor color)
/* Draw a line from one point to another using Brezenham line algorithm. */
{
if (x1 == x2)
{
int y,height;
if (y1 > y2)
{
y = y2;
height = y1-y2+1;
}
else
{
y = y1;
height = y2-y1+1;
}
rgDrawBox(rg, x1, y, 1, height, color);
}
else if (y1 == y2)
{
int x,width;
if (x1 > x2)
{
x = x2;
width = x1-x2+1;
}
else
{
x = x1;
width = x2-x1+1;
}
rgDrawBox(rg, x, y1, width, 1, color);
}
else
{
int duty_cycle;
int incy;
int delta_x, delta_y;
int dots;
delta_y = y2-y1;
delta_x = x2-x1;
if (delta_y < 0)
{
delta_y = -delta_y;
incy = -1;
}
else
{
incy = 1;
}
if (delta_x < 0)
{
delta_x = -delta_x;
incy = -incy;
x1 = x2;
y1 = y2;
}
duty_cycle = (delta_x - delta_y)/2;
if (delta_x >= delta_y)
{
dots = delta_x+1;
while (--dots >= 0)
{
rgBlendDot(rg,x1,y1,color);
duty_cycle -= delta_y;
x1 += 1;
if (duty_cycle < 0)
{
duty_cycle += delta_x; /* update duty cycle */
y1+=incy;
}
}
}
else
{
dots = delta_y+1;
while (--dots >= 0)
{
rgBlendDot(rg,x1,y1,color);
duty_cycle += delta_x;
y1+=incy;
if (duty_cycle > 0)
{
duty_cycle -= delta_y; /* update duty cycle */
x1 += 1;
}
}
}
}
}
struct rgbaColor rgbaLightRainbowColor(double pos)
/* Giving a position 0.0 to 1.0 in rainbow, return color. */
{
double maxHue = 360.0;
struct hslColor hsl = {pos*maxHue, 1000, 750};
struct rgbColor rgb = mgHslToRgb(hsl);
struct rgbaColor rgba = {rgb.r, rgb.g, rgb.b, 255};
return rgba;
}
void drawRainbowBar(struct rgbaGfx *rg, int x, int y, int width, int height)
/* Draw a horizontal bar in rainbow colors. */
{
int i;
for (i=0; i<width; ++i)
{
struct rgbaColor rgba = rgbaLightRainbowColor((double)i/width);
rgDrawBox(rg, x+i, y, 1, height, rgba);
}
}
void drawBigWigAt(char *fileName, struct rgbaGfx *rg, struct rgbaColor col,
int xOff, int yOff, int width, int height)
/* Load in data and draw bigWig part at given position. */
{
struct bbiFile *bwf = bigWigFileOpen(fileName);
struct bbiSummaryElement summary[width];
if (bigWigSummaryArrayExtended(bwf, chrom, chromStart, chromEnd, width, summary))
{
int i;
double pixelScale = (double)height/(maxVal - minVal + 1);
for (i=0; i<width; ++i)
{
struct bbiSummaryElement *sum = &summary[i];
if (sum->validCount > 0)
{
int x = xOff + i;
double val = sum->sumData/sum->validCount;
if (val > maxVal) val = maxVal;
if (val < minVal) val = minVal;
double scaledVal = pixelScale * val;
rgDrawBox(rg, x, yOff + height - scaledVal, 1, scaledVal, col);
}
}
}
bigWigFileClose(&bwf);
}
void rgbaGfxTest(char *inNames[], int inCount, char *output)
/* rgbaGfxTest - Test out rgbaGfx system.. */
{
-int width = 700, heightOne = 50, spaceBetween=10;
+int width = 700, heightOne = 50, spaceBetween=6;
int lineHeight = heightOne + spaceBetween;
int height = lineHeight * (inCount+1);
struct rgbaGfx *rg = rgbaGfxNew(width, height);
rgbaGfxSetToSolidWhite(rg);
#ifdef OLD
struct rgbaColor red = {255, 128, 128, 255};
struct rgbaColor green = {128, 255, 128, 255};
struct rgbaColor blue = {128, 128, 255, 255};
struct rgbaColor weakBlue = {200,200,255,255};
rgDrawBox(rg, 50, 100, 200, 200, red);
rgDrawBox(rg, 100, 50, 200, 200, blue);
rgDrawBox(rg, 150, 0, 50, 500, green);
rgDrawBox(rg, 0, 150, 500, 50, weakBlue);
drawRainbowBar(rg, 0, 275, 500, 50);
#endif /* OLD */
int i;
for (i=0; i<inCount; ++i)
{
struct rgbaColor col = rgbaLightRainbowColor((double)i/inCount);
- drawBigWigAt(inNames[i], rg, col, 0, 0, width, heightOne);
- drawBigWigAt(inNames[i], rg, col, 0, (1+i)*lineHeight, width, heightOne);
+ uglyf("color %d,%d,%d\n", col.r, col.g, col.b);
+ drawBigWigAt(inNames[i], rg, col, 0, spaceBetween, width, heightOne);
+ drawBigWigAt(inNames[i], rg, col, 0, (1+i)*lineHeight + spaceBetween, width, heightOne);
}
savePng(output, rg);
}
int main(int argc, char *argv[])
/* Process command line. */
{
optionInit(&argc, argv, options);
if (argc < 3)
usage();
rgbaGfxTest(argv+1, argc-2, argv[argc-1]);
return 0;
}