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:
parent
46c655caf0
commit
8f7c2c7110
@ -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
|
||||
|
27
Makefile.am
27
Makefile.am
@ -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
39
TODO
@ -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!
|
||||
|
||||
|
||||
|
||||
|
||||
|
15
configure.ac
15
configure.ac
@ -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
|
||||
|
@ -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>.
|
||||
|
@ -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 );
|
||||
|
@ -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 } },
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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"))
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user