sort out alpha going to and from 16-bit

rewritten sRGB <-> scRGB so that 16-bit alpha is scaled to float 8
This commit is contained in:
John Cupitt 2015-02-12 17:50:38 +00:00
parent 46c655caf0
commit 8f7c2c7110
11 changed files with 290 additions and 171 deletions

View File

@ -3,7 +3,7 @@
- add fliphor(), flipver(), rot90(), rot180(), rot270() convenience methods to
Python
- add shift option to cast
- better alpha handling for 16 <-> 8 bit colour conversions
- sRGB2scRGB and scRGB2sRGB scale 16-bit alpha to and from 8-bit
6/2/15 started 7.42.3
- bump version for back-compat ABI change

View File

@ -17,15 +17,6 @@ P8_COMPILE_DIR =
P8_DIST_DIR = python
endif
# turn docs on or off
if ENABLE_DOCS
D_DIST_DIR =
D_BUILD_DIR = doc
else
D_DIST_DIR = doc
D_BUILD_DIR =
endif
SUBDIRS = \
libvips \
libvipsCC \
@ -36,8 +27,7 @@ SUBDIRS = \
doc \
test \
$(P_COMPILE_DIR) \
$(P8_COMPILE_DIR) \
$(D_BUILD_DIR)
$(P8_COMPILE_DIR)
EXTRA_DIST = \
m4 \
@ -51,30 +41,17 @@ EXTRA_DIST = \
depcomp \
README.md \
$(P_DIST_DIR) \
$(P8_DIST_DIR) \
$(D_DIST_DIR)
$(P8_DIST_DIR)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = vips.pc vipsCC.pc vips-cpp.pc
if ENABLE_DOCS
install-exec-hook:
-rm -rf ${DESTDIR}$(datadir)/doc/vips
$(mkinstalldirs) ${DESTDIR}$(datadir)/doc/vips
-cp -r ${top_srcdir}/doc/html ${top_srcdir}/doc/pdf ${DESTDIR}$(datadir)/doc/vips
endif
dist-hook:
# make sure we don't get any .svn dirs from EXTRA_DIST
# also "fred" gets left around occasionally
-find $(distdir) -name .svn -exec rm -rf {} \;
-find $(distdir) -name fred -exec rm {} \;
uninstall-hook:
# make sure we have write permission for 'rm'
-chmod -R u+w ${DESTDIR}$(datadir)/doc/vips
-rm -rf ${DESTDIR}$(datadir)/doc/vips
ACLOCAL_AMFLAGS = -I m4
DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc --enable-introspection

39
TODO
View File

@ -1,40 +1,14 @@
- at the moment we have a policy of just ignoring extra bands
we are proposing to change this to modify band 2, 4 or 5, if present, when
going to and from RGB16 or GREY16
if we make this change, we must support it for all transforms of this type,
not just for a couple, or it'll be incredibly confusing
vips_process_n() could use cast(shift = TRUE)
vips_colour_build() could use cast shift too
- use vips_sRGB2RGB16()
- check vips_sRGB2scRGB() with a 16-bit source ... what does it do for alpha?
alpha is untouched ... rgb->0-1, alpha stays at 0-65535
maybe should move everything to 0-1? otherwise when we do scRGB2sRGB we'll
(effectively) do alpha * 256
but what if we then do scRGB -> XYZ (for example), should alpha stay 0 - 1?
- tiff pyramid builder:
- only write level 0 once ... append levels 1 and up afterwards
- try to copy levels 1 and up without decompress / recompress
- we have
im.flip("horizontal")
maybe add fliphor() and flipver() as convenience functions, cf. .sin() etc.
- why can't we do
@ -50,7 +24,8 @@
im = Vips.Image.jpegload(sys.argv[1], access = "sequential")
nope, fails too
nope, fails too ... mysterious!

View File

@ -243,20 +243,6 @@ else
fi
AC_DEFINE_UNQUOTED(VIPS_ICC_DIR,"$profile_dir",[default directory for ICC profiles])
# option to stop docs installing ... eg. freebsd likes this
AC_ARG_ENABLE(docs,
AS_HELP_STRING([--enable-docs], [install docs (default: yes)]))
if test x"$enable_docs" != x"no"; then
AM_CONDITIONAL(ENABLE_DOCS, true)
enable_docs=yes
fi
if test x"$enable_docs" != x"yes"; then
AM_CONDITIONAL(ENABLE_DOCS, false)
enable_docs=no
fi
# we want largefile support, if possible
AC_SYS_LARGEFILE
@ -851,7 +837,6 @@ open files in binary mode: $vips_binary_open
enable debug: $enable_debug
build deprecated components: $enable_deprecated
build docs with gtkdoc: $enable_gtk_doc
install docs: $enable_docs
gobject introspection: $found_introspection
build vips7 Python binding: $with_python
install vips8 Python overrides: $enable_pyvips8

