diff options
author | Thomas White <taw@physics.org> | 2020-02-26 14:20:04 +0100 |
---|---|---|
committer | Thomas White <taw@physics.org> | 2020-07-29 18:42:24 +0200 |
commit | cb47e755858296d59f4ceb373bcd20b045004f56 (patch) | |
tree | 5526da31f373c3e1323dbae80f12caa13b9e38e8 | |
parent | ca3b3162f037506ae224e0f8bb7c6f669a43d1b1 (diff) |
Move colour scale and pixbuf rendering to libcrystfel
Also, split into two files (colscale and render), and remove TIFF stuff.
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | libcrystfel/CMakeLists.txt | 7 | ||||
-rw-r--r-- | libcrystfel/config.h.cmake.in | 1 | ||||
-rw-r--r-- | libcrystfel/src/colscale.c | 246 | ||||
-rw-r--r-- | libcrystfel/src/colscale.h (renamed from src/hdfsee-render.h) | 45 | ||||
-rw-r--r-- | libcrystfel/src/peaks.h | 1 | ||||
-rw-r--r-- | libcrystfel/src/render.c | 336 | ||||
-rw-r--r-- | libcrystfel/src/render.h | 25 | ||||
-rw-r--r-- | src/geoptimiser.c | 3 | ||||
-rw-r--r-- | src/hdfsee-render.c | 419 | ||||
-rw-r--r-- | src/render_hkl.c | 2 |
11 files changed, 471 insertions, 616 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d8e9dd06..2311b565 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -311,7 +311,7 @@ list(APPEND CRYSTFEL_EXECUTABLES ambigator) # ---------------------------------------------------------------------- # geoptimiser -set(GEOPTIMISER_SOURCES src/geoptimiser.c src/hdfsee-render.c) +set(GEOPTIMISER_SOURCES src/geoptimiser.c) add_executable(geoptimiser ${GEOPTIMISER_SOURCES}) target_include_directories(geoptimiser PRIVATE ${COMMON_INCLUDES}) target_link_libraries(geoptimiser ${COMMON_LIBRARIES}) diff --git a/libcrystfel/CMakeLists.txt b/libcrystfel/CMakeLists.txt index 15d4ba19..1e30bf81 100644 --- a/libcrystfel/CMakeLists.txt +++ b/libcrystfel/CMakeLists.txt @@ -76,6 +76,7 @@ set(LIBCRYSTFEL_SOURCES src/rational.c src/spectrum.c src/datatemplate.c + src/colscale.c ${BISON_symopp_OUTPUTS} ${FLEX_symopl_OUTPUTS} ) @@ -119,6 +120,7 @@ set(LIBCRYSTFEL_HEADERS src/rational.h src/spectrum.h src/datatemplate.h + src/colscale.h ) if (DOXYGEN_FOUND) @@ -177,6 +179,11 @@ if (CURSES_FOUND) target_link_libraries(${PROJECT_NAME} PRIVATE ${CURSES_LIBRARIES}) endif (CURSES_FOUND) +if (GDKPIXBUF_FOUND) + target_include_directories(${PROJECT_NAME} PRIVATE ${GDKPIXBUF_INCLUDE_DIRS}) + target_link_libraries(${PROJECT_NAME} PRIVATE ${GDKPIXBUF_LIBRARIES}) +endif (GDKPIXBUF_FOUND) + target_compile_options(${PROJECT_NAME} PRIVATE -Wall) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${LIBCRYSTFEL_HEADERS}") diff --git a/libcrystfel/config.h.cmake.in b/libcrystfel/config.h.cmake.in index 731e6fe0..3433e043 100644 --- a/libcrystfel/config.h.cmake.in +++ b/libcrystfel/config.h.cmake.in @@ -8,6 +8,7 @@ #cmakedefine HAVE_FDIP #cmakedefine HAVE_CURSES #cmakedefine HAVE_GZBUFFER +#cmakedefine HAVE_GDKPIXBUF #cmakedefine HAVE_FORKPTY_PTY_H #cmakedefine HAVE_FORKPTY_UTIL_H diff --git a/libcrystfel/src/colscale.c b/libcrystfel/src/colscale.c new file mode 100644 index 00000000..d541b384 --- /dev/null +++ b/libcrystfel/src/colscale.c @@ -0,0 +1,246 @@ +/* + * colscale.c + * + * Colour scales + * + * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, + * a research centre of the Helmholtz Association. + * + * Authors: + * 2009-2012,2014 Thomas White <taw@physics.org> + * + * This file is part of CrystFEL. + * + * CrystFEL 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 3 of the License, or + * (at your option) any later version. + * + * CrystFEL 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 CrystFEL. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <stdlib.h> +#include <math.h> +#include <stdint.h> + +#include "colscale.h" + +/** \file colscale.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) ) { + p = fabs(val) / (max/6.0); + *rp = 0.0; + *gp = 0.5*p; + *bp = 0.0; + return; + } + 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_geoptimiser(double val, double max, + double *rp, double *gp, double *bp) +{ + double r; + double p; + + r = val/max; + + if ( val < 0.0 ) { + *rp = 0.0; + *gp = 0.0; + *bp = 0.0; + return; + } + + if ( r >= 0.0 && r < 0.059 ) { + p = (r-0.0)/(0.059-0.0); + *rp = 0.0; + *gp = 0.0; + *bp = ((91.0/256.0)-0.0)*p; + return; + } + + if ( r >= 0.059 && r < 0.220 ) { + p = (r-0.059)/(0.220-0.059); + *rp = ((122.0/256.0)-0.0)*p; + *gp = 0.0; + *bp = ((227.0/256.0)-(91.0/256.0))*p+(91.0/256.0); + return; + } + + if ( r >= 0.220 && r < 0.376 ) { + p = (r-0.220)/(0.376-0.220); + *rp = ((195.0/256.0)-(122.0/256.0))*p+(122.0/256.0); + *gp = 0.0; + *bp = ((93.0/256.0)-(227.0/256.0))*p+(227.0/256.0); + return; + } + + if ( r >= 0.376 && r < 0.498 ) { + p = (r-0.376)/(0.498-0.376); + *rp = ((238.0/256.0)-(195.0/256.0))*p+(195.0/256.0); + *gp = ((76.0/256.0)-0.0)*p; + *bp = (0.0-(93.0/256.0))*p+(93.0/256.0); + return; + } + + if ( r >= 0.498 && r < 0.564 ) { + p = (r-0.498)/(0.564-0.498); + *rp = (1.0-(238.0/256.0))*p+(238.0/256.0); + *gp = ((117.0/256.0)-(76.0/256.0))*p+(76.0/256.0); + *bp = 0.0; + return; + } + + if ( r >= 0.564 && r < 0.815 ) { + p = (r-0.564)/(0.815-0.564); + *rp = 1.0; + *gp = ((234.0/256.0)-(117.0/256.0))*p+(117.0/256.0); + *bp = 0.0; + return; + } + + if ( r >= 0.815 && r < 1.0 ) { + p = (r-0.815)/(1.0-0.815); + *rp = 1.0; + *gp = (1.0-(234.0/256.0))*p+(234.0/256.0); + *bp = (1.0-0.0)*p; + return; + } + + if ( r >= 1.0 ) { + *rp = 1.0; *gp = 1.0; *bp = 1.0; + return; + } +} + + +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; + + case SCALE_GEOPTIMISER : + render_geoptimiser(val, max, rp, gp, bp); + break; + } +} diff --git a/src/hdfsee-render.h b/libcrystfel/src/colscale.h index b60e2247..41e8c9e8 100644 --- a/src/hdfsee-render.h +++ b/libcrystfel/src/colscale.h @@ -1,13 +1,13 @@ /* - * hdfsee-render.h + * colscale.h * - * Rendering bits for hdfsee + * Colour scales * * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. * * Authors: - * 2011-2015 Thomas White <taw@physics.org> + * 2009-2012 Thomas White <taw@physics.org> * * This file is part of CrystFEL. * @@ -26,28 +26,37 @@ * */ -#ifndef HDFSEE_RENDER_H -#define HDFSEE_RENDER_H - #ifdef HAVE_CONFIG_H #include <config.h> #endif -#ifdef HAVE_GDKPIXBUF -#include <gdk-pixbuf/gdk-pixbuf.h> +#ifndef COLSCALE_H +#define COLSCALE_H -extern GdkPixbuf **render_panels(struct image *image, - int binning, int scale, double boost, - int *n_pixbufs); +/** + * \file colscale.h + * Colour scales for rendering + */ -extern GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale); +enum { + SCALE_COLOUR, + SCALE_MONO, + SCALE_INVMONO, + SCALE_RATIO, + SCALE_GEOPTIMISER +}; -#endif /* HAVE_GDKPIXBUF */ +#ifdef __cplusplus +extern "C" { +#endif -extern int render_tiff_fp(struct image *image, const char *filename, int min_x, - int max_x, int min_y, int max_y); +/* Colour scale lookup */ +extern void render_scale(double val, double max, int scale, + double *rp, double *gp, double *bp); -extern int render_tiff_int16(struct image *image, const char *filename, double boost, - int min_x, int max_x, int min_y, int max_y); -#endif /* HDFSEE_RENDER_H */ +#ifdef __cplusplus +} +#endif + +#endif /* COLSCALE_H */ diff --git a/libcrystfel/src/peaks.h b/libcrystfel/src/peaks.h index 6e61758c..89388652 100644 --- a/libcrystfel/src/peaks.h +++ b/libcrystfel/src/peaks.h @@ -39,6 +39,7 @@ #include "reflist.h" #include "crystal.h" +#include "image.h" #ifdef __cplusplus extern "C" { diff --git a/libcrystfel/src/render.c b/libcrystfel/src/render.c index 284f4c46..b8bcae4d 100644 --- a/libcrystfel/src/render.c +++ b/libcrystfel/src/render.c @@ -1,7 +1,7 @@ /* * render.c * - * Render a high dynamic range buffer in some sensible way + * Render image data to GdkPixbufs * * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. @@ -35,217 +35,229 @@ #include <math.h> #include <stdint.h> +#ifdef HAVE_GDKPIXBUF +#include <gdk-pixbuf/gdk-pixbuf.h> +#endif + -#include "hdf5-file.h" #include "render.h" #include "peaks.h" -#include "filters.h" -#include "utils.h" +#include "colscale.h" /** \file render.h */ -static void render_rgb(double val, double max, - double *rp, double *gp, double *bp) +static float *get_binned_panel(struct image *image, int binning, + int pi, double *max, int *pw, int *ph) { - 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) ) { - p = fabs(val) / (max/6.0); - *rp = 0.0; - *gp = 0.5*p; - *bp = 0.0; - return; - } - if ( (val > max) ) { - s = 6; - } - switch ( s ) { + float *data; + int x, y; + int w, h; + struct panel *p = &image->det->panels[pi]; + + /* Some pixels might get discarded */ + w = p->w / binning; + h = p->h / binning; + *pw = w; + *ph = h; + + data = malloc(w*h*sizeof(float)); - case 0 : /* Black to blue */ - r = 0; g = 0; b = p; - break; + *max = 0.0; + for ( x=0; x<w; x++ ) { + for ( y=0; y<h; y++ ) { - case 1 : /* Blue to pink */ - r = p; g = 0; b = 1.0; - break; + double total; + size_t xb, yb; + int bad = 0; + double val; - case 2 : /* Pink to red */ - r = 1.0; g = 0; b = (1.0-p)*1.0; - break; + total = 0; + for ( xb=0; xb<binning; xb++ ) { + for ( yb=0; yb<binning; yb++ ) { - case 3 : /* Red to Orange */ - r = 1.0; g = 0.5*p; b = 0; - break; + double v; + int fs, ss; - case 4 : /* Orange to Yellow */ - r = 1.0; g = 0.5 + 0.5*p; b = 0; - break; + fs = binning*x+xb; + ss = binning*y+yb; + v = image->dp[pi][fs+ss*p->w]; + total += v; - case 5 : /* Yellow to White */ - r = 1.0; g = 1.0; b = 1.0*p; - break; + if ( (image->bad != NULL) + && (image->bad[pi][fs+ss*p->w]) ) bad = 1; - case 6 : /* Pixel has hit the maximum value */ - r = 1.0; g = 1.0; b = 1.0; - break; + } + } + val = total / ((double)binning * (double)binning); + + if ( bad ) { + data[x+w*y] = -INFINITY; + } else { + data[x+w*y] = val; + if ( val > *max ) *max = val; + } + + } } - *rp = r; - *gp = g; - *bp = b; + return data; +} + + +#ifdef HAVE_GDKPIXBUF + +/* NB This function is shared between render_get_image() and + * render_get_colour_scale() */ +static void render_free_data(guchar *data, gpointer p) +{ + free(data); } -static void render_geoptimiser(double val, double max, - double *rp, double *gp, double *bp) +static GdkPixbuf *render_panel(float *hdr, int scale, double max, int w, int h) { - double r; - double p; + guchar *data; + int x, y; - r = val/max; + /* Rendered (colourful) version */ + data = malloc(3*w*h); + if ( data == NULL ) return NULL; - if ( val < 0.0 ) { - *rp = 0.0; - *gp = 0.0; - *bp = 0.0; - return; - } + /* These x,y coordinates are measured relative to the bottom-left + * corner */ + for ( y=0; y<h; y++ ) { + for ( x=0; x<w; x++ ) { - if ( r >= 0.0 && r < 0.059 ) { - p = (r-0.0)/(0.059-0.0); - *rp = 0.0; - *gp = 0.0; - *bp = ((91.0/256.0)-0.0)*p; - return; - } + double val; + double r, g, b; - if ( r >= 0.059 && r < 0.220 ) { - p = (r-0.059)/(0.220-0.059); - *rp = ((122.0/256.0)-0.0)*p; - *gp = 0.0; - *bp = ((227.0/256.0)-(91.0/256.0))*p+(91.0/256.0); - return; - } + val = hdr[x+w*y]; - if ( r >= 0.220 && r < 0.376 ) { - p = (r-0.220)/(0.376-0.220); - *rp = ((195.0/256.0)-(122.0/256.0))*p+(122.0/256.0); - *gp = 0.0; - *bp = ((93.0/256.0)-(227.0/256.0))*p+(227.0/256.0); - return; - } + if ( val > -INFINITY ) { - if ( r >= 0.376 && r < 0.498 ) { - p = (r-0.376)/(0.498-0.376); - *rp = ((238.0/256.0)-(195.0/256.0))*p+(195.0/256.0); - *gp = ((76.0/256.0)-0.0)*p; - *bp = (0.0-(93.0/256.0))*p+(93.0/256.0); - return; - } + render_scale(val, max, scale, &r, &g, &b); + + /* Stuff inside square brackets makes this pixel go to + * the expected location in the pixbuf (which measures + * from the top-left corner */ + data[3*( x+w*y )+0] = 255*r; + data[3*( x+w*y )+1] = 255*g; + data[3*( x+w*y )+2] = 255*b; + + } else { + + data[3*( x+w*y )+0] = 30; + data[3*( x+w*y )+1] = 20; + data[3*( x+w*y )+2] = 0; - if ( r >= 0.498 && r < 0.564 ) { - p = (r-0.498)/(0.564-0.498); - *rp = (1.0-(238.0/256.0))*p+(238.0/256.0); - *gp = ((117.0/256.0)-(76.0/256.0))*p+(76.0/256.0); - *bp = 0.0; - return; + } + + } } - if ( r >= 0.564 && r < 0.815 ) { - p = (r-0.564)/(0.815-0.564); - *rp = 1.0; - *gp = ((234.0/256.0)-(117.0/256.0))*p+(117.0/256.0); - *bp = 0.0; - return; + /* Create the pixbuf from the 8-bit display data */ + return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, + w, h, w*3, render_free_data, NULL); + +} + + +/* Render an image into multiple pixbufs according to geometry */ +GdkPixbuf **render_panels(struct image *image, + int binning, int scale, double boost, + int *n_pixbufs) +{ + int i; + int np = image->det->n_panels; + GdkPixbuf **pixbufs; + float **hdrs; + double max; + int *ws, *hs; + + hdrs = calloc(np, sizeof(float *)); + ws = calloc(np, sizeof(int)); + hs = calloc(np, sizeof(int)); + if ( (hdrs == NULL) || (ws == NULL) || (hs == NULL) ) { + *n_pixbufs = 0; + return NULL; } - if ( r >= 0.815 && r < 1.0 ) { - p = (r-0.815)/(1.0-0.815); - *rp = 1.0; - *gp = (1.0-(234.0/256.0))*p+(234.0/256.0); - *bp = (1.0-0.0)*p; - return; + /* Find overall max value for whole image */ + max = 0.0; + for ( i=0; i<np; i++ ) { + double this_max = 0.0; + hdrs[i] = get_binned_panel(image, binning, i, &this_max, + &ws[i], &hs[i]); + if ( this_max > max ) max = this_max; } - if ( r >= 1.0 ) { - *rp = 1.0; *gp = 1.0; *bp = 1.0; - return; + max /= boost; + if ( max <= 6 ) { max = 10; } + + pixbufs = calloc(np, sizeof(GdkPixbuf*)); + if ( pixbufs == NULL ) { + *n_pixbufs = 0; + return NULL; } -} + for ( i=0; i<np; i++ ) { + + pixbufs[i] = render_panel(hdrs[i], scale, max, ws[i], hs[i]); + + free(hdrs[i]); -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); } -} + free(hdrs); + free(ws); + free(hs); + *n_pixbufs = np; -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; + return pixbufs; } -static void render_invmono(double val, double max, - double *rp, double *gp, double *bp) +GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale) { - 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; -} + guchar *data; + size_t x, y; + int max; + data = malloc(3*w*h); + if ( data == NULL ) return NULL; -void render_scale(double val, double max, int scale, - double *rp, double *gp, double *bp) -{ - switch ( scale ) { + max = h-(h/6); - case SCALE_COLOUR : - render_rgb(val, max, rp, gp, bp); - break; + for ( y=0; y<h; y++ ) { - case SCALE_MONO : - render_mono(val, max, rp, gp, bp); - break; + double r, g, b; + int val; - case SCALE_INVMONO : - render_invmono(val, max, rp, gp, bp); - break; + val = y-(h/6); - case SCALE_RATIO : - render_ratio(val, max, rp, gp, bp); - break; + render_scale(val, max, scale, &r, &g, &b); - case SCALE_GEOPTIMISER : - render_geoptimiser(val, max, rp, gp, bp); - break; + data[3*( 0+w*(h-1-y) )+0] = 0; + data[3*( 0+w*(h-1-y) )+1] = 0; + data[3*( 0+w*(h-1-y) )+2] = 0; + for ( x=1; x<w; x++ ) { + data[3*( x+w*(h-1-y) )+0] = 255*r; + data[3*( x+w*(h-1-y) )+1] = 255*g; + data[3*( x+w*(h-1-y) )+2] = 255*b; + } + + } + + y = h/6; + for ( x=1; x<w; x++ ) { + data[3*( x+w*(h-1-y) )+0] = 255; + data[3*( x+w*(h-1-y) )+1] = 255; + data[3*( x+w*(h-1-y) )+2] = 255; } + + return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, + w, h, w*3, render_free_data, NULL); } + +#endif /* HAVE_GDKPIXBUF */ diff --git a/libcrystfel/src/render.h b/libcrystfel/src/render.h index a3292515..411c50ce 100644 --- a/libcrystfel/src/render.h +++ b/libcrystfel/src/render.h @@ -1,7 +1,7 @@ /* * render.h * - * Render a high dynamic range buffer in some sensible way + * Render image data to GdkPixbufs * * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, * a research centre of the Helmholtz Association. @@ -33,27 +33,26 @@ #ifndef RENDER_H #define RENDER_H +#include "image.h" + /** * \file render.h - * Colour scale for rendering + * Render image data to GdkPixbufs */ -enum { - SCALE_COLOUR, - SCALE_MONO, - SCALE_INVMONO, - SCALE_RATIO, - SCALE_GEOPTIMISER -}; - #ifdef __cplusplus extern "C" { #endif -/* Colour scale lookup */ -extern void render_scale(double val, double max, int scale, - double *rp, double *gp, double *bp); +#ifdef HAVE_GDKPIXBUF +#include <gdk-pixbuf/gdk-pixbuf.h> + +extern GdkPixbuf *render_get_colour_scale(size_t w, size_t h, int scale); +extern GdkPixbuf **render_panels(struct image *image, + int binning, int scale, double boost, + int *n_pixbufs); +#endif /* HAVE_GDKPIXBUF */ #ifdef __cplusplus } diff --git a/src/geoptimiser.c b/src/geoptimiser.c index 233edac4..136cca39 100644 --- a/src/geoptimiser.c +++ b/src/geoptimiser.c @@ -60,8 +60,7 @@ #include "image.h" #include "utils.h" #include "render.h" - -#include "hdfsee-render.h" +#include "colscale.h" struct imagefeature; diff --git a/src/hdfsee-render.c b/src/hdfsee-render.c deleted file mode 100644 index 38f6ddfc..00000000 --- a/src/hdfsee-render.c +++ /dev/null @@ -1,419 +0,0 @@ -/* - * hdfsee-render.c - * - * Rendering bits for hdfsee - * - * Copyright © 2012-2020 Deutsches Elektronen-Synchrotron DESY, - * a research centre of the Helmholtz Association. - * - * Authors: - * 2011-2012,2015 Thomas White <taw@physics.org> - * - * This file is part of CrystFEL. - * - * CrystFEL 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 3 of the License, or - * (at your option) any later version. - * - * CrystFEL 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 CrystFEL. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <math.h> -#include <stdint.h> -#include <assert.h> - - -#ifdef HAVE_GDKPIXBUF -#include <gdk-pixbuf/gdk-pixbuf.h> -#endif - -#ifdef HAVE_TIFF -#include <tiffio.h> -#endif - -#include <render.h> -#include <image.h> - -static float *get_binned_panel(struct image *image, int binning, - int pi, double *max, int *pw, int *ph) -{ - float *data; - int x, y; - int w, h; - struct panel *p = &image->det->panels[pi]; - - /* Some pixels might get discarded */ - w = p->w / binning; - h = p->h / binning; - *pw = w; - *ph = h; - - data = malloc(w*h*sizeof(float)); - - *max = 0.0; - for ( x=0; x<w; x++ ) { - for ( y=0; y<h; y++ ) { - - double total; - size_t xb, yb; - int bad = 0; - double val; - - total = 0; - for ( xb=0; xb<binning; xb++ ) { - for ( yb=0; yb<binning; yb++ ) { - - double v; - int fs, ss; - - fs = binning*x+xb; - ss = binning*y+yb; - v = image->dp[pi][fs+ss*p->w]; - total += v; - - if ( (image->bad != NULL) - && (image->bad[pi][fs+ss*p->w]) ) bad = 1; - - } - } - - val = total / ((double)binning * (double)binning); - - if ( bad ) { - data[x+w*y] = -INFINITY; - } else { - data[x+w*y] = val; - if ( val > *max ) *max = val; - } - - } - } - - return data; -} - - -#ifdef HAVE_GDKPIXBUF - -/* NB This function is shared between render_get_image() and - * render_get_colour_scale() */ -static void render_free_data(guchar *data, gpointer p) -{ - free(data); -} - - -static GdkPixbuf *render_panel(float *hdr, int scale, double max, int w, int h) -{ - guchar *data; - int x, y; - - /* Rendered (colourful) version */ - data = malloc(3*w*h); - if ( data == NULL ) return NULL; - - /* These x,y coordinates are measured relative to the bottom-left - * corner */ - for ( y=0; y<h; y++ ) { - for ( x=0; x<w; x++ ) { - - double val; - double r, g, b; - - val = hdr[x+w*y]; - - if ( val > -INFINITY ) { - - render_scale(val, max, scale, &r, &g, &b); - - /* Stuff inside square brackets makes this pixel go to - * the expected location in the pixbuf (which measures - * from the top-left corner */ - data[3*( x+w*y )+0] = 255*r; - data[3*( x+w*y )+1] = 255*g; - data[3*( x+w*y )+2] = 255*b; - - } else { - - data[3*( x+w*y )+0] = 30; - data[3*( x+w*y )+1] = 20; - data[3*( x+w*y )+2] = 0; - - } - - } - } - - /* Create the pixbuf from the 8-bit display data */ - return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, - w, h, w*3, render_free_data, NULL); - -} - - -/* Render an image into multiple pixbufs according to geometry */ -GdkPixbuf **render_panels(struct image *image, - int binning, int scale, double boost, - int *n_pixbufs) -{ - int i; - int np = image->det->n_panels; - GdkPixbuf **pixbufs; - float **hdrs; - double max; - int *ws, *hs; - - hdrs = calloc(np, sizeof(float *)); - ws = calloc(np, sizeof(int)); - hs = calloc(np, sizeof(int)); - if ( (hdrs == NULL) || (ws == NULL) || (hs == NULL) ) { - *n_pixbufs = 0; - return NULL; - } - - /* Find overall max value for whole image */ - max = 0.0; - for ( i=0; i<np; i++ ) { - double this_max = 0.0; - hdrs[i] = get_binned_panel(image, binning, i, &this_max, - &ws[i], &hs[i]); - if ( this_max > max ) max = this_max; - } - - max /= boost; - if ( max <= 6 ) { max = 10; } - - pixbufs = calloc(np, sizeof(GdkPixbuf*)); - if ( pixbufs == NULL ) { - *n_pixbufs = 0; - return NULL; - } - - for ( i=0; i<np; i++ ) { - - pixbufs[i] = render_panel(hdrs[i], scale, max, ws[i], hs[i]); - - free(hdrs[i]); - - } - - free(hdrs); - free(ws); - free(hs); - *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-(h/6); - - for ( y=0; y<h; y++ ) { - - double r, g, b; - int val; - - val = y-(h/6); - - render_scale(val, max, scale, &r, &g, &b); - - data[3*( 0+w*(h-1-y) )+0] = 0; - data[3*( 0+w*(h-1-y) )+1] = 0; - data[3*( 0+w*(h-1-y) )+2] = 0; - for ( x=1; x<w; x++ ) { - data[3*( x+w*(h-1-y) )+0] = 255*r; - data[3*( x+w*(h-1-y) )+1] = 255*g; - data[3*( x+w*(h-1-y) )+2] = 255*b; - } - - } - - y = h/6; - for ( x=1; x<w; x++ ) { - data[3*( x+w*(h-1-y) )+0] = 255; - data[3*( x+w*(h-1-y) )+1] = 255; - data[3*( x+w*(h-1-y) )+2] = 255; - } - - return gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, FALSE, 8, - w, h, w*3, render_free_data, NULL); -} - -#endif /* HAVE_GDKPIXBUF */ - -int render_tiff_fp(struct image *image, const char *filename, int min_x, int max_x, - int min_y, int max_y) -{ -#ifdef HAVE_TIFF - TIFF *th; - int16_t *line; - int x, y; - int width = max_x - min_x; - int height = max_y - min_y; - float *buf; - - if ( image == NULL ) return 1; - if ( image->det == NULL ) return 1; - if ( image->det->n_panels == 0 ) return 1; - - buf = calloc(width * height, sizeof(float)); - if ( buf == NULL ) return 1; - - /* Prepare image data */ - for ( y=min_y; y<max_y; y++ ) { - for ( x=min_x; x<max_x; x++ ) { - - int invalid; - float val; - signed int pn; - struct panel *p; - double dfs, dss; - int fs, ss; - - invalid = reverse_2d_mapping(x, y, image->det, &p, &dfs, &dss); - if ( invalid ) continue; - - fs = dfs; - ss = dss; /* Explicit rounding */ - - pn = panel_number(image->det, p); - assert(pn != -1); - p = &image->det->panels[pn]; - val = image->dp[pn][fs + p->w* ss]; - - buf[(x - min_x) + (y - min_y) * width] = val; - - } - } - - th = TIFFOpen(filename, "w"); - if ( th == NULL ) return 1; - - TIFFSetField(th, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField(th, TIFFTAG_IMAGELENGTH, 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, 0)); - - line = _TIFFmalloc(TIFFScanlineSize(th)); - - for ( y=0; y<height; y++ ) { - TIFFWriteScanline(th, &buf[y*width], y, 0); - } - _TIFFfree(line); - - TIFFClose(th); - free(buf); -#else /* HAVE_TIFF */ - STATUS("No TIFF support.\n"); -#endif /* HAVE_TIFF */ - return 0; -} - - -int render_tiff_int16(struct image *image, const char *filename, double boost, - int min_x, int max_x, int min_y, int max_y) -{ -#ifdef HAVE_TIFF - TIFF *th; - int16_t *line; - int x, y; - int width = max_x - min_x; - int height = max_y - min_y; - int16_t *buf; - - if ( image == NULL ) return 1; - if ( image->det == NULL ) return 1; - if ( image->det->n_panels == 0 ) return 1; - - buf = calloc(width * height, sizeof(int16_t)); - if ( buf == NULL ) return 1; - - /* Prepare image data */ - for ( y=min_y; y<max_y; y++ ) { - for ( x=min_x; x<max_x; x++ ) { - - int val, invalid; - unsigned short out; - signed int pn; - struct panel *p; - double dfs, dss; - int fs, ss; - - invalid = reverse_2d_mapping(x, y, image->det, &p, &dfs, &dss); - if ( invalid ) continue; - - fs = dfs; - ss = dss; /* Explicit rounding */ - - pn = panel_number(image->det, p); - assert(pn != -1); - p = &image->det->panels[pn]; - val = image->dp[pn][fs + p->w* ss]; - - if ( val < -32767 ) { - out = -32767; - } else if ( val > 32767 ) { - out = 32767; - } else { - out = val; - } - - buf[(x - min_x) + (y - min_y) * width] = out; - - } - } - - th = TIFFOpen(filename, "w"); - if ( th == NULL ) return 1; - - TIFFSetField(th, TIFFTAG_IMAGEWIDTH, width); - TIFFSetField(th, TIFFTAG_IMAGELENGTH, 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, 0)); - - line = _TIFFmalloc(TIFFScanlineSize(th)); - - for ( y=0; y<height; y++ ) { - TIFFWriteScanline(th, &buf[y*width], y, 0); - } - _TIFFfree(line); - - TIFFClose(th); - free(buf); -#else /* HAVE_TIFF */ - STATUS("No TIFF support.\n"); -#endif /* HAVE_TIFF */ - return 0; -} diff --git a/src/render_hkl.c b/src/render_hkl.c index 5f39766c..715bd73c 100644 --- a/src/render_hkl.c +++ b/src/render_hkl.c @@ -47,7 +47,7 @@ #include "utils.h" #include "symmetry.h" -#include "render.h" +#include "colscale.h" #include "render_hkl.h" #include "reflist.h" #include "reflist-utils.h" |