started moving disp funcs
This commit is contained in:
parent
5fff90bc95
commit
2ce7bc9618
@ -2,7 +2,7 @@
|
||||
- redone im_Lab2XYZ(), im_XYZ2Lab(), im_Lab2LCh(), im_LCh2Lab(), im_UCS2LCh,
|
||||
im_LCh2UCS(), im_XYZ2Yxy(), im_Yxy2XYZ(), im_float2rad(), im_rad2float(),
|
||||
im_Lab2LabQ(), im_LabQ2Lab(), im_Lab2LabS(), im_LabS2Lab(), im_LabQ2LabS(),
|
||||
im_LabS2LabQ() as classes
|
||||
im_LabS2LabQ(), im_LabQ2disp() as classes
|
||||
|
||||
13/9/12 started 7.30.3
|
||||
- linecache sized itself too large
|
||||
|
465
libvips/colour/LabQ2sRGB.c
Normal file
465
libvips/colour/LabQ2sRGB.c
Normal file
@ -0,0 +1,465 @@
|
||||
/* Turn Lab 32bit packed format into displayable rgb. Fast, but very
|
||||
* inaccurate: for display only! Note especially that this dithers and will
|
||||
* give different results on different runs.
|
||||
*
|
||||
* 5/11/97 Steve Perry
|
||||
* - adapted from old ip code
|
||||
* 7/11/97 JC
|
||||
* - small tidies, added to VIPS
|
||||
* - LUT build split into separate function
|
||||
* 21/9/12
|
||||
* - redone as a class
|
||||
* - sRGB only, support for other RGBs is now via lcms
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 VipsColourCode VipsLabQ2sRGB;
|
||||
typedef VipsColourCodeClass VipsLabQ2sRGBClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsLabQ2sRGB, vips_LabQ2sRGB, VIPS_TYPE_COLOUR_CODE );
|
||||
|
||||
/* Structure for holding information about a display device. See the BARCO
|
||||
* papers for details on the fields.
|
||||
*/
|
||||
struct im_col_display {
|
||||
/* All private.
|
||||
*/
|
||||
char *d_name; /* Display name */
|
||||
float d_mat[3][3]; /* XYZ -> luminance matrix */
|
||||
float d_YCW; /* Luminosity of reference white */
|
||||
float d_xCW; /* x, y for reference white */
|
||||
float d_yCW;
|
||||
float d_YCR; /* Light o/p for reference white */
|
||||
float d_YCG;
|
||||
float d_YCB;
|
||||
int d_Vrwr; /* Pixel values for ref. white */
|
||||
int d_Vrwg;
|
||||
int d_Vrwb;
|
||||
float d_Y0R; /* Residual light for black pixel */
|
||||
float d_Y0G;
|
||||
float d_Y0B;
|
||||
float d_gammaR; /* Gamma values for the three guns */
|
||||
float d_gammaG;
|
||||
float d_gammaB;
|
||||
float d_B; /* 'Background' (like brightness) */
|
||||
float d_P; /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* 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))
|
||||
|
||||
/* We used to have loads of these, now just sRGB.
|
||||
*/
|
||||
static struct im_col_display srgb_profile = {
|
||||
"sRGB",
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ 3.2410, -1.5374, -0.4986 },
|
||||
{ -0.9692, 1.8760, 0.0416 },
|
||||
{ 0.0556, -0.2040, 1.0570 }
|
||||
},
|
||||
|
||||
80.0, /* Luminosity of reference white */
|
||||
.3127, .3291, /* x, y for reference white */
|
||||
100, 100, 100, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
1, 1, 1, /* Residual light o/p for black pixel */
|
||||
2.4, 2.4, 2.4, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* A set of LUTs for quick LabQ->sRGB transforms.
|
||||
*/
|
||||
static VipsPel vips_red[64 * 64 * 64];
|
||||
static VipsPel vips_green[64 * 64 * 64];
|
||||
static VipsPel vips_blue[64 * 64 * 64];
|
||||
|
||||
/* Make look_up tables for the Yr,Yb,Yg <=> r,g,b conversions.
|
||||
*/
|
||||
static void *
|
||||
calcul_tables( struct im_col_tab_disp *table )
|
||||
{
|
||||
struct im_col_display *d = &srgb_profile;
|
||||
|
||||
int i, j;
|
||||
float a, ga_i, ga, c, f, yo, p;
|
||||
float maxr, maxg, maxb;
|
||||
double **temp;
|
||||
|
||||
c = (d->d_B - 100.0) / 500.0;
|
||||
|
||||
/**** Red ****/
|
||||
yo = d->d_Y0R;
|
||||
a = d->d_YCR - yo;
|
||||
ga = d->d_gammaR;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwr / p;
|
||||
|
||||
maxr = (float) d->d_Vrwr;
|
||||
table->ristep = maxr / 1500.0;
|
||||
table->rstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yr2r[i] = f * (pow( i * table->rstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_r2Yr[i] = yo +
|
||||
a * pow( i * table->ristep / f + c, ga );
|
||||
|
||||
/**** Green ****/
|
||||
yo = d->d_Y0G;
|
||||
a = d->d_YCG - yo;
|
||||
ga = d->d_gammaG;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwg / p;
|
||||
|
||||
maxg = (float)d->d_Vrwg;
|
||||
table->gistep = maxg / 1500.0;
|
||||
table->gstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yg2g[i] = f * (pow( i * table->gstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_g2Yg[i] = yo +
|
||||
a * pow( i * table->gistep / f + c, ga );
|
||||
|
||||
/**** Blue ****/
|
||||
yo = d->d_Y0B;
|
||||
a = d->d_YCB - yo;
|
||||
ga = d->d_gammaB;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwb / p;
|
||||
|
||||
maxb = (float)d->d_Vrwb;
|
||||
table->bistep = maxb / 1500.0;
|
||||
table->bstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yb2b[i] = f * (pow( i * table->bstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_b2Yb[i] = yo +
|
||||
a * pow( i * table->bistep / f + c, ga );
|
||||
|
||||
if( !(temp = im_dmat_alloc( 0, 2, 0, 2 )) )
|
||||
return( NULL );
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
for( j = 0; j < 3; j++ ) {
|
||||
table->mat_XYZ2lum[i][j] = d->d_mat[i][j];
|
||||
temp[i][j] = d->d_mat[i][j];
|
||||
}
|
||||
|
||||
if( im_invmat( temp, 3 ) ) {
|
||||
im_free_dmat( temp, 0, 2, 0, 2 );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
for( j = 0; j < 3; j++ )
|
||||
table->mat_lum2XYZ[i][j] = temp[i][j];
|
||||
|
||||
im_free_dmat( temp, 0, 2, 0, 2 );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static struct im_col_tab_disp *
|
||||
vips_col_make_tables_RGB( void )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
static struct im_col_tab_disp table;
|
||||
|
||||
(void) g_once( &once, calcul_tables, &table );
|
||||
|
||||
return( &table );
|
||||
}
|
||||
|
||||
/* Computes the transform: r,g,b => Yr,Yg,Yb. It finds Y values in
|
||||
* lookup tables and calculates X, Y, Z.
|
||||
*/
|
||||
int
|
||||
vips_col_sRGB2XYZ( int r, int g, int b, float *X, float *Y, float *Z )
|
||||
{
|
||||
struct im_col_tab_disp *table = vips_col_make_tables_RGB();
|
||||
float *mat = &table->mat_lum2XYZ[0][0];
|
||||
|
||||
float Yr, Yg, Yb;
|
||||
int i;
|
||||
|
||||
r = VIPS_CLIP( 0, r, 255 );
|
||||
g = VIPS_CLIP( 0, g, 255 );
|
||||
b = VIPS_CLIP( 0, b, 255 );
|
||||
|
||||
i = r / table->ristep;
|
||||
Yr = table->t_r2Yr[i];
|
||||
|
||||
i = g / table->gistep;
|
||||
Yg = table->t_g2Yg[i];
|
||||
|
||||
i = b / table->bistep;
|
||||
Yb = table->t_b2Yb[i];
|
||||
|
||||
*X = mat[0] * Yr + mat[1] * Yg + mat[2] * Yb;
|
||||
*Y = mat[3] * Yr + mat[4] * Yg + mat[5] * Yb;
|
||||
*Z = mat[6] * Yr + mat[7] * Yg + mat[8] * Yb;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Turn XYZ into display colour. Return or=1 for out of gamut - rgb will
|
||||
* contain an approximation of the right colour.
|
||||
*/
|
||||
int
|
||||
vips_col_XYZ2rgb( float X, float Y, float Z,
|
||||
int *r_ret, int *g_ret, int *b_ret,
|
||||
int *or_ret )
|
||||
{
|
||||
struct im_col_tab_disp *table = vips_col_make_tables_RGB();
|
||||
float *mat = &table->mat_XYZ2lum[0][0];
|
||||
|
||||
int or = 0; /* Out of range flag */
|
||||
|
||||
float Yr, Yg, Yb;
|
||||
int Yint;
|
||||
int r, g, b;
|
||||
|
||||
/* Multiply through the matrix to get luminosity values.
|
||||
*/
|
||||
Yr = mat[0] * X + mat[1] * Y + mat[2] * Z;
|
||||
Yg = mat[3] * X + mat[4] * Y + mat[5] * Z;
|
||||
Yb = mat[6] * X + mat[7] * Y + mat[8] * Z;
|
||||
|
||||
/* Any negatives? If yes, set the out-of-range flag and bump up.
|
||||
*/
|
||||
if( Yr < d->d_Y0R ) {
|
||||
or = 1;
|
||||
Yr = d->d_Y0R;
|
||||
}
|
||||
if( Yg < d->d_Y0G ) {
|
||||
or = 1;
|
||||
Yg = d->d_Y0G;
|
||||
}
|
||||
if( Yb < d->d_Y0B ) {
|
||||
or = 1;
|
||||
Yb = d->d_Y0B;
|
||||
}
|
||||
|
||||
/* Work out colour value (0-Vrw) to feed the tube to get that
|
||||
* luminosity.
|
||||
*/
|
||||
Yint = (Yr - d->d_Y0R) / table->rstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
r = IM_RINT( table->t_Yr2r[Yint] );
|
||||
|
||||
Yint = (Yg - d->d_Y0G) / table->gstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
g = IM_RINT( table->t_Yg2g[Yint] );
|
||||
|
||||
Yint = (Yb - d->d_Y0B) / table->bstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
b = IM_RINT( table->t_Yb2b[Yint] );
|
||||
|
||||
*r_ret = r;
|
||||
*g_ret = g;
|
||||
*b_ret = b;
|
||||
|
||||
*or_ret = or;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Build Lab->disp tables.
|
||||
*/
|
||||
static void
|
||||
build_tables( void )
|
||||
{
|
||||
int l, a, b;
|
||||
int t;
|
||||
|
||||
for( l = 0; l < 64; l++ ) {
|
||||
for( a = 0; a < 64; a++ ) {
|
||||
for( b = 0; b < 64; b++ ) {
|
||||
/* Scale to lab space.
|
||||
*/
|
||||
float L = (l << 2) * (100.0/256.0);
|
||||
float A = (signed char) (a << 2);
|
||||
float B = (signed char) (b << 2);
|
||||
float X, Y, Z;
|
||||
int rb, gb, bb;
|
||||
int oflow;
|
||||
|
||||
vips_col_Lab2XYZ( L, A, B, &X, &Y, &Z );
|
||||
vips_col_XYZ2rgb( X, Y, Z,
|
||||
&rb, &gb, &bb, &oflow );
|
||||
|
||||
t = INDEX( l, a, b );
|
||||
vips_red[t] = rb;
|
||||
vips_green[t] = gb;
|
||||
vips_blue[t] = bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vips_col_make_tables_LabQ2sRGB( void )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
(void) g_once( &once, calcul_tables, NULL );
|
||||
}
|
||||
|
||||
/* Process a buffer of data.
|
||||
*/
|
||||
static void
|
||||
vips_LabQ2sRGB_line( VipsColour *colour, VipsPel *q, VipsPel **in, int width )
|
||||
{
|
||||
unsigned char *p = (unsigned char *) in[0];
|
||||
|
||||
int i, t;
|
||||
|
||||
/* Current error.
|
||||
*/
|
||||
int le = 0;
|
||||
int ae = 0;
|
||||
int be = 0;
|
||||
|
||||
for( i = 0; i < width; i++ ) {
|
||||
/* Get colour, add in error from previous pixel.
|
||||
*/
|
||||
int L = p[0] + le;
|
||||
int A = (signed char) p[1] + ae;
|
||||
int B = (signed char) p[2] + be;
|
||||
|
||||
p += 4;
|
||||
|
||||
/* Look out for overflow.
|
||||
*/
|
||||
L = VIPS_MIN( 255, L );
|
||||
A = VIPS_MIN( 127, A );
|
||||
B = VIPS_MIN( 127, B );
|
||||
|
||||
/* Find new quant error. This will always be +ve.
|
||||
*/
|
||||
le = L & 3;
|
||||
ae = A & 3;
|
||||
be = B & 3;
|
||||
|
||||
/* Scale to 0-63.
|
||||
*/
|
||||
L = (L >> 2) & 63;
|
||||
A = (A >> 2) & 63;
|
||||
B = (B >> 2) & 63;
|
||||
|
||||
/* Convert to RGB.
|
||||
*/
|
||||
t = INDEX( L, A, B );
|
||||
q[0] = vips_red[t];
|
||||
q[1] = vips_green[t];
|
||||
q[2] = vips_blue[t];
|
||||
|
||||
q += 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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();
|
||||
}
|
||||
|
||||
static void
|
||||
vips_LabQ2sRGB_init( VipsLabQ2sRGB *LabQ2sRGB )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_LabQ2sRGB:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
*
|
||||
* Unpack a LabQ (#IM_CODING_LABQ) image to a three-band short image.
|
||||
*
|
||||
* See also: im_LabS2LabQ(), im_LabQ2sRGB(), im_rad2float().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_LabQ2sRGB( VipsImage *in, VipsImage **out, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "LabQ2sRGB", ap, in, out );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
@ -3,7 +3,6 @@ noinst_LTLIBRARIES = libcolour.la
|
||||
libcolour_la_SOURCES = \
|
||||
colour.c \
|
||||
colour_funcs.c \
|
||||
disp.c \
|
||||
colour_dispatch.c \
|
||||
derived.c \
|
||||
Lab2XYZ.c \
|
||||
@ -22,7 +21,7 @@ libcolour_la_SOURCES = \
|
||||
Lab2LabS.c \
|
||||
LabS2LabQ.c \
|
||||
LabQ2LabS.c \
|
||||
im_LabQ2disp.c \
|
||||
LabQ2sRGB.c \
|
||||
im_icc_transform.c \
|
||||
im_lab_morph.c \
|
||||
im_XYZ2disp.c \
|
||||
|
@ -1,618 +0,0 @@
|
||||
/* Convert to and from display RGB
|
||||
*
|
||||
* 28/10/09
|
||||
* - from colour.c
|
||||
* 14/12/09
|
||||
* - oop, im_disp2Lab() was broken
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
/* Tables we've generated, indexed by display name.
|
||||
*/
|
||||
static GHashTable *im__col_display_tables = NULL;
|
||||
|
||||
/* Values for IM_TYPE_sRGB.
|
||||
*/
|
||||
static struct im_col_display srgb_profile = {
|
||||
"sRGB",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ 3.2410, -1.5374, -0.4986 },
|
||||
{ -0.9692, 1.8760, 0.0416 },
|
||||
{ 0.0556, -0.2040, 1.0570 }
|
||||
},
|
||||
|
||||
80.0, /* Luminosity of reference white */
|
||||
.3127, .3291, /* x, y for reference white */
|
||||
100, 100, 100, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
1, 1, 1, /* Residual light o/p for black pixel */
|
||||
2.4, 2.4, 2.4, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Values for my Ultra2, 20/2/98. Figures from a Minolta CA-100 CRT analyser.
|
||||
* Contrast at max, brightness at 42, room lights out.
|
||||
*/
|
||||
static struct im_col_display ultra2 = {
|
||||
"ultra2-20/2/98",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .704, -0.302, -.103 },
|
||||
{ -.708, 1.317, .032 },
|
||||
{ .005, -.015, .071 }
|
||||
},
|
||||
|
||||
64.0, /* Luminosity of reference white */
|
||||
.2137, .3291, /* x, y for reference white */
|
||||
14.4, 44.0, 5.4, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
0.03, 0.03, 0.03, /* Residual light o/p for black pixel */
|
||||
2.5, 2.5, 2.4, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Values for our display. These were obtained with a TV analyser in late
|
||||
* Feb. 1990. The reference white is simply r=g=b=255.
|
||||
*/
|
||||
static struct im_col_display im_col_screen_white = {
|
||||
"Screen",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .660, -0.276, -.10 },
|
||||
{ -.663, 1.293, .0265 },
|
||||
{ .003, -.017, .0734 }
|
||||
},
|
||||
|
||||
58.7, /* Luminosity of reference white */
|
||||
.284, .273, /* x, y for reference white */
|
||||
14.2, 38.4, 6.1, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
0.0, 0.0, 0.0, /* Residual light o/p for black pixel */
|
||||
2.8, 2.9, 2.9, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Adjusted version of above for SPARCstation2 screens. Turn down the gamma
|
||||
* to make blacks blacker.
|
||||
*/
|
||||
static struct im_col_display im_col_SPARC_white = {
|
||||
"SPARC",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .660, -0.276, -.10 },
|
||||
{ -.663, 1.293, .0265 },
|
||||
{ .003, -.017, .0734 }
|
||||
},
|
||||
|
||||
58.7, /* Luminosity of reference white */
|
||||
.284, .273, /* x, y for reference white */
|
||||
14.2, 38.4, 4, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
0.0, 0.0, 0.0, /* Residual light o/p for black pixel */
|
||||
2.0, 2.0, 2.0, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Values for D65 white. This gives a smaller range of colours than
|
||||
* screen_white.
|
||||
*/
|
||||
static struct im_col_display im_col_D65_white = {
|
||||
"D65",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .660, -0.276, -.10 },
|
||||
{ -.663, 1.293, .0265 },
|
||||
{ .003, -.017, .0734 }
|
||||
},
|
||||
|
||||
49.9, /* Luminosity of reference white */
|
||||
.3127, .3290, /* x, y for reference white */
|
||||
11.6, 35.0, 3.3, /* Light o/p for reference white */
|
||||
241, 255, 177, /* Pixel values for ref. white */
|
||||
0.1, 0.1, 0.1, /* Residual light o/p for black pixel */
|
||||
2.8, 2.9, 2.7, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Values for Barco calibrator monitor
|
||||
*/
|
||||
static struct im_col_display im_col_barco_white = {
|
||||
"Barco",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .749, -0.322, -.123 },
|
||||
{ -.755, 1.341, .033 },
|
||||
{ .007, -.019, .0898 }
|
||||
},
|
||||
|
||||
80.0, /* Luminosity of reference white */
|
||||
.3128, .3292, /* x, y for reference white */
|
||||
20.45, 52.73, 6.81, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
0.02, 0.053, 0.007, /* Residual light o/p for black pixel */
|
||||
2.23, 2.13, 2.12, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Values for Mitsubishi dye-sub colour printer.
|
||||
*/
|
||||
static struct im_col_display im_col_mitsubishi = {
|
||||
"Mitsubishi_3_colour",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ 1.1997, -0.6296, -0.2755 },
|
||||
{ -1.1529, 1.7383, -0.1074 },
|
||||
{ -0.047, -0.109, 0.3829 }
|
||||
},
|
||||
|
||||
95, /* Luminosity of reference white */
|
||||
.3152, .3316, /* x, y for reference white */
|
||||
25.33, 42.57, 15.85, /* Y all red, Y all green, Y all blue */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
1.0, 1.0, 1.0, /* Residual light o/p for black pixel */
|
||||
1.0, 1.0, 1.0, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
/* Display LAB of 100, 0, 0 as 255, 255, 255.
|
||||
*/
|
||||
static struct im_col_display im_col_relative = {
|
||||
"relative",
|
||||
DISP_DUMB,
|
||||
{ /* XYZ -> luminance matrix */
|
||||
{ .660, -0.276, -.10 },
|
||||
{ -.663, 1.293, .0265 },
|
||||
{ .003, -.017, .0734 }
|
||||
},
|
||||
|
||||
100.0, /* Luminosity of reference white */
|
||||
.284, .273, /* x, y for reference white */
|
||||
24.23, 69.20, 6.57, /* Light o/p for reference white */
|
||||
255, 255, 255, /* Pixel values for ref. white */
|
||||
0.0, 0.0, 0.0, /* Residual light o/p for black pixel */
|
||||
2.3, 2.3, 2.3, /* Gamma values for the three guns */
|
||||
100, /* 'Background' (like brightness) */
|
||||
100 /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
struct im_col_display *
|
||||
im_col_displays( int n )
|
||||
{
|
||||
static struct im_col_display *displays[] = {
|
||||
&im_col_screen_white, /* index 0 */
|
||||
&im_col_SPARC_white, /* index 1 */
|
||||
&im_col_D65_white, /* index 2 */
|
||||
&im_col_barco_white, /* index 3 */
|
||||
&im_col_mitsubishi, /* index 4 */
|
||||
&im_col_relative, /* index 5 */
|
||||
&ultra2, /* index 6 */
|
||||
&srgb_profile, /* index 7 */
|
||||
NULL
|
||||
};
|
||||
|
||||
if( n < 0 || n > IM_NUMBER( displays ) )
|
||||
return( NULL );
|
||||
|
||||
return( displays[n] );
|
||||
}
|
||||
|
||||
struct im_col_display *
|
||||
im_col_display_name( const char *name )
|
||||
{
|
||||
int i;
|
||||
struct im_col_display *d;
|
||||
|
||||
for( i = 0; (d = im_col_displays( i )); i++ )
|
||||
if( g_ascii_strcasecmp( d->d_name, name ) == 0 )
|
||||
return( d );
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
/* Make look_up tables for the Yr,Yb,Yg <=> r,g,b conversions.
|
||||
*/
|
||||
static void
|
||||
calcul_tables( struct im_col_display *d, struct im_col_tab_disp *table )
|
||||
{
|
||||
int i;
|
||||
float a, ga_i, ga, c, f, yo, p;
|
||||
float maxr, maxg, maxb;
|
||||
|
||||
c = (d->d_B - 100.0) / 500.0;
|
||||
|
||||
/**** Red ****/
|
||||
yo = d->d_Y0R;
|
||||
a = d->d_YCR - yo;
|
||||
ga = d->d_gammaR;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwr / p;
|
||||
|
||||
maxr = (float) d->d_Vrwr;
|
||||
table->ristep = maxr / 1500.0;
|
||||
table->rstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yr2r[i] = f * (pow( i * table->rstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_r2Yr[i] = yo +
|
||||
a * pow( i * table->ristep / f + c, ga );
|
||||
|
||||
/**** Green ****/
|
||||
yo = d->d_Y0G;
|
||||
a = d->d_YCG - yo;
|
||||
ga = d->d_gammaG;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwg / p;
|
||||
|
||||
maxg = (float)d->d_Vrwg;
|
||||
table->gistep = maxg / 1500.0;
|
||||
table->gstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yg2g[i] = f * (pow( i * table->gstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_g2Yg[i] = yo +
|
||||
a * pow( i * table->gistep / f + c, ga );
|
||||
|
||||
/**** Blue ****/
|
||||
yo = d->d_Y0B;
|
||||
a = d->d_YCB - yo;
|
||||
ga = d->d_gammaB;
|
||||
ga_i = 1.0 / ga;
|
||||
p = d->d_P / 100.0;
|
||||
f = d->d_Vrwb / p;
|
||||
|
||||
maxb = (float)d->d_Vrwb;
|
||||
table->bistep = maxb / 1500.0;
|
||||
table->bstep = a / 1500.0;
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_Yb2b[i] = f * (pow( i * table->bstep / a, ga_i ) - c);
|
||||
|
||||
for( i = 0; i < 1501; i++ )
|
||||
table->t_b2Yb[i] = yo +
|
||||
a * pow( i * table->bistep / f + c, ga );
|
||||
}
|
||||
|
||||
/* Make the lookup tables for rgb. Pass an IMAGE to allocate memory from.
|
||||
*/
|
||||
struct im_col_tab_disp *
|
||||
im_col_make_tables_RGB( IMAGE *im, struct im_col_display *d )
|
||||
{
|
||||
struct im_col_tab_disp *table;
|
||||
double **temp;
|
||||
int i, j;
|
||||
|
||||
if( !(table = IM_NEW( im, struct im_col_tab_disp )) )
|
||||
return( NULL );
|
||||
|
||||
if( d->d_type == DISP_DUMB )
|
||||
calcul_tables( d, table );
|
||||
|
||||
if( !(temp = im_dmat_alloc( 0, 2, 0, 2 )) )
|
||||
return( NULL );
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
for( j = 0; j < 3; j++ ) {
|
||||
table->mat_XYZ2lum[i][j] = d->d_mat[i][j];
|
||||
temp[i][j] = d->d_mat[i][j];
|
||||
}
|
||||
|
||||
if( im_invmat( temp, 3 ) ) {
|
||||
im_free_dmat( temp, 0, 2, 0, 2 );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
for( i = 0; i < 3; i++ )
|
||||
for( j = 0; j < 3; j++ )
|
||||
table->mat_lum2XYZ[i][j] = temp[i][j];
|
||||
|
||||
im_free_dmat( temp, 0, 2, 0, 2 );
|
||||
|
||||
return( table );
|
||||
}
|
||||
|
||||
struct im_col_tab_disp *
|
||||
im_col_display_get_table( struct im_col_display *d )
|
||||
{
|
||||
struct im_col_tab_disp *table;
|
||||
|
||||
if( !im__col_display_tables )
|
||||
im__col_display_tables = g_hash_table_new(
|
||||
g_str_hash, g_str_equal );
|
||||
|
||||
if( !(table = g_hash_table_lookup( im__col_display_tables,
|
||||
d->d_name )) ) {
|
||||
table = im_col_make_tables_RGB( NULL, d );
|
||||
g_hash_table_insert( im__col_display_tables, d->d_name, table );
|
||||
}
|
||||
|
||||
return( table );
|
||||
}
|
||||
|
||||
/* Computes the transform: r,g,b => Yr,Yg,Yb. It finds Y values in
|
||||
* lookup tables and calculates X, Y, Z.
|
||||
*/
|
||||
int
|
||||
im_col_rgb2XYZ( struct im_col_display *d,
|
||||
int r, int g, int b, float *X, float *Y, float *Z )
|
||||
{
|
||||
struct im_col_tab_disp *table = im_col_display_get_table( d );
|
||||
float *mat = &table->mat_lum2XYZ[0][0];
|
||||
|
||||
float Yr, Yg, Yb;
|
||||
int i;
|
||||
|
||||
if( r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 ) {
|
||||
im_error( "im_col_rgb2XYZ", "%s", _( "out of range [0,255]" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
switch( d->d_type ) {
|
||||
case DISP_DUMB:
|
||||
/* Convert rgb to Yr, Yg, Yb. 3 times: r, g, b.
|
||||
*/
|
||||
i = r / table->ristep;
|
||||
Yr = table->t_r2Yr[i];
|
||||
|
||||
i = g / table->gistep;
|
||||
Yg = table->t_g2Yg[i];
|
||||
|
||||
i = b / table->bistep;
|
||||
Yb = table->t_b2Yb[i];
|
||||
|
||||
break;
|
||||
|
||||
case DISP_BARCO:
|
||||
Yr = d->d_Y0R + r*(d->d_YCR-d->d_Y0R)/255.0;
|
||||
Yg = d->d_Y0G + g*(d->d_YCG-d->d_Y0G)/255.0;
|
||||
Yb = d->d_Y0B + b*(d->d_YCB-d->d_Y0B)/255.0;
|
||||
break;
|
||||
|
||||
default:
|
||||
im_error( "im_col_rgb2XYZ", "%s", _( "bad display type" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Multiply through the inverse matrix to get XYZ values.
|
||||
*/
|
||||
*X = mat[0] * Yr + mat[1] * Yg + mat[2] * Yb;
|
||||
*Y = mat[3] * Yr + mat[4] * Yg + mat[5] * Yb;
|
||||
*Z = mat[6] * Yr + mat[7] * Yg + mat[8] * Yb;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Turn XYZ into display colour. Return or=1 for out of gamut - rgb will
|
||||
* contain an approximation of the right colour.
|
||||
*/
|
||||
int
|
||||
im_col_XYZ2rgb( struct im_col_display *d,
|
||||
float X, float Y, float Z, int *r_ret, int *g_ret, int *b_ret,
|
||||
int *or_ret )
|
||||
{
|
||||
struct im_col_tab_disp *table = im_col_display_get_table( d );
|
||||
float *mat = &table->mat_XYZ2lum[0][0];
|
||||
|
||||
int or = 0; /* Out of range flag */
|
||||
|
||||
float Yr, Yg, Yb;
|
||||
int Yint;
|
||||
int r, g, b;
|
||||
|
||||
/* Multiply through the matrix to get luminosity values.
|
||||
*/
|
||||
Yr = mat[0] * X + mat[1] * Y + mat[2] * Z;
|
||||
Yg = mat[3] * X + mat[4] * Y + mat[5] * Z;
|
||||
Yb = mat[6] * X + mat[7] * Y + mat[8] * Z;
|
||||
|
||||
/* Any negatives? If yes, set the out-of-range flag and bump up.
|
||||
*/
|
||||
if( Yr < d->d_Y0R ) {
|
||||
or = 1;
|
||||
Yr = d->d_Y0R;
|
||||
}
|
||||
if( Yg < d->d_Y0G ) {
|
||||
or = 1;
|
||||
Yg = d->d_Y0G;
|
||||
}
|
||||
if( Yb < d->d_Y0B ) {
|
||||
or = 1;
|
||||
Yb = d->d_Y0B;
|
||||
}
|
||||
|
||||
/* Work out colour value (0-Vrw) to feed the tube to get that
|
||||
* luminosity. Easy for BARCOs, harder for others.
|
||||
*/
|
||||
switch( d->d_type ) {
|
||||
case DISP_DUMB:
|
||||
Yint = (Yr - d->d_Y0R) / table->rstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
r = IM_RINT( table->t_Yr2r[Yint] );
|
||||
|
||||
Yint = (Yg - d->d_Y0G) / table->gstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
g = IM_RINT( table->t_Yg2g[Yint] );
|
||||
|
||||
Yint = (Yb - d->d_Y0B) / table->bstep;
|
||||
if( Yint > 1500 ) {
|
||||
or = 1;
|
||||
Yint = 1500;
|
||||
}
|
||||
b = IM_RINT( table->t_Yb2b[Yint] );
|
||||
|
||||
break;
|
||||
|
||||
case DISP_BARCO:
|
||||
r = IM_RINT( ((Yr - d->d_Y0R) / (d->d_YCR - d->d_Y0R)) * 255 );
|
||||
g = IM_RINT( ((Yg - d->d_Y0G) / (d->d_YCG - d->d_Y0G)) * 255 );
|
||||
b = IM_RINT( ((Yb - d->d_Y0B) / (d->d_YCB - d->d_Y0B)) * 255 );
|
||||
|
||||
/* Any silly values? Set out of range and adjust.
|
||||
*/
|
||||
if( r > d->d_Vrwr ) {
|
||||
or = 1;
|
||||
r = d->d_Vrwr;
|
||||
}
|
||||
if( g > d->d_Vrwg ) {
|
||||
or = 1;
|
||||
g = d->d_Vrwg;
|
||||
}
|
||||
if( b > d->d_Vrwb ) {
|
||||
or = 1;
|
||||
b = d->d_Vrwb;
|
||||
}
|
||||
if( r < 0 ) {
|
||||
or = 1;
|
||||
r = 0;
|
||||
}
|
||||
if( g < 0 ) {
|
||||
or = 1;
|
||||
g = 0;
|
||||
}
|
||||
if( b < 0 ) {
|
||||
or = 1;
|
||||
b = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
im_error( "XYZ2rgb", "%s", _( "display unknown" ) );
|
||||
return( -1 );
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
*r_ret = r;
|
||||
*g_ret = g;
|
||||
*b_ret = b;
|
||||
|
||||
*or_ret = or;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_Lab2disp:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
*
|
||||
* Convert an image from LabQ (Coding == IM_CODING_LABQ) to XYZ.
|
||||
*
|
||||
* Convert to and from display RGB. These functions are still used by nip2,
|
||||
* but most programs will be better off with im_icc_transform() and friends.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
*/
|
||||
int
|
||||
im_Lab2disp( IMAGE *in, IMAGE *out, struct im_col_display *disp )
|
||||
{
|
||||
IMAGE *t[1];
|
||||
|
||||
if( im_open_local_array( out, t, 1, "im_Lab2disp:1", "p" ) ||
|
||||
im_Lab2XYZ( in, t[0] ) ||
|
||||
im_XYZ2disp( t[0], out, disp ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_dECMC_fromdisp( IMAGE *im1, IMAGE *im2,
|
||||
IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[4];
|
||||
|
||||
if( im_open_local_array( out, t, 4, "im_dECMC_fromdisp:1", "p" ) ||
|
||||
im_disp2XYZ( im1, t[0], d ) ||
|
||||
im_XYZ2Lab( t[0], t[1] ) ||
|
||||
im_disp2XYZ( im2, t[2], d ) ||
|
||||
im_XYZ2Lab( t[2], t[3] ) ||
|
||||
im_dECMC_fromLab( t[1], t[3], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_dE_fromdisp( IMAGE *im1, IMAGE *im2, IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[2];
|
||||
|
||||
if( im_open_local_array( out, t, 2, "im_dE_fromdisp:1", "p" ) ||
|
||||
im_disp2XYZ( im1, t[0], d ) ||
|
||||
im_disp2XYZ( im2, t[1], d ) ||
|
||||
im_dE_fromXYZ( t[0], t[1], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_disp2Lab( IMAGE *in, IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[1];
|
||||
|
||||
if( im_open_local_array( out, t, 1, "im_disp2Lab:1", "p" ) ||
|
||||
im_disp2XYZ( in, t[0], d ) ||
|
||||
im_XYZ2Lab( t[0], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -1,192 +0,0 @@
|
||||
/* Turn Lab 32bit packed format into displayable rgb. Fast, but very
|
||||
* inaccurate: for display only! Note especially that this dithers and will
|
||||
* give different results on different runs.
|
||||
*
|
||||
* 5/11/97 Steve Perry
|
||||
* - adapted from old ip code
|
||||
* 7/11/97 JC
|
||||
* - small tidies, added to VIPS
|
||||
* - LUT build split into separate function
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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 <assert.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
/* Hold a display characterisation, and a set of tables
|
||||
* computed from that.
|
||||
*/
|
||||
typedef struct {
|
||||
struct im_col_display *disp;
|
||||
VipsPel red[ 64 * 64 * 64 ];
|
||||
VipsPel green[ 64 * 64 * 64 ];
|
||||
VipsPel blue[ 64 * 64 * 64 ];
|
||||
} CalibrateInfo;
|
||||
|
||||
/* Do our own indexing of the arrays, to make sure we get efficient mults.
|
||||
*/
|
||||
#define index( L, A, B ) (L + (A << 6) + (B << 12))
|
||||
|
||||
/* Process a buffer of data.
|
||||
*/
|
||||
static void
|
||||
imb_LabQ2disp( VipsPel *p, VipsPel *q, int n, CalibrateInfo *cal )
|
||||
{
|
||||
int x, t;
|
||||
|
||||
/* Current error.
|
||||
*/
|
||||
int le = 0;
|
||||
int ae = 0;
|
||||
int be = 0;
|
||||
|
||||
for( x = 0; x < n; x++ ) {
|
||||
/* Get colour, add in error from previous pixel.
|
||||
*/
|
||||
int L = p[0] + le;
|
||||
int A = (signed char) p[1] + ae;
|
||||
int B = (signed char) p[2] + be;
|
||||
p += 4;
|
||||
|
||||
/* Look out for overflow.
|
||||
*/
|
||||
L = IM_MIN( 255, L );
|
||||
A = IM_MIN( 127, A );
|
||||
B = IM_MIN( 127, B );
|
||||
|
||||
/* Find new quant error. This will always be +ve.
|
||||
*/
|
||||
le = L & 3;
|
||||
ae = A & 3;
|
||||
be = B & 3;
|
||||
|
||||
/* Scale to 0-63.
|
||||
*/
|
||||
L = (L >> 2) & 63;
|
||||
A = (A >> 2) & 63;
|
||||
B = (B >> 2) & 63;
|
||||
|
||||
/* Convert to RGB.
|
||||
*/
|
||||
t = index( L, A, B );
|
||||
q[0] = cal->red[t];
|
||||
q[1] = cal->green[t];
|
||||
q[2] = cal->blue[t];
|
||||
q += 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build Lab->disp tables.
|
||||
*/
|
||||
void *
|
||||
im_LabQ2disp_build_table( IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
CalibrateInfo *cal;
|
||||
int l, a, b;
|
||||
int t;
|
||||
|
||||
if( !(cal = IM_NEW( out, CalibrateInfo )) )
|
||||
return( NULL );
|
||||
cal->disp = d;
|
||||
|
||||
/* Build our tables.
|
||||
*/
|
||||
for( l = 0; l < 64; l++ ) {
|
||||
for( a = 0; a < 64; a++ ) {
|
||||
for( b = 0; b < 64; b++ ) {
|
||||
/* Scale to lab space.
|
||||
*/
|
||||
float L = (l << 2) * (100.0/256.0);
|
||||
float A = (signed char) (a << 2);
|
||||
float B = (signed char) (b << 2);
|
||||
float X, Y, Z;
|
||||
int rb, gb, bb;
|
||||
int oflow;
|
||||
|
||||
/* Convert to XYZ.
|
||||
*/
|
||||
im_col_Lab2XYZ( L, A, B, &X, &Y, &Z );
|
||||
|
||||
/* Convert to display.
|
||||
*/
|
||||
im_col_XYZ2rgb( cal->disp,
|
||||
X, Y, Z, &rb, &gb, &bb, &oflow );
|
||||
|
||||
/* Save RGB.
|
||||
*/
|
||||
t = index( l, a, b );
|
||||
cal->red[t] = rb;
|
||||
cal->green[t] = gb;
|
||||
cal->blue[t] = bb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return( (void *) cal );
|
||||
}
|
||||
|
||||
int
|
||||
im_LabQ2disp_table( IMAGE *in, IMAGE *out, void *table )
|
||||
{
|
||||
CalibrateInfo *cal = (CalibrateInfo *) table;
|
||||
|
||||
if( im_check_coding_labq( "im_LabQ2disp", in ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_cp_desc( out, in ) )
|
||||
return( -1 );
|
||||
out->Bands = 3;
|
||||
out->BandFmt = IM_BANDFMT_UCHAR;
|
||||
out->Coding = IM_CODING_NONE;
|
||||
out->Type = IM_TYPE_RGB;
|
||||
|
||||
if( im_wrapone( in, out, (im_wrapone_fn) imb_LabQ2disp, cal, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_LabQ2disp( IMAGE *in, IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
void *table;
|
||||
|
||||
if( !(table = im_LabQ2disp_build_table( out, d )) ||
|
||||
im_LabQ2disp_table( in, out, table ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -2451,3 +2451,60 @@ im_LabS2LabQ( IMAGE *in, IMAGE *out )
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_Lab2disp( IMAGE *in, IMAGE *out, struct im_col_display *disp )
|
||||
{
|
||||
IMAGE *t[1];
|
||||
|
||||
if( im_open_local_array( out, t, 1, "im_Lab2disp:1", "p" ) ||
|
||||
im_Lab2XYZ( in, t[0] ) ||
|
||||
im_XYZ2disp( t[0], out, disp ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_dECMC_fromdisp( IMAGE *im1, IMAGE *im2,
|
||||
IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[4];
|
||||
|
||||
if( im_open_local_array( out, t, 4, "im_dECMC_fromdisp:1", "p" ) ||
|
||||
im_disp2XYZ( im1, t[0], d ) ||
|
||||
im_XYZ2Lab( t[0], t[1] ) ||
|
||||
im_disp2XYZ( im2, t[2], d ) ||
|
||||
im_XYZ2Lab( t[2], t[3] ) ||
|
||||
im_dECMC_fromLab( t[1], t[3], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_dE_fromdisp( IMAGE *im1, IMAGE *im2, IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[2];
|
||||
|
||||
if( im_open_local_array( out, t, 2, "im_dE_fromdisp:1", "p" ) ||
|
||||
im_disp2XYZ( im1, t[0], d ) ||
|
||||
im_disp2XYZ( im2, t[1], d ) ||
|
||||
im_dE_fromXYZ( t[0], t[1], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_disp2Lab( IMAGE *in, IMAGE *out, struct im_col_display *d )
|
||||
{
|
||||
IMAGE *t[1];
|
||||
|
||||
if( im_open_local_array( out, t, 1, "im_disp2Lab:1", "p" ) ||
|
||||
im_disp2XYZ( in, t[0], d ) ||
|
||||
im_XYZ2Lab( t[0], out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ pkginclude_HEADERS = \
|
||||
convolution.h \
|
||||
debug.h \
|
||||
dispatch.h \
|
||||
disp.h \
|
||||
enumtypes.h \
|
||||
error.h \
|
||||
operation.h \
|
||||
|
@ -92,10 +92,7 @@ extern "C" {
|
||||
#define VIPS_D3250_Y0 (100.0)
|
||||
#define VIPS_D3250_Z0 (45.8501)
|
||||
|
||||
struct im_col_display;
|
||||
|
||||
int vips_LabQ2disp( VipsImage *in, VipsImage **out,
|
||||
struct im_col_display *disp, ... )
|
||||
int vips_LabQ2sRGB( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_rad2float( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
@ -121,8 +118,7 @@ int vips_Lab2XYZ( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_XYZ2Lab( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_XYZ2disp( VipsImage *in, VipsImage **out,
|
||||
struct im_col_display *disp, ... )
|
||||
int vips_XYZ2sRGB( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_LCh2UCS( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
@ -154,6 +150,10 @@ float vips_col_Lucs2L( float Lucs );
|
||||
float vips_col_Cucs2C( float Cucs );
|
||||
float vips_col_Chucs2h( float C, float hucs );
|
||||
|
||||
int vips_col_XYZ2sRGB( float X, float Y, float Z,
|
||||
int *r_ret, int *g_ret, int *b_ret,
|
||||
int *or_ret );
|
||||
int vips_col_sRGB2XYZ( int r, int g, int b, float *X, float *Y, float *Z );
|
||||
|
||||
|
||||
|
||||
|
@ -1,118 +0,0 @@
|
||||
/* VIPS display conversions.
|
||||
*
|
||||
* 23/10/09
|
||||
* - from colour.h
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IM_DISP_H
|
||||
#define IM_DISP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
/* Two kinds of display. A DISP_BARCO does gamma correction etc etc for us and
|
||||
* needs only a colour space transform, a DISP_DUMB is an ordinary display and
|
||||
* needs a full range of corrections.
|
||||
*/
|
||||
enum im_col_disp_type {
|
||||
DISP_BARCO = 0,
|
||||
DISP_DUMB
|
||||
};
|
||||
|
||||
/* Structure for holding information about a display device. See the BARCO
|
||||
* papers for details on the fields.
|
||||
*/
|
||||
struct im_col_display {
|
||||
/* All private.
|
||||
*/
|
||||
/*< private >*/
|
||||
char *d_name; /* Display name */
|
||||
enum im_col_disp_type d_type; /* Display type */
|
||||
float d_mat[3][3]; /* XYZ -> luminance matrix */
|
||||
float d_YCW; /* Luminosity of reference white */
|
||||
float d_xCW; /* x, y for reference white */
|
||||
float d_yCW;
|
||||
float d_YCR; /* Light o/p for reference white */
|
||||
float d_YCG;
|
||||
float d_YCB;
|
||||
int d_Vrwr; /* Pixel values for ref. white */
|
||||
int d_Vrwg;
|
||||
int d_Vrwb;
|
||||
float d_Y0R; /* Residual light for black pixel */
|
||||
float d_Y0G;
|
||||
float d_Y0B;
|
||||
float d_gammaR; /* Gamma values for the three guns */
|
||||
float d_gammaG;
|
||||
float d_gammaB;
|
||||
float d_B; /* 'Background' (like brightness) */
|
||||
float d_P; /* 'Picture' (like contrast) */
|
||||
};
|
||||
|
||||
int im_col_rgb2XYZ( struct im_col_display *d,
|
||||
int r, int g, int b,
|
||||
float *X, float *Y, float *Z );
|
||||
int im_col_XYZ2rgb(
|
||||
struct im_col_display *d,
|
||||
float X, float Y, float Z,
|
||||
int *r_ret, int *g_ret, int *b_ret,
|
||||
int *or_ret );
|
||||
|
||||
int im_XYZ2disp( VipsImage *in, VipsImage *out, struct im_col_display *d );
|
||||
int im_Lab2disp( VipsImage *in, VipsImage *out, struct im_col_display *d );
|
||||
int im_LabQ2disp( VipsImage *in, VipsImage *out, struct im_col_display *d );
|
||||
int im_disp2XYZ( VipsImage *in, VipsImage *out, struct im_col_display *d );
|
||||
int im_disp2Lab( VipsImage *in, VipsImage *out, struct im_col_display *d );
|
||||
|
||||
/* Colour display values and arrays
|
||||
&im_col_screen_white, index 0
|
||||
&im_col_SPARC_white, index 1
|
||||
&im_col_D65_white, index 2
|
||||
&im_col_barco_white, index 3
|
||||
&im_col_mitsubishi, index 4
|
||||
&im_col_relative, index 5
|
||||
&ultra2, index 6
|
||||
&srgb_profile, index 7
|
||||
*/
|
||||
struct im_col_display *im_col_displays( int n );
|
||||
struct im_col_display *im_col_display_name( const char *name );
|
||||
|
||||
void *im_LabQ2disp_build_table( VipsImage *out, struct im_col_display *d );
|
||||
int im_LabQ2disp_table( VipsImage *in, VipsImage *out, void *table );
|
||||
|
||||
int im_dE_fromdisp( VipsImage *in1, VipsImage *in2, VipsImage *out,
|
||||
struct im_col_display *d );
|
||||
int im_dECMC_fromdisp( VipsImage *in1, VipsImage *in2, VipsImage *out,
|
||||
struct im_col_display *d );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*IM_DISP_H*/
|
@ -184,27 +184,6 @@ int im__colour_unary( const char *domain,
|
||||
VipsImage **im__insert_base( const char *domain,
|
||||
VipsImage *in1, VipsImage *in2, VipsImage *out );
|
||||
|
||||
/* Structure for holding the lookup tables for XYZ<=>rgb conversion.
|
||||
* Also holds the luminance to XYZ matrix and the inverse one.
|
||||
*/
|
||||
struct im_col_tab_disp {
|
||||
/*< private >*/
|
||||
float t_Yr2r[1501]; /* Conversion of Yr to r */
|
||||
float t_Yg2g[1501]; /* Conversion of Yg to g */
|
||||
float t_Yb2b[1501]; /* Conversion of Yb to b */
|
||||
float t_r2Yr[1501]; /* Conversion of r to Yr */
|
||||
float t_g2Yg[1501]; /* Conversion of g to Yg */
|
||||
float t_b2Yb[1501]; /* Conversion of b to Yb */
|
||||
float mat_XYZ2lum[3][3]; /* XYZ to Yr, Yg, Yb matrix */
|
||||
float mat_lum2XYZ[3][3]; /* Yr, Yg, Yb to XYZ matrix */
|
||||
float rstep, gstep, bstep;
|
||||
float ristep, gistep, bistep;
|
||||
};
|
||||
|
||||
struct im_col_tab_disp *im_col_make_tables_RGB( VipsImage *im,
|
||||
struct im_col_display *d );
|
||||
struct im_col_tab_disp *im_col_display_get_table( struct im_col_display *d );
|
||||
|
||||
int im__fftproc( VipsImage *dummy,
|
||||
VipsImage *in, VipsImage *out, im__fftproc_fn fn );
|
||||
|
||||
|
@ -132,7 +132,6 @@ extern "C" {
|
||||
#include <vips/freq_filt.h>
|
||||
#include <vips/resample.h>
|
||||
#include <vips/colour.h>
|
||||
#include <vips/disp.h>
|
||||
#include <vips/inplace.h>
|
||||
#include <vips/other.h>
|
||||
#include <vips/video.h>
|
||||
|
Loading…
Reference in New Issue
Block a user