LabQ <-> Lab as classes

This commit is contained in:
John Cupitt 2012-09-20 21:21:08 +01:00
parent 59513b6869
commit 2e1b8bb9ef
12 changed files with 182 additions and 128 deletions

View File

@ -28,6 +28,8 @@
* 1/11/09
* - gtkdoc
* - cleanups
* 20/9/12
* - redo as a class
*/
/*
@ -66,65 +68,91 @@
#include <vips/vips.h>
#include "colour.h"
typedef VipsColourCode VipsLab2LabQ;
typedef VipsColourCodeClass VipsLab2LabQClass;
G_DEFINE_TYPE( VipsLab2LabQ, vips_Lab2LabQ, VIPS_TYPE_COLOUR_CODE );
/* @(#) convert float Lab to packed Lab32 format 10 11 11 bits
* works only on buffers, not IMAGEs
* Copyright 1993 K.Martinez
* Modified: 3/5/93, 16/6/93
*/
void
imb_Lab2LabQ( float *inp, unsigned char *outbuf, int n )
static void
vips_Lab2LabQ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
float *f, fval;
int lsbs, intv;
int Xc;
unsigned char *out;
float *p = (float *) in[0];
out = outbuf;
f = inp;
for( Xc = 0; Xc < n; Xc++) {
/* Scale L up to 10 bits. Add 0.5 rather than call IM_RINT for
* speed. This will not round negatives correctly! But this
* does not matter, since L is >0. L*=100.0 -> 1023.
float fval;
int lsbs;
int intv;
int i;
for( i = 0; i < width; i++) {
/* Scale L up to 10 bits. Add 0.5 rather than call VIPS_RINT
* for speed. This will not round negatives correctly! But
* this does not matter, since L is >0. L*=100.0 -> 1023.
*/
intv = 10.23 * f[0] + 0.5; /* scale L up to 10 bits */
if( intv > 1023 )
intv = 1023;
if( intv < 0 )
intv = 0;
intv = 10.23 * p[0] + 0.5; /* scale L up to 10 bits */
intv = VIPS_CLIP( 0, intv, 1023 );
lsbs = (intv & 0x3) << 6; /* 00000011 -> 11000000 */
out[0] = (intv >> 2); /* drop bot 2 bits and store */
fval = 8.0 * f[1]; /* do a */
intv = IM_RINT( fval );
if( intv > 1023 )
intv = 1023;
else if( intv < -1024 )
intv = -1024;
/* Break into bits.
*/
fval = 8.0 * p[1]; /* do a */
intv = VIPS_RINT( fval );
intv = VIPS_CLIP( -1024, intv, 1023 );
lsbs |= (intv & 0x7) << 3; /* 00000111 -> 00111000 */
out[1] = (intv >> 3); /* drop bot 3 bits & store */
fval = 8.0 * f[2]; /* do b */
intv = IM_RINT( fval );
if( intv > 1023 )
intv = 1023;
else if( intv < -1024 )
intv = -1024;
fval = 8.0 * p[2]; /* do b */
intv = VIPS_RINT( fval );
intv = VIPS_CLIP( -1024, intv, 1023 );
lsbs |= (intv & 0x7);
out[2] = (intv >> 3);
out[3] = lsbs; /* store lsb band */
f += 3;
p += 3;
out += 4;
}
}
void
vips__Lab2LabQ_vec( VipsPel *out, float *in, int width )
{
vips_Lab2LabQ_line( NULL, out, (VipsPel **) &in, width );
}
static void
vips_Lab2LabQ_class_init( VipsLab2LabQClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class );
object_class->nickname = "Lab2LabQ";
object_class->description = _( "transform float Lab to LabQ coding" );
colour_class->process_line = vips_Lab2LabQ_line;
colour_class->coding = VIPS_CODING_LABQ;
colour_class->interpretation = VIPS_INTERPRETATION_LABQ;
colour_class->format = VIPS_FORMAT_UCHAR;
colour_class->bands = 4;
code_class->input_coding = VIPS_CODING_NONE;
code_class->input_format = VIPS_FORMAT_FLOAT;
code_class->input_bands = 3;
}
static void
vips_Lab2LabQ_init( VipsLab2LabQ *Lab2LabQ )
{
}
/**
* im_Lab2LabQ:
* vips_Lab2LabQ:
* @in: input image
* @out: output image
*
@ -135,26 +163,14 @@ imb_Lab2LabQ( float *inp, unsigned char *outbuf, int n )
* Returns: 0 on success, -1 on error.
*/
int
im_Lab2LabQ( IMAGE *in, IMAGE *out )
vips_Lab2LabQ( VipsImage *in, VipsImage **out, ... )
{
IMAGE *t[1];
va_list ap;
int result;
if( im_check_uncoded( "im_Lab2LabQ", in ) ||
im_check_bands( "im_Lab2LabQ", in, 3 ) ||
im_open_local_array( out, t, 1, "im_Lab2LabQ", "p" ) ||
im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) )
return( -1 );
va_start( ap, out );
result = vips_call_split( "Lab2LabQ", ap, in, out );
va_end( ap );
if( im_cp_desc( out, t[0] ) )
return( -1 );
out->Bands = 4;
out->Type = IM_TYPE_LABQ;
out->BandFmt = IM_BANDFMT_UCHAR;
out->Coding = IM_CODING_LABQ;
if( im_wrapone( t[0], out,
(im_wrapone_fn) imb_Lab2LabQ, NULL, NULL ) )
return( -1 );
return( 0 );
return( result );
}

