Example #1
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 );
}
Example #2
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( &reg->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 );
}
Example #3
0
/**
 * im_draw_mask:
 * @image: image to draw on
 * @x: draw mask here
 * @y: draw mask here
 * @ink: value to draw
 * @mask_im: mask of 0/255 values showing where to plot
 *
 * Draw a mask on the image. @mask_im is a monochrome 8-bit image with 0/255
 * for transparent or @ink coloured points. Intermediate values blend the ink
 * with the pixel. Use with im_text() to draw text on an image.
 *
 * @ink is an array of bytes 
 * containing a valid pixel for the image's format.
 * It must have at least IM_IMAGE_SIZEOF_PEL( @image ) bytes.
 *
 * See also: im_draw_circle(), im_text(), im_draw_line_user().
 *
 * Returns: 0 on success, or -1 on error.
 */
int
im_draw_mask( VipsImage *image, VipsImage *mask_im, int x, int y, PEL *ink )
{
	Mask *mask;

	if( !(mask = mask_new( image, x, y, ink, mask_im )) )
		return( -1 );

	/* Any points to plot?
	 */
	if( im_rect_isempty( &mask->image_clip ) ) {
		mask_free( mask );
		return( 0 );
	}

	/* Loop through image plotting where required.
	 */
	switch( image->Coding ) {
	case IM_CODING_LABQ:
		if( mask_draw_labq( mask ) ) {
			mask_free( mask );
			return( 0 );
		}
		break;

	case IM_CODING_NONE:
		if( mask_draw( mask ) ) {
			mask_free( mask );
			return( 0 );
		}
		break;

	default:
		g_assert( 0 );
	}

	mask_free( mask );

	return( 0 );
}
Example #4
0
/**
 * 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 );
}
Example #5
0
/**
 * im_draw_smudge:
 * @image: image to smudge
 * @left: area to smudge
 * @top: area to smudge
 * @width: area to smudge
 * @height: area to smudge
 *
 * Smudge a section of @image. Each pixel in the area @left, @top, @width,
 * @height is replaced by the average of the surrounding 3x3 pixels. 
 *
 * This an inplace operation, so @image is changed. It does not thread and will
 * not work well as part of a pipeline. On 32-bit machines it will be limited
 * to 2GB images.
 *
 * See also: im_draw_line().
 *
 * Returns: 0 on success, or -1 on error.
 */
int
im_draw_smudge( VipsImage *im, int left, int top, int width, int height )
{
	Rect area, image, clipped;
	IMAGE *t[2];

	area.left = left;
	area.top = top;
	area.width = width;
	area.height = height;
	image.left = 0;
	image.top = 0;
	image.width = im->Xsize;
	image.height = im->Ysize;
	im_rect_intersectrect( &area, &image, &clipped );
	if( im_rect_isempty( &clipped ) )
		return( 0 );

	if( !blur ) {
		blur = im_create_imaskv( "im_draw_smudge", 3, 1, 1, 4, 1 );
		blur->scale = 6;
	}

	if( !(t[0] = im_open( "im_draw_smudge", "p" )) )
		return( -1 );
	if( !(t[1] = im_open_local( t[0], "im_draw_smudge", "p" )) ||
		im_convsep( im, t[0], blur ) ||
		im_extract_area( t[0], t[1], 
			clipped.left, clipped.top, 
			clipped.width, clipped.height ) ||
		im_draw_image( im, t[1], clipped.left, clipped.top ) ) {
		im_close( t[0] );
		return( -1 );
	}
	im_close( t[0] );

	return( 0 );
}
Example #6
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 );
}
Example #7
0
/**
 * im_draw_rect:
 * @image: image to draw on
 * @left: area to paint
 * @top: area to paint
 * @width: area to paint
 * @height: area to paint
 * @fill: fill the rect
 * @ink: paint with this colour
 *
 * Paint pixels within @left, @top, @width, @height in @image with @ink. If
 * @fill is zero, just paint a 1-pixel-wide outline.
 *
 * See also: im_draw_circle().
 *
 * Returns: 0 on success, or -1 on error.
 */
