From 52a188c3c5a5d83fc6244add19cadcdd79a4f369 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 26 Sep 2012 14:53:14 +0100 Subject: [PATCH] new icc stuff now works --- TODO | 11 +++ libvips/colour/LCh2Lab.c | 4 +- libvips/colour/LCh2UCS.c | 4 +- libvips/colour/Lab2LCh.c | 4 +- libvips/colour/Lab2LabQ.c | 20 +++-- libvips/colour/Lab2LabS.c | 18 ++-- libvips/colour/Lab2XYZ.c | 5 +- libvips/colour/LabQ2Lab.c | 16 ++-- libvips/colour/LabQ2LabS.c | 16 ++-- libvips/colour/LabQ2sRGB.c | 16 ++-- libvips/colour/LabS2Lab.c | 18 ++-- libvips/colour/LabS2LabQ.c | 20 +++-- libvips/colour/UCS2LCh.c | 4 +- libvips/colour/XYZ2Lab.c | 5 +- libvips/colour/XYZ2Yxy.c | 4 +- libvips/colour/XYZ2sRGB.c | 20 +++-- libvips/colour/Yxy2XYZ.c | 4 +- libvips/colour/colour.c | 47 +++++----- libvips/colour/colour.h | 22 +---- libvips/colour/float2rad.c | 20 +++-- libvips/colour/icc_transform.c | 140 +++++++++++++++++++---------- libvips/colour/rad2float.c | 16 ++-- libvips/colour/sRGB2XYZ.c | 20 +++-- libvips/deprecated/vips7compat.c | 3 +- libvips/foreign/foreign.c | 30 ++++++- libvips/foreign/vipssave.c | 3 - libvips/include/vips/colour.h | 5 +- libvips/include/vips/vips7compat.h | 4 +- libvips/iofuncs/error.c | 4 +- 29 files changed, 302 insertions(+), 201 deletions(-) diff --git a/TODO b/TODO index 1d80d2cf..e22e1812 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,16 @@ - im_icc_ac2rc needs doing once we have a general 'convert' operator +- auto cast to float in XYZ2sRGB seems broken? + +- should we have a better thing to stop convert_saveable running for vips + images? + +- convert_saveable should become a lot simpler with a general colourspace + converter + +- export should allow use of the embedded profile as an output? + + - boolean.c has diff --git a/libvips/colour/LCh2Lab.c b/libvips/colour/LCh2Lab.c index 5743ca0a..629ebf55 100644 --- a/libvips/colour/LCh2Lab.c +++ b/libvips/colour/LCh2Lab.c @@ -118,12 +118,14 @@ vips_LCh2Lab_class_init( VipsLCh2LabClass *class ) object_class->description = _( "transform LCh to Lab" ); colour_class->process_line = vips_LCh2Lab_line; - colour_class->interpretation = VIPS_INTERPRETATION_LAB; } static void vips_LCh2Lab_init( VipsLCh2Lab *LCh2Lab ) { + VipsColour *colour = VIPS_COLOUR( LCh2Lab ); + + colour->interpretation = VIPS_INTERPRETATION_LAB; } /** diff --git a/libvips/colour/LCh2UCS.c b/libvips/colour/LCh2UCS.c index 564189d4..ddbca0b1 100644 --- a/libvips/colour/LCh2UCS.c +++ b/libvips/colour/LCh2UCS.c @@ -178,12 +178,14 @@ vips_LCh2UCS_class_init( VipsLCh2UCSClass *class ) object_class->description = _( "transform LCh to UCS" ); colour_class->process_line = vips_LCh2UCS_line; - colour_class->interpretation = VIPS_INTERPRETATION_UCS; } static void vips_LCh2UCS_init( VipsLCh2UCS *LCh2UCS ) { + VipsColour *colour = VIPS_COLOUR( LCh2UCS ); + + colour->interpretation = VIPS_INTERPRETATION_UCS; } /** diff --git a/libvips/colour/Lab2LCh.c b/libvips/colour/Lab2LCh.c index 39f6dace..fef8f298 100644 --- a/libvips/colour/Lab2LCh.c +++ b/libvips/colour/Lab2LCh.c @@ -131,12 +131,14 @@ vips_Lab2LCh_class_init( VipsLab2LChClass *class ) object_class->description = _( "transform Lab to LCh" ); colour_class->process_line = vips_Lab2LCh_line; - colour_class->interpretation = VIPS_INTERPRETATION_LCH; } static void vips_Lab2LCh_init( VipsLab2LCh *Lab2LCh ) { + VipsColour *colour = VIPS_COLOUR( Lab2LCh ); + + colour->interpretation = VIPS_INTERPRETATION_LCH; } /** diff --git a/libvips/colour/Lab2LabQ.c b/libvips/colour/Lab2LabQ.c index 7d081d74..91240c67 100644 --- a/libvips/colour/Lab2LabQ.c +++ b/libvips/colour/Lab2LabQ.c @@ -130,25 +130,27 @@ vips_Lab2LabQ_class_init( VipsLab2LabQClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "Lab2LabQ"; object_class->description = _( "transform float Lab to LabQ coding" ); colour_class->process_line = vips_Lab2LabQ_line; - colour_class->coding = VIPS_CODING_LABQ; - colour_class->interpretation = VIPS_INTERPRETATION_LABQ; - colour_class->format = VIPS_FORMAT_UCHAR; - colour_class->bands = 4; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_format = VIPS_FORMAT_FLOAT; - code_class->input_bands = 3; } static void vips_Lab2LabQ_init( VipsLab2LabQ *Lab2LabQ ) { + VipsColour *colour = VIPS_COLOUR( Lab2LabQ ); + VipsColourCode *code = VIPS_COLOUR_CODE( Lab2LabQ ); + + colour->coding = VIPS_CODING_LABQ; + colour->interpretation = VIPS_INTERPRETATION_LABQ; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 4; + + code->input_coding = VIPS_CODING_NONE; + code->input_format = VIPS_FORMAT_FLOAT; + code->input_bands = 3; } /** diff --git a/libvips/colour/Lab2LabS.c b/libvips/colour/Lab2LabS.c index c80a2d97..96c68403 100644 --- a/libvips/colour/Lab2LabS.c +++ b/libvips/colour/Lab2LabS.c @@ -74,24 +74,26 @@ vips_Lab2LabS_class_init( VipsLab2LabSClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "Lab2LabS"; object_class->description = _( "transform float Lab to signed short" ); colour_class->process_line = vips_Lab2LabS_line; - colour_class->interpretation = VIPS_INTERPRETATION_LABS; - colour_class->format = VIPS_FORMAT_SHORT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_format = VIPS_FORMAT_FLOAT; - code_class->input_bands = 3; } static void vips_Lab2LabS_init( VipsLab2LabS *Lab2LabS ) { + VipsColour *colour = VIPS_COLOUR( Lab2LabS ); + VipsColourCode *code = VIPS_COLOUR_CODE( Lab2LabS ); + + colour->interpretation = VIPS_INTERPRETATION_LABS; + colour->format = VIPS_FORMAT_SHORT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_NONE; + code->input_format = VIPS_FORMAT_FLOAT; + code->input_bands = 3; } /** diff --git a/libvips/colour/Lab2XYZ.c b/libvips/colour/Lab2XYZ.c index 5d2c25da..80994275 100644 --- a/libvips/colour/Lab2XYZ.c +++ b/libvips/colour/Lab2XYZ.c @@ -168,7 +168,6 @@ vips_Lab2XYZ_class_init( VipsLab2XYZClass *class ) object_class->build = vips_Lab2XYZ_build; colour_class->process_line = vips_Lab2XYZ_line; - colour_class->interpretation = VIPS_INTERPRETATION_XYZ; VIPS_ARG_BOXED( class, "temp", 110, _( "Temperature" ), @@ -181,9 +180,13 @@ vips_Lab2XYZ_class_init( VipsLab2XYZClass *class ) static void vips_Lab2XYZ_init( VipsLab2XYZ *Lab2XYZ ) { + VipsColour *colour = VIPS_COLOUR( Lab2XYZ ); + Lab2XYZ->X0 = VIPS_D65_X0; Lab2XYZ->Y0 = VIPS_D65_Y0; Lab2XYZ->Z0 = VIPS_D65_Z0; + + colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** diff --git a/libvips/colour/LabQ2Lab.c b/libvips/colour/LabQ2Lab.c index 827f31d1..db3f8166 100644 --- a/libvips/colour/LabQ2Lab.c +++ b/libvips/colour/LabQ2Lab.c @@ -118,23 +118,25 @@ vips_LabQ2Lab_class_init( VipsLabQ2LabClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "LabQ2Lab"; object_class->description = _( "unpack a LabQ image to float Lab" ); colour_class->process_line = vips_LabQ2Lab_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_LAB; - colour_class->format = VIPS_FORMAT_FLOAT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_LABQ; } static void vips_LabQ2Lab_init( VipsLabQ2Lab *LabQ2Lab ) { + VipsColour *colour = VIPS_COLOUR( LabQ2Lab ); + VipsColourCode *code = VIPS_COLOUR_CODE( LabQ2Lab ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_LAB; + colour->format = VIPS_FORMAT_FLOAT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_LABQ; } /** diff --git a/libvips/colour/LabQ2LabS.c b/libvips/colour/LabQ2LabS.c index 7d25eae0..bfaa492a 100644 --- a/libvips/colour/LabQ2LabS.c +++ b/libvips/colour/LabQ2LabS.c @@ -98,23 +98,25 @@ vips_LabQ2LabS_class_init( VipsLabQ2LabSClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "LabQ2LabS"; object_class->description = _( "unpack a LabQ image to short Lab" ); colour_class->process_line = vips_LabQ2LabS_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_LABS; - colour_class->format = VIPS_FORMAT_SHORT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_LABQ; } static void vips_LabQ2LabS_init( VipsLabQ2LabS *LabQ2LabS ) { + VipsColour *colour = VIPS_COLOUR( LabQ2LabS ); + VipsColourCode *code = VIPS_COLOUR_CODE( LabQ2LabS ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_LABS; + colour->format = VIPS_FORMAT_SHORT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_LABQ; } /** diff --git a/libvips/colour/LabQ2sRGB.c b/libvips/colour/LabQ2sRGB.c index b736c9f1..7248f4cc 100644 --- a/libvips/colour/LabQ2sRGB.c +++ b/libvips/colour/LabQ2sRGB.c @@ -432,18 +432,11 @@ vips_LabQ2sRGB_class_init( VipsLabQ2sRGBClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "LabQ2sRGB"; object_class->description = _( "unpack a LabQ image to short Lab" ); colour_class->process_line = vips_LabQ2sRGB_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_sRGB; - colour_class->format = VIPS_FORMAT_UCHAR; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_LABQ; vips_col_make_tables_LabQ2sRGB(); } @@ -451,6 +444,15 @@ vips_LabQ2sRGB_class_init( VipsLabQ2sRGBClass *class ) static void vips_LabQ2sRGB_init( VipsLabQ2sRGB *LabQ2sRGB ) { + VipsColour *colour = VIPS_COLOUR( LabQ2sRGB ); + VipsColourCode *code = VIPS_COLOUR_CODE( LabQ2sRGB ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_sRGB; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 3; + + code->input_coding = VIPS_CODING_LABQ; } /** diff --git a/libvips/colour/LabS2Lab.c b/libvips/colour/LabS2Lab.c index 3df6211c..6bce80b8 100644 --- a/libvips/colour/LabS2Lab.c +++ b/libvips/colour/LabS2Lab.c @@ -72,24 +72,26 @@ vips_LabS2Lab_class_init( VipsLabS2LabClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "LabS2Lab"; object_class->description = _( "transform signed short Lab to float" ); colour_class->process_line = vips_LabS2Lab_line; - colour_class->interpretation = VIPS_INTERPRETATION_LAB; - colour_class->format = VIPS_FORMAT_FLOAT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_format = VIPS_FORMAT_SHORT; - code_class->input_bands = 3; } static void vips_LabS2Lab_init( VipsLabS2Lab *LabS2Lab ) { + VipsColour *colour = VIPS_COLOUR( LabS2Lab ); + VipsColourCode *code = VIPS_COLOUR_CODE( LabS2Lab ); + + colour->interpretation = VIPS_INTERPRETATION_LAB; + colour->format = VIPS_FORMAT_FLOAT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_NONE; + code->input_format = VIPS_FORMAT_SHORT; + code->input_bands = 3; } /** diff --git a/libvips/colour/LabS2LabQ.c b/libvips/colour/LabS2LabQ.c index 7a337a45..992120a6 100644 --- a/libvips/colour/LabS2LabQ.c +++ b/libvips/colour/LabS2LabQ.c @@ -120,25 +120,27 @@ vips_LabS2LabQ_class_init( VipsLabS2LabQClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "LabS2LabQ"; object_class->description = _( "transform short Lab to LabQ coding" ); colour_class->process_line = vips_LabS2LabQ_line; - colour_class->coding = VIPS_CODING_LABQ; - colour_class->interpretation = VIPS_INTERPRETATION_LABQ; - colour_class->format = VIPS_FORMAT_UCHAR; - colour_class->bands = 4; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_format = VIPS_FORMAT_SHORT; - code_class->input_bands = 3; } static void vips_LabS2LabQ_init( VipsLabS2LabQ *LabS2LabQ ) { + VipsColour *colour = VIPS_COLOUR( LabS2LabQ ); + VipsColourCode *code = VIPS_COLOUR_CODE( LabS2LabQ ); + + colour->coding = VIPS_CODING_LABQ; + colour->interpretation = VIPS_INTERPRETATION_LABQ; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 4; + + code->input_coding = VIPS_CODING_NONE; + code->input_format = VIPS_FORMAT_SHORT; + code->input_bands = 3; } /** diff --git a/libvips/colour/UCS2LCh.c b/libvips/colour/UCS2LCh.c index 4f1a2c8b..9c813d0d 100644 --- a/libvips/colour/UCS2LCh.c +++ b/libvips/colour/UCS2LCh.c @@ -265,13 +265,15 @@ vips_UCS2LCh_class_init( VipsUCS2LChClass *class ) object_class->description = _( "transform LCh to UCS" ); colour_class->process_line = vips_UCS2LCh_line; - colour_class->interpretation = VIPS_INTERPRETATION_LCH; } static void vips_UCS2LCh_init( VipsUCS2LCh *UCS2LCh ) { + VipsColour *colour = VIPS_COLOUR( UCS2LCh ); + vips_col_make_tables_UCS(); + colour->interpretation = VIPS_INTERPRETATION_LCH; } /** diff --git a/libvips/colour/XYZ2Lab.c b/libvips/colour/XYZ2Lab.c index 99392e2d..f4705485 100644 --- a/libvips/colour/XYZ2Lab.c +++ b/libvips/colour/XYZ2Lab.c @@ -226,7 +226,6 @@ vips_XYZ2Lab_class_init( VipsXYZ2LabClass *class ) object_class->build = vips_XYZ2Lab_build; colour_class->process_line = vips_XYZ2Lab_line; - colour_class->interpretation = VIPS_INTERPRETATION_LAB; VIPS_ARG_BOXED( class, "temp", 110, _( "Temperature" ), @@ -239,9 +238,13 @@ vips_XYZ2Lab_class_init( VipsXYZ2LabClass *class ) static void vips_XYZ2Lab_init( VipsXYZ2Lab *XYZ2Lab ) { + VipsColour *colour = VIPS_COLOUR( XYZ2Lab ); + XYZ2Lab->X0 = VIPS_D65_X0; XYZ2Lab->Y0 = VIPS_D65_Y0; XYZ2Lab->Z0 = VIPS_D65_Z0; + + colour->interpretation = VIPS_INTERPRETATION_LAB; } /** diff --git a/libvips/colour/XYZ2Yxy.c b/libvips/colour/XYZ2Yxy.c index d8b4f504..39e4a3c0 100644 --- a/libvips/colour/XYZ2Yxy.c +++ b/libvips/colour/XYZ2Yxy.c @@ -91,12 +91,14 @@ vips_XYZ2Yxy_class_init( VipsXYZ2YxyClass *class ) object_class->description = _( "transform XYZ to Yxy" ); colour_class->process_line = vips_XYZ2Yxy_line; - colour_class->interpretation = VIPS_INTERPRETATION_YXY; } static void vips_XYZ2Yxy_init( VipsXYZ2Yxy *XYZ2Yxy ) { + VipsColour *colour = VIPS_COLOUR( XYZ2Yxy ); + + colour->interpretation = VIPS_INTERPRETATION_YXY; } /** diff --git a/libvips/colour/XYZ2sRGB.c b/libvips/colour/XYZ2sRGB.c index 83fcb1e2..61eab867 100644 --- a/libvips/colour/XYZ2sRGB.c +++ b/libvips/colour/XYZ2sRGB.c @@ -101,25 +101,27 @@ vips_XYZ2sRGB_class_init( VipsXYZ2sRGBClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "XYZ2sRGB"; object_class->description = _( "convert an XYZ image to sRGB" ); colour_class->process_line = vips_XYZ2sRGB_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_sRGB; - colour_class->format = VIPS_FORMAT_UCHAR; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_bands = 3; - code_class->input_format = VIPS_FORMAT_FLOAT; } static void vips_XYZ2sRGB_init( VipsXYZ2sRGB *XYZ2sRGB ) { + VipsColour *colour = VIPS_COLOUR( XYZ2sRGB ); + VipsColourCode *code = VIPS_COLOUR_CODE( XYZ2sRGB ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_sRGB; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 3; + + code->input_coding = VIPS_CODING_NONE; + code->input_bands = 3; + code->input_format = VIPS_FORMAT_FLOAT; } /** diff --git a/libvips/colour/Yxy2XYZ.c b/libvips/colour/Yxy2XYZ.c index 3f656bdd..e7e80967 100644 --- a/libvips/colour/Yxy2XYZ.c +++ b/libvips/colour/Yxy2XYZ.c @@ -92,12 +92,14 @@ vips_Yxy2XYZ_class_init( VipsYxy2XYZClass *class ) object_class->description = _( "transform Yxy to XYZ" ); colour_class->process_line = vips_Yxy2XYZ_line; - colour_class->interpretation = VIPS_INTERPRETATION_XYZ; } static void vips_Yxy2XYZ_init( VipsYxy2XYZ *Yxy2XYZ ) { + VipsColour *colour = VIPS_COLOUR( Yxy2XYZ ); + + colour->interpretation = VIPS_INTERPRETATION_XYZ; } /** diff --git a/libvips/colour/colour.c b/libvips/colour/colour.c index 637021e8..34191083 100644 --- a/libvips/colour/colour.c +++ b/libvips/colour/colour.c @@ -165,11 +165,6 @@ vips_colour_class_init( VipsColourClass *class ) operation_class->flags = VIPS_OPERATION_SEQUENTIAL; - class->coding = VIPS_CODING_NONE; - class->interpretation = VIPS_INTERPRETATION_sRGB; - class->format = VIPS_FORMAT_UCHAR; - class->bands = 3; - VIPS_ARG_IMAGE( class, "out", 100, _( "Output" ), _( "Output image" ), @@ -180,12 +175,10 @@ vips_colour_class_init( VipsColourClass *class ) static void vips_colour_init( VipsColour *colour ) { - VipsColourClass *class = VIPS_COLOUR_GET_CLASS( colour ); - - colour->coding = class->coding; - colour->interpretation = class->interpretation; - colour->format = class->format; - colour->bands = class->bands; + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_sRGB; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 3; } G_DEFINE_ABSTRACT_TYPE( VipsColourSpace, vips_colour_space, VIPS_TYPE_COLOUR ); @@ -258,7 +251,6 @@ vips_colour_space_class_init( VipsColourSpaceClass *class ) { GObjectClass *gobject_class = G_OBJECT_CLASS( class ); VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class ); - VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); gobject_class->set_property = vips_object_set_property; gobject_class->get_property = vips_object_get_property; @@ -267,11 +259,6 @@ vips_colour_space_class_init( VipsColourSpaceClass *class ) vobject_class->description = _( "colour space transformations" ); vobject_class->build = vips_colour_space_build; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_sRGB; - colour_class->format = VIPS_FORMAT_FLOAT; - colour_class->bands = 3; - VIPS_ARG_IMAGE( class, "in", 1, _( "Input" ), _( "Input image" ), @@ -282,6 +269,15 @@ vips_colour_space_class_init( VipsColourSpaceClass *class ) static void vips_colour_space_init( VipsColourSpace *space ) { + VipsColour *colour = (VipsColour *) space; + + /* What we write. interpretation should be overwritten in subclass + * builds. + */ + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_LAB; + colour->format = VIPS_FORMAT_FLOAT; + colour->bands = 3; } G_DEFINE_ABSTRACT_TYPE( VipsColourCode, vips_colour_code, VIPS_TYPE_COLOUR ); @@ -302,6 +298,16 @@ vips_colour_code_build( VipsObject *object ) in = code->in; extra = NULL; + /* If this is a LABQ and the coder wants uncoded, unpack. + */ + if( in && + in->Coding == VIPS_CODING_LABQ && + code->input_coding == VIPS_CODING_NONE ) { + if( vips_LabQ2Lab( in, &t[0], NULL ) ) + return( -1 ); + in = t[0]; + } + if( in && vips_check_coding( VIPS_OBJECT_CLASS( class )->nickname, in, code->input_coding ) ) @@ -378,8 +384,6 @@ vips_colour_code_class_init( VipsColourCodeClass *class ) vobject_class->description = _( "change colour coding" ); vobject_class->build = vips_colour_code_build; - class->input_coding = VIPS_CODING_ERROR; - VIPS_ARG_IMAGE( class, "in", 1, _( "Input" ), _( "Input image" ), @@ -390,11 +394,6 @@ vips_colour_code_class_init( VipsColourCodeClass *class ) static void vips_colour_code_init( VipsColourCode *code ) { - VipsColourCodeClass *class = VIPS_COLOUR_CODE_GET_CLASS( code ); - - code->input_coding = class->input_coding; - code->input_format = class->input_format; - code->input_bands = class->input_bands; } /* Called from iofuncs to init all operations in this dir. Use a plugin system diff --git a/libvips/colour/colour.h b/libvips/colour/colour.h index 992941bd..4e30d448 100644 --- a/libvips/colour/colour.h +++ b/libvips/colour/colour.h @@ -89,13 +89,6 @@ typedef struct _VipsColourClass { */ VipsColourProcessFn process_line; - /* Init fields on instance from these. - */ - VipsCoding coding; - VipsInterpretation interpretation; - VipsBandFormat format; - int bands; - } VipsColourClass; GType vips_colour_get_type( void ); @@ -155,7 +148,7 @@ typedef struct _VipsColourCode { VipsImage *in; - /* Test in against these, init them from class. + /* Test in against these. */ VipsCoding input_coding; VipsBandFormat input_format; @@ -166,19 +159,6 @@ typedef struct _VipsColourCode { typedef struct _VipsColourCodeClass { VipsColourClass parent_class; - /* Input must be in this coding. - */ - VipsCoding input_coding; - - /* If set, cast input to this. - */ - VipsBandFormat input_format; - - /* If >0, the number of bands we process. Extra bands are removed and - * reattached to the output, if it's uncoded. - */ - int input_bands; - } VipsColourCodeClass; GType vips_colour_code_get_type( void ); diff --git a/libvips/colour/float2rad.c b/libvips/colour/float2rad.c index 90b4d8c3..9c15b0b2 100644 --- a/libvips/colour/float2rad.c +++ b/libvips/colour/float2rad.c @@ -192,26 +192,28 @@ vips_float2rad_class_init( VipsFloat2radClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "float2rad"; object_class->description = _( "transform float RGB to Radiance coding" ); colour_class->process_line = vips_float2rad_line; - colour_class->coding = VIPS_CODING_RAD; - colour_class->interpretation = VIPS_INTERPRETATION_sRGB; - colour_class->format = VIPS_FORMAT_UCHAR; - colour_class->bands = 4; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_format = VIPS_FORMAT_FLOAT; - code_class->input_bands = 3; } static void vips_float2rad_init( VipsFloat2rad *float2rad ) { + VipsColour *colour = VIPS_COLOUR( float2rad ); + VipsColourCode *code = VIPS_COLOUR_CODE( float2rad ); + + colour->coding = VIPS_CODING_RAD; + colour->interpretation = VIPS_INTERPRETATION_sRGB; + colour->format = VIPS_FORMAT_UCHAR; + colour->bands = 4; + + code->input_coding = VIPS_CODING_NONE; + code->input_format = VIPS_FORMAT_FLOAT; + code->input_bands = 3; } /** diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index b188a5d7..e062359e 100644 --- a/libvips/colour/icc_transform.c +++ b/libvips/colour/icc_transform.c @@ -188,26 +188,6 @@ vips_icc_build( VipsObject *object ) return( -1 ); } - if( icc->in_profile && - !cmsIsIntentSupported( icc->in_profile, - icc->intent, LCMS_USED_AS_INPUT ) ) - vips_warn( class->nickname, - _( "intent %d (%s) not supported by " - "input profile; falling back to default intent " - "(usually PERCEPTUAL)" ), - icc->intent, - vips_enum_nick( VIPS_TYPE_INTENT, icc->intent ) ); - - if( icc->out_profile && - !cmsIsIntentSupported( icc->out_profile, - icc->intent, LCMS_USED_AS_OUTPUT ) ) - vips_warn( class->nickname, - _( "intent %d (%s) not supported by " - "profile; falling back to default intent " - "(usually PERCEPTUAL)" ), - icc->intent, - vips_enum_nick( VIPS_TYPE_INTENT, icc->intent ) ); - if( icc->in_profile && code->in ) { switch( cmsGetColorSpace( icc->in_profile ) ) { @@ -281,14 +261,14 @@ vips_icc_build( VipsObject *object ) return( -1 ); } - /* At least one must be a device profile, see the buffer processor. + /* At least one must be a device profile. */ if( icc->in_profile && icc->out_profile && cmsGetColorSpace( icc->in_profile ) == cmsSigLabData && cmsGetColorSpace( icc->out_profile ) == cmsSigLabData ) { vips_error( class->nickname, - "%s", _( "no device profiles" ) ); + "%s", _( "no device profile" ) ); return( -1 ); } @@ -360,6 +340,20 @@ typedef VipsIccClass VipsIccImportClass; G_DEFINE_TYPE( VipsIccImport, vips_icc_import, VIPS_TYPE_ICC ); +static void +vips_check_intent( const char *domain, + cmsHPROFILE profile, VipsIntent intent, int direction ) +{ + if( profile && + !cmsIsIntentSupported( profile, intent, direction ) ) + vips_warn( domain, + _( "intent %d (%s) not supported by " + "%s profile; falling back to default intent" ), + intent, vips_enum_nick( VIPS_TYPE_INTENT, intent ), + direction == LCMS_USED_AS_INPUT ? + _( "input" ) : _( "output" ) ); +} + static int vips_icc_import_build( VipsObject *object ) { @@ -368,12 +362,24 @@ vips_icc_import_build( VipsObject *object ) VipsIcc *icc = (VipsIcc *) object; VipsIccImport *import = (VipsIccImport *) object; + /* We read the input profile like this: + * + * embedded filename action + * 0 0 image + * 1 0 image + * 0 1 file + * 1 1 image, then fall back to file + * + * see also import_build. + */ + if( code->in && - import->embedded && + (import->embedded || + !import->input_profile_filename) && vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { void *data; size_t data_length; - + if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, &data, &data_length ) || !(icc->in_profile = cmsOpenProfileFromMem( @@ -397,6 +403,9 @@ vips_icc_import_build( VipsObject *object ) return( -1 ); } + vips_check_intent( class->nickname, + icc->in_profile, icc->intent, LCMS_USED_AS_INPUT ); + #ifdef HAVE_LCMS2 { cmsCIExyY white; @@ -415,7 +424,7 @@ vips_icc_import_build( VipsObject *object ) } static void -decode_lab( float *lab, guint16 *fixed, int n ) +decode_lab( guint16 *fixed, float *lab, int n ) { int i; @@ -448,14 +457,14 @@ vips_icc_import_line( VipsColour *colour, const int chunk = VIPS_MIN( width, PIXEL_BUFFER_SIZE ); #ifdef HAVE_LCMS2 - cmsDoTransform( icc->trans, encoded, p, chunk ); + cmsDoTransform( icc->trans, p, encoded, chunk ); #else g_mutex_lock( icc->lock ); - cmsDoTransform( icc->trans, encoded, p, chunk ); + cmsDoTransform( icc->trans, p, encoded, chunk ); g_mutex_unlock( icc->lock ); #endif - decode_lab( q, encoded, chunk ); + decode_lab( encoded, q, chunk ); p += chunk * VIPS_IMAGE_SIZEOF_PEL( colour->out ); q += chunk * 3; @@ -551,6 +560,7 @@ vips_icc_export_build( VipsObject *object ) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsColour *colour = (VipsColour *) object; + VipsColourCode *code = (VipsColourCode *) object; VipsIcc *icc = (VipsIcc *) object; VipsIccExport *export = (VipsIccExport *) object; @@ -565,7 +575,22 @@ vips_icc_export_build( VipsObject *object ) icc->in_profile = cmsCreateLabProfile( NULL ); #endif - if( export->output_profile_filename ) { + if( code->in && + !export->output_profile_filename && + vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { + void *data; + size_t data_length; + + if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, + &data, &data_length ) || + !(icc->out_profile = cmsOpenProfileFromMem( + data, data_length )) ) { + vips_error( class->nickname, + "%s", _( "unable to load embedded profile" ) ); + return( -1 ); + } + } + else if( export->output_profile_filename ) { if( !(icc->out_profile = cmsOpenProfileFromFile( export->output_profile_filename, "r" )) ) { vips_error( class->nickname, @@ -576,6 +601,13 @@ vips_icc_export_build( VipsObject *object ) colour->profile_filename = export->output_profile_filename; } + else { + vips_error( class->nickname, "%s", _( "no output profile" ) ); + return( -1 ); + } + + vips_check_intent( class->nickname, + icc->out_profile, icc->intent, LCMS_USED_AS_OUTPUT ); if( VIPS_OBJECT_CLASS( vips_icc_export_parent_class )->build( object ) ) return( -1 ); @@ -587,7 +619,7 @@ vips_icc_export_build( VipsObject *object ) * lcms-1.0.8. */ static void -encode_lab( guint16 *fixed, float *lab, int n ) +encode_lab( float *lab, guint16 *fixed, int n ) { int i; @@ -637,13 +669,13 @@ vips_icc_export_line( VipsColour *colour, while( width > 0 ) { const int chunk = VIPS_MIN( width, PIXEL_BUFFER_SIZE ); - encode_lab( encoded, p, chunk ); + encode_lab( p, encoded, chunk ); #ifdef HAVE_LCMS2 - cmsDoTransform( icc->trans, q, encoded, chunk ); + cmsDoTransform( icc->trans, encoded, q, chunk ); #else g_mutex_lock( icc->lock ); - cmsDoTransform( icc->trans, q, encoded, chunk ); + cmsDoTransform( icc->trans, encoded, q, chunk ); g_mutex_unlock( icc->lock ); #endif @@ -672,7 +704,7 @@ vips_icc_export_class_init( VipsIccExportClass *class ) VIPS_ARG_STRING( class, "output_profile", 110, _( "Output profile" ), _( "Filename to load output profile from" ), - VIPS_ARGUMENT_REQUIRED_INPUT, + VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsIccExport, output_profile_filename ), NULL ); @@ -693,27 +725,28 @@ vips_icc_export_init( VipsIccExport *export ) * vips_icc_export: * @in: input image * @out: output image - * @output_profile: get the output profile from here * * Optional arguments: * * @intent: transform with this intent * @depth: depth of output image in bits + * @output_profile: get the output profile from here * - * Export an image from D65 LAB to device space with an ICC profile. - * @output_profile is attached to the output image. + * Export an image from D65 LAB to device space with an ICC profile. + * If @output_profile is not set, use the embedded profile, if any. + * If @output_profile is set, export with that and attach it to the output + * image. * * Returns: 0 on success, -1 on error. */ int -vips_icc_export( VipsImage *in, VipsImage **out, - const char *output_profile, ... ) +vips_icc_export( VipsImage *in, VipsImage **out, ... ) { va_list ap; int result; - va_start( ap, output_profile ); - result = vips_call_split( "icc_export", ap, in, out, output_profile ); + va_start( ap, out ); + result = vips_call_split( "icc_export", ap, in, out ); va_end( ap ); return( result ); @@ -741,12 +774,24 @@ vips_icc_transform_build( VipsObject *object ) VipsIcc *icc = (VipsIcc *) object; VipsIccTransform *transform = (VipsIccTransform *) object; + /* We read the input profile like this: + * + * embedded filename action + * 0 0 image + * 1 0 image + * 0 1 file + * 1 1 image, then fall back to file + * + * see also import_build. + */ + if( code->in && - transform->embedded && + (transform->embedded || + !transform->input_profile_filename) && vips_image_get_typeof( code->in, VIPS_META_ICC_NAME ) ) { void *data; size_t data_length; - + if( vips_image_get_blob( code->in, VIPS_META_ICC_NAME, &data, &data_length ) || !(icc->in_profile = cmsOpenProfileFromMem( @@ -782,6 +827,11 @@ vips_icc_transform_build( VipsObject *object ) colour->profile_filename = transform->output_profile_filename; } + vips_check_intent( class->nickname, + icc->in_profile, icc->intent, LCMS_USED_AS_INPUT ); + vips_check_intent( class->nickname, + icc->out_profile, icc->intent, LCMS_USED_AS_OUTPUT ); + if( VIPS_OBJECT_CLASS( vips_icc_transform_parent_class )-> build( object ) ) return( -1 ); @@ -798,10 +848,10 @@ vips_icc_transform_line( VipsColour *colour, VipsIcc *icc = (VipsIcc *) colour; #ifdef HAVE_LCMS2 - cmsDoTransform( icc->trans, out, in[0], width ); + cmsDoTransform( icc->trans, in[0], out, width ); #else g_mutex_lock( icc->lock ); - cmsDoTransform( icc->trans, out, in[0], width ); + cmsDoTransform( icc->trans, in[0], out, width ); g_mutex_unlock( icc->lock ); #endif } diff --git a/libvips/colour/rad2float.c b/libvips/colour/rad2float.c index 1af04954..79cbe3bd 100644 --- a/libvips/colour/rad2float.c +++ b/libvips/colour/rad2float.c @@ -181,24 +181,26 @@ vips_rad2float_class_init( VipsRad2floatClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "rad2float"; object_class->description = _( "unpack Radiance coding to float RGB" ); colour_class->process_line = vips_rad2float_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_sRGB; - colour_class->format = VIPS_FORMAT_FLOAT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_RAD; } static void vips_rad2float_init( VipsRad2float *rad2float ) { + VipsColour *colour = VIPS_COLOUR( rad2float ); + VipsColourCode *code = VIPS_COLOUR_CODE( rad2float ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_sRGB; + colour->format = VIPS_FORMAT_FLOAT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_RAD; } /** diff --git a/libvips/colour/sRGB2XYZ.c b/libvips/colour/sRGB2XYZ.c index 87307768..a00fac73 100644 --- a/libvips/colour/sRGB2XYZ.c +++ b/libvips/colour/sRGB2XYZ.c @@ -87,25 +87,27 @@ vips_sRGB2XYZ_class_init( VipssRGB2XYZClass *class ) { VipsObjectClass *object_class = (VipsObjectClass *) class; VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class ); - VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class ); object_class->nickname = "sRGB2XYZ"; object_class->description = _( "convert an sRGB image to XYZ" ); colour_class->process_line = vips_sRGB2XYZ_line; - colour_class->coding = VIPS_CODING_NONE; - colour_class->interpretation = VIPS_INTERPRETATION_XYZ; - colour_class->format = VIPS_FORMAT_FLOAT; - colour_class->bands = 3; - - code_class->input_coding = VIPS_CODING_NONE; - code_class->input_bands = 3; - code_class->input_format = VIPS_FORMAT_UCHAR; } static void vips_sRGB2XYZ_init( VipssRGB2XYZ *sRGB2XYZ ) { + VipsColour *colour = VIPS_COLOUR( sRGB2XYZ ); + VipsColourCode *code = VIPS_COLOUR_CODE( sRGB2XYZ ); + + colour->coding = VIPS_CODING_NONE; + colour->interpretation = VIPS_INTERPRETATION_XYZ; + colour->format = VIPS_FORMAT_FLOAT; + colour->bands = 3; + + code->input_coding = VIPS_CODING_NONE; + code->input_bands = 3; + code->input_format = VIPS_FORMAT_UCHAR; } /** diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 1a9c64af..bb204325 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -2624,7 +2624,8 @@ im_icc_export_depth( VipsImage *in, VipsImage *out, int depth, { VipsImage *x; - if( vips_icc_export( in, &x, output_profile_filename, + if( vips_icc_export( in, &x, + "output_profile", output_profile_filename, "depth", depth, "intent", intent, NULL ) ) diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index a76ccf98..be544748 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -1095,9 +1095,8 @@ vips_foreign_convert_saveable( VipsForeignSave *save ) */ g_object_ref( in ); - /* Can this class save the coding we are in now? Nothing to do. - * Uncoded images may need to have their formats and bands clipped - * though. + /* For coded images, can this class save the coding we are in now? + * Nothing to do. */ if( in->Coding != VIPS_CODING_NONE && class->coding[in->Coding] ) { @@ -1107,6 +1106,18 @@ vips_foreign_convert_saveable( VipsForeignSave *save ) return( 0 ); } + /* For uncoded images, if this saver supports ANY bands and this + * format we have nothing to do. + */ + if( in->Coding == VIPS_CODING_NONE && + class->saveable == VIPS_SAVEABLE_ANY && + class->format_table[in->BandFmt] == in->BandFmt ) { + VIPS_UNREF( save->ready ); + save->ready = in; + + return( 0 ); + } + /* Otherwise ... we need to decode and then (possibly) recode at the * end. */ @@ -1300,6 +1311,19 @@ vips_foreign_convert_saveable( VipsForeignSave *save ) in->Type == VIPS_INTERPRETATION_LAB ) { VipsImage *out; + if( vips_Lab2XYZ( in, &out, NULL ) ) { + g_object_unref( in ); + return( -1 ); + } + g_object_unref( in ); + + in = out; + } + + if( in->Bands == 3 && + in->Type == VIPS_INTERPRETATION_XYZ ) { + VipsImage *out; + if( vips_XYZ2sRGB( in, &out, NULL ) ) { g_object_unref( in ); return( -1 ); diff --git a/libvips/foreign/vipssave.c b/libvips/foreign/vipssave.c index f08111e4..eb3a1913 100644 --- a/libvips/foreign/vipssave.c +++ b/libvips/foreign/vipssave.c @@ -87,9 +87,6 @@ vips_foreign_save_vips_build( VipsObject *object ) #define D VIPS_FORMAT_DOUBLE #define DX VIPS_FORMAT_DPCOMPLEX -/* Type promotion for division. Sign and value preserving. Make sure - * these match the case statement in complexform_buffer() above. - */ static int vips_bandfmt_vips[10] = { /* UC C US S UI I F X D DX */ UC, C, US, S, UI, I, F, X, D, DX diff --git a/libvips/include/vips/colour.h b/libvips/include/vips/colour.h index 440bab8d..6e318554 100644 --- a/libvips/include/vips/colour.h +++ b/libvips/include/vips/colour.h @@ -155,12 +155,11 @@ int vips_Lab2LabS( VipsImage *in, VipsImage **out, ... ) int vips_icc_present( void ); int vips_icc_transform( VipsImage *in, VipsImage **out, - const char *output_profile_filename, ... ) + const char *output_profile, ... ) __attribute__((sentinel)); int vips_icc_import( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); -int vips_icc_export( VipsImage *in, VipsImage **out, - const char *output_profile, ... ) +int vips_icc_export( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); int vips_icc_ac2rc( VipsImage *in, VipsImage *out, const char *profile_filename ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 04f5e4bf..8094cf55 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -142,9 +142,9 @@ extern "C" { #define REGION VipsRegion #define IM_INTENT_PERCEPTUAL VIPS_INTENT_PERCEPTUAL -#define IM_INTENT_RELATIVE_COLORIMETRIC VIPS_INTENT_RELATIVE_COLORIMETRIC +#define IM_INTENT_RELATIVE_COLORIMETRIC VIPS_INTENT_RELATIVE #define IM_INTENT_SATURATION VIPS_INTENT_SATURATION -#define IM_INTENT_ABSOLUTE_COLORIMETRIC VIPS_INTENT_ABSOLUTE_COLORIMETRIC +#define IM_INTENT_ABSOLUTE_COLORIMETRIC VIPS_INTENT_ABSOLUTE /* Renamed macros. */ diff --git a/libvips/iofuncs/error.c b/libvips/iofuncs/error.c index b9657dd6..d45e57b3 100644 --- a/libvips/iofuncs/error.c +++ b/libvips/iofuncs/error.c @@ -480,7 +480,7 @@ vips_check_coding_noneorlabq( const char *domain, VipsImage *im ) if( im->Coding != VIPS_CODING_NONE && im->Coding != VIPS_CODING_LABQ ) { vips_error( domain, - "%s", _( "image coding must be NONE or LABQ" ) ); + "%s", _( "image coding must be 'none' or 'labq'" ) ); return( -1 ); } @@ -533,7 +533,7 @@ int vips_check_coding( const char *domain, VipsImage *im, VipsCoding coding ) { if( im->Coding != coding ) { - vips_error( domain, _( "%s coding only" ), + vips_error( domain, _( "coding '%s' only" ), vips_enum_nick( VIPS_TYPE_CODING, coding ) ); return( -1 ); }