/** * im_region_region: * @reg: region to operate upon * @dest: region to connect to * @r: #Rect of pixels you need to be able to address * @x: postion of @r in @dest * @y: postion of @r in @dest * * Make IM_REGION_ADDR() on @reg go to @dest instead. * * @r is the part of @reg which you want to be able to address (this * effectively becomes the valid field), (@x, @y) is the top LH corner of the * corresponding area in @dest. * * Performs all clipping necessary to ensure that @reg->valid is indeed * valid. * * If the region we attach to is modified, we can be left with dangling * pointers! If the region we attach to is on another image, the two images * must have * the same sizeof( pel ). * * Returns: 0 on success, or -1 for error. */ int im_region_region( REGION *reg, REGION *dest, Rect *r, int x, int y ) { Rect image; Rect wanted; Rect clipped; Rect clipped2; Rect final; /* Sanity check. */ if( !dest->data || IM_IMAGE_SIZEOF_PEL( dest->im ) != IM_IMAGE_SIZEOF_PEL( reg->im ) ) { im_error( "im_region_region", "%s", _( "inappropriate region type" ) ); return( -1 ); } im__region_check_ownership( reg ); /* We can't test g_assert( dest->thread == g_thread_self() ); * since we can have several threads writing to the same region in * threadgroup. */ /* Clip r against size of the image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Translate to dest's coordinate space and clip against the available * pixels. */ wanted.left = x + (clipped.left - r->left); wanted.top = y + (clipped.top - r->top); wanted.width = clipped.width; wanted.height = clipped.height; /* Test that dest->valid is large enough. */ if( !im_rect_includesrect( &dest->valid, &wanted ) ) { im_error( "im_region_region", "%s", _( "dest too small" ) ); return( -1 ); } /* Clip against the available pixels. */ im_rect_intersectrect( &wanted, &dest->valid, &clipped2 ); /* Translate back to reg's coordinate space and set as valid. */ final.left = r->left + (clipped2.left - wanted.left);
/* Copy image, changing header fields. */ static int im_copy_set_all( IMAGE *in, IMAGE *out, VipsType type, float xres, float yres, int xoffset, int yoffset, int bands, VipsBandFmt bandfmt, VipsCoding coding ) { /* Check args. */ if( im_check_coding_known( "im_copy", in ) || im_piocheck( in, out ) ) return( -1 ); if( coding != IM_CODING_NONE && coding != IM_CODING_LABQ && coding != IM_CODING_RAD ) { im_error( "im_copy", "%s", _( "coding must be NONE, LABQ or RAD" ) ); return( -1 ); } if( bandfmt < 0 || bandfmt > IM_BANDFMT_DPCOMPLEX ) { im_error( "im_copy", _( "bandfmt must be in range [0,%d]" ), IM_BANDFMT_DPCOMPLEX ); return( -1 ); } if( im_cp_desc( out, in ) ) return( -1 ); out->Type = type; out->Xres = xres; out->Yres = yres; out->Xoffset = xoffset; out->Yoffset = yoffset; out->Bands = bands; out->BandFmt = bandfmt; out->Coding = coding; /* Sanity check: we (may) have changed bytes-per-pixel since we've * changed Bands and BandFmt ... bad! */ if( IM_IMAGE_SIZEOF_PEL( in ) != IM_IMAGE_SIZEOF_PEL( out ) ) { im_error( "im_copy", "%s", _( "sizeof( pixel ) has changed" ) ); return( -1 ); } /* Generate! */ if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) || im_generate( out, im_start_one, copy_gen, im_stop_one, in, NULL ) ) return( -1 ); 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 ); }
/** * 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 ); }
/** * im_region_buffer: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available as a * memory buffer. * * Returns: 0 on success, or -1 for error. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } /* Have we been asked to drop caches? We want to throw everything * away. * * If not, try to reuse the current buffer. */ if( reg->invalid ) { im_region_reset( reg ); if( !(reg->buffer = im_buffer_new( im, &clipped )) ) return( -1 ); } else { /* Don't call im_region_reset() ... we combine buffer unref * and new buffer ref in one call to reduce malloc/free * cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); } /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; 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 ); }
/* Swap pairs of bytes. */ static void im_copy_swap2_gen( PEL *in, PEL *out, int width, IMAGE *im ) { int x; int sz = IM_IMAGE_SIZEOF_PEL( im ) * width; /* Bytes in buffer */ for( x = 0; x < sz; x += 2 ) { out[x] = in[x + 1]; out[x + 1] = in[x]; } }
static int write_block( REGION *region, Rect *area, void *a ) { Write *write = (Write *) a; int i; for( i = 0; i < area->height; i++ ) { PEL *p = (PEL *) IM_REGION_ADDR( region, area->left, area->top + i ); if( im__write( write->fd, p, IM_IMAGE_SIZEOF_PEL(write->in)*area->width ) ) return( -1 ); } return( 0 ); }
/* Region should be a pixel buffer. On return, check * reg->buffer->done to see if there are pixels there already. Otherwise, you * need to calculate. */ int im_region_buffer( REGION *reg, Rect *r ) { IMAGE *im = reg->im; Rect image; Rect clipped; im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = im->Xsize; image.height = im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_buffer", _( "valid clipped to nothing" ) ); return( -1 ); } /* Already have stuff? */ if( reg->type == IM_REGION_BUFFER && im_rect_includesrect( ®->valid, &clipped ) && reg->buffer && !reg->buffer->invalid ) return( 0 ); /* Don't call im_region_reset() ... we combine buffer unref and new * buffer ref in one call to reduce malloc/free cycling. */ IM_FREEF( im_window_unref, reg->window ); if( !(reg->buffer = im_buffer_unref_ref( reg->buffer, im, &clipped )) ) return( -1 ); /* Init new stuff. */ reg->valid = reg->buffer->area; reg->bpl = IM_IMAGE_SIZEOF_PEL( im ) * reg->buffer->area.width; reg->type = IM_REGION_BUFFER; reg->data = reg->buffer->buf; 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 ); }
/* Swap 8- of bytes. */ static void im_copy_swap8_gen( PEL *in, PEL *out, int width, IMAGE *im ) { int x; int sz = IM_IMAGE_SIZEOF_PEL( im ) * width; /* Bytes in buffer */ for( x = 0; x < sz; x += 8 ) { out[x] = in[x + 7]; out[x + 1] = in[x + 6]; out[x + 2] = in[x + 5]; out[x + 3] = in[x + 4]; out[x + 4] = in[x + 3]; out[x + 5] = in[x + 2]; out[x + 6] = in[x + 1]; out[x + 7] = in[x]; } }
/* Read a ppm/pgm file using mmap(). */ static int read_mmap( FILE *fp, const char *filename, int msb_first, IMAGE *out ) { const int header_offset = ftell( fp ); IMAGE *t[2]; if( im_open_local_array( out, t, 2, "im_ppm2vips", "p" ) || im_raw2vips( filename, t[0], out->Xsize, out->Ysize, IM_IMAGE_SIZEOF_PEL( out ), header_offset ) || im_copy_morph( t[0], t[1], out->Bands, out->BandFmt, out->Coding ) || im_copy_native( t[1], out, msb_first ) ) return( -1 ); return( 0 ); }
/* Copy rect from from to to. */ static void copy_region( REGION *from, REGION *to, Rect *area ) { int y; /* Area should be inside both from and to. */ g_assert( im_rect_includesrect( &from->valid, area ) ); g_assert( im_rect_includesrect( &to->valid, area ) ); /* Loop down common area, copying. */ for( y = area->top; y < IM_RECT_BOTTOM( area ); y++ ) { PEL *p = (PEL *) IM_REGION_ADDR( from, area->left, y ); PEL *q = (PEL *) IM_REGION_ADDR( to, area->left, y ); memcpy( q, p, IM_IMAGE_SIZEOF_PEL( from->im ) * area->width ); } }
Draw * im__draw_init( Draw *draw, IMAGE *im, PEL *ink ) { if( im_rwcheck( im ) ) return( NULL ); draw->im = im; draw->ink = NULL; draw->lsize = IM_IMAGE_SIZEOF_LINE( im ); draw->psize = IM_IMAGE_SIZEOF_PEL( im ); draw->noclip = FALSE; if( ink ) { if( !(draw->ink = (PEL *) im_malloc( NULL, draw->psize )) ) return( NULL ); memcpy( draw->ink, ink, draw->psize ); } return( draw ); }
/** * im_draw_image: * @image: image to draw on * @sub: image to draw * @x: position to insert * @y: position to insert * * Draw @sub on top of @image at position @x, @y. The two images must have the * same * Coding. If @sub has 1 band, the bands will be duplicated to match the * number of bands in @image. @sub will be converted to @image's format, see * im_clip2fmt(). * * See also: im_insert(). * * Returns: 0 on success, or -1 on error. */ int im_draw_image( VipsImage *image, VipsImage *sub, int x, int y ) { Rect br, sr, clip; PEL *p, *q; int z; /* Make rects for main and sub and clip. */ br.left = 0; br.top = 0; br.width = image->Xsize; br.height = image->Ysize; sr.left = x; sr.top = y; sr.width = sub->Xsize; sr.height = sub->Ysize; im_rect_intersectrect( &br, &sr, &clip ); if( im_rect_isempty( &clip ) ) return( 0 ); if( !(sub = im__inplace_base( "im_draw_image", image, sub, image )) || im_rwcheck( image ) || im_incheck( sub ) ) return( -1 ); /* Loop, memcpying sub to main. */ p = (PEL *) IM_IMAGE_ADDR( sub, clip.left - x, clip.top - y ); q = (PEL *) IM_IMAGE_ADDR( image, clip.left, clip.top ); for( z = 0; z < clip.height; z++ ) { memcpy( (char *) q, (char *) p, clip.width * IM_IMAGE_SIZEOF_PEL( sub ) ); p += IM_IMAGE_SIZEOF_LINE( sub ); q += IM_IMAGE_SIZEOF_LINE( image ); } return( 0 ); }
/* Copy from one region to another. Copy area r from inside reg to dest, * positioning the area of pixels at x, y. */ void im__copy_region( REGION *reg, REGION *dest, Rect *r, int x, int y ) { int z; int len = IM_IMAGE_SIZEOF_PEL( reg->im ) * r->width; char *p = IM_REGION_ADDR( reg, r->left, r->top ); char *q = IM_REGION_ADDR( dest, x, y ); int plsk = IM_REGION_LSKIP( reg ); int qlsk = IM_REGION_LSKIP( dest ); #ifdef DEBUG /* Find the area we will write to in dest. */ Rect output; printf( "im__copy_region: sanity check\n" ); output.left = x; output.top = y; output.width = r->width; output.height = r->height; /* Must be inside dest->valid. */ assert( im_rect_includesrect( &dest->valid, &output ) ); /* Check the area we are reading from in reg. */ assert( im_rect_includesrect( ®->valid, r ) ); #endif /*DEBUG*/ for( z = 0; z < r->height; z++ ) { memcpy( q, p, len ); p += plsk; q += qlsk; } }
static int buffer_move( im_buffer_t *buffer, Rect *area ) { IMAGE *im = buffer->im; size_t new_bsize; g_assert( buffer->ref_count == 1 ); buffer->area = *area; im_buffer_undone( buffer ); g_assert( !buffer->done ); new_bsize = (size_t) IM_IMAGE_SIZEOF_PEL( im ) * area->width * area->height; if( buffer->bsize < new_bsize ) { buffer->bsize = new_bsize; IM_FREE( buffer->buf ); if( !(buffer->buf = im_malloc( NULL, buffer->bsize )) ) return( -1 ); } return( 0 ); }
/* Make a new buffer. */ im_buffer_t * im_buffer_new( IMAGE *im, Rect *area ) { im_buffer_t *buffer; if( !(buffer = IM_NEW( NULL, im_buffer_t )) ) return( NULL ); buffer->ref_count = 1; buffer->im = im; buffer->area = *area; buffer->done = FALSE; buffer->cache = NULL; buffer->bsize = (size_t) IM_IMAGE_SIZEOF_PEL( im ) * area->width * area->height; if( !(buffer->buf = im_malloc( NULL, buffer->bsize )) ) { im_buffer_unref( buffer ); return( NULL ); } #ifdef DEBUG printf( "** im_buffer_new: left = %d, top = %d, " "width = %d, height = %d (%p)\n", buffer->area.left, buffer->area.top, buffer->area.width, buffer->area.height, buffer ); #endif /*DEBUG*/ #ifdef DEBUG g_mutex_lock( im__global_lock ); im__buffers_all = g_slist_prepend( im__buffers_all, buffer ); printf( "%d buffers in vips\n", g_slist_length( im__buffers_all ) ); g_mutex_unlock( im__global_lock ); #endif /*DEBUG*/ return( buffer ); }
int im_resize_linear( IMAGE *in, IMAGE *out, int X, int Y ) { double dx, dy, xscale, yscale; double Xnew, Ynew; /* inv. coord. of the interpolated pt */ int x, y; int Xint, Yint; int bb; PEL *input, *opline; PEL *q, *p; int ils, ips, ies; /* Input and output line, pel and */ int ols, ops, oes; /* element sizes */ if( im_iocheck( in, out ) ) return( -1 ); if( im_iscomplex( in ) ) { im_errormsg( "im_lowpass: non-complex input only" ); return( -1 ); } if( in->Coding != IM_CODING_NONE ) { im_errormsg("im_lowpass: input should be uncoded"); return( -1 ); } if( im_cp_desc( out, in ) ) return( -1 ); out->Xsize = X; out->Ysize = Y; if( im_setupout( out ) ) return( -1 ); ils = IM_IMAGE_SIZEOF_LINE( in ); ips = IM_IMAGE_SIZEOF_PEL( in ); ies = IM_IMAGE_SIZEOF_ELEMENT( in ); ols = IM_IMAGE_SIZEOF_LINE( out ); ops = IM_IMAGE_SIZEOF_PEL( out ); oes = IM_IMAGE_SIZEOF_ELEMENT( out ); /* buffer lines ***************/ if( !(opline = IM_ARRAY( out, ols, PEL )) ) return( -1 ); /* Resampling *************/ input = (PEL*) in->data; xscale = ((double)in->Xsize-1)/(X-1); yscale = ((double)in->Ysize-1)/(Y-1); for (y=0; y<Y; y++) { q = opline; for (x=0; x<X; x++) { Xnew = x*xscale; Ynew = y*yscale; Xint = floor(Xnew); Yint = floor(Ynew); dx = Xnew - Xint; dy = Ynew - Yint; p = input + Xint*ips + Yint*ils; switch( in->BandFmt ) { case IM_BANDFMT_UCHAR: LOOP( unsigned char); break; case IM_BANDFMT_USHORT: LOOP( unsigned short ); break; case IM_BANDFMT_UINT: LOOP( unsigned int ); break; 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: im_errormsg( "im_lowpass: unsupported image type" ); return( -1 ); /*NOTREACHED*/ } } if (im_writeline(y, out, opline) ) return(-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 ); }
/** * im_region_image: * @reg: region to operate upon * @r: #Rect of pixels you need to be able to address * * The region is transformed so that at least @r pixels are available directly * from the image. The image needs to be a memory buffer or represent a file * on disc that has been mapped or can be mapped. * * Returns: 0 on success, or -1 for error. */ int im_region_image( REGION *reg, Rect *r ) { Rect image; Rect clipped; /* Sanity check. */ im__region_check_ownership( reg ); /* Clip against image. */ image.top = 0; image.left = 0; image.width = reg->im->Xsize; image.height = reg->im->Ysize; im_rect_intersectrect( r, &image, &clipped ); /* Test for empty. */ if( im_rect_isempty( &clipped ) ) { im_error( "im_region_image", "%s", _( "valid clipped to nothing" ) ); return( -1 ); } if( reg->im->data ) { /* We have the whole image available ... easy! */ im_region_reset( reg ); /* We can't just set valid = clipped, since this may be an * incompletely calculated memory buffer. Just set valid to r. */ reg->valid = clipped; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->im->data + (gint64) clipped.top * IM_IMAGE_SIZEOF_LINE( reg->im ) + clipped.left * IM_IMAGE_SIZEOF_PEL( reg->im ); reg->type = IM_REGION_OTHER_IMAGE; } else if( reg->im->dtype == IM_OPENIN ) { /* No complete image data ... but we can use a rolling window. */ if( reg->type != IM_REGION_WINDOW || !reg->window || reg->window->top > clipped.top || reg->window->top + reg->window->height < clipped.top + clipped.height ) { im_region_reset( reg ); if( !(reg->window = im_window_ref( reg->im, clipped.top, clipped.height )) ) return( -1 ); reg->type = IM_REGION_WINDOW; } /* Note the area the window actually represents. */ reg->valid.left = 0; reg->valid.top = reg->window->top; reg->valid.width = reg->im->Xsize; reg->valid.height = reg->window->height; reg->bpl = IM_IMAGE_SIZEOF_LINE( reg->im ); reg->data = reg->window->data; } else { im_error( "im_region_image", "%s", _( "bad image type" ) ); return( -1 ); } 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 ); }