int
im_draw_rect( IMAGE *image, 
	int left, int top, int width, int height, int fill, VipsPel *ink )
{
	Rect im, rect, clipped;
	Draw draw;

	if( !fill ) 
		return( im_draw_rect( image, left, top, width, 1, 1, ink ) ||
			im_draw_rect( image, 
				left + width - 1, top, 1, height, 1, ink ) ||
			im_draw_rect( image, 
				left, top + height - 1, width, 1, 1, ink ) ||
			im_draw_rect( image, left, top, 1, height, 1, ink ) );

	int x, y;
	VipsPel *to;
	VipsPel *q;

	/* Find area we plot.
	 */
	im.left = 0;
	im.top = 0;
	im.width = image->Xsize;
	im.height = image->Ysize;
	rect.left = left;
	rect.top = top;
	rect.width = width;
	rect.height = height;
	im_rect_intersectrect( &rect, &im, &clipped );

	/* Any points left to plot?
	 */
	if( im_rect_isempty( &clipped ) )
		return( 0 );

	if( im_check_coding_known( "im_draw_rect", image ) ||
		!im__draw_init( &draw, image, ink ) )
		return( -1 );

	/* We plot the first line pointwise, then memcpy() it for the
	 * subsequent lines.
	 */
	to = IM_IMAGE_ADDR( image, clipped.left, clipped.top );

	q = to;
	for( x = 0; x < clipped.width; x++ ) {
		im__draw_pel( &draw, q );
		q += draw.psize;
	}

	q = to + draw.lsize;
	for( y = 1; y < clipped.height; y++ ) {
		memcpy( q, to, clipped.width * draw.psize );
		q += draw.lsize;
	}

	im__draw_free( &draw );

	return( 0 );
}
Example #8
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 );
}
Example #9
0
/* Smear a section of an IMAGE. As above, but shift it left a bit.
 */
int
im_smear( IMAGE *im, int ix, int iy, Rect *r )
{	
	int x, y, a, b, c;
	int ba = im->Bands;
	int el = ba * im->Xsize;
	Rect area, image, clipped;
	double total[ 256 ];

	if( im_rwcheck( im ) )
		return( -1 );

	/* Don't do the margins.
	 */
	area = *r;
	area.left += ix;
	area.top += iy;
	image.left = 0;
	image.top = 0;
	image.width = im->Xsize;
	image.height = im->Ysize;
	im_rect_marginadjust( &image, -1 );
	image.left--;
	im_rect_intersectrect( &area, &image, &clipped );

	/* Any left?
	 */
	if( im_rect_isempty( &clipped ) )
		return( 0 );

/* What we do for each type.
 */
#define SMEAR(TYPE) \
	for( y = clipped.top; y < clipped.top + clipped.height; y++ ) \
		for( x = clipped.left;  \
			x < clipped.left + clipped.width; x++ ) { \
			TYPE *to = (TYPE *) im->data + x * ba + y * el; \
			TYPE *from = to - el; \
			TYPE *f; \
 			\
			for( a = 0; a < ba; a++ ) \
				total[a] = 0.0; \
			\
			for( a = 0; a < 3; a++ ) { \
				f = from; \
				for( b = 0; b < 3; b++ ) \
					for( c = 0; c < ba; c++ ) \
						total[c] += *f++; \
				from += el; \
			} \
 			\
			for( a = 0; a < ba; a++ ) \
				to[a] = (40 * (double) to[a+ba] + total[a]) \
					/ 49.0; \
		}

	/* Loop through the remaining pixels.
	 */
	switch( im->BandFmt ) {
	case IM_BANDFMT_UCHAR: 
		SMEAR(unsigned char); 
		break; 

	case IM_BANDFMT_CHAR: 
		SMEAR(char); 
		break; 

	case IM_BANDFMT_USHORT: 
		SMEAR(unsigned short); 
		break; 

	case IM_BANDFMT_SHORT: 
		SMEAR(short); 
		break; 

	case IM_BANDFMT_UINT: 
		SMEAR(unsigned int); 
		break; 

	case IM_BANDFMT_INT: 
		SMEAR(int); 
		break; 

	case IM_BANDFMT_FLOAT: 
		SMEAR(float); 
		break; 

	case IM_BANDFMT_DOUBLE: 
		SMEAR(double); 
		break; 

	/* Do complex types too. Just treat as float and double, but with
	 * twice the number of bands.
	 */
	case IM_BANDFMT_COMPLEX:
		/* Twice number of bands: double size and bands.
		 */
		ba *= 2;
		el *= 2;

		SMEAR(float);

		break;

	case IM_BANDFMT_DPCOMPLEX:
		/* Twice number of bands: double size and bands.
		 */
		ba *= 2;
		el *= 2;

		SMEAR(double);

		break;

	default:
		im_error( "im_smear", "%s", _( "unknown band format" ) );
		return( -1 );
	}

	return( 0 );
}
Example #10
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 );
}