From 27b7332a60597fc1e4fab72f9478c1b926af3f75 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 3 Jun 2013 10:26:09 +0100 Subject: [PATCH] im_msb() -> class and some cleanups add a --band option --- ChangeLog | 3 +- TODO | 1 + libvips/conversion/Makefile.am | 2 +- libvips/conversion/bandary.c | 5 +- libvips/conversion/bandbool.c | 14 +- libvips/conversion/cast.c | 2 +- libvips/conversion/conversion.c | 2 + libvips/conversion/im_msb.c | 225 ---------------------- libvips/conversion/msb.c | 298 +++++++++++++++++++++++++++++ libvips/deprecated/vips7compat.c | 32 ++++ libvips/include/vips/conversion.h | 5 +- libvips/include/vips/vips7compat.h | 2 + po/POTFILES.in | 2 +- 13 files changed, 351 insertions(+), 242 deletions(-) delete mode 100644 libvips/conversion/im_msb.c create mode 100644 libvips/conversion/msb.c diff --git a/ChangeLog b/ChangeLog index 5c0da2a3..4621596e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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 diff --git a/TODO b/TODO index 9ece20c6..e482d706 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,4 @@ +- can we get rid of the extra copy in vips_scale() etc. - look at diff --git a/libvips/conversion/Makefile.am b/libvips/conversion/Makefile.am index 838f8104..83f6b9cb 100644 --- a/libvips/conversion/Makefile.am +++ b/libvips/conversion/Makefile.am @@ -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 \ diff --git a/libvips/conversion/bandary.c b/libvips/conversion/bandary.c index fba92bd7..bd9eb894 100644 --- a/libvips/conversion/bandary.c +++ b/libvips/conversion/bandary.c @@ -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 diff --git a/libvips/conversion/bandbool.c b/libvips/conversion/bandbool.c index a2b508f2..96cb3527 100644 --- a/libvips/conversion/bandbool.c +++ b/libvips/conversion/bandbool.c @@ -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; diff --git a/libvips/conversion/cast.c b/libvips/conversion/cast.c index b3086042..1828286d 100644 --- a/libvips/conversion/cast.c +++ b/libvips/conversion/cast.c @@ -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; diff --git a/libvips/conversion/conversion.c b/libvips/conversion/conversion.c index b3cf8128..9b86e5c2 100644 --- a/libvips/conversion/conversion.c +++ b/libvips/conversion/conversion.c @@ -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 diff --git a/libvips/conversion/im_msb.c b/libvips/conversion/im_msb.c deleted file mode 100644 index db0ec71a..00000000 --- a/libvips/conversion/im_msb.c +++ /dev/null @@ -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 -#endif /*HAVE_CONFIG_H */ -#include - -#include - -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 ) ); -} diff --git a/libvips/conversion/msb.c b/libvips/conversion/msb.c new file mode 100644 index 00000000..97a123e3 --- /dev/null +++ b/libvips/conversion/msb.c @@ -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 +#endif /*HAVE_CONFIG_H */ +#include + +#include + +#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 ); +} + diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index bf6ed317..07d2bcf2 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -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 ) { diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index 61afbc4a..4ab54c60 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -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, diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index b6354ef9..505aa4fc 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -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 ); diff --git a/po/POTFILES.in b/po/POTFILES.in index b3c09c75..a94e4b1c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -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