libvips/libvips/colour/colour.c

264 lines
6.4 KiB
C
Raw Normal View History

2012-04-04 10:39:09 +02:00
/* base class for all colour operations
2009-08-16 17:00:08 +02:00
*/
/*
2012-04-04 10:39:09 +02:00
Copyright (C) 1991-2005 The National Gallery
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
2009-08-16 17:00:08 +02:00
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
2012-04-04 10:39:09 +02:00
GNU General Public License for more details.
2009-08-16 17:00:08 +02:00
2012-04-04 10:39:09 +02:00
You should have received a copy of the GNU General Public License
2009-08-16 17:00:08 +02:00
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
*/
2012-04-04 10:39:09 +02:00
/*
#define DEBUG
*/
2009-08-16 17:00:08 +02:00
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
2012-04-04 10:39:09 +02:00
#include <stdlib.h>
2009-08-16 17:00:08 +02:00
#include <math.h>
#include <vips/vips.h>
2012-04-04 10:39:09 +02:00
#include "colour.h"
2009-08-16 17:00:08 +02:00
2012-04-04 10:39:09 +02:00
G_DEFINE_ABSTRACT_TYPE( VipsColour, vips_colour, VIPS_TYPE_OPERATION );
2009-08-16 17:00:08 +02:00
/* Maximum number of input images -- why not?
*/
#define MAX_INPUT_IMAGES (64)
2012-04-04 10:39:09 +02:00
static int
vips_colour_gen( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
2009-08-16 17:00:08 +02:00
{
VipsRegion **ir = (VipsRegion **) seq;
2012-04-04 10:39:09 +02:00
VipsColour *colour = VIPS_COLOUR( b );
VipsColourClass *class = VIPS_COLOUR_GET_CLASS( colour );
Rect *r = &or->valid;
2009-08-16 17:00:08 +02:00
VipsPel *p[MAX_INPUT_IMAGES], *q;
int i, y;
2009-08-16 17:00:08 +02:00
/* Prepare all input regions and make buffer pointers.
*/
for( i = 0; ir[i]; i++ ) {
if( vips_region_prepare( ir[i], r ) )
return( -1 );
p[i] = (VipsPel *) VIPS_REGION_ADDR( ir[i], r->left, r->top );
}
p[i] = NULL;
2012-04-04 10:39:09 +02:00
q = (VipsPel *) VIPS_REGION_ADDR( or, r->left, r->top );
2009-08-16 17:00:08 +02:00
2012-04-04 10:39:09 +02:00
for( y = 0; y < r->height; y++ ) {
2012-09-17 15:49:44 +02:00
class->process_line( colour, q, p, r->width );
2009-08-16 17:00:08 +02:00
for( i = 0; ir[i]; i++ )
p[i] += VIPS_REGION_LSKIP( ir[i] );
2012-04-04 10:39:09 +02:00
q += VIPS_REGION_LSKIP( or );
2009-08-16 17:00:08 +02:00
}
2012-04-04 10:39:09 +02:00
return( 0 );
2009-08-16 17:00:08 +02:00
}
2012-04-04 10:39:09 +02:00
static int
vips_colour_build( VipsObject *object )
2011-11-25 15:34:17 +01:00
{
2012-04-04 10:39:09 +02:00
VipsColour *colour = VIPS_COLOUR( object );
2012-09-18 19:36:48 +02:00
VipsColourClass *class = VIPS_COLOUR_GET_CLASS( colour );
2012-09-17 15:49:44 +02:00
int i;
2012-04-04 10:39:09 +02:00
#ifdef DEBUG
printf( "vips_colour_build: " );
vips_object_print_name( object );
printf( "\n" );
#endif /*DEBUG*/
2011-11-25 15:34:17 +01:00
2012-04-04 10:39:09 +02:00
if( VIPS_OBJECT_CLASS( vips_colour_parent_class )->
build( object ) )
return( -1 );
2011-11-25 15:34:17 +01:00
2012-04-04 10:39:09 +02:00
g_object_set( colour, "out", vips_image_new(), NULL );
2011-11-25 15:34:17 +01:00
if( colour->n > MAX_INPUT_IMAGES ) {
vips_error( "VipsColour",
"%s", _( "too many input images" ) );
return( -1 );
}
2012-09-17 15:49:44 +02:00
for( i = 0; i < colour->n; i++ )
if( vips_image_pio_input( colour->in[i] ) )
return( -1 );
if( vips_image_copy_fields_array( colour->out, colour->in ) )
return( -1 );
2012-09-17 15:49:44 +02:00
vips_demand_hint_array( colour->out,
VIPS_DEMAND_STYLE_THINSTRIP, colour->in );
2012-09-19 13:01:02 +02:00
colour->out->Type = class->interpretation;
if( vips_image_generate( colour->out,
vips_start_many, vips_colour_gen, vips_stop_many,
colour->in, colour ) )
2012-04-04 10:39:09 +02:00
return( -1 );
2011-12-20 15:57:05 +01:00
return( 0 );
}
static void
vips_colour_class_init( VipsColourClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
2012-09-18 15:14:08 +02:00
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
vobject_class->nickname = "colour";
vobject_class->description = _( "colour operations" );
vobject_class->build = vips_colour_build;
2012-09-18 15:14:08 +02:00
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
2012-09-18 19:36:48 +02:00
class->interpretation = VIPS_INTERPRETATION_sRGB;
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsColour, out ) );
}
static void
vips_colour_init( VipsColour *colour )
{
}
2012-09-20 12:05:27 +02:00
G_DEFINE_ABSTRACT_TYPE( VipsColourSpace, vips_space, VIPS_TYPE_COLOUR );
static int
2012-09-20 12:05:27 +02:00
vips_space_build( VipsObject *object )
{
VipsColour *colour = VIPS_COLOUR( object );
2012-09-20 12:05:27 +02:00
VipsColourSpace *space = VIPS_COLOUR_SPACE( object );
VipsImage **t;
2012-09-18 15:14:08 +02:00
t = (VipsImage **) vips_object_local_array( object, 4 );
2012-09-17 15:49:44 +02:00
colour->n = 1;
colour->in = (VipsImage **) vips_object_local_array( object, 1 );
/* We only process float.
*/
2012-09-20 12:05:27 +02:00
if( vips_cast_float( space->in, &t[0], NULL ) )
return( -1 );
2012-09-17 15:49:44 +02:00
colour->in[0] = t[0];
/* If there are more than n bands, process just the first three and
2012-09-17 15:49:44 +02:00
* reattach the rest after. This lets us handle RGBA etc.
*/
if( t[0]->Bands > 3 ) {
if( vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) ||
vips_extract_band( t[0], &t[2], 0,
"n", t[0]->Bands - 3, NULL ) )
return( -1 );
2012-09-18 15:14:08 +02:00
colour->in[0] = t[1];
2012-09-17 15:49:44 +02:00
}
2012-09-17 15:49:44 +02:00
if( colour->in[0] )
g_object_ref( colour->in[0] );
2012-09-20 12:05:27 +02:00
if( VIPS_OBJECT_CLASS( vips_space_parent_class )->
2012-09-17 15:49:44 +02:00
build( object ) )
return( -1 );
2012-09-17 15:49:44 +02:00
/* Reattach higher bands, if necessary.
*/
2012-09-18 15:14:08 +02:00
if( t[0]->Bands > 3 ) {
VipsImage *x;
if( vips_bandjoin2( colour->out, t[2], &x, NULL ) )
return( -1 );
2012-09-18 15:14:08 +02:00
VIPS_UNREF( colour->out );
colour->out = x;
}
2012-04-04 10:39:09 +02:00
return( 0 );
2012-04-02 12:12:40 +02:00
}
2012-04-04 10:39:09 +02:00
static void
2012-09-20 12:05:27 +02:00
vips_space_class_init( VipsColourSpaceClass *class )
2011-11-25 15:34:17 +01:00
{
2012-04-04 10:39:09 +02:00
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
2011-11-25 15:34:17 +01:00
2012-04-04 10:39:09 +02:00
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
2011-11-25 15:34:17 +01:00
2012-09-20 12:05:27 +02:00
vobject_class->nickname = "space";
vobject_class->description = _( "colour space transformations" );
vobject_class->build = vips_space_build;
2011-11-25 15:34:17 +01:00
2012-04-04 10:39:09 +02:00
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
2012-09-20 12:05:27 +02:00
G_STRUCT_OFFSET( VipsColourSpace, in ) );
2011-11-25 15:34:17 +01:00
}
2012-04-04 10:39:09 +02:00
static void
2012-09-20 12:05:27 +02:00
vips_space_init( VipsColourSpace *space )
2011-11-25 15:34:17 +01:00
{
}
2012-04-04 10:39:09 +02:00
/* Called from iofuncs to init all operations in this dir. Use a plugin system
* instead?
*/
void
vips_colour_operation_init( void )
2011-11-25 15:34:17 +01:00
{
2012-09-18 15:14:08 +02:00
extern GType vips_Lab2XYZ_get_type( void );
extern GType vips_XYZ2Lab_get_type( void );
2012-09-18 15:52:21 +02:00
extern GType vips_Lab2LCh_get_type( void );
2012-09-19 13:01:02 +02:00
extern GType vips_LCh2Lab_get_type( void );
extern GType vips_LCh2UCS_get_type( void );
extern GType vips_UCS2LCh_get_type( void );
extern GType vips_Yxy2XYZ_get_type( void );
extern GType vips_XYZ2Yxy_get_type( void );
2011-11-25 15:34:17 +01:00
2012-09-18 15:14:08 +02:00
vips_Lab2XYZ_get_type();
vips_XYZ2Lab_get_type();
2012-09-18 15:52:21 +02:00
vips_Lab2LCh_get_type();
2012-09-19 13:01:02 +02:00
vips_LCh2Lab_get_type();
vips_LCh2UCS_get_type();
vips_UCS2LCh_get_type();
vips_XYZ2Yxy_get_type();
vips_Yxy2XYZ_get_type();
2011-11-25 15:34:17 +01:00
}