im_msb() -> class

and some cleanups

add a --band option
This commit is contained in:
John Cupitt 2013-06-03 10:26:09 +01:00
parent 738fe3aeaf
commit 27b7332a60
13 changed files with 351 additions and 242 deletions

View File

@ -4,7 +4,8 @@
it's cheap so caching doesn't help anyway
- auto rshift down to 8 bits on save, if necessary
- im_gaussnoise(), im_copy_file(), im_grid(), im_scale(), im_scaleps(),
im_wrap(), im_rotquad(), im_zoom(), im_subsample() redone as classes
im_wrap(), im_rotquad(), im_zoom(), im_subsample(), im_msb()
redone as classes
- add --angle option to dzsave
14/5/13 started 7.32.4

1
TODO
View File

@ -1,3 +1,4 @@
- can we get rid of the extra copy in vips_scale() etc.
- look at

View File

@ -27,7 +27,7 @@ libconversion_la_SOURCES = \
ifthenelse.c \
conver_dispatch.c \
im_falsecolour.c \
im_msb.c \
msb.c \
grid.c \
scale.c \
wrap.c \

View File

@ -182,10 +182,9 @@ vips_bandary_class_init( VipsBandaryClass *class )
}
static void
vips_bandary_init( VipsBandary *bandjoin )
vips_bandary_init( VipsBandary *bandary )
{
/* Init our instance fields.
*/
bandary->out_bands = -1;
}
/* Call this before chaining up in _build() to make the operation fall back to

View File

@ -67,10 +67,6 @@ vips_bandbool_build( VipsObject *object )
VipsBandary *bandary = (VipsBandary *) object;
VipsBandbool *bandbool = (VipsBandbool *) object;
if( bandbool->in &&
vips_check_noncomplex( class->nickname, bandbool->in ) )
return( -1 );
/* << and >> don't work over bands.
*/
if( bandbool->operation == VIPS_OPERATION_BOOLEAN_LSHIFT ||
@ -82,9 +78,13 @@ vips_bandbool_build( VipsObject *object )
return( -1 );
}
if( bandbool->in &&
bandbool->in->Bands == 1 )
return( vips_bandary_copy( bandary ) );
if( bandbool->in ) {
if( vips_check_noncomplex( class->nickname, bandbool->in ) )
return( -1 );
if( bandbool->in->Bands == 1 )
return( vips_bandary_copy( bandary ) );
}
bandary->out_bands = 1;
bandary->n = 1;

View File

@ -332,7 +332,7 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b,
VipsRect *r = &or->valid;
int le = r->left;
int to = r->top;
int bo = VIPS_RECT_BOTTOM(r);
int bo = VIPS_RECT_BOTTOM( r );
int sz = VIPS_REGION_N_ELEMENTS( or );
int x, y;

View File

