blob: d5c0a8d040381e02d5f8287935e04e525548450c [file] [log] [blame]
/* @(#) Turn Lab 32bit packed format into displayable rgb. Fast, but very
* @(#) inaccurate: for display only!
* @(#)
* @(#) Usage:
* @(#) int im_LabQ2disp( IMAGE *in, IMAGE *out, struct im_col_display *d )
* @(#)
* @(#) Returns: -1 on error, else 0
*
* 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>
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* Hold a display characterisation, and a set of tables
* computed from that.
*/
typedef struct {
struct im_col_display *disp;
PEL red[ 64 * 64 * 64 ];
PEL green[ 64 * 64 * 64 ];
PEL 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( PEL *p, PEL *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 );
}