| /* @(#) Decrease the size of an image by a power-of-two factor, summing the |
| * @(#) values of pixels, and shifting to give output of the specified band |
| * @(#) format. |
| * @(#) |
| * @(#) int |
| * @(#) im_rightshift_size( |
| * @(#) IMAGE *in, |
| * @(#) IMAGE *out, |
| * @(#) int xshift, |
| * @(#) int yshift, |
| * @(#) int band_fmt |
| * @(#) ); |
| * @(#) |
| * |
| * Copyright: 2006, Tom Vajzovic |
| * |
| * Author: Tom Vajzovic |
| * |
| * Written on: 2006-07-26 |
| * |
| * 2006-12-17 tcv: |
| * - rewrite generator function macros to produce many smaller functions |
| * - remove post-shift-up functionality |
| * 2007-02-02 jc |
| * - added return 0; on success |
| * - FUNCTION_NAME updated |
| */ |
| |
| /* |
| |
| 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <stdlib.h> |
| #include <string.h> |
| |
| #include <vips/vips.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC */ |
| |
| |
| /** LOCAL FUNCTION DECLARATIONS **/ |
| |
| /* function prototype macro */ |
| #define GEN_FUNC( SHIFT_MACRO, FROM_T, TO_T, SUM_T ) \ |
| static int gen_ ## SHIFT_MACRO ## _ ## FROM_T ## _to_ ## TO_T ## _with_ ## SUM_T( \ |
| REGION *to_make, void *seq, void *a, void *b ); |
| |
| /* macros to call function prototype macro for all possible combinations of types and macros */ |
| #define GEN_FUNCS_TO( SIGN, FROM_T, TO_T ) \ |
| GEN_FUNC( PRE_POST_SHIFT, FROM_T, TO_T, SIGN ## 64 ) \ |
| GEN_FUNC( POST_SHIFT, FROM_T, TO_T, SIGN ## 64 ) \ |
| GEN_FUNC( POST_SHIFT, FROM_T, TO_T, SIGN ## 32 ) \ |
| GEN_FUNC( NO_SHIFT, FROM_T, TO_T, SIGN ## 32 ) |
| |
| #define GEN_FUNCS_FROM( SIGN, FROM_T ) \ |
| GEN_FUNCS_TO( SIGN, FROM_T, SIGN ## 32 ) \ |
| GEN_FUNCS_TO( SIGN, FROM_T, SIGN ## 16 ) \ |
| GEN_FUNCS_TO( SIGN, FROM_T, SIGN ## 8 ) |
| |
| #define GEN_FUNCS_SIGN( SIGN ) \ |
| GEN_FUNCS_FROM( SIGN, SIGN ## 32 ) \ |
| GEN_FUNCS_FROM( SIGN, SIGN ## 16 ) \ |
| GEN_FUNCS_FROM( SIGN, SIGN ## 8 ) |
| |
| GEN_FUNCS_SIGN( gint ) |
| GEN_FUNCS_SIGN( guint ) |
| |
| |
| /** FUNCTION DEFINITIONS **/ |
| |
| int |
| im_rightshift_size( IMAGE *in, IMAGE *out, int xshift, int yshift, int band_fmt ){ |
| #define FUNCTION_NAME "im_rightshift_size" |
| int *params; |
| int needbits; |
| int outbits; |
| |
| if( im_piocheck( in, out ) ) |
| return -1; |
| |
| if( xshift < 0 || yshift < 0 ){ |
| im_error( FUNCTION_NAME, "%s", _( "bad arguments" ) ); |
| return -1; |
| } |
| if( ! xshift && ! yshift ){ |
| im_warn( FUNCTION_NAME, "%s", _( "shift by zero: falling back to im_copy" ) ); |
| return im_copy( in, out ); |
| } |
| if( ! in-> Xsize >> xshift || ! in-> Ysize >> yshift ){ |
| im_error( FUNCTION_NAME, "%s", _( "would result in zero size output image" ) ); |
| return -1; |
| } |
| if( ! vips_bandfmt_isint( in->BandFmt ) ){ |
| im_error( FUNCTION_NAME, "%s", _( "integer type images only" ) ); |
| return -1; |
| } |
| if( IM_CODING_NONE != in->Coding ){ |
| im_error( FUNCTION_NAME, "%s", _( "uncoded images only" ) ); |
| return -1; |
| } |
| if( vips_bandfmt_isuint( in->BandFmt ) ){ |
| if( IM_BANDFMT_UCHAR != band_fmt && IM_BANDFMT_USHORT != band_fmt && IM_BANDFMT_UINT != band_fmt ){ |
| im_error( FUNCTION_NAME, "%s", _( "unsigned input means that output must be unsigned int, short or char" ) ); |
| return -1; |
| } |
| } |
| else { |
| if( IM_BANDFMT_CHAR != band_fmt && IM_BANDFMT_SHORT != band_fmt && IM_BANDFMT_INT != band_fmt ){ |
| im_error( FUNCTION_NAME, "%s", _( "signed input means that output must be signed int, short or char" ) ); |
| return -1; |
| } |
| } |
| outbits= im_bits_of_fmt( band_fmt ); |
| |
| if( -1 == outbits ) |
| return -1; |
| |
| needbits= im_bits_of_fmt( in-> BandFmt ) + xshift + yshift; |
| |
| params= IM_ARRAY( out, 4, int ); |
| |
| if( ! params ) |
| return -1; |
| |
| params[ 0 ]= xshift; /* xshift */ |
| params[ 1 ]= yshift; /* yshift */ |
| |
| if( im_cp_desc( out, in ) ) |
| return -1; |
| |
| out-> Xsize >>= xshift; |
| out-> Ysize >>= yshift; |
| out-> Xres/= ( 1 << xshift ); /* x scale */ |
| out-> Yres/= ( 1 << yshift ); /* y scale */ |
| out-> BandFmt= band_fmt; |
| |
| if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) ) |
| return -1; |
| |
| #define RETURN_MACRO( MACRO, FROM_T, TO_T, SUM_T ) \ |
| return im_generate( out, im_start_one, gen_ ## MACRO ## _ ## FROM_T ## _to_ ## TO_T ## _with_ ## SUM_T, im_stop_one, in, params ); |
| |
| #define RETURN_MACRO_OUTS( MACRO, SUM_SIZE, OUT_SIZE ) switch( in-> BandFmt ){ \ |
| \ |
| case IM_BANDFMT_CHAR: \ |
| RETURN_MACRO( MACRO, gint8, gint ## OUT_SIZE, gint ## SUM_SIZE ) \ |
| \ |
| case IM_BANDFMT_UCHAR: \ |
| RETURN_MACRO( MACRO, guint8, guint ## OUT_SIZE, guint ## SUM_SIZE ) \ |
| \ |
| case IM_BANDFMT_SHORT: \ |
| RETURN_MACRO( MACRO, gint16, gint ## OUT_SIZE, gint ## SUM_SIZE ) \ |
| \ |
| case IM_BANDFMT_USHORT: \ |
| RETURN_MACRO( MACRO, guint16, guint ## OUT_SIZE, guint ## SUM_SIZE ) \ |
| \ |
| case IM_BANDFMT_INT: \ |
| RETURN_MACRO( MACRO, gint32, gint ## OUT_SIZE, gint ## SUM_SIZE ) \ |
| \ |
| case IM_BANDFMT_UINT: \ |
| RETURN_MACRO( MACRO, guint32, guint ## OUT_SIZE, guint ## SUM_SIZE ) \ |
| default: \ |
| g_assert( 0 ); \ |
| } |
| |
| #define RETURN_MACRO_SUMSS( MACRO, SUM_SIZE ) switch( im_bits_of_fmt( out->BandFmt ) ){ \ |
| case 32: \ |
| RETURN_MACRO_OUTS( MACRO, SUM_SIZE, 32 ) \ |
| case 16: \ |
| RETURN_MACRO_OUTS( MACRO, SUM_SIZE, 16 ) \ |
| case 8: \ |
| RETURN_MACRO_OUTS( MACRO, SUM_SIZE, 8 ) \ |
| } |
| |
| if( needbits > 64 ){ |
| params[ 2 ]= needbits - 64; |
| params[ 3 ]= 64 - outbits; |
| RETURN_MACRO_SUMSS( PRE_POST_SHIFT, 64 ) |
| } |
| if( needbits > 32 ){ |
| params[ 3 ]= needbits - outbits; |
| RETURN_MACRO_SUMSS( POST_SHIFT, 64 ) |
| } |
| if( needbits > outbits ){ |
| params[ 3 ]= needbits - outbits; |
| RETURN_MACRO_SUMSS( POST_SHIFT, 32 ) |
| } |
| |
| RETURN_MACRO_SUMSS( NO_SHIFT, 32 ) |
| |
| return 0; |
| |
| #undef FUNCTION_NAME |
| } |
| |
| /** LOCAL FUNCTION DEFINITIONS **/ |
| |
| /* macros used in the function creating macro */ |
| #define PRE_POST_SHIFT() pixel+= from[ fx ] >> preshift; \ |
| to[ tx ]= pixel >> postshift; |
| |
| #define POST_SHIFT() pixel+= from[ fx ]; \ |
| to[ tx ]= pixel >> postshift; |
| |
| #define NO_SHIFT() pixel+= from[ fx ]; \ |
| to[ tx ]= pixel; |
| |
| /* function creating macro */ |
| #undef GEN_FUNC |
| #define GEN_FUNC( SHIFT_MACRO, FROM_T, TO_T, SUM_T ) \ |
| static int gen_ ## SHIFT_MACRO ## _ ## FROM_T ## _to_ ## TO_T ## _with_ ## SUM_T( \ |
| REGION *to_make, void *seq, void *a, void *b ){ \ |
| \ |
| REGION *make_from = (REGION *) seq; \ |
| int *params = (int *) b; \ |
| int xshift= params[0]; \ |
| int yshift= params[1]; \ |
| int G_GNUC_UNUSED preshift= params[2]; \ |
| int G_GNUC_UNUSED postshift= params[3]; \ |
| Rect need= { \ |
| to_make-> valid. left << xshift, \ |
| to_make-> valid. top << yshift, \ |
| to_make-> valid. width << xshift, \ |
| to_make-> valid. height << yshift \ |
| }; \ |
| TO_T *to_start= (TO_T*) IM_REGION_ADDR( to_make, to_make-> valid. left, to_make-> valid. top ); \ |
| TO_T *to, *ty_stop; \ |
| SUM_T pixel; \ |
| FROM_T *from_start, *from_row, *from, *fy_stop; \ |
| \ |
| int band, tx, fx; \ |
| int tx_max= to_make-> valid. width * to_make-> im-> Bands; \ |
| int fx_max= to_make-> im-> Bands << xshift; \ |
| \ |
| size_t t_skip= IM_REGION_LSKIP( to_make ) / sizeof( TO_T ); \ |
| size_t f_skip; \ |
| \ |
| if( im_prepare( make_from, &need ) || ! im_rect_includesrect( &make_from-> valid, &need ) ) \ |
| return -1; \ |
| \ |
| from_start= (FROM_T*) IM_REGION_ADDR( make_from, need. left, need. top ); \ |
| f_skip= IM_REGION_LSKIP( make_from ) / sizeof( FROM_T ); \ |
| \ |
| for( band= 0; band < make_from-> im-> Bands; ++band ){ \ |
| \ |
| to= to_start + band; \ |
| ty_stop= to + t_skip * to_make-> valid. height; \ |
| \ |
| from_row= from_start + band; \ |
| \ |
| for( ; to < ty_stop; to+= t_skip, from_row+= f_skip << yshift ) \ |
| for( tx= 0; tx < tx_max; tx+= to_make-> im-> Bands ){ \ |
| \ |
| from= from_row + ( tx << xshift ); \ |
| fy_stop= from + ( f_skip << yshift ); \ |
| \ |
| pixel= 0; \ |
| \ |
| for( ; from < fy_stop; from+= f_skip ) \ |
| for( fx= 0; fx < fx_max; fx+= to_make-> im-> Bands ) \ |
| SHIFT_MACRO() \ |
| } \ |
| } \ |
| return 0; \ |
| } |
| |
| /* create functions for all possible combinations of types and macros */ |
| GEN_FUNCS_SIGN( gint ) |
| GEN_FUNCS_SIGN( guint ) |