/** * im_read_point: * @image: image to read from * @x: position to read * @y: position to read * @ink: read value here * * Reads a single point on an image. * * @ink is an array of bytes to contain a valid pixel for the image's format. * It must have at least IM_IMAGE_SIZEOF_PEL( @im ) bytes. * * See also: im_draw_point(). * * Returns: 0 on success, or -1 on error. */ int im_read_point( VipsImage *image, int x, int y, VipsPel *ink ) { REGION *reg; Rect area; if( im_check_coding_known( "im_draw_point", image ) || !(reg = im_region_create( image )) ) return( -1 ); area.left = x; area.top = y; area.width = 1; area.height = 1; if( im_prepare( reg, &area ) ) { im_region_free( reg ); return( -1 ); } memcpy( ink, IM_REGION_ADDR( reg, x, y ), IM_IMAGE_SIZEOF_PEL( image ) ); im_region_free( reg ); return( 0 ); }
/* Rotate a small piece. */ static int rot270_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; /* Output area. */ Rect *r = &or->valid; int le = r->left; int ri = IM_RECT_RIGHT(r); int to = r->top; int bo = IM_RECT_BOTTOM(r); int x, y, i; /* Pixel geometry. */ int ps, ls; /* Find the area of the input image we need. */ Rect need; need.left = in->Xsize - bo; need.top = le; need.width = r->height; need.height = r->width; if( im_prepare( ir, &need ) ) return( -1 ); /* Find PEL size and line skip for ir. */ ps = IM_IMAGE_SIZEOF_PEL( in ); ls = IM_REGION_LSKIP( ir ); /* Rotate the bit we now have. */ for( y = to; y < bo; y++ ) { /* Start of this output line. */ PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); /* Corresponding position in ir. */ PEL *p = (PEL *) IM_REGION_ADDR( ir, need.left + need.width - (y - to) - 1, need.top ); for( x = le; x < ri; x++ ) { for( i = 0; i < ps; i++ ) q[i] = p[i]; q += ps; p += ls; } } return( 0 ); }
/* The vector codepath. */ static int morph_vector_gen( REGION *or, void *vseq, void *a, void *b ) { MorphSequence *seq = (MorphSequence *) vseq; Morph *morph = (Morph *) b; INTMASK *mask = morph->mask; REGION *ir = seq->ir; Rect *r = &or->valid; int sz = IM_REGION_N_ELEMENTS( or ); Rect s; int y, j; VipsExecutor executor[MAX_PASS]; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += mask->xsize - 1; s.height += mask->ysize - 1; if( im_prepare( ir, &s ) ) return( -1 ); #ifdef DEBUG printf( "morph_vector_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top ); #endif /*DEBUG*/ for( j = 0; j < morph->n_pass; j++ ) vips_executor_set_program( &executor[j], morph->pass[j].vector, sz ); for( y = 0; y < r->height; y++ ) { for( j = 0; j < morph->n_pass; j++ ) { void *d; /* The last pass goes to the output image, * intermediate passes go to t2. */ if( j == morph->n_pass - 1 ) d = IM_REGION_ADDR( or, r->left, r->top + y ); else d = seq->t2; vips_executor_set_scanline( &executor[j], ir, r->left, r->top + y ); vips_executor_set_array( &executor[j], morph->pass[j].r, seq->t1 ); vips_executor_set_destination( &executor[j], d ); vips_executor_run( &executor[j] ); IM_SWAP( void *, seq->t1, seq->t2 ); } } return( 0 ); }
/* Fastcor generate function. */ static int fastcor_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *ref = (IMAGE *) b; Rect irect; Rect *r = &or->valid; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int ri = IM_RECT_RIGHT(r); int x, y, i, j; int lsk; /* What part of ir do we need? */ irect.left = or->valid.left; irect.top = or->valid.top; irect.width = or->valid.width + ref->Xsize - 1; irect.height = or->valid.height + ref->Ysize - 1; if( im_prepare( ir, &irect ) ) return( -1 ); lsk = IM_REGION_LSKIP( ir ); /* Loop over or. */ for( y = to; y < bo; y++ ) { PEL *a = (PEL *) IM_REGION_ADDR( ir, le, y ); unsigned int *q = (unsigned int *) IM_REGION_ADDR( or, le, y ); for( x = le; x < ri; x++ ) { int sum = 0; PEL *b = (PEL *) ref->data; PEL *a1 = a; for( j = 0; j < ref->Ysize; j++ ) { PEL *a2 = a1; for( i = 0; i < ref->Xsize; i++ ) { int t = *b++ - *a2++; sum += t * t; } a1 += lsk; } *q++ = sum; a += 1; } } return( 0 ); }
/* Flip a small area. */ static int flip_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; Rect *r = &or->valid; Rect in; char *p, *q; int x, y, z; int le = r->left; int ri = IM_RECT_RIGHT(r); int to = r->top; int bo = IM_RECT_BOTTOM(r); int ps = IM_IMAGE_SIZEOF_PEL( ir->im ); /* sizeof pel */ int hgt = ir->im->Xsize - r->width; int lastx; /* Transform to input coordinates. */ in = *r; in.left = hgt - r->left; /* Find x of final pixel in input area. */ lastx = IM_RECT_RIGHT( &in ) - 1; /* Ask for input we need. */ if( im_prepare( ir, &in ) ) return( -1 ); /* Loop, copying and reversing lines. */ for( y = to; y < bo; y++ ) { p = IM_REGION_ADDR( ir, lastx, y ); q = IM_REGION_ADDR( or, le, y ); for( x = le; x < ri; x++ ) { /* Copy the pel. */ for( z = 0; z < ps; z++ ) q[z] = p[z]; /* Skip forwards in out, back in in. */ q += ps; p -= ps; } } return( 0 ); }
/* Bandjoin generate function. */ static int bandjoin_gen( REGION *or, void *seq, void *a, void *b ) { REGION **ir = (REGION **) seq; Rect *r = &or->valid; int le = r->left; int ri = IM_RECT_RIGHT(r); int to = r->top; int bo = IM_RECT_BOTTOM(r); int x, y, z; int i1s = IM_IMAGE_SIZEOF_PEL( ir[0]->im ); int i2s = IM_IMAGE_SIZEOF_PEL( ir[1]->im ); /* Ask for input we need. */ if( im_prepare( ir[0], r ) ) return( -1 ); if( im_prepare( ir[1], r ) ) return( -1 ); /* Perform join. */ for( y = to; y < bo; y++ ) { PEL *i1 = (PEL *) IM_REGION_ADDR( ir[0], le, y ); PEL *i2 = (PEL *) IM_REGION_ADDR( ir[1], le, y ); PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); for( x = le; x < ri; x++ ) { /* Copy bytes from first file. */ for( z = 0; z < i1s; z++ ) *q++ = *i1++; /* Copy bytes from in2. */ for( z = 0; z < i2s; z++ ) *q++ = *i2++; } } return( 0 ); }
/* A ushort index image. */ static int hist_scan_ushort( REGION *reg, void *seq, void *a, void *b, gboolean *stop ) { Histogram *hist = (Histogram *) seq; Rect *r = ®->valid; IMAGE *value = hist->value; int bands = value->Bands; int width = r->width; int y, mx; /* Need the correspondiing area of the value image. */ if( im_prepare( hist->vreg, r ) ) return( -1 ); /* Accumulate! */ mx = hist->mx; for( y = 0; y < r->height; y++ ) { unsigned short *i = (unsigned short *) IM_REGION_ADDR( reg, r->left, r->top + y ); PEL *v = (PEL *) IM_REGION_ADDR( hist->vreg, r->left, r->top + y ); switch( value->BandFmt ) { case IM_BANDFMT_UCHAR: ACCUMULATE_USHORT( unsigned char ); break; case IM_BANDFMT_CHAR: ACCUMULATE_USHORT( signed char ); break; case IM_BANDFMT_USHORT: ACCUMULATE_USHORT( unsigned short ); break; case IM_BANDFMT_SHORT: ACCUMULATE_USHORT( signed short ); break; case IM_BANDFMT_UINT: ACCUMULATE_USHORT( unsigned int ); break; case IM_BANDFMT_INT: ACCUMULATE_USHORT( signed int ); break; case IM_BANDFMT_FLOAT: ACCUMULATE_USHORT( float ); break; case IM_BANDFMT_DOUBLE: ACCUMULATE_USHORT( double ); break; default: g_assert( 0 ); } } /* Note the maximum. */ hist->mx = mx; return( 0 ); }
/* Fastcor generate function. */ static int fastcor_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *ref = (IMAGE *) b; Rect irect; Rect *r = &or->valid; int x, y, i, j; int lsk; /* What part of ir do we need? */ irect.left = or->valid.left; irect.top = or->valid.top; irect.width = or->valid.width + ref->Xsize - 1; irect.height = or->valid.height + ref->Ysize - 1; if( im_prepare( ir, &irect ) ) return( -1 ); lsk = IM_REGION_LSKIP( ir ); /* Loop over or. */ for( y = 0; y < r->height; y++ ) { unsigned int *q = (unsigned int *) IM_REGION_ADDR( or, r->left, r->top + y ); for( x = 0; x < r->width; x++ ) { VipsPel *b = ref->data; VipsPel *a = IM_REGION_ADDR( ir, r->left + x, r->top + y ); int sum; sum = 0; for( j = 0; j < ref->Ysize; j++ ) { for( i = 0; i < ref->Xsize; i++ ) { int t = b[i] - a[i]; sum += t * t; } a += lsk; b += ref->Xsize; } q[x] = sum; } } return( 0 ); }
/* Fetch one pixel at a time ... good for very large shrinks. */ static int point_shrink_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; SubsampleInfo *st = (SubsampleInfo *) b; Rect *r = &or->valid; int le = r->left; int ri = IM_RECT_RIGHT( r ); int to = r->top; int bo = IM_RECT_BOTTOM(r); int ps = IM_IMAGE_SIZEOF_PEL( in ); Rect s; int x, y; int k; /* Loop down the region. */ for( y = to; y < bo; y++ ) { char *q = IM_REGION_ADDR( or, le, y ); char *p; /* Loop across the region, in owidth sized pieces. */ for( x = le; x < ri; x++ ) { /* Ask for input. */ s.left = x * st->xshrink; s.top = y * st->yshrink; s.width = 1; s.height = 1; if( im_prepare( ir, &s ) ) return( -1 ); /* Append new pels to output. */ p = IM_REGION_ADDR( ir, s.left, s.top ); for( k = 0; k < ps; k++ ) q[k] = p[k]; q += ps; } } return( 0 ); }
/* Zerox generate function. */ static int zerox_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; int flag = GPOINTER_TO_INT( b ); Rect irect; Rect *r = &or->valid; /* Range of pixels we loop over. */ int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM( r ); int ba = in->Bands; int ne = ba * r->width; int i, y; /* We need to be able to see one pixel to the right. */ irect.top = r->top; irect.left = r->left; irect.width = r->width + 1; irect.height = r->height; if( im_prepare( ir, &irect ) ) return( -1 ); for( y = to; y < bo; y++ ) { PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y ); PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); switch( in->BandFmt ) { case IM_BANDFMT_CHAR: LOOP( signed char ); break; case IM_BANDFMT_SHORT: LOOP( signed short ); break; case IM_BANDFMT_INT: LOOP( signed int ); break; case IM_BANDFMT_FLOAT: LOOP( float ); break; case IM_BANDFMT_DOUBLE: LOOP( double ); break; default: g_assert( 0 ); } } return( 0 ); }
/* Copy a small area. */ static int copy_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; Rect *r = &or->valid; /* Ask for input we need. */ if( im_prepare( ir, r ) ) return( -1 ); /* Attach output region to that. */ if( im_region_region( or, ir, r, r->left, r->top ) ) return( -1 ); return( 0 ); }
/** LOCAL FUNCTIONS DEFINITIONS **/ static int cont_surf_gen (REGION * to_make, void * seq, void *unrequired, void * b) { /* I don't need *in, but I will recieve it anyway since im_start_one() needs it */ REGION * make_from = (REGION *) seq; cont_surf_params_t * params = (cont_surf_params_t *) b; unsigned int *row = (unsigned int *) IM_REGION_ADDR (to_make, to_make->valid.left, to_make->valid.top); int xoff; int y; int bottom = to_make->valid.top + to_make->valid.height; size_t lskip = IM_REGION_LSKIP (to_make) / sizeof (unsigned int); Rect area = { params->spacing * to_make->valid.left, params->spacing * to_make->valid.top, DOUBLE_ADD_ONE (params->half_win_size) + (params->spacing * (to_make->valid.width - 1)), DOUBLE_ADD_ONE (params->half_win_size) + (params->spacing * (to_make->valid.height - 1)) }; if (im_prepare (make_from, &area) || !im_rect_equalsrect (&make_from->valid, &area)) return -1; for (y = to_make->valid.top; y < bottom; ++y, row += lskip) for (xoff = 0; xoff < to_make->valid.width; ++xoff) row[xoff] = calc_cont (make_from, DOUBLE (params->half_win_size), (xoff + to_make->valid.left) * params->spacing, y * params->spacing); return 0; }
/* Do a map. */ static int maplut_gen( REGION *or, void *vseq, void *a, void *b ) { Seq *seq = (Seq *) vseq; IMAGE *in = (IMAGE *) a; LutInfo *st = (LutInfo *) b; REGION *ir = seq->ir; Rect *r = &or->valid; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int np = r->width; /* Pels across region */ int ne = IM_REGION_N_ELEMENTS( or ); /* Number of elements */ int x, y, z, i; /* Get input ready. */ if( im_prepare( ir, r ) ) return( -1 ); /* Process! */ if( st->nb == 1 ) /* One band lut. */ outer_switch( loop1, loop1c, loop1g, loop1cg ) else /* Many band lut. */ if( ir->im->Bands == 1 ) /* ... but 1 band input. */ outer_switch( loop1m, loop1cm, loop1gm, loop1cgm ) else outer_switch( loop, loopc, loopg, loopcg ) return( 0 ); }
/* Dilate! */ static int dilate_gen( REGION *or, void *vseq, void *a, void *b ) { SeqInfo *seq = (SeqInfo *) vseq; INTMASK *msk = (INTMASK *) b; REGION *ir = seq->ir; int *soff = seq->soff; int *coff = seq->coff; Rect *r = &or->valid; Rect s; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int sz = IM_REGION_N_ELEMENTS( or ); int *t; int x, y; int result, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += msk->xsize - 1; s.height += msk->ysize - 1; if( im_prepare( ir, &s ) ) return( -1 ); #ifdef DEBUG printf( "erode_gen: preparing %dx%d pixels\n", s.width, s.height ); #endif /*DEBUG*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous im_prepare(). */ if( seq->last_bpl != IM_REGION_LSKIP( ir ) ) { seq->last_bpl = IM_REGION_LSKIP( ir ); seq->ss = 0; seq->cs = 0; for( t = msk->coeff, y = 0; y < msk->ysize; y++ ) for( x = 0; x < msk->xsize; x++, t++ ) switch( *t ) { case 255: soff[seq->ss++] = IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir, le, to ); break; case 128: break; case 0: coff[seq->cs++] = IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir, le, to ); break; default: im_error( "im_dilate", _( "bad mask element (%d " "should be 0, 128 or 255)" ), *t ); return( -1 ); } } /* Dilate! */ for( y = to; y < bo; y++ ) { PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y ); PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); /* Loop along line. */ for( x = 0; x < sz; x++, q++, p++ ) { /* Search for a hit on the set list. */ result = 0; for( i = 0; i < seq->ss; i++ ) if( p[soff[i]] ) { /* Found a match! */ result = 255; break; } /* No set pixels ... search for a hit in the clear * pixels. */ if( !result ) for( i = 0; i < seq->cs; i++ ) if( !p[coff[i]] ) { /* Found a match! */ result = 255; break; } *q = result; } } return( 0 ); }
static int stretch_gen( REGION *or, void *vseq, void *a, void *b ) { SeqInfo *seq = (SeqInfo *) vseq; StretchInfo *sin = (StretchInfo *) b; REGION *ir = seq->ir; Rect *r = &or->valid; Rect r1; int x, y; /* What mask do we start with? */ int xstart = (r->left + sin->xoff) % 34; /* What part of input do we need for this output? */ r1.left = r->left - (r->left + sin->xoff) / 34; r1.top = r->top; x = IM_RECT_RIGHT( r ); x = x - (x + sin->xoff) / 34 + 3; r1.width = x - r1.left; r1.height = r->height + 3; if( im_prepare( ir, &r1 ) ) return( -1 ); /* Fill the first three lines of the buffer. */ for( y = 0; y < 3; y++ ) { unsigned short *p = (unsigned short *) IM_REGION_ADDR( ir, r1.left, y + r1.top ); unsigned short *q = seq->buf + seq->lsk*y; make_xline( sin, p, q, r->width, xstart ); } /* Loop for subsequent lines: stretch a new line of x pels, and * interpolate a line of output from the 3 previous xes plus this new * one. */ for( y = 0; y < r->height; y++ ) { /* Next line of fresh input pels. */ unsigned short *p = (unsigned short *) IM_REGION_ADDR( ir, r1.left, y + r1.top + 3 ); /* Next line we fill in the buffer. */ int boff = (y + 3)%4; unsigned short *q = seq->buf + boff*seq->lsk; /* Line we write in output. */ unsigned short *q1 = (unsigned short *) IM_REGION_ADDR( or, r->left, y + r->top ); /* Process this new xline. */ make_xline( sin, p, q, r->width, xstart ); /* Generate new output line. */ make_yline( sin, seq->lsk, boff, seq->buf, q1, r->width, sin->yoff ); } return( 0 ); }
/* lhist generate function. */ static int lhist_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; LhistInfo *inf = (LhistInfo *) b; Rect *r = &or->valid; Rect irect; int x, y, i, j; int lsk; int centre; /* Offset to move to centre of window */ /* What part of ir do we need? */ irect.left = or->valid.left; irect.top = or->valid.top; irect.width = or->valid.width + inf->xwin; irect.height = or->valid.height + inf->ywin; if( im_prepare( ir, &irect ) ) return( -1 ); lsk = IM_REGION_LSKIP( ir ); centre = lsk * (inf->ywin / 2) + inf->xwin / 2; for( y = 0; y < r->height; y++ ) { /* Get input and output pointers for this line. */ VipsPel *p = IM_REGION_ADDR( ir, r->left, r->top + y ); VipsPel *q = IM_REGION_ADDR( or, r->left, r->top + y ); VipsPel *p1; int hist[256]; /* Find histogram for start of this line. */ memset( hist, 0, 256 * sizeof( int ) ); p1 = p; for( j = 0; j < inf->ywin; j++ ) { for( i = 0; i < inf->xwin; i++ ) hist[p1[i]] += 1; p1 += lsk; } /* Loop for output pels. */ for( x = 0; x < r->width; x++ ) { /* Sum histogram up to current pel. */ int target = p[centre]; int sum; sum = 0; for( i = 0; i < target; i++ ) sum += hist[i]; /* Transform. */ q[x] = sum * 256 / inf->npels; /* Adapt histogram - remove the pels from the left hand * column, add in pels for a new right-hand column. */ p1 = p; for( j = 0; j < inf->ywin; j++ ) { hist[p1[0]] -= 1; hist[p1[inf->xwin]] += 1; p1 += lsk; } p += 1; } } return( 0 ); }
/* Top-bottom blend function for IM_CODING_LABQ images. */ static int tb_blend_labpack( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg ) { REGION *rir = inf->rir; REGION *sir = inf->sir; Rect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. This * will just look at the top 8 bits of L, not all 10, but should be OK. */ if( make_firstlast( inf, ovlap, oreg ) ) return( -1 ); /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if( im_prepare( rir, &prr ) ) return( -1 ); if( im_prepare( sir, &psr ) ) return( -1 ); /* Loop down overlap area. */ for( y = oreg->top, yr = prr.top, ys = psr.top; y < IM_RECT_BOTTOM( oreg ); y++, yr++, ys++ ) { VipsPel *pr = IM_REGION_ADDR( rir, prr.left, yr ); VipsPel *ps = IM_REGION_ADDR( sir, psr.left, ys ); VipsPel *q = IM_REGION_ADDR( or, oreg->left, y ); const int j = oreg->left - ovlap->overlap.left; const int *first = ovlap->first + j; const int *last = ovlap->last + j; float *fq = inf->merge; float *r = inf->from1; float *s = inf->from2; /* Unpack two bits we want. */ vips__LabQ2Lab_vec( r, pr, oreg->width ); vips__LabQ2Lab_vec( s, ps, oreg->width ); /* Blend as floats. */ fblend( float, 3, r, s, fq ); /* Re-pack to output buffer. */ vips__Lab2LabQ_vec( q, inf->merge, oreg->width ); } return( 0 ); }
/* Top-bottom blend function for non-labpack images. */ static int tb_blend( REGION *or, MergeInfo *inf, Overlapping *ovlap, Rect *oreg ) { REGION *rir = inf->rir; REGION *sir = inf->sir; IMAGE *im = or->im; Rect prr, psr; int y, yr, ys; /* Make sure we have a complete first/last set for this area. */ if( make_firstlast( inf, ovlap, oreg ) ) return( -1 ); /* Part of rr which we will output. */ prr = *oreg; prr.left -= ovlap->rarea.left; prr.top -= ovlap->rarea.top; /* Part of sr which we will output. */ psr = *oreg; psr.left -= ovlap->sarea.left; psr.top -= ovlap->sarea.top; /* Make pixels. */ if( im_prepare( rir, &prr ) ) return( -1 ); if( im_prepare( sir, &psr ) ) return( -1 ); /* Loop down overlap area. */ for( y = oreg->top, yr = prr.top, ys = psr.top; y < IM_RECT_BOTTOM( oreg ); y++, yr++, ys++ ) { VipsPel *pr = IM_REGION_ADDR( rir, prr.left, yr ); VipsPel *ps = IM_REGION_ADDR( sir, psr.left, ys ); VipsPel *q = IM_REGION_ADDR( or, oreg->left, y ); const int j = oreg->left - ovlap->overlap.left; const int *first = ovlap->first + j; const int *last = ovlap->last + j; switch( im->BandFmt ) { case IM_BANDFMT_UCHAR: iblend( unsigned char, im->Bands, pr, ps, q ); break; case IM_BANDFMT_CHAR: iblend( signed char, im->Bands, pr, ps, q ); break; case IM_BANDFMT_USHORT: iblend( unsigned short, im->Bands, pr, ps, q ); break; case IM_BANDFMT_SHORT: iblend( signed short, im->Bands, pr, ps, q ); break; case IM_BANDFMT_UINT: iblend( unsigned int, im->Bands, pr, ps, q ); break; case IM_BANDFMT_INT: iblend( signed int, im->Bands, pr, ps, q ); break; case IM_BANDFMT_FLOAT: fblend( float, im->Bands, pr, ps, q ); break; case IM_BANDFMT_DOUBLE: fblend( double, im->Bands, pr, ps, q ); break; case IM_BANDFMT_COMPLEX: fblend( float, im->Bands*2, pr, ps, q ); break; case IM_BANDFMT_DPCOMPLEX: fblend( double, im->Bands*2, pr, ps, q ); break; default: im_error( "im_tbmerge", "%s", _( "internal error" ) ); return( -1 ); } } return( 0 ); }
/* Make first/last for oreg. */ static int make_firstlast( MergeInfo *inf, Overlapping *ovlap, Rect *oreg ) { REGION *rir = inf->rir; REGION *sir = inf->sir; Rect rr, sr; int x; int missing; /* We're going to build first/last ... lock it from other generate * threads. In fact it's harmless if we do get two writers, but we may * avoid duplicating work. */ g_mutex_lock( ovlap->fl_lock ); /* Do we already have first/last for this area? Bail out if we do. */ missing = 0; for( x = oreg->left; x < IM_RECT_RIGHT( oreg ); x++ ) { const int j = x - ovlap->overlap.left; const int first = ovlap->first[j]; if( first < 0 ) { missing = 1; break; } } if( !missing ) { /* No work to do! */ g_mutex_unlock( ovlap->fl_lock ); return( 0 ); } /* Entire height of overlap in ref for oreg ... we know oreg is inside * overlap. */ rr.left = oreg->left; rr.top = ovlap->overlap.top; rr.width = oreg->width; rr.height = ovlap->overlap.height; rr.left -= ovlap->rarea.left; rr.top -= ovlap->rarea.top; /* Same in sec. */ sr.left = oreg->left; sr.top = ovlap->overlap.top; sr.width = oreg->width; sr.height = ovlap->overlap.height; sr.left -= ovlap->sarea.left; sr.top -= ovlap->sarea.top; /* Make pixels. */ if( im_prepare( rir, &rr ) || im_prepare( sir, &sr ) ) { g_mutex_unlock( ovlap->fl_lock ); return( -1 ); } /* Make first/last cache. */ for( x = 0; x < oreg->width; x++ ) { const int j = (x + oreg->left) - ovlap->overlap.left; int *first = &ovlap->first[j]; int *last = &ovlap->last[j]; /* Done this line already? */ if( *first < 0 ) { /* Search for top/bottom of overlap on this scan-line. */ if( find_top( sir, first, x + sr.left, sr.top, sr.height ) || find_bot( rir, last, x + rr.left, rr.top, rr.height ) ) { g_mutex_unlock( ovlap->fl_lock ); return( -1 ); } /* Translate to output space. */ *first += ovlap->sarea.top; *last += ovlap->rarea.top; /* Clip to maximum blend width, if necessary. */ if( ovlap->mwidth >= 0 && *last - *first > ovlap->mwidth ) { int shrinkby = (*last - *first) - ovlap->mwidth; *first += shrinkby / 2; *last -= shrinkby / 2; } } } g_mutex_unlock( ovlap->fl_lock ); return( 0 ); }
/* stdif generate function. */ static int stdif_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; StdifInfo *inf = (StdifInfo *) b; int npel = inf->xwin * inf->ywin; Rect *r = &or->valid; Rect irect; int x, y, i, j; int lsk; int centre; /* Offset to move to centre of window */ /* What part of ir do we need? */ irect.left = or->valid.left; irect.top = or->valid.top; irect.width = or->valid.width + inf->xwin; irect.height = or->valid.height + inf->ywin; if( im_prepare( ir, &irect ) ) return( -1 ); lsk = IM_REGION_LSKIP( ir ); centre = lsk * (inf->ywin / 2) + inf->xwin / 2; for( y = 0; y < r->height; y++ ) { /* Get input and output pointers for this line. */ VipsPel *p = IM_REGION_ADDR( ir, r->left, r->top + y ); VipsPel *q = IM_REGION_ADDR( or, r->left, r->top + y ); /* Precompute some factors. */ double f1 = inf->a * inf->m0; double f2 = 1.0 - inf->a; double f3 = inf->b * inf->s0; VipsPel *p1; int sum; int sum2; /* Find sum, sum of squares for the start of this line. */ sum = 0; sum2 = 0; p1 = p; for( j = 0; j < inf->ywin; j++ ) { for( i = 0; i < inf->xwin; i++ ) { int t = p1[i]; sum += t; sum2 += t * t; } p1 += lsk; } /* Loop for output pels. */ for( x = 0; x < r->width; x++ ) { /* Find stats. */ double mean = (double) sum / npel; double var = (double) sum2 / npel - (mean * mean); double sig = sqrt( var ); /* Transform. */ double res = f1 + f2 * mean + ((double) p[centre] - mean) * (f3 / (inf->s0 + inf->b * sig)); /* And write. */ if( res < 0.0 ) q[x] = 0; else if( res >= 256.0 ) q[x] = 255; else q[x] = res + 0.5; /* Adapt sums - remove the pels from the left hand * column, add in pels for a new right-hand column. */ p1 = p; for( j = 0; j < inf->ywin; j++ ) { int t1 = p1[0]; int t2 = p1[inf->xwin]; sum -= t1; sum2 -= t1 * t1; sum += t2; sum2 += t2 * t2; p1 += lsk; } p += 1; } } return( 0 ); }
/* Subsample a REGION. We fetch in IM_MAX_WIDTH pixel-wide strips, left-to-right * across the input. */ static int line_shrink_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; SubsampleInfo *st = (SubsampleInfo *) b; Rect *r = &or->valid; int le = r->left; int ri = IM_RECT_RIGHT( r ); int to = r->top; int bo = IM_RECT_BOTTOM(r); int ps = IM_IMAGE_SIZEOF_PEL( in ); int owidth = IM_MAX_WIDTH / st->xshrink; Rect s; int x, y; int z, k; /* Loop down the region. */ for( y = to; y < bo; y++ ) { char *q = IM_REGION_ADDR( or, le, y ); char *p; /* Loop across the region, in owidth sized pieces. */ for( x = le; x < ri; x += owidth ) { /* How many pixels do we make this time? */ int ow = IM_MIN( owidth, ri - x ); /* Ask for this many from input ... can save a * little here! */ int iw = ow * st->xshrink - (st->xshrink - 1); /* Ask for input. */ s.left = x * st->xshrink; s.top = y * st->yshrink; s.width = iw; s.height = 1; if( im_prepare( ir, &s ) ) return( -1 ); /* Append new pels to output. */ p = IM_REGION_ADDR( ir, s.left, s.top ); for( z = 0; z < ow; z++ ) { for( k = 0; k < ps; k++ ) q[k] = p[k]; q += ps; p += ps * st->xshrink; } } } return( 0 ); }
static int replicate_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; IMAGE *in = (IMAGE *) a; Rect *r = &or->valid; int twidth = in->Xsize; int theight = in->Ysize; int x, y; Rect tile; /* Find top left of tiles we need. */ int xs = (r->left / twidth) * twidth; int ys = (r->top / theight) * theight; /* The tile enclosing the top-left corner of the requested area. */ tile.left = xs; tile.top = ys; tile.width = twidth; tile.height = theight; /* If the request fits inside a single tile, we can just pointer-copy. */ if( im_rect_includesrect( &tile, r ) ) { Rect irect; /* Translate request to input space. */ irect = *r; irect.left -= xs; irect.top -= ys; if( im_prepare( ir, &irect ) ) return( -1 ); if( im_region_region( or, ir, r, irect.left, irect.top ) ) return( -1 ); return( 0 ); } for( y = ys; y < IM_RECT_BOTTOM( r ); y += theight ) for( x = xs; x < IM_RECT_RIGHT( r ); x += twidth ) { Rect paint; /* Whole tile at x, y */ tile.left = x; tile.top = y; tile.width = twidth; tile.height = theight; /* Which parts touch the area of the output we are * building. */ im_rect_intersectrect( &tile, r, &paint ); /* Translate back to ir coordinates. */ paint.left -= x; paint.top -= y; g_assert( !im_rect_isempty( &paint ) ); /* Render into or. */ if( im_prepare_to( ir, or, &paint, paint.left + x, paint.top + y ) ) return( -1 ); } return( 0 ); }
/* Shrink a REGION. */ static int shrink_gen( REGION *or, void *vseq, void *a, void *b ) { SeqInfo *seq = (SeqInfo *) vseq; ShrinkInfo *st = (ShrinkInfo *) b; REGION *ir = seq->ir; Rect *r = &or->valid; Rect s; int le = r->left; int ri = IM_RECT_RIGHT( r ); int to = r->top; int bo = IM_RECT_BOTTOM(r); int x, y, z, k; /* What part of the input image do we need? Very careful: round left * down, round right up. */ s.left = r->left * st->xshrink; s.top = r->top * st->yshrink; s.width = ceil( IM_RECT_RIGHT( r ) * st->xshrink ) - s.left; s.height = ceil( IM_RECT_BOTTOM( r ) * st->yshrink ) - s.top; if( im_prepare( ir, &s ) ) return( -1 ); /* Init offsets for pel addressing. Note that offsets must be for the * type we will address the memory array with. */ for( z = 0, y = 0; y < st->mh; y++ ) for( x = 0; x < st->mw; x++ ) seq->off[z++] = (IM_REGION_ADDR( ir, x, y ) - IM_REGION_ADDR( ir, 0, 0 )) / IM_IMAGE_SIZEOF_ELEMENT( ir->im ); switch( ir->im->BandFmt ) { case IM_BANDFMT_UCHAR: ishrink(unsigned char); break; case IM_BANDFMT_CHAR: ishrink(char); break; case IM_BANDFMT_USHORT: ishrink(unsigned short); break; case IM_BANDFMT_SHORT: ishrink(short); break; case IM_BANDFMT_UINT: ishrink(unsigned int); break; case IM_BANDFMT_INT: ishrink(int); break; case IM_BANDFMT_FLOAT: fshrink(float); break; case IM_BANDFMT_DOUBLE: fshrink(double); break; default: im_error( "im_shrink", "%s", _( "unsupported input format" ) ); return( -1 ); } return( 0 ); }
/* Make sure we have first/last for this area. */ static int make_firstlast( MergeInfo *inf, Overlapping *ovlap, Rect *oreg ) { REGION *rir = inf->rir; REGION *sir = inf->sir; Rect rr, sr; int y, yr, ys; int missing; /* We're going to build first/last ... lock it from other generate * threads. In fact it's harmless if we do get two writers, but we may * avoid duplicating work. */ g_mutex_lock( ovlap->fl_lock ); /* Do we already have first/last for this area? Bail out if we do. */ missing = 0; for( y = oreg->top; y < IM_RECT_BOTTOM( oreg ); y++ ) { const int j = y - ovlap->overlap.top; const int first = ovlap->first[j]; if( first < 0 ) { missing = 1; break; } } if( !missing ) { /* No work to do! */ g_mutex_unlock( ovlap->fl_lock ); return( 0 ); } /* Entire width of overlap in ref for scan-lines we want. */ rr.left = ovlap->overlap.left; rr.top = oreg->top; rr.width = ovlap->overlap.width; rr.height = oreg->height; rr.left -= ovlap->rarea.left; rr.top -= ovlap->rarea.top; /* Entire width of overlap in sec for scan-lines we want. */ sr.left = ovlap->overlap.left; sr.top = oreg->top; sr.width = ovlap->overlap.width; sr.height = oreg->height; sr.left -= ovlap->sarea.left; sr.top -= ovlap->sarea.top; #ifdef DEBUG printf( "im__lrmerge: making first/last for areas:\n" ); printf( "ref: left = %d, top = %d, width = %d, height = %d\n", rr.left, rr.top, rr.width, rr.height ); printf( "sec: left = %d, top = %d, width = %d, height = %d\n", sr.left, sr.top, sr.width, sr.height ); #endif /* Make pixels. */ if( im_prepare( rir, &rr ) || im_prepare( sir, &sr ) ) { g_mutex_unlock( ovlap->fl_lock ); return( -1 ); } /* Make first/last cache. */ for( y = oreg->top, yr = rr.top, ys = sr.top; y < IM_RECT_BOTTOM( oreg ); y++, yr++, ys++ ) { const int j = y - ovlap->overlap.top; int *first = &ovlap->first[j]; int *last = &ovlap->last[j]; /* Done this line already? */ if( *first < 0 ) { /* Search for start/end of overlap on this scan-line. */ if( find_first( sir, first, sr.left, ys, sr.width ) || find_last( rir, last, rr.left, yr, rr.width ) ) { g_mutex_unlock( ovlap->fl_lock ); return( -1 ); } /* Translate to output space. */ *first += ovlap->sarea.left; *last += ovlap->rarea.left; /* Clip to maximum blend width, if necessary. */ if( ovlap->mwidth >= 0 && *last - *first > ovlap->mwidth ) { int shrinkby = (*last - *first) - ovlap->mwidth; *first += shrinkby / 2; *last -= shrinkby / 2; } } } g_mutex_unlock( ovlap->fl_lock ); return( 0 ); }
static int gradcor_gen( REGION *to_make, void *vptr_seq, void *unrequired, void *vptr_grads ){ gradcor_seq_t *seq= (gradcor_seq_t*) vptr_seq; REGION *make_from= seq-> reg; IMAGE **grads= (IMAGE**) vptr_grads; IMAGE *small_xgrad= grads[0]; IMAGE *small_ygrad= grads[1]; Rect require= { to_make-> valid. left, to_make-> valid. top, to_make-> valid. width + small_xgrad-> Xsize, to_make-> valid. height + small_ygrad-> Ysize }; size_t region_xgrad_width= require. width - 1; size_t region_ygrad_height= require. height - 1; if( im_prepare( make_from, &require ) ) return -1; #define FILL_BUFFERS( TYPE ) /* fill region_xgrad */ \ { \ TYPE *reading= (TYPE*) IM_REGION_ADDR( make_from, require. left, require. top ); \ size_t read_skip= ( IM_REGION_LSKIP( make_from ) / sizeof(TYPE) ) - region_xgrad_width; \ size_t area_need= region_xgrad_width * require. height; \ \ if( seq-> region_xgrad_area < area_need ){ \ free( seq-> region_xgrad ); \ seq-> region_xgrad= malloc( area_need * sizeof(int) ); \ if( ! seq-> region_xgrad ) \ return -1; \ seq-> region_xgrad_area= area_need; \ } \ { \ int *writing= seq-> region_xgrad; \ int *write_end= writing + area_need; \ int *write_stop; \ for( ; writing < write_end; reading+= read_skip ) \ for( write_stop= writing + region_xgrad_width; writing < write_stop; ++reading, ++writing ) \ *writing= reading[1] - reading[0]; \ } \ } \ { /* fill region_ygrad */ \ TYPE *reading= (TYPE*) IM_REGION_ADDR( make_from, require. left, require. top ); \ size_t read_line= IM_REGION_LSKIP( make_from ) / sizeof(TYPE); \ size_t read_skip= read_line - require. width; \ size_t area_need= require. width * region_ygrad_height; \ \ if( seq-> region_ygrad_area < area_need ){ \ free( seq-> region_ygrad ); \ seq-> region_ygrad= malloc( area_need * sizeof(int) ); \ if( ! seq-> region_ygrad ) \ return -1; \ seq-> region_ygrad_area= area_need; \ } \ { \ int *writing= seq-> region_ygrad; \ int *write_end= writing + area_need; \ int *write_stop; \ for( ; writing < write_end; reading+= read_skip ) \ for( write_stop= writing + require. width; writing < write_stop; ++reading, ++writing ) \ *writing= reading[ read_line ] - reading[0]; \ } \ } switch( make_from-> im-> BandFmt ){ case IM_BANDFMT_UCHAR: FILL_BUFFERS( unsigned char ) break; case IM_BANDFMT_CHAR: FILL_BUFFERS( signed char ) break; case IM_BANDFMT_USHORT: FILL_BUFFERS( unsigned short int ) break; case IM_BANDFMT_SHORT: FILL_BUFFERS( signed short int ) break; case IM_BANDFMT_UINT: FILL_BUFFERS( unsigned int ) break; case IM_BANDFMT_INT: FILL_BUFFERS( signed int ) break; default: g_assert( 0 ); } { /* write to output */ size_t write_skip= IM_REGION_LSKIP( to_make ) / sizeof( float ); float *writing= (float*) IM_REGION_ADDR_TOPLEFT( to_make ); float *write_end= writing + write_skip * to_make-> valid. height; float *write_stop; size_t write_width= to_make-> valid. width; size_t small_xgrad_width= small_xgrad-> Xsize; size_t small_ygrad_width= small_ygrad-> Xsize; int *small_xgrad_end= (int*) small_xgrad-> data + small_xgrad_width * small_xgrad-> Ysize; int *small_ygrad_end= (int*) small_ygrad-> data + small_ygrad_width * small_ygrad-> Ysize; int *region_xgrad_start= seq-> region_xgrad; int *region_ygrad_start= seq-> region_ygrad; size_t region_xgrad_start_skip= region_xgrad_width - write_width; size_t region_ygrad_start_skip= require. width - write_width; size_t region_xgrad_read_skip= region_xgrad_width - small_xgrad_width; size_t region_ygrad_read_skip= require. width - small_ygrad_width; write_skip-= write_width; for( ; writing < write_end; writing+= write_skip, region_xgrad_start+= region_xgrad_start_skip, region_ygrad_start+= region_ygrad_start_skip ) for( write_stop= writing + write_width; writing < write_stop; ++writing, ++region_xgrad_start, ++region_ygrad_start ){ gint64 sum= 0; { int *small_xgrad_read= (int*) small_xgrad-> data; int *small_xgrad_stop; int *region_xgrad_read= region_xgrad_start; for( ; small_xgrad_read < small_xgrad_end; region_xgrad_read+= region_xgrad_read_skip ) for( small_xgrad_stop= small_xgrad_read + small_xgrad_width; small_xgrad_read < small_xgrad_stop; ++small_xgrad_read, ++region_xgrad_read ) sum+= *small_xgrad_read * *region_xgrad_read; } { int *small_ygrad_read= (int*) small_ygrad-> data; int *small_ygrad_stop; int *region_ygrad_read= region_ygrad_start; for( ; small_ygrad_read < small_ygrad_end; region_ygrad_read+= region_ygrad_read_skip ) for( small_ygrad_stop= small_ygrad_read + small_ygrad_width; small_ygrad_read < small_ygrad_stop; ++small_ygrad_read, ++region_ygrad_read ) sum+= *small_ygrad_read * *region_ygrad_read; } *writing= sum; } } return 0; }
/* Erode! */ static int erode_gen( REGION *or, void *vseq, void *a, void *b ) { MorphSequence *seq = (MorphSequence *) vseq; Morph *morph = (Morph *) b; INTMASK *mask = morph->mask; REGION *ir = seq->ir; int *soff = seq->soff; int *coff = seq->coff; Rect *r = &or->valid; Rect s; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); int sz = IM_REGION_N_ELEMENTS( or ); int *t; int x, y; int result, i; /* Prepare the section of the input image we need. A little larger * than the section of the output image we are producing. */ s = *r; s.width += mask->xsize - 1; s.height += mask->ysize - 1; if( im_prepare( ir, &s ) ) return( -1 ); #ifdef DEBUG printf( "erode_gen: preparing %dx%d@%dx%d pixels\n", s.width, s.height, s.left, s.top ); #endif /*DEBUG*/ /* Scan mask, building offsets we check when processing. Only do this * if the bpl has changed since the previous im_prepare(). */ if( seq->last_bpl != IM_REGION_LSKIP( ir ) ) { seq->last_bpl = IM_REGION_LSKIP( ir ); seq->ss = 0; seq->cs = 0; for( t = mask->coeff, y = 0; y < mask->ysize; y++ ) for( x = 0; x < mask->xsize; x++, t++ ) switch( *t ) { case 255: soff[seq->ss++] = IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir, le, to ); break; case 128: break; case 0: coff[seq->cs++] = IM_REGION_ADDR( ir, x + le, y + to ) - IM_REGION_ADDR( ir, le, to ); break; default: g_assert( 0 ); } } /* Erode! */ for( y = to; y < bo; y++ ) { VipsPel *p = IM_REGION_ADDR( ir, le, y ); VipsPel *q = IM_REGION_ADDR( or, le, y ); /* Loop along line. */ for( x = 0; x < sz; x++, q++, p++ ) { /* Check all set pixels are set. */ result = 255; for( i = 0; i < seq->ss; i++ ) if( !p[soff[i]] ) { /* Found a mismatch! */ result = 0; break; } /* Check all clear pixels are clear. */ if( result ) for( i = 0; i < seq->cs; i++ ) if( p[coff[i]] ) { result = 0; break; } *q = result; } } return( 0 ); }
static int affinei_gen( REGION *or, void *seq, void *a, void *b ) { REGION *ir = (REGION *) seq; const IMAGE *in = (IMAGE *) a; const Affine *affine = (Affine *) b; const int window_offset = vips_interpolate_get_window_offset( affine->interpolate ); const VipsInterpolateMethod interpolate = vips_interpolate_get_method( affine->interpolate ); /* Area we generate in the output image. */ const Rect *r = &or->valid; const int le = r->left; const int ri = IM_RECT_RIGHT( r ); const int to = r->top; const int bo = IM_RECT_BOTTOM( r ); const Rect *iarea = &affine->trn.iarea; const Rect *oarea = &affine->trn.oarea; int ps = IM_IMAGE_SIZEOF_PEL( in ); int x, y, z; Rect image, want, need, clipped; #ifdef DEBUG printf( "affine: generating left=%d, top=%d, width=%d, height=%d\n", r->left, r->top, r->width, r->height ); #endif /*DEBUG*/ /* We are generating this chunk of the transformed image. */ want = *r; want.left += oarea->left; want.top += oarea->top; /* Find the area of the input image we need. */ im__transform_invert_rect( &affine->trn, &want, &need ); /* Now go to space (2) above. */ need.left += iarea->left; need.top += iarea->top; /* Add a border for interpolation. Plus one for rounding errors. */ im_rect_marginadjust( &need, window_offset + 1 ); /* Clip against the size of (2). */ image.left = 0; image.top = 0; image.width = in->Xsize; image.height = in->Ysize; im_rect_intersectrect( &need, &image, &clipped ); /* Outside input image? All black. */ if( im_rect_isempty( &clipped ) ) { im_region_black( or ); return( 0 ); } /* We do need some pixels from the input image to make our output - * ask for them. */ if( im_prepare( ir, &clipped ) ) return( -1 ); #ifdef DEBUG printf( "affine: preparing left=%d, top=%d, width=%d, height=%d\n", clipped.left, clipped.top, clipped.width, clipped.height ); #endif /*DEBUG*/ /* Resample! x/y loop over pixels in the output image (5). */ for( y = to; y < bo; y++ ) { /* Input clipping rectangle. */ const int ile = iarea->left; const int ito = iarea->top; const int iri = iarea->left + iarea->width; const int ibo = iarea->top + iarea->height; /* Derivative of matrix. */ const double ddx = affine->trn.ia; const double ddy = affine->trn.ic; /* Continuous cods in transformed space. */ const double ox = le + oarea->left - affine->trn.dx; const double oy = y + oarea->top - affine->trn.dy; /* Continuous cods in input space. */ double ix, iy; PEL *q; /* To (3). */ ix = affine->trn.ia * ox + affine->trn.ib * oy; iy = affine->trn.ic * ox + affine->trn.id * oy; /* Now move to (2). */ ix += iarea->left; iy += iarea->top; q = (PEL *) IM_REGION_ADDR( or, le, y ); for( x = le; x < ri; x++ ) { int fx, fy; fx = FLOOR( ix ); fy = FLOOR( iy ); /* Clipping! */ if( fx < ile || fx >= iri || fy < ito || fy >= ibo ) { for( z = 0; z < ps; z++ ) q[z] = 0; } else { interpolate( affine->interpolate, q, ir, ix, iy ); } ix += ddx; iy += ddy; q += ps; } } return( 0 ); }
static int ifthenelse_gen( REGION *or, void *seq, void *client1, void *client2 ) { REGION **ir = (REGION **) seq; Rect *r = &or->valid; int le = r->left; int to = r->top; int bo = IM_RECT_BOTTOM(r); IMAGE *c = ir[0]->im; IMAGE *a = ir[1]->im; int size, width; int i, x, y, z; int all0, alln0; if( c->Bands == 1 ) { /* Copying PEL-sized units with a one-band conditional. */ size = IM_IMAGE_SIZEOF_PEL( a ); width = r->width; } else { /* Copying ELEMENT sized-units with an n-band conditional. */ size = IM_IMAGE_SIZEOF_ELEMENT( a ); width = r->width * a->Bands; } if( im_prepare( ir[0], r ) ) return( -1 ); /* Is the conditional all zero or all non-zero? We can avoid asking * for one of the inputs to be calculated. */ all0 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) == 0; alln0 = *((PEL *) IM_REGION_ADDR( ir[0], le, to )) != 0; for( y = to; y < bo; y++ ) { PEL *p = (PEL *) IM_REGION_ADDR( ir[0], le, y ); for( x = 0; x < width; x++ ) { all0 &= p[x] == 0; alln0 &= p[x] != 0; } if( !all0 && !alln0 ) break; } if( alln0 ) { /* All non-zero. Point or at the then image. */ if( im_prepare( ir[1], r ) || im_region_region( or, ir[1], r, r->left, r->top ) ) return( -1 ); } else if( all0 ) { /* All zero. Point or at the else image. */ if( im_prepare( ir[2], r ) || im_region_region( or, ir[2], r, r->left, r->top ) ) return( -1 ); } else { /* Mix of set and clear ... ask for both then and else parts * and interleave. */ if( im_prepare( ir[1], r ) || im_prepare( ir[2], r ) ) return( -1 ); for( y = to; y < bo; y++ ) { PEL *cp = (PEL *) IM_REGION_ADDR( ir[0], le, y ); PEL *ap = (PEL *) IM_REGION_ADDR( ir[1], le, y ); PEL *bp = (PEL *) IM_REGION_ADDR( ir[2], le, y ); PEL *q = (PEL *) IM_REGION_ADDR( or, le, y ); for( x = 0, i = 0; i < width; i++, x += size ) { if( cp[i] ) for( z = x; z < x + size; z++ ) q[z] = ap[z]; else for( z = x; z < x + size; z++ ) q[z] = bp[z]; } } } return( 0 ); }