diff --git a/ChangeLog b/ChangeLog index 1171436b..17ef851f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,7 +3,8 @@ im_LCh2UCS(), im_XYZ2Yxy(), im_Yxy2XYZ(), im_float2rad(), im_rad2float(), im_Lab2LabQ(), im_LabQ2Lab(), im_Lab2LabS(), im_LabS2Lab(), im_LabQ2LabS(), im_LabS2LabQ(), im_LabQ2disp(), im_XYZ2disp(), im_disp2XYZ(), - im_icc_import*(), im_icc_export*(), im_icc_transform*() as classes + im_icc_import*(), im_icc_export*(), im_icc_transform*(), im_dE_fromLab() + as classes - added vips_colour_convert(), replaces all derived conversions - dzsave can write zoomify and google maps layout as well - tilecache supports threaded access diff --git a/libvips/colour/Makefile.am b/libvips/colour/Makefile.am index bdeac870..08f916b9 100644 --- a/libvips/colour/Makefile.am +++ b/libvips/colour/Makefile.am @@ -4,6 +4,7 @@ libcolour_la_SOURCES = \ colour.c \ colour_funcs.c \ colour_dispatch.c \ + dE76.c \ icc_transform.c \ Lab2XYZ.c \ Lab2LCh.c \ @@ -26,7 +27,6 @@ libcolour_la_SOURCES = \ sRGB2XYZ.c \ im_lab_morph.c \ im_dE00_fromLab.c \ - im_dECMC_fromLab.c \ - im_dE_fromLab.c + im_dECMC_fromLab.c INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@ diff --git a/libvips/colour/colour.c b/libvips/colour/colour.c index 6dd84291..d7b148a8 100644 --- a/libvips/colour/colour.c +++ b/libvips/colour/colour.c @@ -396,6 +396,179 @@ vips_colour_code_init( VipsColourCode *code ) { } +G_DEFINE_ABSTRACT_TYPE( VipsColourDifference, vips_colour_difference, + VIPS_TYPE_COLOUR ); + +static int +vips_colour_difference_build( VipsObject *object ) +{ + VipsColour *colour = VIPS_COLOUR( object ); + VipsColourDifference *difference = VIPS_COLOUR_DIFFERENCE( object ); + VipsColourDifferenceClass *class = + VIPS_COLOUR_DIFFERENCE_GET_CLASS( object ); + + VipsImage **t; + VipsImage *left; + VipsImage *right; + VipsImage *extra; + + t = (VipsImage **) vips_object_local_array( object, 10 ); + + left = difference->left; + right = difference->right; + extra = NULL; + + /* Unpack LABQ images, + */ + if( left && + left->Coding == VIPS_CODING_LABQ ) { + if( vips_LabQ2Lab( left, &t[0], NULL ) ) + return( -1 ); + left = t[0]; + } + if( right && + right->Coding == VIPS_CODING_LABQ ) { + if( vips_LabQ2Lab( right, &t[1], NULL ) ) + return( -1 ); + right = t[1]; + } + + if( left && + vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname, + left ) ) + return( -1 ); + if( right && + vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname, + right ) ) + return( -1 ); + + /* Detach and reattach extra bands, if any. If both left and right + * have extra bands, give up. + */ + if( left && + left->Bands > 3 && + right && + right->Bands > 3 ) { + vips_error( VIPS_OBJECT_CLASS( class )->nickname, + "%s", "both images have extra bands" ); + return( -1 ); + } + + if( left && + left->Bands > 3 ) { + if( vips_extract_band( left, &t[2], 0, + "n", 3, + NULL ) ) + return( -1 ); + if( vips_extract_band( left, &t[3], 3, + "n", left->Bands - 3, + NULL ) ) + return( -1 ); + left = t[2]; + extra = t[3]; + } + + if( right && + right->Bands > 3 ) { + if( vips_extract_band( right, &t[4], 0, + "n", 3, + NULL ) ) + return( -1 ); + if( vips_extract_band( right, &t[5], 3, + "n", right->Bands - 3, + NULL ) ) + return( -1 ); + right = t[4]; + extra = t[5]; + } + + if( vips_check_bands_atleast( VIPS_OBJECT_CLASS( class )->nickname, + left, 3 ) ) + return( -1 ); + if( vips_check_bands_atleast( VIPS_OBJECT_CLASS( class )->nickname, + right, 3 ) ) + return( -1 ); + + if( vips_colour_convert( left, &t[6], + difference->interpretation, NULL ) ) + return( -1 ); + left = t[6]; + if( vips_colour_convert( right, &t[7], + difference->interpretation, NULL ) ) + return( -1 ); + right = t[7]; + + /* We only process float. + */ + if( vips_cast_float( left, &t[8], NULL ) ) + return( -1 ); + left = t[8]; + if( vips_cast_float( right, &t[9], NULL ) ) + return( -1 ); + right = t[9]; + + colour->n = 2; + colour->in = (VipsImage **) vips_object_local_array( object, 2 ); + colour->in[0] = left; + colour->in[1] = right; + if( colour->in[0] ) + g_object_ref( colour->in[0] ); + if( colour->in[1] ) + g_object_ref( colour->in[1] ); + + if( VIPS_OBJECT_CLASS( vips_colour_space_parent_class )-> + build( object ) ) + return( -1 ); + + /* Reattach higher bands, if necessary. + */ + if( extra ) { + VipsImage *x; + + if( vips_bandjoin2( colour->out, extra, &x, NULL ) ) + return( -1 ); + + VIPS_UNREF( colour->out ); + + colour->out = x; + } + + return( 0 ); +} + +static void +vips_colour_difference_class_init( VipsColourDifferenceClass *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + vobject_class->nickname = "difference"; + vobject_class->description = _( "calculate colour difference" ); + vobject_class->build = vips_colour_difference_build; + + VIPS_ARG_IMAGE( class, "left", 1, + _( "Left" ), + _( "Left-hand input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsColourDifference, left ) ); + + VIPS_ARG_IMAGE( class, "right", 2, + _( "Right" ), + _( "Right-hand input image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsColourDifference, right ) ); + +} + +static void +vips_colour_difference_init( VipsColourDifference *difference ) +{ +} + + /* A colour-transforming function. */ typedef int (*VipsColourTransformFn)( VipsImage *in, VipsImage **out, ... ); diff --git a/libvips/colour/colour.h b/libvips/colour/colour.h index 4e30d448..2e977b53 100644 --- a/libvips/colour/colour.h +++ b/libvips/colour/colour.h @@ -163,6 +163,43 @@ typedef struct _VipsColourCodeClass { GType vips_colour_code_get_type( void ); +/* Difference between two colour images. + */ + +#define VIPS_TYPE_COLOUR_DIFFERENCE (vips_colour_difference_get_type()) +#define VIPS_COLOUR_DIFFERENCE( obj ) \ + (G_TYPE_CHECK_INSTANCE_CAST( (obj), \ + VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifference )) +#define VIPS_COLOUR_DIFFERENCE_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_CAST( (klass), \ + VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifferenceClass)) +#define VIPS_IS_COLOUR_DIFFERENCE( obj ) \ + (G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_COLOUR_DIFFERENCE )) +#define VIPS_IS_COLOUR_DIFFERENCE_CLASS( klass ) \ + (G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_COLOUR_DIFFERENCE )) +#define VIPS_COLOUR_DIFFERENCE_GET_CLASS( obj ) \ + (G_TYPE_INSTANCE_GET_CLASS( (obj), \ + VIPS_TYPE_COLOUR_DIFFERENCE, VipsColourDifferenceClass )) + +typedef struct _VipsColourDifference { + VipsColour parent_instance; + + VipsImage *left; + VipsImage *right; + + /* Both get converted to this space. + */ + VipsInterpretation interpretation; + +} VipsColourDifference; + +typedef struct _VipsColourDifferenceClass { + VipsColourClass parent_class; + +} VipsColourDifferenceClass; + +GType vips_colour_difference_get_type( void ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/colour/colour_funcs.c b/libvips/colour/colour_funcs.c index 094d04e6..e8e64407 100644 --- a/libvips/colour/colour_funcs.c +++ b/libvips/colour/colour_funcs.c @@ -68,7 +68,7 @@ #include /** - * im_col_pythagoras: + * vips_pythagoras: * @L1: Input coordinate 1 * @a1: Input coordinate 1 * @b1: Input coordinate 1 @@ -79,13 +79,13 @@ * Pythagorean distance between two points in colour space. Lab/XYZ/UCS etc. */ float -im_col_pythagoras( float L1, float a1, float b1, float L2, float a2, float b2 ) +vips_pythagoras( float L1, float a1, float b1, float L2, float a2, float b2 ) { float dL = L1 - L2; float da = a1 - a2; float db = b1 - b2; - return( sqrt( dL*dL + da*da + db*db ) ); + return( sqrt( dL * dL + da * da + db * db ) ); } /* Functions to convert from Lab to uniform colour space and back. diff --git a/libvips/colour/im_dE_fromLab.c b/libvips/colour/dE76.c similarity index 52% rename from libvips/colour/im_dE_fromLab.c rename to libvips/colour/dE76.c index 5e208ffc..c8ba51cc 100644 --- a/libvips/colour/im_dE_fromLab.c +++ b/libvips/colour/dE76.c @@ -6,6 +6,8 @@ * 31/10/09 * - use im__colour_binary() * - gtkdoc comment + * 25/10/12 + * - redone as a class */ /* @@ -40,19 +42,32 @@ #include #include -#include +#include + +#include "colour.h" + +typedef struct _VipsdE76 { + VipsColourDifference parent_instance; + +} VipsdE76; + +typedef VipsColourSpaceClass VipsdE76Class; + +G_DEFINE_TYPE( VipsdE76, vips_dE76, VIPS_TYPE_COLOUR_DIFFERENCE ); /* Find the difference between two buffers of LAB data. */ -void -imb_dE_fromLab( float **p, float *q, int n ) +static void +vips_dE76_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width ) { - float *p1 = p[0]; - float *p2 = p[1]; + float *p1 = (float *) in[0]; + float *p2 = (float *) in[1]; + float *q = (float *) out; + int x; - for( x = 0; x < n; x++ ) { - q[x] = im_col_pythagoras( + for( x = 0; x < width; x++ ) { + q[x] = vips_pythagoras( p1[0], p1[1], p1[2], p2[0], p2[1], p2[2] ); p1 += 3; @@ -60,20 +75,41 @@ imb_dE_fromLab( float **p, float *q, int n ) } } +static void +vips_dE76_class_init( VipsdE76Class *class ) +{ + VipsObjectClass *object_class = (VipsObjectClass *) class; + VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); + + object_class->nickname = "dE76"; + object_class->description = _( "calculate dE76" ); + + colour_class->process_line = vips_dE76_line; +} + +static void +vips_dE76_init( VipsdE76 *dE76 ) +{ +} + /** - * im_dE_fromLab: - * @in1: first input image - * @in2: second input image + * vips_dE76: + * @in: input image * @out: output image * - * Calculate CIE dE 1976 from two Lab images. + * Calculate dE 76. * - * Returns: 0 on success, -1 on error. + * Returns: 0 on success, -1 on error */ -int -im_dE_fromLab( IMAGE *in1, IMAGE *in2, IMAGE *out ) +int +vips_dE76( VipsImage *left, VipsImage *right, VipsImage **out, ... ) { - return( im__colour_difference( "im_dE_fromLab", - in1, in2, out, - (im_wrapmany_fn) imb_dE_fromLab, NULL, NULL ) ); + va_list ap; + int result; + + va_start( ap, out ); + result = vips_call_split( "dE76", ap, left, right, out ); + va_end( ap ); + + return( result ); } diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index f843ff2f..073ccc47 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -2773,3 +2773,20 @@ im_dE_fromXYZ( IMAGE *in1, IMAGE *in2, IMAGE *out ) return( 0 ); } + +int +im_dE_fromLab( IMAGE *in1, IMAGE *in2, IMAGE *out ) +{ + VipsImage *x; + + if( vips_dE76( in1, in2, &x, + NULL ) ) + return( -1 ); + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} diff --git a/libvips/include/vips/colour.h b/libvips/include/vips/colour.h index a31e5fa5..87e744b2 100644 --- a/libvips/include/vips/colour.h +++ b/libvips/include/vips/colour.h @@ -168,6 +168,9 @@ int vips_icc_export( VipsImage *in, VipsImage **out, ... ) int vips_icc_ac2rc( VipsImage *in, VipsImage *out, const char *profile_filename ); +int vips_dE76( VipsImage *left, VipsImage *right, VipsImage **out, ... ) + __attribute__((sentinel)); + void vips_col_Lab2XYZ( float L, float a, float b, float *X, float *Y, float *Z ); void vips_col_XYZ2Lab( float X, float Y, float Z, @@ -193,7 +196,7 @@ int vips_col_sRGB2XYZ( int r, int g, int b, float *X, float *Y, float *Z ); /* Colour loading and conversion functions. */ -float im_col_pythagoras( float L1, float a1, float b1, +float vips_pythagoras( float L1, float a1, float b1, float L2, float a2, float b2 ); float im_col_dECMC( @@ -204,7 +207,6 @@ float im_col_dE00( int im_dECMC_fromLab( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_dE00_fromLab( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_dE_fromXYZ( VipsImage *in1, VipsImage *in2, VipsImage *out ); -int im_dE_fromLab( VipsImage *in1, VipsImage *in2, VipsImage *out ); int im_lab_morph( VipsImage *in, VipsImage *out, DOUBLEMASK *mask, diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 49567e29..41ecede3 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -89,6 +89,7 @@ extern "C" { #define im_col_L2Lucs vips_col_L2Lucs #define im_col_C2Cucs vips_col_C2Cucs #define im_col_Ch2hucs vips_col_Ch2hucs +#define im_col_pythagoras vips_pythagoras #define im_col_make_tables_UCS vips_col_make_tables_UCS #define im_col_Lucs2L vips_col_Lucs2L @@ -775,6 +776,8 @@ int im_UCS2Lab( VipsImage *in, VipsImage *out ); int im_Lab2UCS( VipsImage *in, VipsImage *out ); int im_XYZ2UCS( VipsImage *in, VipsImage *out ); +int im_dE_fromLab( VipsImage *in1, VipsImage *in2, VipsImage *out ); + /* ruby-vips uses this */ #define vips_class_map_concrete_all vips_class_map_all