Merge remote-tracking branch 'origin/master'

This commit is contained in:
John Cupitt 2012-12-14 01:28:31 +00:00
commit 418427b8f9
18 changed files with 524 additions and 222 deletions

View File

@ -31,6 +31,7 @@
- add binary complex operations, with cross_phase as the only one so far - add binary complex operations, with cross_phase as the only one so far
- added vips_bandbool(), with vips_bandand(), _bandor(), _bandeor() as - added vips_bandbool(), with vips_bandand(), _bandor(), _bandeor() as
convenience functions convenience functions
- added scRGB colourspace, linear light float space with sRGB primaries
14/11/12 started 7.30.6 14/11/12 started 7.30.6
- capture tiff warnings earlier - capture tiff warnings earlier

2
TODO
View File

@ -1,3 +1,5 @@
- does radiance import give 0-1 RGB images? we could tag them as scRGB
- now we've removed round-to-nearest from NN, we need something extra in the - now we've removed round-to-nearest from NN, we need something extra in the
affine transform to displace the input cods affine transform to displace the input cods

View File

@ -18,6 +18,10 @@
* - faster and more accurate sRGB <-> XYZ conversion * - faster and more accurate sRGB <-> XYZ conversion
* 6/11/12 * 6/11/12
* - added a 16-bit path * - added a 16-bit path
* 11/12/12
* - spot NaN, Inf in XYZ2RGB, they break LUT indexing
* - split sRGB <-> XYZ into sRGB <-> scRGB <-> XYZ so we can support
* scRGB as a colourspace
*/ */
/* /*
@ -84,30 +88,6 @@ static int vips_Y2v_16[65536 + 1];
*/ */
static float vips_v2Y_16[65536]; static float vips_v2Y_16[65536];
/* We need Y in 0 - 100. We can save three muls later if we pre-scale the
* matrix.
*
* The matrix already includes the D65 channel weighting, so we just scale by
* Y.
*/
#define SCALE (VIPS_D65_Y0)
/* linear RGB -> XYZ matrix.
*/
static float vips_mat_RGB2XYZ[3][3] = {
{ SCALE * 0.4124, SCALE * 0.3576, SCALE * 0.18056 },
{ SCALE * 0.2126, SCALE * 0.7152, SCALE * 0.0722 },
{ SCALE * 0.0193, SCALE * 0.1192, SCALE * 0.9505 }
};
/* XYZ -> linear RGB matrix.
*/
static float vips_mat_XYZ2RGB[3][3] = {
{ 3.2406 / SCALE, -1.5372 / SCALE, -0.4986 / SCALE },
{ -0.9689 / SCALE, 1.8758 / SCALE, 0.0415 / SCALE },
{ 0.0557 / SCALE, -0.2040 / SCALE, 1.0570 / SCALE }
};
/* Do our own indexing of the arrays below to make sure we get efficient mults. /* Do our own indexing of the arrays below to make sure we get efficient mults.
*/ */
#define INDEX( L, A, B ) (L + (A << 6) + (B << 12)) #define INDEX( L, A, B ) (L + (A << 6) + (B << 12))
@ -118,6 +98,29 @@ static VipsPel vips_red[64 * 64 * 64];
static VipsPel vips_green[64 * 64 * 64]; static VipsPel vips_green[64 * 64 * 64];
static VipsPel vips_blue[64 * 64 * 64]; static VipsPel vips_blue[64 * 64 * 64];
/* sRGB to scRGB.
*
* @range is eg. 256 for 8-bit data.
*/
static int
vips_col_sRGB2scRGB( int range, float *lut,
int r, int g, int b, float *R, float *G, float *B )
{
int maxval = range - 1;
int i;
i = VIPS_CLIP( 0, r, maxval );
*R = lut[i];
i = VIPS_CLIP( 0, g, maxval );
*G = lut[i];
i = VIPS_CLIP( 0, b, maxval );
*B = lut[i];
return( 0 );
}
/* Create the sRGB linear and unlinear luts. @range is eg. 256 for 8-bit luts. /* Create the sRGB linear and unlinear luts. @range is eg. 256 for 8-bit luts.
*/ */
static void static void
@ -176,43 +179,12 @@ vips_col_make_tables_RGB_8( void )
} }
} }
/* RGB to XYZ.
*
* @range is eg. 256 for 8-bit data,
*/
static int
vips_col_sRGB2XYZ( int range, float *lut,
int r, int g, int b, float *X, float *Y, float *Z )
{
int maxval = range - 1;
float Yr, Yg, Yb;
int i;
i = VIPS_CLIP( 0, r, maxval );
Yr = lut[i];
i = VIPS_CLIP( 0, g, maxval );
Yg = lut[i];
i = VIPS_CLIP( 0, b, maxval );
Yb = lut[i];
*X = vips_mat_RGB2XYZ[0][0] * Yr +
vips_mat_RGB2XYZ[0][1] * Yg + vips_mat_RGB2XYZ[0][2] * Yb;
*Y = vips_mat_RGB2XYZ[1][0] * Yr +
vips_mat_RGB2XYZ[1][1] * Yg + vips_mat_RGB2XYZ[1][2] * Yb;
*Z = vips_mat_RGB2XYZ[2][0] * Yr +
vips_mat_RGB2XYZ[2][1] * Yg + vips_mat_RGB2XYZ[2][2] * Yb;
return( 0 );
}
int int
vips_col_sRGB2XYZ_8( int r, int g, int b, float *X, float *Y, float *Z ) vips_col_sRGB2scRGB_8( int r, int g, int b, float *R, float *G, float *B )
{ {
vips_col_make_tables_RGB_8(); vips_col_make_tables_RGB_8();
return( vips_col_sRGB2XYZ( 256, vips_v2Y_8, r, g, b, X, Y, Z ) ); return( vips_col_sRGB2scRGB( 256, vips_v2Y_8, r, g, b, R, G, B ) );
} }
static void * static void *
@ -240,25 +212,55 @@ vips_col_make_tables_RGB_16( void )
} }
int int
vips_col_sRGB2XYZ_16( int r, int g, int b, float *X, float *Y, float *Z ) vips_col_sRGB2scRGB_16( int r, int g, int b, float *R, float *G, float *B )
{ {
vips_col_make_tables_RGB_16(); vips_col_make_tables_RGB_16();
return( vips_col_sRGB2XYZ( 65536, vips_v2Y_16, r, g, b, X, Y, Z ) ); return( vips_col_sRGB2scRGB( 65536, vips_v2Y_16, r, g, b, R, G, B ) );
} }
/* Turn XYZ into display colour. Return or=1 for out of gamut - rgb will /* The matrix already includes the D65 channel weighting, so we just scale by
* contain an approximation of the right colour. * Y.
*/
#define SCALE (VIPS_D65_Y0)
/* scRGB to XYZ.
*/
int
vips_col_scRGB2XYZ( float R, float G, float B, float *X, float *Y, float *Z )
{
*X = SCALE * 0.4124 * R + SCALE * 0.3576 * G + SCALE * 0.18056 * B;
*Y = SCALE * 0.2126 * R + SCALE * 0.7152 * G + SCALE * 0.07220 * B;
*Z = SCALE * 0.0193 * R + SCALE * 0.1192 * G + SCALE * 0.9505 * B;
return( 0 );
}
/* Turn XYZ into scRGB.
*/
int
vips_col_XYZ2scRGB( float X, float Y, float Z, float *R, float *G, float *B )
{
*R = 3.2406 / SCALE * X + -1.5372 / SCALE * Y + -0.4986 / SCALE * Z;
*G = -0.9689 / SCALE * X + 1.8758 / SCALE * Y + 0.0415 / SCALE * Z;
*B = 0.0557 / SCALE * X + -0.2040 / SCALE * Y + 1.0570 / SCALE * Z;
return( 0 );
}
/* Turn scRGB into sRGB. Return or=1 for out of gamut - rgb will contain an
* approximation of the right colour.
*
* Return -1 for NaN, Inf etc.
*/ */
static int static int
vips_col_XYZ2sRGB( int range, int *lut, vips_col_scRGB2sRGB( int range, int *lut,
float X, float Y, float Z, float R, float G, float B,
int *r, int *g, int *b, int *r, int *g, int *b,
int *or_ret ) int *or_ret )
{ {
int maxval = range - 1; int maxval = range - 1;
float Yr, Yg, Yb;
int or; int or;
float Yf; float Yf;
int Yi; int Yi;
@ -267,9 +269,9 @@ vips_col_XYZ2sRGB( int range, int *lut,
/* XYZ can be Nan, Inf etc. Throw those values out, they will break /* XYZ can be Nan, Inf etc. Throw those values out, they will break
* our clipping. * our clipping.
*/ */
if( !isnormal( X ) || if( !isnormal( R ) ||
!isnormal( Y ) || !isnormal( G ) ||
!isnormal( Z ) ) { !isnormal( B ) ) {
*r = 0; *r = 0;
*g = 0; *g = 0;
*b = 0; *b = 0;
@ -277,15 +279,6 @@ vips_col_XYZ2sRGB( int range, int *lut,
return( -1 ); return( -1 );
} }
/* Multiply through the matrix to get luminosity values.
*/
Yr = vips_mat_XYZ2RGB[0][0] * X +
vips_mat_XYZ2RGB[0][1] * Y + vips_mat_XYZ2RGB[0][2] * Z;
Yg = vips_mat_XYZ2RGB[1][0] * X +
vips_mat_XYZ2RGB[1][1] * Y + vips_mat_XYZ2RGB[1][2] * Z;
Yb = vips_mat_XYZ2RGB[2][0] * X +
vips_mat_XYZ2RGB[2][1] * Y + vips_mat_XYZ2RGB[2][2] * Z;
/* Clip range, set the out-of-range flag. /* Clip range, set the out-of-range flag.
*/ */
#define CLIP( L, V, H ) { \ #define CLIP( L, V, H ) { \
@ -307,20 +300,20 @@ vips_col_XYZ2sRGB( int range, int *lut,
or = 0; or = 0;
Yf = Yr * maxval; Yf = R * maxval;
CLIP( 0, Yf, maxval); CLIP( 0, Yf, maxval );
Yi = (int) Yf; Yi = (int) Yf;
v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi);
*r = VIPS_RINT( v ); *r = VIPS_RINT( v );
Yf = Yg * maxval; Yf = G * maxval;
CLIP( 0, Yf, maxval); CLIP( 0, Yf, maxval );
Yi = (int) Yf; Yi = (int) Yf;
v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi);
*g = VIPS_RINT( v ); *g = VIPS_RINT( v );
Yf = Yb * maxval; Yf = B * maxval;
CLIP( 0, Yf, maxval); CLIP( 0, Yf, maxval );
Yi = (int) Yf; Yi = (int) Yf;
v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi); v = lut[Yi] + (lut[Yi + 1] - lut[Yi]) * (Yf - Yi);
*b = VIPS_RINT( v ); *b = VIPS_RINT( v );
@ -332,24 +325,24 @@ vips_col_XYZ2sRGB( int range, int *lut,
} }
int int
vips_col_XYZ2sRGB_8( float X, float Y, float Z, vips_col_scRGB2sRGB_8( float R, float G, float B,
int *r, int *g, int *b, int *r, int *g, int *b,
int *or ) int *or )
{ {
vips_col_make_tables_RGB_8(); vips_col_make_tables_RGB_8();
return( vips_col_XYZ2sRGB( 256, vips_Y2v_8, X, Y, Z, r, g, b, or ) ); return( vips_col_scRGB2sRGB( 256, vips_Y2v_8, R, G, B, r, g, b, or ) );
} }
int int
vips_col_XYZ2sRGB_16( float X, float Y, float Z, vips_col_scRGB2sRGB_16( float R, float G, float B,
int *r, int *g, int *b, int *r, int *g, int *b,
int *or ) int *or )
{ {
vips_col_make_tables_RGB_16(); vips_col_make_tables_RGB_16();
return( vips_col_XYZ2sRGB( 65536, vips_Y2v_16, return( vips_col_scRGB2sRGB( 65536, vips_Y2v_16,
X, Y, Z, r, g, b, or ) ); R, G, B, r, g, b, or ) );
} }
/* Build Lab->disp dither tables. /* Build Lab->disp dither tables.
@ -369,11 +362,13 @@ build_tables( void *client )
float A = (signed char) (a << 2); float A = (signed char) (a << 2);
float B = (signed char) (b << 2); float B = (signed char) (b << 2);
float X, Y, Z; float X, Y, Z;
float Rf, Gf, Bf;
int rb, gb, bb; int rb, gb, bb;
int oflow; int oflow;
vips_col_Lab2XYZ( L, A, B, &X, &Y, &Z ); vips_col_Lab2XYZ( L, A, B, &X, &Y, &Z );
vips_col_XYZ2sRGB_8( X, Y, Z, vips_col_XYZ2scRGB( X, Y, Z, &Rf, &Gf, &Bf );
vips_col_scRGB2sRGB_8( Rf, Gf, Bf,
&rb, &gb, &bb, &oflow ); &rb, &gb, &bb, &oflow );
t = INDEX( l, a, b ); t = INDEX( l, a, b );

View File

@ -25,7 +25,9 @@ libcolour_la_SOURCES = \
LabS2LabQ.c \ LabS2LabQ.c \
LabQ2LabS.c \ LabQ2LabS.c \
LabQ2sRGB.c \ LabQ2sRGB.c \
XYZ2sRGB.c \ sRGB2scRGB.c \
sRGB2XYZ.c scRGB2XYZ.c \
XYZ2scRGB.c \
scRGB2sRGB.c
INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

118
libvips/colour/XYZ2scRGB.c Normal file
View File

@ -0,0 +1,118 @@
/* Turn XYZ to scRGB colourspace.
*
* 11/12/12
* - from Yxy2XYZ.c
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
#include "colour.h"
typedef VipsColourSpace VipsXYZ2scRGB;
typedef VipsColourSpaceClass VipsXYZ2scRGBClass;
G_DEFINE_TYPE( VipsXYZ2scRGB, vips_XYZ2scRGB, VIPS_TYPE_COLOUR_SPACE );
void
vips_XYZ2scRGB_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
float *p = (float *) in[0];
float *q = (float *) out;
int i;
for( i = 0; i < width; i++ ) {
float X = p[0];
float Y = p[1];
float Z = p[2];
float R, G, B;
p += 3;
vips_col_XYZ2scRGB( X, Y, Z, &R, &G, &B );
q[0] = R;
q[1] = G;
q[2] = B;
q += 3;
}
}
static void
vips_XYZ2scRGB_class_init( VipsXYZ2scRGBClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
object_class->nickname = "XYZ2scRGB";
object_class->description = _( "transform XYZ to scRGB" );
colour_class->process_line = vips_XYZ2scRGB_line;
}
static void
vips_XYZ2scRGB_init( VipsXYZ2scRGB *XYZ2scRGB )
{
VipsColour *colour = VIPS_COLOUR( XYZ2scRGB );
colour->interpretation = VIPS_INTERPRETATION_scRGB;
}
/**
* vips_XYZ2scRGB:
* @in: input image
* @out: output image
*
* Turn XYZ to Yxy.
*
* Returns: 0 on success, -1 on error
*/
int
vips_XYZ2scRGB( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "XYZ2scRGB", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -798,6 +798,10 @@ vips_colour_operation_init( void )
extern GType vips_LabQ2sRGB_get_type( void ); extern GType vips_LabQ2sRGB_get_type( void );
extern GType vips_XYZ2sRGB_get_type( void ); extern GType vips_XYZ2sRGB_get_type( void );
extern GType vips_sRGB2XYZ_get_type( void ); extern GType vips_sRGB2XYZ_get_type( void );
extern GType vips_sRGB2scRGB_get_type( void );
extern GType vips_scRGB2XYZ_get_type( void );
extern GType vips_XYZ2scRGB_get_type( void );
extern GType vips_scRGB2sRGB_get_type( void );
#if defined(HAVE_LCMS) || defined(HAVE_LCMS2) #if defined(HAVE_LCMS) || defined(HAVE_LCMS2)
extern GType vips_icc_import_get_type( void ); extern GType vips_icc_import_get_type( void );
extern GType vips_icc_export_get_type( void ); extern GType vips_icc_export_get_type( void );
@ -825,8 +829,10 @@ vips_colour_operation_init( void )
vips_rad2float_get_type(); vips_rad2float_get_type();
vips_float2rad_get_type(); vips_float2rad_get_type();
vips_LabQ2sRGB_get_type(); vips_LabQ2sRGB_get_type();
vips_XYZ2sRGB_get_type(); vips_sRGB2scRGB_get_type();
vips_sRGB2XYZ_get_type(); vips_scRGB2XYZ_get_type();
vips_XYZ2scRGB_get_type();
vips_scRGB2sRGB_get_type();
#if defined(HAVE_LCMS) || defined(HAVE_LCMS2) #if defined(HAVE_LCMS) || defined(HAVE_LCMS2)
vips_icc_import_get_type(); vips_icc_import_get_type();
vips_icc_export_get_type(); vips_icc_export_get_type();

View File

@ -49,9 +49,9 @@
#include "colour.h" #include "colour.h"
static int static int
vips_XYZ2RGB16( VipsImage *in, VipsImage **out, ... ) vips_scRGB2RGB16( VipsImage *in, VipsImage **out, ... )
{ {
return( vips_XYZ2sRGB( in, out, "depth", 16, NULL ) ); return( vips_scRGB2sRGB( in, out, "depth", 16, NULL ) );
} }
/* A colour-transforming function. /* A colour-transforming function.
@ -82,6 +82,7 @@ typedef struct _VipsColourRoute {
#define LCH VIPS_INTERPRETATION_LCH #define LCH VIPS_INTERPRETATION_LCH
#define CMC VIPS_INTERPRETATION_CMC #define CMC VIPS_INTERPRETATION_CMC
#define LABS VIPS_INTERPRETATION_LABS #define LABS VIPS_INTERPRETATION_LABS
#define scRGB VIPS_INTERPRETATION_scRGB
#define sRGB VIPS_INTERPRETATION_sRGB #define sRGB VIPS_INTERPRETATION_sRGB
#define RGB16 VIPS_INTERPRETATION_RGB16 #define RGB16 VIPS_INTERPRETATION_RGB16
#define YXY VIPS_INTERPRETATION_YXY #define YXY VIPS_INTERPRETATION_YXY
@ -94,8 +95,9 @@ static VipsColourRoute vips_colour_routes[] = {
{ XYZ, LCH, { vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { XYZ, LCH, { vips_XYZ2Lab, vips_Lab2LCh, NULL } },
{ XYZ, CMC, { vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { XYZ, CMC, { vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ XYZ, LABS, { vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { XYZ, LABS, { vips_XYZ2Lab, vips_Lab2LabS, NULL } },
{ XYZ, sRGB, { vips_XYZ2sRGB, NULL } }, { XYZ, scRGB, { vips_XYZ2scRGB, NULL } },
{ XYZ, RGB16, { vips_XYZ2RGB16, NULL } }, { XYZ, sRGB, { vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } },
{ XYZ, RGB16, { vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } },
{ XYZ, YXY, { vips_XYZ2Yxy, NULL } }, { XYZ, YXY, { vips_XYZ2Yxy, NULL } },
{ LAB, XYZ, { vips_Lab2XYZ, NULL } }, { LAB, XYZ, { vips_Lab2XYZ, NULL } },
@ -103,8 +105,10 @@ static VipsColourRoute vips_colour_routes[] = {
{ LAB, LCH, { vips_Lab2LCh, NULL } }, { LAB, LCH, { vips_Lab2LCh, NULL } },
{ LAB, CMC, { vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LAB, CMC, { vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ LAB, LABS, { vips_Lab2LabS, NULL } }, { LAB, LABS, { vips_Lab2LabS, NULL } },
{ LAB, sRGB, { vips_Lab2XYZ, vips_XYZ2sRGB, NULL } }, { LAB, scRGB, { vips_Lab2XYZ, vips_XYZ2scRGB, NULL } },
{ LAB, RGB16, { vips_Lab2XYZ, vips_XYZ2RGB16, NULL } }, { LAB, sRGB, { vips_Lab2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } },
{ LAB, RGB16, { vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2RGB16, NULL } },
{ LAB, YXY, { vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LAB, YXY, { vips_Lab2XYZ, vips_XYZ2Yxy, NULL } },
{ LABQ, XYZ, { vips_LabQ2Lab, vips_Lab2XYZ, NULL } }, { LABQ, XYZ, { vips_LabQ2Lab, vips_Lab2XYZ, NULL } },
@ -112,8 +116,10 @@ static VipsColourRoute vips_colour_routes[] = {
{ LABQ, LCH, { vips_LabQ2Lab, vips_Lab2LCh, NULL } }, { LABQ, LCH, { vips_LabQ2Lab, vips_Lab2LCh, NULL } },
{ LABQ, CMC, { vips_LabQ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LABQ, CMC, { vips_LabQ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ LABQ, LABS, { vips_LabQ2LabS, NULL } }, { LABQ, LABS, { vips_LabQ2LabS, NULL } },
{ LABQ, scRGB, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB } },
{ LABQ, sRGB, { vips_LabQ2sRGB, NULL } }, { LABQ, sRGB, { vips_LabQ2sRGB, NULL } },
{ LABQ, RGB16, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2RGB16, NULL } }, { LABQ, RGB16, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2RGB16, NULL } },
{ LABQ, YXY, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LABQ, YXY, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } },
{ LCH, XYZ, { vips_LCh2Lab, vips_Lab2XYZ, NULL } }, { LCH, XYZ, { vips_LCh2Lab, vips_Lab2XYZ, NULL } },
@ -121,8 +127,11 @@ static VipsColourRoute vips_colour_routes[] = {
{ LCH, LABQ, { vips_LCh2Lab, vips_Lab2LabQ, NULL } }, { LCH, LABQ, { vips_LCh2Lab, vips_Lab2LabQ, NULL } },
{ LCH, CMC, { vips_LCh2CMC, NULL } }, { LCH, CMC, { vips_LCh2CMC, NULL } },
{ LCH, LABS, { vips_LCh2Lab, vips_Lab2LabS, NULL } }, { LCH, LABS, { vips_LCh2Lab, vips_Lab2LabS, NULL } },
{ LCH, sRGB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2sRGB, NULL } }, { LCH, scRGB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } },
{ LCH, RGB16, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2RGB16, NULL } }, { LCH, sRGB, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2sRGB, NULL } },
{ LCH, RGB16, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2RGB16, NULL } },
{ LCH, YXY, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LCH, YXY, { vips_LCh2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } },
{ CMC, XYZ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, NULL } }, { CMC, XYZ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, NULL } },
@ -130,10 +139,12 @@ static VipsColourRoute vips_colour_routes[] = {
{ CMC, LABQ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabQ, NULL } }, { CMC, LABQ, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabQ, NULL } },
{ CMC, LCH, { vips_CMC2LCh, NULL } }, { CMC, LCH, { vips_CMC2LCh, NULL } },
{ CMC, LABS, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabS, NULL } }, { CMC, LABS, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2LabS, NULL } },
{ CMC, scRGB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ,
vips_XYZ2scRGB, NULL } },
{ CMC, sRGB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, { CMC, sRGB, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ,
vips_XYZ2sRGB, NULL } }, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } },
{ CMC, RGB16, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, { CMC, RGB16, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ,
vips_XYZ2RGB16, NULL } }, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } },
{ CMC, YXY, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ, { CMC, YXY, { vips_CMC2LCh, vips_LCh2Lab, vips_Lab2XYZ,
vips_XYZ2Yxy, NULL } }, vips_XYZ2Yxy, NULL } },
@ -142,19 +153,37 @@ static VipsColourRoute vips_colour_routes[] = {
{ LABS, LABQ, { vips_LabS2LabQ, NULL } }, { LABS, LABQ, { vips_LabS2LabQ, NULL } },
{ LABS, LCH, { vips_LabS2Lab, vips_Lab2LCh, NULL } }, { LABS, LCH, { vips_LabS2Lab, vips_Lab2LCh, NULL } },
{ LABS, CMC, { vips_LabS2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } }, { LABS, CMC, { vips_LabS2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ LABS, sRGB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2sRGB, NULL } }, { LABS, scRGB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } },
{ LABS, RGB16, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2RGB16, NULL } }, { LABS, sRGB, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2sRGB, NULL } },
{ LABS, RGB16, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,
vips_scRGB2RGB16, NULL } },
{ LABS, YXY, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } }, { LABS, YXY, { vips_LabS2Lab, vips_Lab2XYZ, vips_XYZ2Yxy, NULL } },
{ sRGB, XYZ, { vips_sRGB2XYZ, NULL } }, { scRGB, XYZ, { vips_scRGB2XYZ, NULL } },
{ sRGB, LAB, { vips_sRGB2XYZ, vips_XYZ2Lab, NULL } }, { scRGB, LAB, { vips_scRGB2XYZ, vips_XYZ2Lab, NULL } },
{ sRGB, LABQ, { vips_sRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } }, { scRGB, LABQ, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabQ, NULL } },
{ sRGB, LCH, { vips_sRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } }, { scRGB, LCH, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, NULL } },
{ sRGB, CMC, { vips_sRGB2XYZ, vips_XYZ2Lab, vips_Lab2LCh, { scRGB, CMC, { vips_scRGB2XYZ, vips_XYZ2Lab,
vips_LCh2CMC, NULL } }, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ sRGB, LABS, { vips_sRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { scRGB, sRGB, { vips_scRGB2sRGB, NULL } },
{ sRGB, RGB16, { vips_sRGB2XYZ, vips_XYZ2RGB16, NULL } }, { scRGB, LABS, { vips_scRGB2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } },
{ sRGB, YXY, { vips_sRGB2XYZ, vips_XYZ2Yxy, NULL } }, { scRGB, RGB16, { vips_scRGB2RGB16, NULL } },
{ scRGB, YXY, { vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } },
{ sRGB, XYZ, { vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } },
{ sRGB, LAB, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab, NULL } },
{ sRGB, LABQ, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab,
vips_Lab2LabQ, NULL } },
{ sRGB, LCH, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab,
vips_Lab2LCh, NULL } },
{ sRGB, CMC, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab,
vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ sRGB, scRGB, { vips_sRGB2scRGB, NULL } },
{ sRGB, LABS, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab,
vips_Lab2LabS, NULL } },
{ sRGB, RGB16, { vips_sRGB2scRGB, vips_scRGB2RGB16, NULL } },
{ sRGB, YXY, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } },
{ YXY, XYZ, { vips_Yxy2XYZ, NULL } }, { YXY, XYZ, { vips_Yxy2XYZ, NULL } },
{ YXY, LAB, { vips_Yxy2XYZ, vips_XYZ2Lab, NULL } }, { YXY, LAB, { vips_Yxy2XYZ, vips_XYZ2Lab, NULL } },
@ -163,8 +192,9 @@ static VipsColourRoute vips_colour_routes[] = {
{ YXY, CMC, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LCh, { YXY, CMC, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LCh,
vips_LCh2CMC, NULL } }, vips_LCh2CMC, NULL } },
{ YXY, LABS, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } }, { YXY, LABS, { vips_Yxy2XYZ, vips_XYZ2Lab, vips_Lab2LabS, NULL } },
{ YXY, sRGB, { vips_Yxy2XYZ, vips_XYZ2sRGB, NULL } }, { YXY, scRGB, { vips_Yxy2XYZ, vips_XYZ2scRGB, NULL } },
{ YXY, RGB16, { vips_Yxy2XYZ, vips_XYZ2RGB16, NULL } }, { YXY, sRGB, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2sRGB, NULL } },
{ YXY, RGB16, { vips_Yxy2XYZ, vips_XYZ2scRGB, vips_scRGB2RGB16, NULL } },
}; };
/* Is an image in a supported colourspace. /* Is an image in a supported colourspace.

View File

@ -1,10 +1,13 @@
/* Convert Radiance 32bit packed format to float. /* Convert Radiance 32bit packed format to float.
*
* 3/3/09 * 3/3/09
* - from LabQ2Lab and Radiance sources * - from LabQ2Lab and Radiance sources
* 2/11/09 * 2/11/09
* - gtkdoc * - gtkdoc
* 20/9/12 * 20/9/12
* redo as a class * - redo as a class
* 13/12/12
* - tag output as scRGB, since it'll be 0-1
*/ */
/* /*
@ -196,7 +199,7 @@ vips_rad2float_init( VipsRad2float *rad2float )
VipsColourCode *code = VIPS_COLOUR_CODE( rad2float ); VipsColourCode *code = VIPS_COLOUR_CODE( rad2float );
colour->coding = VIPS_CODING_NONE; colour->coding = VIPS_CODING_NONE;
colour->interpretation = VIPS_INTERPRETATION_sRGB; colour->interpretation = VIPS_INTERPRETATION_scRGB;
colour->format = VIPS_FORMAT_FLOAT; colour->format = VIPS_FORMAT_FLOAT;
colour->bands = 3; colour->bands = 3;

View File

@ -1,4 +1,4 @@
/* Turn displayable rgb files to XYZ. /* Turn displayable rgb files to scRGB.
* *
* Modified: * Modified:
* 15/11/94 JC * 15/11/94 JC
@ -10,7 +10,9 @@
* - redone as a class * - redone as a class
* - sRGB only, support for other RGBs is now via lcms * - sRGB only, support for other RGBs is now via lcms
* 6/11/12 * 6/11/12
* - add 15-bit sRGB import * - add 16-bit sRGB import
* 11/12/12
* - cut about to make sRGB2scRGB.c
*/ */
/* /*
@ -51,15 +53,15 @@
#include "colour.h" #include "colour.h"
typedef VipsColourCode VipssRGB2XYZ; typedef VipsColourCode VipssRGB2scRGB;
typedef VipsColourCodeClass VipssRGB2XYZClass; typedef VipsColourCodeClass VipssRGB2scRGBClass;
G_DEFINE_TYPE( VipssRGB2XYZ, vips_sRGB2XYZ, VIPS_TYPE_COLOUR_CODE ); G_DEFINE_TYPE( VipssRGB2scRGB, vips_sRGB2scRGB, VIPS_TYPE_COLOUR_CODE );
/* Convert a buffer of 8-bit pixels. /* Convert a buffer of 8-bit pixels.
*/ */
static void static void
vips_sRGB2XYZ_line_8( float *q, VipsPel *p, int width ) vips_sRGB2scRGB_line_8( float *q, VipsPel *p, int width )
{ {
int i; int i;
@ -67,15 +69,16 @@ vips_sRGB2XYZ_line_8( float *q, VipsPel *p, int width )
int r = p[0]; int r = p[0];
int g = p[1]; int g = p[1];
int b = p[2]; int b = p[2];
float X, Y, Z;
float R, G, B;
p += 3; p += 3;
vips_col_sRGB2XYZ_8( r, g, b, &X, &Y, &Z ); vips_col_sRGB2scRGB_8( r, g, b, &R, &G, &B );
q[0] = X; q[0] = R;
q[1] = Y; q[1] = G;
q[2] = Z; q[2] = B;
q += 3; q += 3;
} }
@ -84,7 +87,7 @@ vips_sRGB2XYZ_line_8( float *q, VipsPel *p, int width )
/* Convert a buffer of 16-bit pixels. /* Convert a buffer of 16-bit pixels.
*/ */
static void static void
vips_sRGB2XYZ_line_16( float *q, unsigned short *p, int width ) vips_sRGB2scRGB_line_16( float *q, unsigned short *p, int width )
{ {
int i; int i;
@ -92,34 +95,35 @@ vips_sRGB2XYZ_line_16( float *q, unsigned short *p, int width )
int r = p[0]; int r = p[0];
int g = p[1]; int g = p[1];
int b = p[2]; int b = p[2];
float X, Y, Z;
float R, G, B;
p += 3; p += 3;
vips_col_sRGB2XYZ_16( r, g, b, &X, &Y, &Z ); vips_col_sRGB2scRGB_16( r, g, b, &R, &G, &B );
q[0] = X; q[0] = R;
q[1] = Y; q[1] = G;
q[2] = Z; q[2] = B;
q += 3; q += 3;
} }
} }
static void static void
vips_sRGB2XYZ_line( VipsColour *colour, vips_sRGB2scRGB_line( VipsColour *colour,
VipsPel *out, VipsPel **in, int width ) VipsPel *out, VipsPel **in, int width )
{ {
if( colour->in[0]->BandFmt == VIPS_FORMAT_UCHAR ) if( colour->in[0]->BandFmt == VIPS_FORMAT_UCHAR )
vips_sRGB2XYZ_line_8( (float *) out, vips_sRGB2scRGB_line_8( (float *) out,
(VipsPel *) in[0], width ); (VipsPel *) in[0], width );
else else
vips_sRGB2XYZ_line_16( (float *) out, vips_sRGB2scRGB_line_16( (float *) out,
(unsigned short *) in[0], width ); (unsigned short *) in[0], width );
} }
static int static int
vips_sRGB2XYZ_build( VipsObject *object ) vips_sRGB2scRGB_build( VipsObject *object )
{ {
VipsColourCode *code = (VipsColourCode *) object; VipsColourCode *code = (VipsColourCode *) object;
@ -128,7 +132,7 @@ vips_sRGB2XYZ_build( VipsObject *object )
code->in->BandFmt == VIPS_FORMAT_USHORT ? code->in->BandFmt == VIPS_FORMAT_USHORT ?
VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR; VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR;
if( VIPS_OBJECT_CLASS( vips_sRGB2XYZ_parent_class )-> if( VIPS_OBJECT_CLASS( vips_sRGB2scRGB_parent_class )->
build( object ) ) build( object ) )
return( -1 ); return( -1 );
@ -136,26 +140,26 @@ vips_sRGB2XYZ_build( VipsObject *object )
} }
static void static void
vips_sRGB2XYZ_class_init( VipssRGB2XYZClass *class ) vips_sRGB2scRGB_class_init( VipssRGB2scRGBClass *class )
{ {
VipsObjectClass *object_class = (VipsObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
object_class->nickname = "sRGB2XYZ"; object_class->nickname = "sRGB2scRGB";
object_class->description = _( "convert an sRGB image to XYZ" ); object_class->description = _( "convert an sRGB image to scRGB" );
object_class->build = vips_sRGB2XYZ_build; object_class->build = vips_sRGB2scRGB_build;
colour_class->process_line = vips_sRGB2XYZ_line; colour_class->process_line = vips_sRGB2scRGB_line;
} }
static void static void
vips_sRGB2XYZ_init( VipssRGB2XYZ *sRGB2XYZ ) vips_sRGB2scRGB_init( VipssRGB2scRGB *sRGB2scRGB )
{ {
VipsColour *colour = VIPS_COLOUR( sRGB2XYZ ); VipsColour *colour = VIPS_COLOUR( sRGB2scRGB );
VipsColourCode *code = VIPS_COLOUR_CODE( sRGB2XYZ ); VipsColourCode *code = VIPS_COLOUR_CODE( sRGB2scRGB );
colour->coding = VIPS_CODING_NONE; colour->coding = VIPS_CODING_NONE;
colour->interpretation = VIPS_INTERPRETATION_XYZ; colour->interpretation = VIPS_INTERPRETATION_scRGB;
colour->format = VIPS_FORMAT_FLOAT; colour->format = VIPS_FORMAT_FLOAT;
colour->bands = 3; colour->bands = 3;
@ -169,26 +173,25 @@ vips_sRGB2XYZ_init( VipssRGB2XYZ *sRGB2XYZ )
} }
/** /**
* vips_sRGB2XYZ: * vips_sRGB2scRGB:
* @in: input image * @in: input image
* @out: output image * @out: output image
* *
* Convert an sRGB image to XYZ. * Convert an sRGB image to scRGB.
* *
* See also: im_LabS2LabQ(), im_sRGB2XYZ(), im_rad2float(). * See also: vips_sRGB2XYZ(), vips_rad2float().
* *
* Returns: 0 on success, -1 on error. * Returns: 0 on success, -1 on error.
*/ */
int int
vips_sRGB2XYZ( VipsImage *in, VipsImage **out, ... ) vips_sRGB2scRGB( VipsImage *in, VipsImage **out, ... )
{ {
va_list ap; va_list ap;
int result; int result;
va_start( ap, out ); va_start( ap, out );
result = vips_call_split( "sRGB2XYZ", ap, in, out ); result = vips_call_split( "sRGB2scRGB", ap, in, out );
va_end( ap ); va_end( ap );
return( result ); return( result );
} }

123
libvips/colour/scRGB2XYZ.c Normal file
View File

@ -0,0 +1,123 @@
/* Turn scRGB to XYZ colourspace.
*
* Modified:
* 29/5/02 JC
* - from lab2xyz
* 2/11/09
* - gtkdoc
* - cleanups
* 20/9/12
* redo as a class
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <math.h>
#include <vips/vips.h>
#include "colour.h"
typedef VipsColourSpace VipsscRGB2XYZ;
typedef VipsColourSpaceClass VipsscRGB2XYZClass;
G_DEFINE_TYPE( VipsscRGB2XYZ, vips_scRGB2XYZ, VIPS_TYPE_COLOUR_SPACE );
void
vips_scRGB2XYZ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
float *p = (float *) in[0];
float *q = (float *) out;
int i;
for( i = 0; i < width; i++ ) {
float R = p[0];
float G = p[1];
float B = p[2];
float X, Y, Z;
p += 3;
vips_col_scRGB2XYZ( R, G, B, &X, &Y, &Z );
q[0] = X;
q[1] = Y;
q[2] = Z;
q += 3;
}
}
static void
vips_scRGB2XYZ_class_init( VipsscRGB2XYZClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
object_class->nickname = "scRGB2XYZ";
object_class->description = _( "transform scRGB to XYZ" );
colour_class->process_line = vips_scRGB2XYZ_line;
}
static void
vips_scRGB2XYZ_init( VipsscRGB2XYZ *scRGB2XYZ )
{
VipsColour *colour = VIPS_COLOUR( scRGB2XYZ );
colour->interpretation = VIPS_INTERPRETATION_XYZ;
}
/**
* vips_scRGB2XYZ:
* @in: input image
* @out: output image
*
* Turn XYZ to scRGB.
*
* Returns: 0 on success, -1 on error
*/
int
vips_scRGB2XYZ( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "scRGB2XYZ", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -1,4 +1,4 @@
/* Turn XYZ files into displayable rgb. /* Turn scRGB files into displayable rgb.
* *
* Author: J-P. Laurent * Author: J-P. Laurent
* Modified: * Modified:
@ -23,6 +23,8 @@
* - sRGB only, support for other RGBs is now via lcms * - sRGB only, support for other RGBs is now via lcms
* 6/11/12 * 6/11/12
* - added 16-bit option * - added 16-bit option
* 11/12/12
* - cut about to make scRGB2sRGB.c
*/ */
/* /*
@ -63,32 +65,32 @@
#include "colour.h" #include "colour.h"
typedef struct _VipsXYZ2sRGB { typedef struct _VipsscRGB2sRGB {
VipsColourCode parent_instance; VipsColourCode parent_instance;
int depth; int depth;
} VipsXYZ2sRGB; } VipsscRGB2sRGB;
typedef VipsColourCodeClass VipsXYZ2sRGBClass; typedef VipsColourCodeClass VipsscRGB2sRGBClass;
G_DEFINE_TYPE( VipsXYZ2sRGB, vips_XYZ2sRGB, VIPS_TYPE_COLOUR_CODE ); G_DEFINE_TYPE( VipsscRGB2sRGB, vips_scRGB2sRGB, VIPS_TYPE_COLOUR_CODE );
/* Process a buffer of data. /* Process a buffer of data.
*/ */
static void static void
vips_XYZ2sRGB_line_8( VipsPel *q, float *p, int width ) vips_scRGB2sRGB_line_8( VipsPel *q, float *p, int width )
{ {
int i; int i;
for( i = 0; i < width; i++ ) { for( i = 0; i < width; i++ ) {
float X = p[0]; float R = p[0];
float Y = p[1]; float G = p[1];
float Z = p[2]; float B = p[2];
int r, g, b; int r, g, b;
int or; int or;
vips_col_XYZ2sRGB_8( X, Y, Z, &r, &g, &b, &or ); vips_col_scRGB2sRGB_8( R, G, B, &r, &g, &b, &or );
p += 3; p += 3;
@ -101,19 +103,19 @@ vips_XYZ2sRGB_line_8( VipsPel *q, float *p, int width )
} }
static void static void
vips_XYZ2sRGB_line_16( unsigned short *q, float *p, int width ) vips_scRGB2sRGB_line_16( unsigned short *q, float *p, int width )
{ {
int i; int i;
for( i = 0; i < width; i++ ) { for( i = 0; i < width; i++ ) {
float X = p[0]; float R = p[0];
float Y = p[1]; float G = p[1];
float Z = p[2]; float B = p[2];
int r, g, b; int r, g, b;
int or; int or;
vips_col_XYZ2sRGB_16( X, Y, Z, &r, &g, &b, &or ); vips_col_scRGB2sRGB_16( R, G, B, &r, &g, &b, &or );
p += 3; p += 3;
@ -126,25 +128,27 @@ vips_XYZ2sRGB_line_16( unsigned short *q, float *p, int width )
} }
static void static void
vips_XYZ2sRGB_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width ) vips_scRGB2sRGB_line( VipsColour *colour,
VipsPel *out, VipsPel **in, int width )
{ {
VipsXYZ2sRGB *XYZ2sRGB = (VipsXYZ2sRGB *) colour; VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) colour;
if( XYZ2sRGB->depth == 16 ) if( scRGB2sRGB->depth == 16 )
vips_XYZ2sRGB_line_16( (unsigned short *) out, (float *) in[0], vips_scRGB2sRGB_line_16( (unsigned short *) out,
width ); (float *) in[0], width );
else else
vips_XYZ2sRGB_line_8( (VipsPel *) out, (float *) in[0], width ); vips_scRGB2sRGB_line_8( (VipsPel *) out,
(float *) in[0], width );
} }
static int static int
vips_XYZ2sRGB_build( VipsObject *object ) vips_scRGB2sRGB_build( VipsObject *object )
{ {
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsXYZ2sRGB *XYZ2sRGB = (VipsXYZ2sRGB *) object; VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) object;
VipsColour *colour = VIPS_COLOUR( XYZ2sRGB ); VipsColour *colour = VIPS_COLOUR( scRGB2sRGB );
switch( XYZ2sRGB->depth ) { switch( scRGB2sRGB->depth ) {
case 16: case 16:
colour->interpretation = VIPS_INTERPRETATION_RGB16; colour->interpretation = VIPS_INTERPRETATION_RGB16;
colour->format = VIPS_FORMAT_USHORT; colour->format = VIPS_FORMAT_USHORT;
@ -161,14 +165,14 @@ vips_XYZ2sRGB_build( VipsObject *object )
return( -1 ); return( -1 );
} }
if( VIPS_OBJECT_CLASS( vips_XYZ2sRGB_parent_class )->build( object ) ) if( VIPS_OBJECT_CLASS( vips_scRGB2sRGB_parent_class )->build( object ) )
return( -1 ); return( -1 );
return( 0 ); return( 0 );
} }
static void static void
vips_XYZ2sRGB_class_init( VipsXYZ2sRGBClass *class ) vips_scRGB2sRGB_class_init( VipsscRGB2sRGBClass *class )
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS( class ); GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class; VipsObjectClass *object_class = (VipsObjectClass *) class;
@ -177,25 +181,25 @@ vips_XYZ2sRGB_class_init( VipsXYZ2sRGBClass *class )
gobject_class->set_property = vips_object_set_property; gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property; gobject_class->get_property = vips_object_get_property;
object_class->nickname = "XYZ2sRGB"; object_class->nickname = "scRGB2sRGB";
object_class->description = _( "convert an XYZ image to sRGB" ); object_class->description = _( "convert an scRGB image to sRGB" );
object_class->build = vips_XYZ2sRGB_build; object_class->build = vips_scRGB2sRGB_build;
colour_class->process_line = vips_XYZ2sRGB_line; colour_class->process_line = vips_scRGB2sRGB_line;
VIPS_ARG_INT( class, "depth", 130, VIPS_ARG_INT( class, "depth", 130,
_( "Depth" ), _( "Depth" ),
_( "Output device space depth in bits" ), _( "Output device space depth in bits" ),
VIPS_ARGUMENT_OPTIONAL_INPUT, VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsXYZ2sRGB, depth ), G_STRUCT_OFFSET( VipsscRGB2sRGB, depth ),
8, 16, 8 ); 8, 16, 8 );
} }
static void static void
vips_XYZ2sRGB_init( VipsXYZ2sRGB *XYZ2sRGB ) vips_scRGB2sRGB_init( VipsscRGB2sRGB *scRGB2sRGB )
{ {
VipsColour *colour = VIPS_COLOUR( XYZ2sRGB ); VipsColour *colour = VIPS_COLOUR( scRGB2sRGB );
VipsColourCode *code = VIPS_COLOUR_CODE( XYZ2sRGB ); VipsColourCode *code = VIPS_COLOUR_CODE( scRGB2sRGB );
/* Just the default, can be overridden, see above. /* Just the default, can be overridden, see above.
*/ */
@ -208,11 +212,11 @@ vips_XYZ2sRGB_init( VipsXYZ2sRGB *XYZ2sRGB )
code->input_bands = 3; code->input_bands = 3;
code->input_format = VIPS_FORMAT_FLOAT; code->input_format = VIPS_FORMAT_FLOAT;
XYZ2sRGB->depth = 8; scRGB2sRGB->depth = 8;
} }
/** /**
* vips_XYZ2sRGB: * vips_scRGB2sRGB:
* @in: input image * @in: input image
* @out: output image * @out: output image
* *
@ -220,20 +224,20 @@ vips_XYZ2sRGB_init( VipsXYZ2sRGB *XYZ2sRGB )
* *
* @depth: depth of output image in bits * @depth: depth of output image in bits
* *
* Convert an XYZ image to sRGB. Set @depth to 16 to get 16-bit output. * Convert an scRGB image to sRGB. Set @depth to 16 to get 16-bit output.
* *
* See also: im_LabS2LabQ(), im_XYZ2sRGB(), im_rad2float(). * See also: im_LabS2LabQ(), im_scRGB2sRGB(), im_rad2float().
* *
* Returns: 0 on success, -1 on error. * Returns: 0 on success, -1 on error.
*/ */
int int
vips_XYZ2sRGB( VipsImage *in, VipsImage **out, ... ) vips_scRGB2sRGB( VipsImage *in, VipsImage **out, ... )
{ {
va_list ap; va_list ap;
int result; int result;
va_start( ap, out ); va_start( ap, out );
result = vips_call_split( "XYZ2sRGB", ap, in, out ); result = vips_call_split( "scRGB2sRGB", ap, in, out );
va_end( ap ); va_end( ap );
return( result ); return( result );

View File

@ -2495,7 +2495,7 @@ im_dE_fromdisp( IMAGE *im1, IMAGE *im2, IMAGE *out, struct im_col_display *d )
int int
im_disp2Lab( IMAGE *in, IMAGE *out, struct im_col_display *d ) im_disp2Lab( IMAGE *in, IMAGE *out, struct im_col_display *d )
{ {
IMAGE *t[1]; VipsImage *t[1];
if( im_open_local_array( out, t, 1, "im_disp2Lab:1", "p" ) || if( im_open_local_array( out, t, 1, "im_disp2Lab:1", "p" ) ||
im_disp2XYZ( in, t[0], d ) || im_disp2XYZ( in, t[0], d ) ||
@ -2508,15 +2508,13 @@ im_disp2Lab( IMAGE *in, IMAGE *out, struct im_col_display *d )
int int
im_sRGB2XYZ( IMAGE *in, IMAGE *out ) im_sRGB2XYZ( IMAGE *in, IMAGE *out )
{ {
VipsImage *x; VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) out, 2 );
if( vips_sRGB2XYZ( in, &x, NULL ) ) if( vips_sRGB2scRGB( in, &t[0], NULL ) ||
vips_scRGB2XYZ( t[0], &t[1], NULL ) ||
im_copy( t[1], out ) )
return( -1 ); return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 ); return( 0 );
} }
@ -2524,15 +2522,13 @@ im_sRGB2XYZ( IMAGE *in, IMAGE *out )
int int
im_XYZ2sRGB( IMAGE *in, IMAGE *out ) im_XYZ2sRGB( IMAGE *in, IMAGE *out )
{ {
VipsImage *x; VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) out, 2 );
if( vips_XYZ2sRGB( in, &x, NULL ) ) if( vips_XYZ2scRGB( in, &t[0], NULL ) ||
vips_scRGB2sRGB( t[0], &t[1], NULL ) ||
im_copy( t[1], out ) )
return( -1 ); return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 ); return( 0 );
} }