View File

@ -16,6 +16,8 @@
* - L* = 100.0 now handled correctly
* 2/11/09
* - gtkdoc
* 20/9/12
* - redo as a class
*/
/*
@ -53,6 +55,13 @@
#include <vips/vips.h>
#include "colour.h"
typedef VipsColourCode VipsLabQ2Lab;
typedef VipsColourCodeClass VipsLabQ2LabClass;
G_DEFINE_TYPE( VipsLabQ2Lab, vips_LabQ2Lab, VIPS_TYPE_COLOUR_CODE );
/* imb_LabQ2Lab: CONVERT n pels from packed 32bit Lab to float values
* in a buffer
* ARGS: VipsPel *inp pointer to first byte of Lab32 buffer
@ -60,47 +69,76 @@
* int n number of pels to process
* (C) K.Martinez 2/5/93
*/
void
imb_LabQ2Lab( VipsPel *inp, float *outbuf, int n )
static void
vips_LabQ2Lab_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
signed char *b; /* to read input bytes */
signed char *p = (signed char *) in[0];
float *q = (float *) out;
int l;
int lsbs; /* for lsbs byte */
int c; /* counter */
float *out;
int i; /* counter */
/* Read input with a signed pointer to get signed ab easily.
*/
b = (signed char *) inp;
out = outbuf;
for( c = 0; c < n; c++ ) {
for( i = 0; i < width; i++ ) {
/* Get extra bits.
*/
lsbs = ((unsigned char *) b)[3];
lsbs = ((unsigned char *) p)[3];
/* Build L.
*/
l = ((unsigned char *)b)[0];
l = ((unsigned char *)p)[0];
l = (l << 2) | (lsbs >> 6);
out[0] = (float) l * (100.0 / 1023.0);
q[0] = (float) l * (100.0 / 1023.0);
/* Build a.
*/
l = (b[1] << 3) | ((lsbs >> 3) & 0x7);
out[1] = (float) l * 0.125;
l = (p[1] << 3) | ((lsbs >> 3) & 0x7);
q[1] = (float) l * 0.125;
/* And b.
*/
l = (b[2] << 3) | (lsbs & 0x7);
out[2] = (float) l * 0.125;
l = (p[2] << 3) | (lsbs & 0x7);
q[2] = (float) l * 0.125;
b += 4;
out += 3;
p += 4;
q += 3;
}
}
void
vips__LabQ2Lab_vec( float *out, VipsPel *in, int width )
{
vips_LabQ2Lab_line( NULL, (VipsPel *) out, &in, width );
}
static void
vips_LabQ2Lab_class_init( VipsLabQ2LabClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
VipsColourCodeClass *code_class = VIPS_COLOUR_CODE_CLASS( class );
object_class->nickname = "LabQ2Lab";
object_class->description = _( "unpack a LabQ image to float Lab" );
colour_class->process_line = vips_LabQ2Lab_line;
colour_class->coding = VIPS_CODING_NONE;
colour_class->interpretation = VIPS_INTERPRETATION_LAB;
colour_class->format = VIPS_FORMAT_FLOAT;
colour_class->bands = 3;
code_class->input_coding = VIPS_CODING_LABQ;
}
static void
vips_LabQ2Lab_init( VipsLabQ2Lab *LabQ2Lab )
{
}
/**
* im_LabQ2Lab:
* vips_LabQ2Lab:
* @in: input image
* @out: output image
*
@ -111,21 +149,14 @@ imb_LabQ2Lab( VipsPel *inp, float *outbuf, int n )
* Returns: 0 on success, -1 on error.
*/
int
im_LabQ2Lab( IMAGE *in, IMAGE *out )
vips_LabQ2Lab( VipsImage *in, VipsImage **out, ... )
{
if( im_check_coding_labq( "im_LabQ2Lab", in ) )
return( -1 );
va_list ap;
int result;
if( im_cp_desc( out, in ) )
return( -1 );
out->Bands = 3;
out->Type = IM_TYPE_LAB;
out->BandFmt = IM_BANDFMT_FLOAT;
out->Coding = IM_CODING_NONE;
va_start( ap, out );
result = vips_call_split( "LabQ2Lab", ap, in, out );
va_end( ap );
if( im_wrapone( in, out,
(im_wrapone_fn) imb_LabQ2Lab, NULL, NULL ) )
return( -1 );
return( 0 );
return( result );
}

