/* * render.c * * Render a high dynamic range buffer in some sensible way * * (c) 2006-2011 Thomas White * * Part of CrystFEL - crystallography with a FEL * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_GTK #include #endif #include #include #include #ifdef HAVE_LIBPNG #include #endif #ifdef HAVE_TIFF #include #endif #include "hdf5-file.h" #include "render.h" #include "peaks.h" #include "filters.h" #include "utils.h" static void render_rgb(double val, double max, double *rp, double *gp, double *bp) { int s; double p; double r, g, b; s = val / (max/6); p = fmod(val, max/6.0); p /= (max/6.0); r = 0.0; g = 0.0; b = 0.0; if ( (val < 0.0) ) { s = 0; p = 0; } if ( (val > max) ) { s = 6; } switch ( s ) { case 0 : { /* Black to blue */ r = 0; g = 0; b = p; break; } case 1 : { /* Blue to pink */ r = p; g = 0; b = 1.0; break; } case 2 : { /* Pink to red */ r = 1.0; g = 0; b = (1.0-p)*1.0; break; } case 3 : { /* Red to Orange */ r = 1.0; g = 0.5*p; b = 0; break; } case 4 : { /* Orange to Yellow */ r = 1.0; g = 0.5 + 0.5*p; b = 0; break; } case 5 : { /* Yellow to White */ r = 1.0; g = 1.0; b = 1.0*p; break; } case 6 : { /* Pixel has hit the maximum value */ r = 1.0; g = 1.0; b = 1.0; break; } } *rp = r; *gp = g; *bp = b; } static void render_ratio(double val, double max, double *rp, double *gp, double *bp) { if ( val <= 1.0 ) { render_rgb(val, 2.0, rp, gp, bp); } else { /* Your homework is to simplify this expression */ val = ((val-1.0)/(max-1.0)) * (max/2.0) + max/2.0; render_rgb(val, max, rp, gp, bp); } } static void render_mono(double val, double max, double *rp, double *gp, double *bp) { double p; p = val / max; if ( val < 0.0 ) p = 0.0; if ( val > max ) p = 1.0; *rp = p; *gp = p; *bp = p; } static void render_invmono(double val, double max, double *rp, double *gp, double *bp) { double p; p = val / max; p = 1.0 - p; if ( val < 0.0 ) p = 1.0; if ( val > max ) p = 0.0; *rp = p; *gp = p; *bp = p; } void render_scale(double val, double max, int scale, double *rp, double *gp, double *bp) { switch ( scale ) { case SCALE_COLOUR : render_rgb(val, max, rp, gp, bp); break; case SCALE_MONO : render_mono(val, max, rp, gp, bp); break; case SCALE_INVMONO : render_invmono(val, max, rp, gp, bp); break; case SCALE_RATIO : render_ratio(val, max, rp, gp, bp); break; } } #ifdef HAVE_GTK static float *get_binned_panel(struct image *image, int binning, int min_fs, int max_fs, int min_ss, int max_ss) { float *data; int x, y; int w, h; int fw; float *in; fw = image->width; in = image->data; /* Some pixels might get discarded */ w = (max_fs - min_fs + 1) / binning; h = (max_ss - min_ss + 1) / binning; data = malloc(w*h*sizeof(float)); for ( x=0; xwidth*image->height; i++ ) { if ( image->data[i] > max ) max = image->data[i]; } hdr = get_binned_panel(image, binning, min_fs, max_fs, min_ss, max_ss); if ( hdr == NULL ) return NULL; /* Rendered (colourful) version */ data = malloc(3*w*h); if ( data == NULL ) { free(hdr); return NULL; } max /= boost; if ( max <= 6 ) { max = 10; } /* These x,y coordinates are measured relative to the bottom-left * corner */ for ( y=0; ydet->n_panels; GdkPixbuf **pixbufs; pixbufs = calloc(np, sizeof(GdkPixbuf*)); if ( pixbufs == NULL ) { *n_pixbufs = 0; return NULL; } for ( i=0; idet->panels[i].min_fs, image->det->panels[i].max_fs, image->det->panels[i].min_ss, image->det->panels[i].max_ss); } *n_pixbufs = np; return pixbufs; } GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale) { guchar *data; size_t x, y; int max; data = malloc(3*w*h); if ( data == NULL ) return NULL; max = h; for ( y=0; ywidth); TIFFSetField(th, TIFFTAG_IMAGELENGTH, image->height); TIFFSetField(th, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(th, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); TIFFSetField(th, TIFFTAG_BITSPERSAMPLE, 32); TIFFSetField(th, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(th, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(th, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(th, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(th, image->width*4)); line = _TIFFmalloc(TIFFScanlineSize(th)); for ( y=0; yheight; y++ ) { memcpy(line, &image->data[(image->height-1-y)*image->width], image->width*4); TIFFWriteScanline(th, line, y, 0); } _TIFFfree(line); TIFFClose(th); #else STATUS("No TIFF support.\n"); #endif return 0; } int render_tiff_int16(struct image *image, const char *filename, double boost) { #ifdef HAVE_TIFF TIFF *th; int16_t *line; int x, y; double max; th = TIFFOpen(filename, "w"); if ( th == NULL ) return 1; TIFFSetField(th, TIFFTAG_IMAGEWIDTH, image->width); TIFFSetField(th, TIFFTAG_IMAGELENGTH, image->height); TIFFSetField(th, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(th, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); /* (signed) */ TIFFSetField(th, TIFFTAG_BITSPERSAMPLE, 16); TIFFSetField(th, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); TIFFSetField(th, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(th, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(th, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(th, image->width*4)); line = _TIFFmalloc(TIFFScanlineSize(th)); max = 0.0; for ( y=0; yheight; y++ ) { for ( x=0;xwidth; x++ ) { double val; val = image->data[x+image->height*y]; if ( val > max ) max = val; } } max /= 32767.0; for ( y=0; yheight; y++ ) { for ( x=0;xwidth; x++ ) { double val; val = image->data[x+(image->height-1-y)*image->width]; val *= ((double)boost/max); /* Clamp to 16-bit range, * and work round inability of most readers to deal * with signed integers. */ val += 1000.0; if ( val > 32767.0 ) val = 32767.0; if ( val < 0.0 ) val = 0.0; line[x] = val; } TIFFWriteScanline(th, line, y, 0); } _TIFFfree(line); TIFFClose(th); #else STATUS("No TIFF support.\n"); #endif return 0; } #endif /* HAVE_GTK */