#include #include #include #include "pngoutput.h" #include "colourspace.h" #include "wavelength.h" const double brightness = 1.5; void output_srgb_scanline( double *output, int line, int width, int height ) { double vpos = (double) line / (double) ( height - 1 ); double wx, wy, wz; int i; vpos = 1.0 - vpos; /* use D65 */ xyy_to_xyz( 0.3127, 0.3290, brightness, &wx, &wy, &wz ); for( i = 0; i < width; i++ ) { double upos = (double) i / (double) ( width - 1 ); double curX, curY, curZ; double xpos, ypos; uvy_to_xyz( upos, vpos, brightness, &curX, &curY, &curZ ); xpos = curX / ( curX + curY + curZ ); ypos = curY / ( curX + curY + curZ ); xyy_to_xyz( xpos, ypos, brightness, &curX, &curY, &curZ ); if( xy_in_gamut( xpos, ypos ) && curX >= 0.0 && curY >= 0.0 && curZ >= 0.0 ) { double r, g, b; double ri, gi, bi; xyz_to_srgb( curX, curY, curZ, &r, &g, &b ); if( r >= 0.0 && g >= 0.0 && b >= 0.0 ) { xyy_to_xyz( xpos, ypos, brightness + (brightness * 0.2), &curX, &curY, &curZ ); xyz_to_srgb( curX, curY, curZ, &r, &g, &b ); } closest_in_gamut_srgb( r, g, b, wx, wy, wz, &ri, &gi, &bi ); *output++ = ri; *output++ = gi; *output++ = bi; } else { *output++ = 0.0; *output++ = 0.0; *output++ = 0.0; } } } void quantize_srgb_scanline_8bit( unsigned char *output, double *input, int width ) { while( width-- ) { double r = *input++; double g = *input++; double b = *input++; double rp, gp, bp; linear_to_nonlinear_srgb( r, g, b, &rp, &gp, &bp ); *output++ = (unsigned char) ( ( rp * 255.0 ) + 0.5 ); *output++ = (unsigned char) ( ( gp * 255.0 ) + 0.5 ); *output++ = (unsigned char) ( ( bp * 255.0 ) + 0.5 ); } } void add_wavelengths( double *image, int width, int height ) { int i; for( i = 360; i < 831; i++ ) { double X, Y, Z; double up, vp; int upos, vpos; wavelength_to_xyz( i, &X, &Y, &Z ); up = ( 4.0 * X ) / ( X + ( 15.0 * Y ) + ( 3.0 * Z ) ); vp = ( 9.0 * Y ) / ( X + ( 15.0 * Y ) + ( 3.0 * Z ) ); upos = (int) ( ( up * (double) ( width - 1 ) ) + 0.5 ); vpos = (int) ( ( ( 1.0 - vp ) * (double) ( height - 1 ) ) + 0.5 ); image[ ( vpos * width * 3 ) + ( upos * 3 ) ] = 1.0; image[ ( vpos * width * 3 ) + ( upos * 3 ) + 1 ] = 1.0; image[ ( vpos * width * 3 ) + ( upos * 3 ) + 2 ] = 1.0; } } void add_d65( double *image, int width, int height ) { double X, Y, Z; double x, y; double up, vp; int upos, vpos; x = 0.3127; y = 0.3290; xyy_to_xyz( x, y, brightness, &X, &Y, &Z ); up = ( 4.0 * X ) / ( X + ( 15.0 * Y ) + ( 3.0 * Z ) ); vp = ( 9.0 * Y ) / ( X + ( 15.0 * Y ) + ( 3.0 * Z ) ); upos = (int) ( ( up * (double) ( width - 1 ) ) + 0.5 ); vpos = (int) ( ( ( 1.0 - vp ) * (double) ( height - 1 ) ) + 0.5 ); image[ ( vpos * width * 3 ) + ( upos * 3 ) ] = 1.0; image[ ( vpos * width * 3 ) + ( upos * 3 ) + 1 ] = 1.0; image[ ( vpos * width * 3 ) + ( upos * 3 ) + 2 ] = 1.0; } int main( int argc, char **argv ) { int width = 800; int height = 600; unsigned char *output = (unsigned char *) malloc( width * 3 ); double *rgbimage = (double *) malloc( sizeof( double ) * width * height * 3 ); pngoutput_t *outfile; double biggest = 0.0; double scale; int i; assert( output ); assert( rgbimage ); outfile = pngoutput_new( "uv-srgb.png", width, height, 0.45 ); for( i = 0; i < height; i++ ) { output_srgb_scanline( &(rgbimage[ width * i * 3 ]), i, width, height ); } for( i = 0; i < ( width * height * 3 ); i++ ) { if( rgbimage[ i ] > biggest ) biggest = rgbimage[ i ]; } scale = 1.0 / biggest; for( i = 0; i < ( width * height * 3 ); i++ ) { rgbimage[ i ] *= scale; } add_wavelengths( rgbimage, width, height ); add_d65( rgbimage, width, height ); for( i = 0; i < height; i++ ) { quantize_srgb_scanline_8bit( output, rgbimage + ( width * i * 3 ), width ); pngoutput_scanline( outfile, output ); } pngoutput_delete( outfile ); return 0; }