new icc stuff now works

This commit is contained in:
John Cupitt 2012-09-26 14:53:14 +01:00
parent e793d38aa7
commit 52a188c3c5
29 changed files with 302 additions and 201 deletions

11
TODO
View File

@ -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

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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

View File

@ -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 );

View File

@ -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;
}
/**

View File

@ -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
}

View File

@ -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;
}
/**

View File

@ -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;
}
/**

View File

@ -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 ) )

View File

@ -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 );

View File

@ -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

View File

@ -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 );

View File

@ -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.
*/

View File

@ -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 );
}