View File

@ -9,7 +9,7 @@
<bookinfo>
<title>VIPS Reference Manual</title>
<releaseinfo>
For VIPS 7.42.3.
For VIPS 8.0.0.
The latest version of this documentation can be found on the
<ulink role="online-location"
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.

View File

@ -402,7 +402,6 @@ vips_colour_build( VipsObject *object )
*/
if( vips_cast( extra_bands[i], &t1, out->BandFmt,
"shift", TRUE,
NULL ) ) {
g_object_unref( out );
return( -1 );

View File

@ -74,7 +74,7 @@ vips_scRGB2RGB16( VipsImage *in, VipsImage **out, ... )
}
/* Do these two with a simple cast ... since we're just cast shifting, we can
* short-circuit the extra band processing in vips_colour_build().
* short-circuit the extra band processing.
*/
static int
@ -353,9 +353,8 @@ static VipsColourRoute vips_colour_routes[] = {
{ sRGB, BW, { vips_sRGB2BW, NULL } },
{ sRGB, LABS, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Lab,
vips_Lab2LabS, NULL } },
{ sRGB, RGB16, { vips_sRGB2scRGB, vips_scRGB2RGB16, NULL } },
{ sRGB, GREY16, { vips_sRGB2scRGB, vips_scRGB2RGB16,
vips_RGB162GREY16, NULL } },
{ sRGB, RGB16, { vips_sRGB2RGB16, NULL } },
{ sRGB, GREY16, { vips_sRGB2RGB16, vips_RGB162GREY16, NULL } },
{ sRGB, YXY, { vips_sRGB2scRGB, vips_scRGB2XYZ, vips_XYZ2Yxy, NULL } },
{ RGB16, XYZ, { vips_sRGB2scRGB, vips_scRGB2XYZ, NULL } },
@ -385,9 +384,8 @@ static VipsColourRoute vips_colour_routes[] = {
{ GREY16, CMC, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ,
vips_XYZ2Lab, vips_Lab2LCh, vips_LCh2CMC, NULL } },
{ GREY16, scRGB, { vips_GREY162RGB16, vips_sRGB2scRGB, NULL } },
{ GREY16, sRGB, { vips_GREY162RGB16, vips_sRGB2scRGB,
vips_scRGB2sRGB, NULL } },
{ GREY16, BW, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2sRGB,
{ GREY16, sRGB, { vips_GREY162RGB16, vips_RGB162sRGB, NULL } },
{ GREY16, BW, { vips_GREY162RGB16, vips_RGB162sRGB,
vips_sRGB2BW, NULL } },
{ GREY16, LABS, { vips_GREY162RGB16, vips_sRGB2scRGB, vips_scRGB2XYZ,
vips_XYZ2Lab, vips_Lab2LabS, NULL } },
@ -408,10 +406,9 @@ static VipsColourRoute vips_colour_routes[] = {
{ BW, sRGB, { vips_BW2sRGB, NULL } },
{ BW, LABS, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ,
vips_XYZ2Lab, vips_Lab2LabS, NULL } },
{ BW, RGB16, { vips_BW2sRGB, vips_sRGB2scRGB,
vips_scRGB2RGB16, NULL } },
{ BW, GREY16, { vips_BW2sRGB, vips_sRGB2scRGB,
vips_scRGB2RGB16, vips_RGB162GREY16, NULL } },
{ BW, RGB16, { vips_BW2sRGB, vips_sRGB2RGB16, NULL } },
{ BW, GREY16, { vips_BW2sRGB, vips_sRGB2RGB16,
vips_RGB162GREY16, NULL } },
{ BW, YXY, { vips_BW2sRGB, vips_sRGB2scRGB, vips_scRGB2XYZ,
vips_XYZ2Yxy, NULL } },

View File

@ -13,6 +13,8 @@
* - add 16-bit sRGB import
* 11/12/12
* - cut about to make sRGB2scRGB.c
* 12/2/15
* - add 16-bit alpha handling
*/
/*
@ -54,17 +56,28 @@
#include "pcolour.h"
typedef VipsColourCode VipssRGB2scRGB;
typedef VipsColourCodeClass VipssRGB2scRGBClass;
/* We can't use VipsColourCode as our parent class. We want to handle
* alpha ourselves so we can get 16 -> 8 bit conversion right.
*/
G_DEFINE_TYPE( VipssRGB2scRGB, vips_sRGB2scRGB, VIPS_TYPE_COLOUR_CODE );
typedef struct _VipssRGB2scRGB {
VipsOperation parent_instance;
VipsImage *in;
VipsImage *out;
} VipssRGB2scRGB;
typedef VipsOperationClass VipssRGB2scRGBClass;
G_DEFINE_TYPE( VipssRGB2scRGB, vips_sRGB2scRGB, VIPS_TYPE_OPERATION );
/* Convert a buffer of 8-bit pixels.
*/
static void
vips_sRGB2scRGB_line_8( float * restrict q, VipsPel * restrict p, int width )
vips_sRGB2scRGB_line_8( float * restrict q, VipsPel * restrict p,
int extra_bands, int width )
{
int i;
int i, j;
for( i = 0; i < width; i++ ) {
int r = p[0];
@ -82,6 +95,11 @@ vips_sRGB2scRGB_line_8( float * restrict q, VipsPel * restrict p, int width )
q[2] = B;
q += 3;
for( j = 0; j < extra_bands; j++ )
q[j] = p[j];
p += extra_bands;
q += extra_bands;
}
}
@ -89,9 +107,9 @@ vips_sRGB2scRGB_line_8( float * restrict q, VipsPel * restrict p, int width )
*/
static void
vips_sRGB2scRGB_line_16( float * restrict q, unsigned short * restrict p,
int width )
int extra_bands, int width )
{
int i;
int i, j;
for( i = 0; i < width; i++ ) {
int r = p[0];
@ -109,69 +127,127 @@ vips_sRGB2scRGB_line_16( float * restrict q, unsigned short * restrict p,
q[2] = B;
q += 3;
for( j = 0; j < extra_bands; j++ )
q[j] = p[j] / 256.0;
p += extra_bands;
q += extra_bands;
}
}
static void
vips_sRGB2scRGB_line( VipsColour *colour,
VipsPel *out, VipsPel **in, int width )
static int
vips_sRGB2scRGB_gen( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
if( colour->in[0]->BandFmt == VIPS_FORMAT_UCHAR )
vips_sRGB2scRGB_line_8( (float *) out,
(VipsPel *) in[0], width );
else
vips_sRGB2scRGB_line_16( (float *) out,
(unsigned short *) in[0], width );
VipsRegion *ir = (VipsRegion *) seq;
VipsRect *r = &or->valid;
VipsImage *in = ir->im;
int y;
if( vips_region_prepare( ir, r ) )
return( -1 );
VIPS_GATE_START( "vips_sRGB2scRGB_gen: work" );
for( y = 0; y < r->height; y++ ) {
VipsPel *p = VIPS_REGION_ADDR( ir, r->left, r->top + y );
float *q = (float *)
VIPS_REGION_ADDR( or, r->left, r->top + y );
if( in->BandFmt == VIPS_FORMAT_UCHAR )
vips_sRGB2scRGB_line_8( q, p,
in->Bands - 3, r->width );
else
vips_sRGB2scRGB_line_16( q, (unsigned short *) p,
in->Bands - 3, r->width );
}
VIPS_GATE_STOP( "vips_sRGB2scRGB_gen: work" );
return( 0 );
}
static int
vips_sRGB2scRGB_build( VipsObject *object )
{
VipsColourCode *code = (VipsColourCode *) object;
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipssRGB2scRGB *sRGB2scRGB = (VipssRGB2scRGB *) object;
if( code->in )
code->input_format =
code->in->BandFmt == VIPS_FORMAT_USHORT ?
VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
VipsImage *in;
VipsImage *out;
VipsBandFormat format;
if( VIPS_OBJECT_CLASS( vips_sRGB2scRGB_parent_class )->
build( object ) )
return( -1 );
in = sRGB2scRGB->in;
if( vips_check_bands_atleast( class->nickname, in, 3 ) )
return( -1 );
format = in->BandFmt == VIPS_FORMAT_USHORT ?
VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR;
if( vips_cast( in, &t[0], format, NULL ) )
return( -1 );
in = t[0];
out = vips_image_new();
if( vips_image_pipelinev( out,
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) {
g_object_unref( out );
return( -1 );
}
out->Type = VIPS_INTERPRETATION_scRGB;
out->BandFmt = VIPS_FORMAT_FLOAT;
if( vips_image_generate( out,
vips_start_one, vips_sRGB2scRGB_gen, vips_stop_one,
in, sRGB2scRGB ) ) {
g_object_unref( out );
return( -1 );
}
g_object_set( object, "out", out, NULL );
return( 0 );
}
static void
vips_sRGB2scRGB_class_init( VipssRGB2scRGBClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "sRGB2scRGB";
object_class->description = _( "convert an sRGB image to scRGB" );
object_class->build = vips_sRGB2scRGB_build;
colour_class->process_line = vips_sRGB2scRGB_line;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL_UNBUFFERED;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipssRGB2scRGB, in ) );
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipssRGB2scRGB, out ) );
}
static void
vips_sRGB2scRGB_init( VipssRGB2scRGB *sRGB2scRGB )
{
VipsColour *colour = VIPS_COLOUR( sRGB2scRGB );
VipsColourCode *code = VIPS_COLOUR_CODE( sRGB2scRGB );
colour->coding = VIPS_CODING_NONE;
colour->interpretation = VIPS_INTERPRETATION_scRGB;
colour->format = VIPS_FORMAT_FLOAT;
colour->input_bands = 3;
colour->bands = 3;
code->input_coding = VIPS_CODING_NONE;
/* The default. This can get changed above ^^ if we see a
* 16-bit input.
*/
code->input_format = VIPS_FORMAT_UCHAR;
}
/**
@ -180,9 +256,13 @@ vips_sRGB2scRGB_init( VipssRGB2scRGB *sRGB2scRGB )
* @out: output image
* @...: %NULL-terminated list of optional named arguments
*
* Convert an sRGB image to scRGB.
* Convert an sRGB image to scRGB. The input image can be 8 or 16-bit
* unsigned int.
*
* See also: vips_scRGB2XYZ(), vips_rad2float().
* If the input image is unsigned 16-bit, any extra channels after RGB are
* divided by 256. Thus, scRGB alpha is always 0 - 255.99.
*
* See also: vips_scRGB2XYZ(), vips_scRGB2sRGB(), vips_rad2float().
*
* Returns: 0 on success, -1 on error.
*/

