210 lines
5.4 KiB
C
210 lines
5.4 KiB
C
|
/* @(#) 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;
|
||
|
struct im_col_tab_disp *dtab;
|
||
|
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;
|
||
|
if( !(cal->dtab = im_col_make_tables_RGB( out, d ) ) ) {
|
||
|
if( !out )
|
||
|
im_free( cal );
|
||
|
return( NULL );
|
||
|
}
|
||
|
|
||
|
/* 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, cal->dtab,
|
||
|
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 ( in->Coding != IM_CODING_LABQ ) {
|
||
|
im_errormsg( "im_LabQ2Lab: not a packed Lab image" );
|
||
|
return( -1 );
|
||
|
}
|
||
|
|
||
|
if( im_cp_desc( out, in ) )
|
||
|
return( -1 );
|
||
|
out->Bands = 3;
|
||
|
out->Bbits = IM_BBITS_BYTE;
|
||
|
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 );
|
||
|
}
|