Add cmyk <-> xyz default colourspace conversion

If no lcms2 library has been found, fallback to default
cmyk <-> xyz conversion.
Please note that it is an approximative conversion.
This commit is contained in:
Dimitri Bouron 2018-12-28 17:37:20 +01:00
parent 5bc342b9b2
commit d87bf01fdc
5 changed files with 171 additions and 28 deletions

View File

@ -39,8 +39,6 @@
#include <vips/vips.h>
#ifdef HAVE_LCMS2
#include <stdio.h>
#include <math.h>
@ -49,6 +47,8 @@
#include "pcolour.h"
#include "profiles.h"
#ifdef HAVE_LCMS2
typedef struct _VipsCMYK2XYZ {
VipsOperation parent_instance;
@ -162,22 +162,21 @@ vips_CMYK2XYZ_class_init( VipsCMYK2XYZClass *class )
object_class->nickname = "CMYK2XYZ";
object_class->description = _( "transform CMYK to XYZ" );
object_class->build = vips_CMYK2XYZ_build;
object_class->build = vips_CMYK2XYZ_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsCMYK2XYZ, in ) );
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsCMYK2XYZ, out ) );
}
static void
@ -185,6 +184,72 @@ vips_CMYK2XYZ_init( VipsCMYK2XYZ *CMYK2XYZ )
{
}
#else
typedef VipsColourCode VipsCMYK2XYZ;
typedef VipsColourCodeClass VipsCMYK2XYZClass;
G_DEFINE_TYPE(VipsCMYK2XYZ, vips_CMYK2XYZ, VIPS_TYPE_COLOUR_CODE);
void
vips_CMYK2XYZ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
unsigned char *p = (unsigned char *) in[0];
float *q = (float *) out;
int i;
for (i = 0; i < width; i++) {
float c = p[0] / 255.0;
float m = p[1] / 255.0;
float y = p[2] / 255.0;
float k = p[3] / 255.0;
float r = 1.0 - (c * (1.0 - k) + k);
float g = 1.0 - (m * (1.0 - k) + k);
float b = 1.0 - (y * (1.0 - k) + k);
q[0] = VIPS_D65_X0 * r;
q[1] = VIPS_D65_Y0 * g;
q[2] = VIPS_D65_Z0 * b;
p += 4;
q += 3;
}
}
static void
vips_CMYK2XYZ_class_init( VipsCMYK2XYZClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "CMYK2XYZ";
object_class->description = _( "transform CMYK to XYZ" );
colour_class->process_line = vips_CMYK2XYZ_line;
}
static void
vips_CMYK2XYZ_init( VipsCMYK2XYZ *CMYK2XYZ )
{
VipsColour *colour = VIPS_COLOUR( CMYK2XYZ );
VipsColourCode *code = VIPS_COLOUR_CODE( CMYK2XYZ );
colour->interpretation = VIPS_INTERPRETATION_XYZ;
colour->format = VIPS_FORMAT_FLOAT;
colour->bands = 3;
colour->input_bands = 4;
code->input_coding = VIPS_CODING_NONE;
code->input_format = VIPS_FORMAT_UCHAR;
code->input_interpretation = VIPS_INTERPRETATION_CMYK;
}
#endif /*HAVE_LCMS2*/
/**

View File

@ -40,7 +40,7 @@ libcolour_la_SOURCES = \
scRGB2XYZ.c \
scRGB2BW.c \
XYZ2scRGB.c \
scRGB2sRGB.c
scRGB2sRGB.c
profiles.c:
./wrap_profiles.sh profiles profiles

View File

@ -39,8 +39,6 @@
#include <vips/vips.h>
#ifdef HAVE_LCMS2
#include <stdio.h>
#include <math.h>
@ -49,6 +47,8 @@
#include "pcolour.h"
#include "profiles.h"
#ifdef HAVE_LCMS2
typedef struct _VipsXYZ2CMYK {
VipsOperation parent_instance;
@ -106,22 +106,21 @@ vips_XYZ2CMYK_class_init( VipsXYZ2CMYKClass *class )
object_class->nickname = "XYZ2CMYK";
object_class->description = _( "transform XYZ to CMYK" );
object_class->build = vips_XYZ2CMYK_build;
object_class->build = vips_XYZ2CMYK_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsXYZ2CMYK, in ) );
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsXYZ2CMYK, out ) );
}
static void
@ -129,6 +128,83 @@ vips_XYZ2CMYK_init( VipsXYZ2CMYK *XYZ2CMYK )
{
}
#else
typedef VipsColourCode VipsXYZ2CMYK;
typedef VipsColourCodeClass VipsXYZ2CMYKClass;
G_DEFINE_TYPE(VipsXYZ2CMYK, vips_XYZ2CMYK, VIPS_TYPE_COLOUR_CODE);
void
vips_XYZ2CMYK_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
float *p = (float *) in[0];
unsigned char *q = (unsigned char *) out;
const float epsilon = 0.00001;
int i;
for (i = 0; i < width; i++) {
float c, m, y, k;
float r = p[0] / VIPS_D65_X0;
float g = p[1] / VIPS_D65_Y0;
float b = p[2] / VIPS_D65_Z0;
if (r < epsilon && g < epsilon && b < epsilon)
q[3] = 255.0;
c = 255.0 - r;
m = 255.0 - g;
y = 255.0 - b;
k = c;
k = VIPS_MIN(k, VIPS_MIN(m, y));
c = (c - k) / (255.0 - k) * 255.0;
m = (m - k) / (255.0 - k) * 255.0;
y = (y - k) / (255.0 - k) * 255.0;
q[0] = (unsigned char) VIPS_CLIP(0, c, 255.0);
q[1] = (unsigned char) VIPS_CLIP(0, m, 255.0);
q[2] = (unsigned char) VIPS_CLIP(0, y, 255.0);
q[3] = (unsigned char) VIPS_CLIP(0, k, 255.0);
p += 3;
q += 4;
}
}
static void
vips_XYZ2CMYK_class_init( VipsXYZ2CMYKClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "XYZ2CMYK";
object_class->description = _( "transform XYZ to CMYK" );
colour_class->process_line = vips_XYZ2CMYK_line;
}
static void
vips_XYZ2CMYK_init( VipsXYZ2CMYK *XYZ2CMYK )
{
VipsColour *colour = VIPS_COLOUR( XYZ2CMYK );
VipsColourCode *code = VIPS_COLOUR_CODE( XYZ2CMYK );
colour->interpretation = VIPS_INTERPRETATION_CMYK;
colour->format = VIPS_FORMAT_UCHAR;
colour->bands = 4;
colour->input_bands = 3;
code->input_coding = VIPS_CODING_NONE;
code->input_format = VIPS_FORMAT_FLOAT;
code->input_interpretation = VIPS_INTERPRETATION_XYZ;
}
#endif /*HAVE_LCMS2*/
/**

View File

@ -751,13 +751,13 @@ vips_colour_operation_init( void )
extern GType vips_scRGB2XYZ_get_type( void );
extern GType vips_scRGB2BW_get_type( void );
extern GType vips_XYZ2scRGB_get_type( void );
extern GType vips_scRGB2sRGB_get_type( void );
extern GType vips_scRGB2sRGB_get_type( void );
extern GType vips_CMYK2XYZ_get_type( void );
extern GType vips_XYZ2CMYK_get_type( void );
#ifdef HAVE_LCMS2
extern GType vips_icc_import_get_type( void );
extern GType vips_icc_export_get_type( void );
extern GType vips_icc_transform_get_type( void );
extern GType vips_CMYK2XYZ_get_type( void );
extern GType vips_XYZ2CMYK_get_type( void );
#endif
extern GType vips_dE76_get_type( void );
extern GType vips_dE00_get_type( void );
@ -788,12 +788,12 @@ vips_colour_operation_init( void )
vips_HSV2sRGB_get_type();
vips_XYZ2scRGB_get_type();
vips_scRGB2sRGB_get_type();
vips_CMYK2XYZ_get_type();
vips_XYZ2CMYK_get_type();
#ifdef HAVE_LCMS2
vips_icc_import_get_type();
vips_icc_export_get_type();
vips_icc_transform_get_type();
vips_CMYK2XYZ_get_type();
vips_XYZ2CMYK_get_type();
#endif
vips_dE76_get_type();
vips_dE00_get_type();

View File

@ -21,6 +21,8 @@
* https://github.com/lovell/sharp/issues/193
* 27/12/18
* - add CMYK conversions
* 09/01/2019
* - add CMYK <-> XYZ conversions if no lcms2 has been found
*/
/*
@ -255,8 +257,8 @@ static VipsColourRoute vips_colour_routes[] = {
{ LABQ, LCH, { vips_LabQ2Lab, vips_Lab2LCh, NULL } },
{ LABQ, CMC, { vips_LabQ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ LABQ, LABS, { vips_LabQ2LabS, NULL } },
{ LABQ, CMYK, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2CMYK } },
{ LABQ, scRGB, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB } },
{ LABQ, CMYK, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2CMYK, NULL } },
{ LABQ, scRGB, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB, NULL } },
{ LABQ, sRGB, { vips_LabQ2sRGB, NULL } },
{ LABQ, HSV, { vips_LabQ2sRGB, vips_sRGB2HSV, NULL } },
{ LABQ, BW, { vips_LabQ2Lab, vips_Lab2XYZ, vips_XYZ2scRGB,