@ -131,6 +131,7 @@ vips_conversion_operation_init( void )
extern GType vips_wrap_get_type( void );
extern GType vips_zoom_get_type( void );
extern GType vips_subsample_get_type( void );
extern GType vips_msb_get_type( void );
vips_copy_get_type();
vips_tile_cache_get_type();
@ -159,6 +160,7 @@ vips_conversion_operation_init( void )
vips_wrap_get_type();
vips_zoom_get_type();
vips_subsample_get_type();
vips_msb_get_type();
}
/* The common part of most binary conversion

View File

@ -1,225 +0,0 @@
/* im_msb
*
* Copyright: 2006, The Nottingham Trent University
*
* Author: Tom Vajzovic
*
* Written on: 2006-03-13
* 27/9/06
* - removed extra im_free() in im_copy() fallback
* 4/10/06
* - removed warning on uchar fallback: it happens a lot with nip2 and
* isn't very serious
* 1/2/10
* - revised, cleanups
* - gtkdoc
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/** HEADERS **/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H */
#include <vips/intl.h>
#include <vips/vips.h>
typedef struct _Msb {
size_t index;
size_t width;
size_t repeat;
} Msb;
static void
byte_select( unsigned char *in, unsigned char *out, int n, Msb *msb )
{
unsigned char *stop = out + n * msb->repeat;
for( in += msb->index; out < stop; in += msb->width, ++out )
*out = *in;
}
static void
byte_select_flip( unsigned char *in, unsigned char *out, int n, Msb *msb )
{
unsigned char *stop = out + n * msb->repeat;
for( in += msb->index; out < stop; in += msb->width, ++out )
*out = 0x80 ^ *in;
}
static void
msb_labq( unsigned char *in, unsigned char *out, int n )
{
unsigned char *stop = in + (n << 2);
for( ; in < stop; in += 4, out += 3 ) {
out[0] = in[0];
out[1] = 0x80 ^ in[1];
out[2] = 0x80 ^ in[2];
}
}
/**
* im_msb:
* @in: input image
* @out: output image
*
* Turn any integer image to 8-bit unsigned char by discarding all but the most
* significant byte.
* Signed values are converted to unsigned by adding 128.
*
* This operator also works for LABQ coding.
*
* See also: im_msb_band().
*
* Returns: 0 on success, -1 on error
*/
int
im_msb( IMAGE *in, IMAGE *out )
{
Msb *msb;
im_wrapone_fn func;
if( in->Coding == IM_CODING_NONE &&
in->BandFmt == IM_BANDFMT_UCHAR )
return( im_copy( in, out ) );
if( im_piocheck( in, out ) ||
!(msb = IM_NEW( out, Msb )) )
return( -1 );
if( in->Coding == IM_CODING_NONE ) {
if( im_check_int( "im_msb", in ) )
return( -1 );
msb->width = IM_IMAGE_SIZEOF_ELEMENT( in );
msb->index = im_amiMSBfirst() ? 0 : msb->width - 1;
msb->repeat = in->Bands;
if( vips_bandfmt_isuint( in->BandFmt ) )
func = (im_wrapone_fn) byte_select;
else
func = (im_wrapone_fn) byte_select_flip;
}
else if( IM_CODING_LABQ == in->Coding )
func = (im_wrapone_fn) msb_labq;
else {
im_error( "im_msb", "%s", _( "unknown coding" ) );
return( -1 );
}
if( im_cp_desc( out, in ) )
return( -1 );
out->BandFmt = IM_BANDFMT_UCHAR;
out->Coding = IM_CODING_NONE;
return( im_wrapone( in, out, func, msb, NULL ) );
}
/**
* im_msb_band:
* @in: input image
* @out: output image
* @band: select this band
*
* Turn any integer image to a single-band 8-bit unsigned char by discarding
* all but the most significant byte from the selected band.
* Signed values are converted to unsigned by adding 128.
*
* This operator also works for LABQ coding.
*
* See also: im_msb_band().
*
* Returns: 0 on success, -1 on error
*/
int
im_msb_band( IMAGE *in, IMAGE *out, int band )
{
Msb *msb;
im_wrapone_fn func;
if( band < 0 ) {
im_error( "im_msb_band", "%s", _( "bad arguments" ) );
return( -1 );
}
if( im_piocheck( in, out ) ||
!(msb = IM_NEW( out, Msb )) )
return( -1 );
if( in->Coding == IM_CODING_NONE ) {
if( im_check_int( "im_msb_band", in ) )
return( -1 );
if( band >= in->Bands ) {
im_error( "im_msb_band", "%s",
_( "image does not have that many bands" ) );
return( -1 );
}
msb->width = IM_IMAGE_SIZEOF_ELEMENT( in );
msb->index = im_amiMSBfirst() ?
msb->width * band : msb->width * (band + 1) - 1;
msb->repeat = 1;
if( vips_bandfmt_isuint( in->BandFmt ) )
func = (im_wrapone_fn) byte_select;
else
func = (im_wrapone_fn) byte_select_flip;
}
else if( IM_CODING_LABQ == in->Coding ) {
if( band > 2 ) {
im_error( "im_msb_band", "%s",
_( "image does not have that many bands" ) );
return( -1 );
}
msb->width = 4;
msb->repeat = 1;
msb->index = band;
if( band )
func = (im_wrapone_fn) byte_select_flip;
else
func = (im_wrapone_fn) byte_select;
}
else {
im_error( "im_msb", "%s", _( "unknown coding" ) );
return( -1 );
}
if( im_cp_desc( out, in ) )
return( -1 );
out->BandFmt = IM_BANDFMT_UCHAR;
out->Coding = IM_CODING_NONE;
out->Bands = 1;
return( im_wrapone( in, out, func, msb, NULL ) );
}