View File

@ -25,6 +25,8 @@
* - added 16-bit option
* 11/12/12
* - cut about to make scRGB2sRGB.c
* 12/2/15
* - add 16-bit alpha handling
*/
/*
@ -66,22 +68,29 @@
#include "pcolour.h"
/* We can't use VipsColourCode as our parent class. We want to handle
* alpha ourselves so we can get 16 -> 8 bit conversion right.
*/
typedef struct _VipsscRGB2sRGB {
VipsColourCode parent_instance;
VipsOperation parent_instance;
VipsImage *in;
VipsImage *out;
int depth;
} VipsscRGB2sRGB;
typedef VipsColourCodeClass VipsscRGB2sRGBClass;
typedef VipsOperationClass VipsscRGB2sRGBClass;
G_DEFINE_TYPE( VipsscRGB2sRGB, vips_scRGB2sRGB, VIPS_TYPE_COLOUR_CODE );
G_DEFINE_TYPE( VipsscRGB2sRGB, vips_scRGB2sRGB, VIPS_TYPE_OPERATION );
/* Process a buffer of data.
*/
static void
vips_scRGB2sRGB_line_8( VipsPel * restrict q, float * restrict p, int width )
vips_scRGB2sRGB_line_8( VipsPel * restrict q, float * restrict p,
int extra_bands, int width )
{
int i;
int i, j;
for( i = 0; i < width; i++ ) {
float R = p[0];
@ -100,14 +109,19 @@ vips_scRGB2sRGB_line_8( VipsPel * restrict q, float * restrict p, int width )
q[2] = b;
q += 3;
for( j = 0; j < extra_bands; j++ )
q[j] = p[j];
p += extra_bands;
q += extra_bands;
}
}
static void
vips_scRGB2sRGB_line_16( unsigned short * restrict q, float * restrict p,
int width )
int extra_bands, int width )
{
int i;
int i, j;
for( i = 0; i < width; i++ ) {
float R = p[0];
@ -126,21 +140,47 @@ vips_scRGB2sRGB_line_16( unsigned short * restrict q, float * restrict p,
q[2] = b;
q += 3;
for( j = 0; j < extra_bands; j++ )
q[j] = VIPS_CLIP( 0, p[j] * 256.0, USHRT_MAX );
p += extra_bands;
q += extra_bands;
}
}
static void
vips_scRGB2sRGB_line( VipsColour *colour,
VipsPel *out, VipsPel **in, int width )
static int
vips_scRGB2sRGB_gen( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) colour;
VipsRegion *ir = (VipsRegion *) seq;
VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) b;
VipsRect *r = &or->valid;
VipsImage *in = ir->im;
if( scRGB2sRGB->depth == 16 )
vips_scRGB2sRGB_line_16( (unsigned short *) out,
(float *) in[0], width );
else
vips_scRGB2sRGB_line_8( (VipsPel *) out,
(float *) in[0], width );
int y;
if( vips_region_prepare( ir, r ) )
return( -1 );
VIPS_GATE_START( "vips_scRGB2sRGB_gen: work" );
for( y = 0; y < r->height; y++ ) {
float *p = (float *)
VIPS_REGION_ADDR( ir, r->left, r->top + y );
VipsPel *q = (VipsPel *)
VIPS_REGION_ADDR( or, r->left, r->top + y );
if( scRGB2sRGB->depth == 16 )
vips_scRGB2sRGB_line_16( (unsigned short *) q, p,
in->Bands - 3, r->width );
else
vips_scRGB2sRGB_line_8( q, p,
in->Bands - 3, r->width );
}
VIPS_GATE_STOP( "vips_scRGB2sRGB_gen: work" );
return( 0 );
}
static int
@ -148,17 +188,30 @@ vips_scRGB2sRGB_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsscRGB2sRGB *scRGB2sRGB = (VipsscRGB2sRGB *) object;
VipsColour *colour = VIPS_COLOUR( scRGB2sRGB );
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
VipsImage *in;
VipsBandFormat format;
VipsInterpretation interpretation;
VipsImage *out;
if( VIPS_OBJECT_CLASS( vips_scRGB2sRGB_parent_class )->build( object ) )
return( -1 );
in = scRGB2sRGB->in;
if( vips_check_bands_atleast( class->nickname, in, 3 ) )
return( -1 );
switch( scRGB2sRGB->depth ) {
case 16:
colour->interpretation = VIPS_INTERPRETATION_RGB16;
colour->format = VIPS_FORMAT_USHORT;
interpretation = VIPS_INTERPRETATION_RGB16;
format = VIPS_FORMAT_USHORT;
break;
case 8:
colour->interpretation = VIPS_INTERPRETATION_sRGB;
colour->format = VIPS_FORMAT_UCHAR;
interpretation = VIPS_INTERPRETATION_sRGB;
format = VIPS_FORMAT_UCHAR;
break;
default:
@ -167,8 +220,27 @@ vips_scRGB2sRGB_build( VipsObject *object )
return( -1 );
}
if( VIPS_OBJECT_CLASS( vips_scRGB2sRGB_parent_class )->build( object ) )
if( vips_cast_float( in, &t[0], NULL ) )
return( -1 );
in = t[0];
out = vips_image_new();
if( vips_image_pipelinev( out,
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) {
g_object_unref( out );
return( -1 );
}
out->Type = interpretation;
out->BandFmt = format;
if( vips_image_generate( out,
vips_start_one, vips_scRGB2sRGB_gen, vips_stop_one,
in, scRGB2sRGB ) ) {
g_object_unref( out );
return( -1 );
}
g_object_set( object, "out", out, NULL );
return( 0 );
}
@ -178,7 +250,7 @@ vips_scRGB2sRGB_class_init( VipsscRGB2sRGBClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsColourClass *colour_class = VIPS_COLOUR_CLASS( class );
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -187,7 +259,19 @@ vips_scRGB2sRGB_class_init( VipsscRGB2sRGBClass *class )
object_class->description = _( "convert an scRGB image to sRGB" );
object_class->build = vips_scRGB2sRGB_build;
colour_class->process_line = vips_scRGB2sRGB_line;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL_UNBUFFERED;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsscRGB2sRGB, in ) );
VIPS_ARG_IMAGE( class, "out", 100,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsscRGB2sRGB, out ) );
VIPS_ARG_INT( class, "depth", 130,
_( "Depth" ),
@ -195,25 +279,12 @@ vips_scRGB2sRGB_class_init( VipsscRGB2sRGBClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsscRGB2sRGB, depth ),
8, 16, 8 );
}
static void
vips_scRGB2sRGB_init( VipsscRGB2sRGB *scRGB2sRGB )
{
VipsColour *colour = VIPS_COLOUR( scRGB2sRGB );
VipsColourCode *code = VIPS_COLOUR_CODE( scRGB2sRGB );
/* Just the default, can be overridden, see above.
*/
colour->coding = VIPS_CODING_NONE;
colour->interpretation = VIPS_INTERPRETATION_sRGB;
colour->format = VIPS_FORMAT_UCHAR;
colour->input_bands = 3;
colour->bands = 3;
code->input_coding = VIPS_CODING_NONE;
code->input_format = VIPS_FORMAT_FLOAT;
scRGB2sRGB->depth = 8;
}
@ -229,7 +300,10 @@ vips_scRGB2sRGB_init( VipsscRGB2sRGB *scRGB2sRGB )
*
* Convert an scRGB image to sRGB. Set @depth to 16 to get 16-bit output.
*
* See also: vips_LabS2LabQ(), vips_scRGB2sRGB(), vips_rad2float().
* If @depth is 16, any extra channels after RGB are
* multiplied by 256.
*
* See also: vips_LabS2LabQ(), vips_sRGB2scRGB(), vips_rad2float().
*
* Returns: 0 on success, -1 on error.
*/