View File

@ -16,10 +16,10 @@ libcolour_la_SOURCES = \
Yxy2XYZ.c \
float2rad.c \
rad2float.c \
Lab2LabQ.c \
LabQ2Lab.c \
im_icc_transform.c \
im_Lab2LabQ.c \
im_Lab2LabS.c \
im_LabQ2Lab.c \
im_LabQ2LabS.c \
im_LabQ2disp.c \
im_LabS2LabQ.c \

View File

@ -334,32 +334,6 @@ vips_LabS2LabQ( VipsImage *in, VipsImage **out, ... )
return( result );
}
int
vips_LabQ2Lab( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "im_LabQ2Lab", ap, in, out );
va_end( ap );
return( result );
}
int
vips_Lab2LabQ( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "im_Lab2LabQ", ap, in, out );
va_end( ap );
return( result );
}
int
vips_Yxy2Lab( VipsImage *in, VipsImage **out, ... )
{

View File

@ -5,7 +5,7 @@
* 2/11/09
* - gtkdoc
* 20/9/12
* redo as a class
* - redo as a class
*/
/*

View File

@ -2355,3 +2355,35 @@ im_rad2float( IMAGE *in, IMAGE *out )
return( 0 );
}
int
im_Lab2LabQ( IMAGE *in, IMAGE *out )
{
VipsImage *x;
if( vips_Lab2LabQ( in, &x, NULL ) )
return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 );
}
int
im_LabQ2Lab( IMAGE *in, IMAGE *out )
{
VipsImage *x;
if( vips_LabQ2Lab( in, &x, NULL ) )
return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 );
}

View File

@ -164,9 +164,7 @@ float im_col_dE00(
float L1, float a1, float b1, float L2, float a2, float b2 );
int im_LabQ2XYZ( VipsImage *in, VipsImage *out );
int im_Lab2LabQ( VipsImage *in, VipsImage *out );
int im_Lab2LabS( VipsImage *in, VipsImage *out );
int im_LabQ2Lab( VipsImage *in, VipsImage *out );
int im_LabQ2LabS( VipsImage *in, VipsImage *out );
int im_LabS2LabQ( VipsImage *in, VipsImage *out );
int im_LabS2Lab( VipsImage *in, VipsImage *out );

View File

@ -236,11 +236,12 @@ typedef struct {
} im_colour_temperature;
void imb_XYZ2Lab( float *, float *, int, im_colour_temperature * );
void imb_LabQ2Lab( VipsPel *, float *, int );
void imb_Lab2LabQ( float *, VipsPel *, int );
void imb_LabS2Lab( signed short *, float *, int );
void imb_Lab2LabS( float *, signed short *, int n );
void vips__Lab2LabQ_vec( VipsPel *out, float *in, int width );
void vips__LabQ2Lab_vec( float *out, VipsPel *in, int width );
void im_copy_dmask_matrix( DOUBLEMASK *mask, double **matrix );
void im_copy_matrix_dmask( double **matrix, DOUBLEMASK *mask );

View File

@ -724,6 +724,8 @@ int im_XYZ2Yxy( VipsImage *in, VipsImage *out );
int im_Yxy2XYZ( VipsImage *in, VipsImage *out );
int im_float2rad( VipsImage *in, VipsImage *out );
int im_rad2float( VipsImage *in, VipsImage *out );
int im_Lab2LabQ( VipsImage *in, VipsImage *out );
int im_LabQ2Lab( VipsImage *in, VipsImage *out );
/* ruby-vips uses this
*/

View File

@ -180,7 +180,7 @@ mask_draw_labq( Mask *mask )
mask->image_clip.width * 3, float )) )
return( -1 );
imb_LabQ2Lab( DRAW( mask )->ink, ink_buffer, 1 );
vips__LabQ2Lab_vec( ink_buffer, DRAW( mask )->ink, 1 );
for( y = 0; y < mask->image_clip.height; y++ ) {
VipsPel *to = IM_IMAGE_ADDR( DRAW( mask )->im,
@ -188,9 +188,9 @@ mask_draw_labq( Mask *mask )
VipsPel *mask_line = IM_IMAGE_ADDR( mask->mask_im,
mask->mask_clip.left, y + mask->mask_clip.top );
imb_LabQ2Lab( to, lab_buffer, mask->image_clip.width );
vips__LabQ2Lab_vec( lab_buffer, to, mask->image_clip.width );
DBLEND( float, lab_buffer, ink_buffer );
imb_Lab2LabQ( lab_buffer, to, mask->image_clip.width );
vips__Lab2LabQ_vec( to, lab_buffer, mask->image_clip.width );
}
im_free( lab_buffer );

View File

@ -662,8 +662,8 @@ lr_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg )
/* Unpack two bits we want.
*/
imb_LabQ2Lab( pr, r, oreg->width );
imb_LabQ2Lab( ps, s, oreg->width );
vips__LabQ2Lab_vec( r, pr, oreg->width );
vips__LabQ2Lab_vec( s, ps, oreg->width );
/* Blend as floats.
*/
@ -671,7 +671,7 @@ lr_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg )
/* Re-pack to output buffer.
*/
imb_Lab2LabQ( inf->merge, q, oreg->width );
vips__Lab2LabQ_vec( q, inf->merge, oreg->width );
}
return( 0 );

View File

@ -593,8 +593,8 @@ tb_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg )
/* Unpack two bits we want.
*/
imb_LabQ2Lab( pr, r, oreg->width );
imb_LabQ2Lab( ps, s, oreg->width );
vips__LabQ2Lab_vec( r, pr, oreg->width );
vips__LabQ2Lab_vec( s, ps, oreg->width );
/* Blend as floats.
*/
@ -602,7 +602,7 @@ tb_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg )
/* Re-pack to output buffer.
*/
imb_Lab2LabQ( inf->merge, q, oreg->width );
vips__Lab2LabQ_vec( q, inf->merge, oreg->width );
}
return( 0 );