298
libvips/conversion/msb.c Normal file
View File

@ -0,0 +1,298 @@
/* im_msb
*
* Copyright: 2006, The Nottingham Trent University
*
* Author: Tom Vajzovic
*
* Written on: 2006-03-13
* 27/9/06
* - removed extra im_free() in im_copy() fallback
* 4/10/06
* - removed warning on uchar fallback: it happens a lot with nip2 and
* isn't very serious
* 1/2/10
* - revised, cleanups
* - gtkdoc
* 30/5/13
* - rewrite as a class
* - add --band option, remove im_msb_band()
*/
/*
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., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H */
#include <vips/intl.h>
#include <vips/vips.h>
#include "conversion.h"
#include "bandary.h"
typedef struct _VipsMsb {
VipsConversion parent_instance;
/* Params.
*/
VipsImage *in;
int band;
/* Initial input offset.
*/
int offset;
/* Input step.
*/
int instep;
/* Need to convert signed to unsgned.
*/
gboolean sign;
} VipsMsb;
typedef VipsConversionClass VipsMsbClass;
G_DEFINE_TYPE( VipsMsb, vips_msb, VIPS_TYPE_CONVERSION );
static int
vips_msb_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
{
VipsRegion *ir = (VipsRegion *) seq;
VipsMsb *msb = (VipsMsb *) b;
VipsConversion *conversion = (VipsConversion *) msb;
VipsRect *r = &or->valid;
int le = r->left;
int to = r->top;
int bo = VIPS_RECT_BOTTOM( r );
int sz = r->width * conversion->out->Bands;
int x, y, i;
if( vips_region_prepare( ir, r ) )
return( -1 );
for( y = to; y < bo; y++ ) {
VipsPel *p = VIPS_REGION_ADDR( ir, le, y );
VipsPel *q = VIPS_REGION_ADDR( or, le, y );
if( msb->in->Coding == VIPS_CODING_LABQ &&
msb->band == -1 ) {
/* LABQ, no sub-band select.
*/
for( x = 0; x < r->width; x++ ) {
q[0] = p[0];
q[1] = 0x80 ^ p[1];
q[2] = 0x80 ^ p[2];
q += 4;
p += 3;
}
}
else if( msb->sign ) {
/* Copy, converting signed to unsigned.
*/
p += msb->offset;
for( i = 0; i < sz; i++ ) {
q[i] = 0x80 ^ *p;
p += msb->instep;
}
}
else {
/* Just pick out bytes.
*/
p += msb->offset;
for( i = 0; i < sz; i++ ) {
q[i] = *p;
p += msb->instep;
}
}
}
return( 0 );
}
static int
vips_msb_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsConversion *conversion = (VipsConversion *) object;
VipsMsb *msb = (VipsMsb *) object;
int vbands;
if( VIPS_OBJECT_CLASS( vips_msb_parent_class )->build( object ) )
return( -1 );
if( vips_check_coding_noneorlabq( class->nickname, msb->in ) ||
vips_check_int( class->nickname, msb->in ) )
return( -1 );
/* Effective number of bands this image has.
*/
vbands = msb->in->Coding == VIPS_CODING_LABQ ?
3 : msb->in->Bands;
if( msb->band > vbands - 1 ) {
vips_error( class->nickname, "%s", _( "bad band" ) );
return( -1 );
}
/* Step to next input element.
*/
msb->instep = VIPS_IMAGE_SIZEOF_ELEMENT( msb->in );
/* Offset into first band element of high order byte.
*/
msb->offset = vips_amiMSBfirst() ?
0 : VIPS_IMAGE_SIZEOF_ELEMENT( msb->in ) - 1;
/* If we're picking out a band, they need scaling up.
*/
if( msb->band != -1 ) {
msb->offset += VIPS_IMAGE_SIZEOF_ELEMENT( msb->in ) *
msb->band;
msb->instep *= msb->in->Bands;
}
/* May need to flip sign if we're picking out a band from labq.
*/
if( msb->in->Coding == VIPS_CODING_LABQ &&
msb->band > 0 )
msb->sign = TRUE;
if( msb->in->Coding == VIPS_CODING_NONE &&
!vips_bandfmt_isuint( msb->in->BandFmt ) )
msb->sign = TRUE;
if( msb->band == -1 &&
msb->in->BandFmt == VIPS_FORMAT_UCHAR )
return( vips_image_write( msb->in, conversion->out ) );
if( msb->band == 0 &&
msb->in->Bands == 1 &&
msb->in->BandFmt == VIPS_FORMAT_UCHAR )
return( vips_image_write( msb->in, conversion->out ) );
if( vips_image_copy_fields( conversion->out, msb->in ) )
return( -1 );
vips_demand_hint( conversion->out,
VIPS_DEMAND_STYLE_THINSTRIP, msb->in, NULL );
if( msb->band != -1 )
conversion->out->Bands = 1;
else
conversion->out->Bands = vbands;
conversion->out->BandFmt = VIPS_FORMAT_UCHAR;
conversion->out->Coding = VIPS_CODING_NONE;
if( conversion->out->Bands == 1 )
conversion->out->Type = VIPS_INTERPRETATION_B_W;
else
conversion->out->Type = VIPS_INTERPRETATION_MULTIBAND;
if( vips_image_generate( conversion->out,
vips_start_one, vips_msb_gen, vips_stop_one, msb->in, msb ) )
return( -1 );
return( 0 );
}
static void
vips_msb_class_init( VipsMsbClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *vobject_class = VIPS_OBJECT_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;
vobject_class->nickname = "msb";
vobject_class->description =
_( "pick most-significant byte from an image" );
vobject_class->build = vips_msb_build;
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
VIPS_ARG_IMAGE( class, "in", 0,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsMsb, in ) );
VIPS_ARG_INT( class, "band", 3,
_( "Band" ),
_( "Band to msb" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsMsb, band ),
0, 100000000, 0 );
}
static void
vips_msb_init( VipsMsb *msb )
{
msb->band = -1;
}
/**
* vips_msb:
* @in: input image
* @out: output image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @band: msb just this band
*
* Turn any integer image to 8-bit unsigned char by discarding all but the most
* significant byte. Signed values are converted to unsigned by adding 128.
*
* Use @band to make a one-band 8-bit image.
*
* This operator also works for LABQ coding.
*
* See also: vips_scale(), vips_cast().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_msb( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "msb", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -1527,6 +1527,38 @@ im_scale( VipsImage *in, VipsImage *out )
return( 0 );
}
int
im_msb( VipsImage *in, VipsImage *out )
{
VipsImage *t;
if( vips_msb( in, &t, NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int
im_msb_band( VipsImage *in, VipsImage *out, int band )
{
VipsImage *t;
if( vips_msb( in, &t, "band", band, NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {
g_object_unref( t );
return( -1 );
}
g_object_unref( t );
return( 0 );
}
int
im_wrap( IMAGE *in, IMAGE *out, int x, int y )
{

View File

@ -223,6 +223,8 @@ int vips_cast_dpcomplex( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_scale( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_msb( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_bandjoin( VipsImage **in, VipsImage **out, int n, ... )
__attribute__((sentinel));
@ -261,9 +263,6 @@ int vips_flatten( VipsImage *in, VipsImage **out, ... )
int im_msb( VipsImage *in, VipsImage *out );
int im_msb_band( VipsImage *in, VipsImage *out, int band );
int im_falsecolour( VipsImage *in, VipsImage *out );
int im_text( VipsImage *out, const char *text, const char *font,

View File

@ -715,6 +715,8 @@ int im_gaussnoise( VipsImage *out, int x, int y, double mean, double sigma );
int im_grid( VipsImage *in, VipsImage *out, int tile_height, int across, int down );
int im_scale( VipsImage *in, VipsImage *out );
int im_scaleps( VipsImage *in, VipsImage *out );
int im_msb( VipsImage *in, VipsImage *out );
int im_msb_band( VipsImage *in, VipsImage *out, int band );
int im_zoom( VipsImage *in, VipsImage *out, int xfac, int yfac );
int im_subsample( VipsImage *in, VipsImage *out, int xshrink, int yshrink );

View File

@ -65,7 +65,7 @@ libvips/conversion/subsample.c
libvips/conversion/grid.c
libvips/conversion/extract.c
libvips/conversion/bandjoin.c
libvips/conversion/im_msb.c
libvips/conversion/msb.c
libvips/conversion/black.c
libvips/conversion/bandbool.c
libvips/conversion/copy.c