View File

@ -908,6 +908,26 @@ class Image(Vips.Image):
"""size x size median filter."""
return self.rank(size, size, (size * size) / 2)
def fliphor(self):
"""Flip horizontally."""
return self.flip(Vips.Direction.HORIZONTAL)
def flipver(self):
"""Flip vertically."""
return self.flip(Vips.Direction.VERTICAL)
def rot90(self):
"""Rotate 90 degrees clockwise."""
return self.rot(Vips.Angle.D90)
def rot180(self):
"""Rotate 180 degrees."""
return self.rot(Vips.Angle.D180)
def rot270(self):
"""Rotate 270 degrees clockwise."""
return self.rot(Vips.Angle.D270)
# we need different imageize rules for this operator ... we need to
# imageize th and el to match each other first
@add_doc(generate_docstring("ifthenelse"))

View File

@ -31,12 +31,13 @@ colour_colourspaces = [Vips.Interpretation.XYZ,
Vips.Interpretation.LABS,
Vips.Interpretation.SCRGB,
Vips.Interpretation.SRGB,
Vips.Interpretation.RGB16,
Vips.Interpretation.YXY]
coded_colourspaces = [Vips.Interpretation.LABQ]
mono_colourspaces = [Vips.Interpretation.GREY16,
Vips.Interpretation.B_W]
all_colourspaces = colour_colourspaces + mono_colourspaces + coded_colourspaces
mono_colourspaces = [Vips.Interpretation.B_W]
sixteenbit_colourspaces = [Vips.Interpretation.GREY16,
Vips.Interpretation.RGB16]
all_colourspaces = colour_colourspaces + mono_colourspaces + \
coded_colourspaces + sixteenbit_colourspaces
# an expanding zip ... if either of the args is not a list, duplicate it down
# the other
@ -119,9 +120,20 @@ class TestColour(unittest.TestCase):
for col in colour_colourspaces + [Vips.Interpretation.LAB]:
im = im.colourspace(col)
self.assertEqual(im.interpretation, col)
for i in range(0, 4):
l = im.extract_band(i).min()
h = im.extract_band(i).max()
self.assertAlmostEqual(l, h)
pixel = im.getpoint(10, 10)
self.assertAlmostEqual(pixel[3], 42, places = 2)
# alpha won't be equal for RGB16, but it should be preserved if we go
# there and back
im = im.colourspace(Vips.Interpretation.RGB16)
im = im.colourspace(Vips.Interpretation.LAB)
before = test.getpoint(10, 10)
after = im.getpoint(10, 10)
self.assertAlmostEqualObjects(before, after, places = 1)