View File

@ -6,6 +6,8 @@
* - add radiance write * - add radiance write
* 20/12/11 * 20/12/11
* - reworked as some fns ready for new-style classes * - reworked as some fns ready for new-style classes
* 13/12/12
* - tag RGB rad images as scRGB
*/ */
/* /*
@ -900,7 +902,7 @@ rad2vips_get_header( Read *read, FILE *fin, VipsImage *out )
vips_image_set_string( out, "rad-format", read->format ); vips_image_set_string( out, "rad-format", read->format );
if( strcmp( read->format, COLRFMT ) == 0 ) if( strcmp( read->format, COLRFMT ) == 0 )
out->Type = VIPS_INTERPRETATION_RGB; out->Type = VIPS_INTERPRETATION_scRGB;
else if( strcmp( read->format, CIEFMT ) == 0 ) else if( strcmp( read->format, CIEFMT ) == 0 )
out->Type = VIPS_INTERPRETATION_XYZ; out->Type = VIPS_INTERPRETATION_XYZ;
else else

View File

@ -141,10 +141,16 @@ int vips_Lab2XYZ( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_XYZ2Lab( VipsImage *in, VipsImage **out, ... ) int vips_XYZ2Lab( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_XYZ2sRGB( VipsImage *in, VipsImage **out, ... )
int vips_XYZ2scRGB( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_sRGB2XYZ( VipsImage *in, VipsImage **out, ... ) int vips_scRGB2sRGB( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_sRGB2scRGB( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_scRGB2XYZ( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_LCh2CMC( VipsImage *in, VipsImage **out, ... ) int vips_LCh2CMC( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel)); __attribute__((sentinel));
int vips_CMC2LCh( VipsImage *in, VipsImage **out, ... ) int vips_CMC2LCh( VipsImage *in, VipsImage **out, ... )
@ -193,13 +199,20 @@ float vips_col_Lcmc2L( float Lcmc );
float vips_col_Ccmc2C( float Ccmc ); float vips_col_Ccmc2C( float Ccmc );
float vips_col_Chcmc2h( float C, float hcmc ); float vips_col_Chcmc2h( float C, float hcmc );
int vips_col_XYZ2sRGB_8( float X, float Y, float Z, int vips_col_sRGB2scRGB_8( int r, int g, int b, float *R, float *G, float *B );
int *r, int *g, int *b, int *or_ret ); int vips_col_sRGB2scRGB_16( int r, int g, int b, float *R, float *G, float *B );
int vips_col_sRGB2XYZ_8( int r, int g, int b, float *X, float *Y, float *Z );
int vips_col_XYZ2sRGB_16( float X, float Y, float Z, int vips_col_scRGB2XYZ( float R, float G, float B,
int *r, int *g, int *b, int *or_ret ); float *X, float *Y, float *Z );
int vips_col_sRGB2XYZ_16( int r, int g, int b, float *X, float *Y, float *Z ); int vips_col_XYZ2scRGB( float X, float Y, float Z,
float *R, float *G, float *B );
int vips_col_scRGB2sRGB_8( float R, float G, float B,
int *r, int *g, int *b,
int *or_ret );
int vips_col_scRGB2sRGB_16( float R, float G, float B,
int *r, int *g, int *b,
int *or_ret );
float vips_pythagoras( float L1, float a1, float b1, float vips_pythagoras( float L1, float a1, float b1,
float L2, float a2, float b2 ); float L2, float a2, float b2 );

View File

@ -122,6 +122,7 @@ typedef enum {
* @VIPS_INTERPRETATION_LCH: pixels are in CIE LCh space * @VIPS_INTERPRETATION_LCH: pixels are in CIE LCh space
* @VIPS_INTERPRETATION_LABS: CIE LAB coded as three signed 16-bit values * @VIPS_INTERPRETATION_LABS: CIE LAB coded as three signed 16-bit values
* @VIPS_INTERPRETATION_sRGB: pixels are sRGB * @VIPS_INTERPRETATION_sRGB: pixels are sRGB
* @VIPS_INTERPRETATION_scRGB: pixels are scRGB
* @VIPS_INTERPRETATION_YXY: pixels are CIE Yxy * @VIPS_INTERPRETATION_YXY: pixels are CIE Yxy
* @VIPS_INTERPRETATION_RGB16: generic 16-bit RGB * @VIPS_INTERPRETATION_RGB16: generic 16-bit RGB
* @VIPS_INTERPRETATION_GREY16: generic 16-bit mono * @VIPS_INTERPRETATION_GREY16: generic 16-bit mono
@ -156,7 +157,8 @@ typedef enum {
VIPS_INTERPRETATION_FOURIER = 24, VIPS_INTERPRETATION_FOURIER = 24,
VIPS_INTERPRETATION_RGB16 = 25, VIPS_INTERPRETATION_RGB16 = 25,
VIPS_INTERPRETATION_GREY16 = 26, VIPS_INTERPRETATION_GREY16 = 26,
VIPS_INTERPRETATION_ARRAY = 27 VIPS_INTERPRETATION_ARRAY = 27,
VIPS_INTERPRETATION_scRGB = 28
} VipsInterpretation; } VipsInterpretation;
/** /**

View File

@ -493,6 +493,7 @@ vips_interpretation_get_type( void )
{VIPS_INTERPRETATION_RGB16, "VIPS_INTERPRETATION_RGB16", "rgb16"}, {VIPS_INTERPRETATION_RGB16, "VIPS_INTERPRETATION_RGB16", "rgb16"},
{VIPS_INTERPRETATION_GREY16, "VIPS_INTERPRETATION_GREY16", "grey16"}, {VIPS_INTERPRETATION_GREY16, "VIPS_INTERPRETATION_GREY16", "grey16"},
{VIPS_INTERPRETATION_ARRAY, "VIPS_INTERPRETATION_ARRAY", "array"}, {VIPS_INTERPRETATION_ARRAY, "VIPS_INTERPRETATION_ARRAY", "array"},
{VIPS_INTERPRETATION_scRGB, "VIPS_INTERPRETATION_scRGB", "scrgb"},
{0, NULL, NULL} {0, NULL, NULL}
}; };

View File

@ -441,6 +441,7 @@ vips_image_guess_interpretation( const VipsImage *image )
case VIPS_INTERPRETATION_CMC: case VIPS_INTERPRETATION_CMC:
case VIPS_INTERPRETATION_LCH: case VIPS_INTERPRETATION_LCH:
case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_sRGB:
case VIPS_INTERPRETATION_scRGB:
case VIPS_INTERPRETATION_YXY: case VIPS_INTERPRETATION_YXY:
if( image->Bands < 3 ) if( image->Bands < 3 )
sane = FALSE; sane = FALSE;

View File

@ -457,7 +457,7 @@ vips_image_sanity( VipsObject *object, VipsBuf *buf )
image->Coding != VIPS_CODING_NONE && image->Coding != VIPS_CODING_NONE &&
image->Coding != VIPS_CODING_LABQ && image->Coding != VIPS_CODING_LABQ &&
image->Coding != VIPS_CODING_RAD) || image->Coding != VIPS_CODING_RAD) ||
image->Type > VIPS_INTERPRETATION_ARRAY || image->Type > VIPS_INTERPRETATION_scRGB ||
image->dtype > VIPS_IMAGE_PARTIAL || image->dtype > VIPS_IMAGE_PARTIAL ||
image->dhint > VIPS_DEMAND_STYLE_ANY ) image->dhint > VIPS_DEMAND_STYLE_ANY )
vips_buf_appends( buf, "bad enum\n" ); vips_buf_appends( buf, "bad enum\n" );