/* @(#) 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 #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #ifdef WITH_DMALLOC #include #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 ); }