Beispiel #1
0
/* Set output area of trn so that it just holds all of our input pels.
 */
void
im__transform_set_area( Transformation *trn )
{
	double xA, xB, xC, xD;
	double yA, yB, yC, yD;	
	int xmin, xmax, ymin, ymax;

	im__transform_forward( trn, 
		trn->iarea.left, trn->iarea.top, 
		&xA, &yA );
	im__transform_forward( trn, 
		IM_RECT_RIGHT( &trn->iarea ) - 1, trn->iarea.top, 
		&xB, &yB );
	im__transform_forward( trn, 
		trn->iarea.left, IM_RECT_BOTTOM( &trn->iarea ) - 1, 
		&xC, &yC );
	im__transform_forward( trn, 
		IM_RECT_RIGHT( &trn->iarea ) - 1, 
			IM_RECT_BOTTOM( &trn->iarea ) - 1, 
		&xD, &yD );

	xmin = IM_MIN( xA, IM_MIN( xB, IM_MIN( xC, xD ) ) );
	ymin = IM_MIN( yA, IM_MIN( yB, IM_MIN( yC, yD ) ) );
	xmax = IM_MAX( xA, IM_MAX( xB, IM_MAX( xC, xD ) ) );
	ymax = IM_MAX( yA, IM_MAX( yB, IM_MAX( yC, yD ) ) );

	trn->oarea.left = xmin;
	trn->oarea.top = ymin;
	trn->oarea.width = xmax - xmin + 1;
	trn->oarea.height = ymax - ymin + 1;
}
Beispiel #2
0
/* Transform a rect using a point transformer.
 */
static void
transform_rect( const Transformation *trn, transform_fn transform,
                const Rect *in,		/* In input space */
                Rect *out )		/* In output space */
{
    double x1, y1;		/* Map corners */
    double x2, y2;
    double x3, y3;
    double x4, y4;
    double left, right, top, bottom;

    /* Map input Rect.
     */
    transform( trn, in->left, in->top, &x1, &y1 );
    transform( trn, in->left, IM_RECT_BOTTOM( in ), &x3, &y3 );
    transform( trn, IM_RECT_RIGHT( in ), in->top, &x2, &y2 );
    transform( trn, IM_RECT_RIGHT( in ), IM_RECT_BOTTOM( in ), &x4, &y4 );

    /* Find bounding box for these four corners. Round-to-nearest to try
     * to stop rounding errors growing images.
     */
    left = IM_MIN( x1, IM_MIN( x2, IM_MIN( x3, x4 ) ) );
    right = IM_MAX( x1, IM_MAX( x2, IM_MAX( x3, x4 ) ) );
    top = IM_MIN( y1, IM_MIN( y2, IM_MIN( y3, y4 ) ) );
    bottom = IM_MAX( y1, IM_MAX( y2, IM_MAX( y3, y4 ) ) );

    out->left = IM_RINT( left );
    out->top = IM_RINT( top );
    out->width = IM_RINT( right - left );
    out->height = IM_RINT( bottom - top );
}
Beispiel #3
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 );
}
Beispiel #4
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 );
}
Beispiel #5
0
/* Scroll to make an xywh area visible. If the area is larger than the
 * viewport, position the view at the bottom left if the xywh area ... 
 * this is usually right for workspaces.
 */
void
workspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h )
{
	GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( 
		GTK_SCROLLED_WINDOW( wview->window ) );
	GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( 
		GTK_SCROLLED_WINDOW( wview->window ) );
        Rect *vp = &wview->vp;
        int nx, ny;

        nx = hadj->value;
        if( x + w > IM_RECT_RIGHT( vp ) )
                nx = IM_MAX( 0, (x + w) - vp->width );
        if( x < nx )
                nx = x;

        ny = vadj->value;
        if( y + h > IM_RECT_BOTTOM( vp ) )
                ny = IM_MAX( 0, (y + h) - vp->height );
        if( y < ny )
                ny = y;

#ifdef DEBUG
        printf( "workspaceview_scroll: x=%d, y=%d, w=%d, h=%d, "
                "nx = %d, ny = %d\n", x, y, w, h, nx, ny );
#endif /*DEBUG*/

	adjustments_set_value( hadj, vadj, nx, ny );
}
Beispiel #6
0
static int
vips_rot180_gen( VipsRegion *or, void *seq, void *a, void *b,
	gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	VipsImage *in = (VipsImage *) a;

	/* Output area.
	 */
	VipsRect *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;

	/* Pixel geometry.
	 */
	int ps;

	/* Find the area of the input image we need.
	 */
	Rect need;

	need.left = in->Xsize - ri;
	need.top = in->Ysize - bo;
	need.width = r->width;
	need.height = r->height;
	if( vips_region_prepare( ir, &need ) )
		return( -1 );

	/* Find PEL size and line skip for ir.
	 */
	ps = VIPS_IMAGE_SIZEOF_PEL( in );

	/* Rotate the bit we now have.
	 */
	for( y = to; y < bo; y++ ) {
		/* Start of this output line.
		 */
		VipsPel *q = VIPS_REGION_ADDR( or, le, y );

		/* Corresponding position in ir.
		 */
		VipsPel *p = VIPS_REGION_ADDR( ir, 
			need.left + need.width - 1, 
			need.top + need.height - (y - to) - 1 );

		/* Blap across!
		 */
		for( x = le; x < ri; x++ ) {
			memcpy( q, p, ps );
			q += ps;
			p -= ps;
		}
	}

	return( 0 );
}
Beispiel #7
0
/* Generate function.
 */
static int
make_vert_gen( REGION *or, void *seq, void *a, void *b )
{
	IMAGE *in = (IMAGE *) a;
	Rect *r = &or->valid;
	int le = r->left;
	int to = r->top;
	int ri = IM_RECT_RIGHT( r );
	int bo = IM_RECT_BOTTOM( r );
	int nb = in->Bands;

	int x, y, z;

	for( y = to; y < bo; y++ ) {
		VipsPel *q = IM_REGION_ADDR( or, le, y );
		VipsPel *p = IM_IMAGE_ADDR( in, 0, y );

		switch( in->BandFmt ) {
		case IM_BANDFMT_UCHAR: 	VERT( unsigned char ); break;
		case IM_BANDFMT_CHAR: 	VERT( signed char ); break; 
		case IM_BANDFMT_USHORT: VERT( unsigned short ); break; 
		case IM_BANDFMT_SHORT: 	VERT( signed short ); break; 
		case IM_BANDFMT_UINT: 	VERT( unsigned int ); break; 
		case IM_BANDFMT_INT: 	VERT( signed int );  break; 
		case IM_BANDFMT_FLOAT: 	VERT( float ); break; 
		case IM_BANDFMT_DOUBLE:	VERT( double ); break; 

		default:
			g_assert( 0 ); 
		}
	}

	return( 0 );
}
Beispiel #8
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 );
}
Beispiel #9
0
static void
workspaceview_child_size_cb( Columnview *cview, 
	GtkAllocation *allocation, Workspaceview *wview )
{
	Workspace *ws = WORKSPACE( VOBJECT( wview )->iobject );
	Workspacegroup *wsg = workspace_get_workspacegroup( ws );

	int right, bottom;

	g_assert( IS_WORKSPACEVIEW( wview ) );

	/* Compute a new bounding box for our children.
	 */
	wview->bounding.left = 0;
	wview->bounding.top = 0;
	wview->bounding.width = 0;
	wview->bounding.height = 0;

	(void) view_map( VIEW( wview ),
		(view_map_fn) workspaceview_child_size_sub, 
		&wview->bounding, NULL );

	wview->bounding.width += 1000;
	wview->bounding.height += 1000;

#ifdef DEBUG
{
	Column *col = COLUMN( VOBJECT( cview )->iobject );

	printf( "workspaceview_child_size_cb: cview %s "
		"bb left=%d, top=%d, width=%d, height=%d\n",
		IOBJECT( col )->name, 
		wview->bounding.left,
		wview->bounding.top,
		wview->bounding.width,
		wview->bounding.height );
}
#endif /*DEBUG*/

	/* Resize our fixed if necessary.
	 */
	right = IM_RECT_RIGHT( &wview->bounding );
	bottom = IM_RECT_BOTTOM( &wview->bounding );
	if( right != wview->width || bottom != wview->height ) {
		gtk_widget_set_size_request( GTK_WIDGET( wview->fixed ), 
			right, bottom ); 

		/* Update the model hints ... it uses bounding to position
		 * loads and saves.
		 */
		ws->area = wview->bounding;
		filemodel_set_offset( FILEMODEL( wsg ), 
			ws->area.left, ws->area.top );
	}
}
Beispiel #10
0
/* Generate function.
 */
static int
make_horz_gen( REGION *or, void *seq, void *a, void *b )
{
    IMAGE *in = (IMAGE *) a;
    Rect *r = &or->valid;
    int le = r->left;
    int to = r->top;
    int ri = IM_RECT_RIGHT( r );
    int bo = IM_RECT_BOTTOM( r );
    int nb = in->Bands;
    int lsk = IM_REGION_LSKIP( or );
    int ht = or->im->Ysize;

    int x, y, z;

    for( x = le; x < ri; x++ ) {
        VipsPel *q = IM_REGION_ADDR( or, x, to );
        VipsPel *p = IM_IMAGE_ADDR( in, x, 0 );

        switch( in->BandFmt ) {
        case IM_BANDFMT_UCHAR:
            HORZ( unsigned char );
            break;
        case IM_BANDFMT_CHAR:
            HORZ( signed char );
            break;
        case IM_BANDFMT_USHORT:
            HORZ( unsigned short );
            break;
        case IM_BANDFMT_SHORT:
            HORZ( signed short );
            break;
        case IM_BANDFMT_UINT:
            HORZ( unsigned int );
            break;
        case IM_BANDFMT_INT:
            HORZ( signed int );
            break;
        case IM_BANDFMT_FLOAT:
            HORZ( float );
            break;
        case IM_BANDFMT_DOUBLE:
            HORZ( double );
            break;

        default:
            g_assert( 0 );
        }
    }

    return( 0 );
}
Beispiel #11
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 );
}
Beispiel #12
0
/* Loop over the output region, filling with data from cache.
 */
static int
tile_cache_fill( REGION *out, void *seq, void *a, void *b )
{
	REGION *in = (REGION *) seq;
	Read *read = (Read *) b;
	const int tw = read->tile_width;
	const int th = read->tile_height;
	Rect *r = &out->valid;

	/* Find top left of tiles we need.
	 */
	int xs = (r->left / tw) * tw;
	int ys = (r->top / th) * th;

	int x, y;

	g_mutex_lock( read->lock );

	for( y = ys; y < IM_RECT_BOTTOM( r ); y += th )
		for( x = xs; x < IM_RECT_RIGHT( r ); x += tw ) {
			Tile *tile;
			Rect tarea;
			Rect hit;

			if( !(tile = tile_find( read, in, x, y )) ) {
				g_mutex_unlock( read->lock );
				return( -1 );
			}

			/* The area of the tile.
			 */
			tarea.left = x;
			tarea.top = y;
			tarea.width = tw;
			tarea.height = th;

			/* The part of the tile that we need.
			 */
			im_rect_intersectrect( &tarea, r, &hit );

			copy_region( tile->region, out, &hit );
		}

	g_mutex_unlock( read->lock );

	return( 0 );
}
Beispiel #13
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 );
}
Beispiel #14
0
/* Generate function.
 */
static int
make_xy_gen( REGION *or, void *seq, void *a, void *b )
{
	Rect *r = &or->valid;
	int le = r->left;
	int to = r->top;
	int ri = IM_RECT_RIGHT( r );
	int bo = IM_RECT_BOTTOM( r );

	int x, y;

	for( y = to; y < bo; y++ ) {
		unsigned int *q = (unsigned int *) IM_REGION_ADDR( or, le, y );

		for( x = le; x < ri; x++ ) {
			q[0] = x;
			q[1] = y;
			q += 2;
		}
	}

	return( 0 );
}
Beispiel #15
0
/* Loop over a big region, filling it in many small pieces with threads.
 */
static int
eval_to_region( REGION *or, im_threadgroup_t *tg )
{
	Rect *r = &or->valid;
	Rect image;

	int x, y;

	image.left = 0;
	image.top = 0;
	image.width = or->im->Xsize;
	image.height = or->im->Ysize;

	/* Note we'll be working to fill a contigious area.
	 */
	tg->inplace = 1;

	/* Loop over or, attaching to all sub-parts in turn.
	 */
	for( y = r->top; y < IM_RECT_BOTTOM( r ); y += tg->ph )
		for( x = r->left; x < IM_RECT_RIGHT( r ); x += tg->pw ) {
			im_thread_t *thr;
			Rect pos;
			Rect clipped;

			/* thrs appear on idle when the child thread does
			 * threadgroup_idle_add and hits the 'go' semaphore.
			 */
                        thr = im_threadgroup_get( tg );

			/* Set the position we want to generate with this
			 * thread. Clip against the size of the image and the
			 * space available in or.
			 */
			pos.left = x;
			pos.top = y;
			pos.width = tg->pw;
			pos.height = tg->ph;
			im_rect_intersectrect( &pos, &image, &clipped );
			im_rect_intersectrect( &clipped, r, &clipped );

			/* Note params and start work.
			 */
			thr->oreg = or; 
			thr->pos = clipped; 
			thr->x = clipped.left;
			thr->y = clipped.top;
			im_threadgroup_trigger( thr );

			/* Check for errors.
			 */
			if( im_threadgroup_iserror( tg ) ) {
				/* Don't kill threads yet ... we may want to
				 * get some error stuff out of them.
				 */
				im_threadgroup_wait( tg );
				return( -1 );
			}
		}

	/* Wait for all threads to hit 'go' again.
	 */
	im_threadgroup_wait( tg );

	if( im_threadgroup_iserror( tg ) )
		return( -1 );

	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 );
}
Beispiel #17
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 );
}
Beispiel #18
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 );
}
Beispiel #19
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 );
}
Beispiel #20
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 );
}
Beispiel #21
0
static int 
affinei( IMAGE *in, IMAGE *out, 
	VipsInterpolate *interpolate, Transformation *trn )
{
	Affine *affine;
	double edge;

	/* Make output image.
	 */
	if( im_piocheck( in, out ) ) 
		return( -1 );
	if( im_cp_desc( out, in ) ) 
		return( -1 );

	/* Need a copy of the params for the lifetime of out.
	 */
	if( !(affine = IM_NEW( out, Affine )) )
		return( -1 );
	affine->interpolate = NULL;
	if( im_add_close_callback( out, 
		(im_callback_fn) affine_free, affine, NULL ) )
		return( -1 );
	affine->in = in;
	affine->out = out;
	affine->interpolate = interpolate;
	g_object_ref( interpolate );
	affine->trn = *trn;

	if( im__transform_calc_inverse( &affine->trn ) )
		return( -1 );

	out->Xsize = affine->trn.oarea.width;
	out->Ysize = affine->trn.oarea.height;

	/* Normally SMALLTILE ... except if this is a size up/down affine.
	 */
	if( affine->trn.b == 0.0 && affine->trn.c == 0.0 ) {
		if( im_demand_hint( out, IM_FATSTRIP, in, NULL ) )
			return( -1 );
	}
	else {
		if( im_demand_hint( out, IM_SMALLTILE, in, NULL ) )
			return( -1 );
	}

	/* Check for coordinate overflow ... we want to be able to hold the
	 * output space inside INT_MAX / TRANSFORM_SCALE.
	 */
	edge = INT_MAX / VIPS_TRANSFORM_SCALE;
	if( affine->trn.oarea.left < -edge || affine->trn.oarea.top < -edge ||
		IM_RECT_RIGHT( &affine->trn.oarea ) > edge || 
		IM_RECT_BOTTOM( &affine->trn.oarea ) > edge ) {
		im_error( "im_affinei", 
			"%s", _( "output coordinates out of range" ) );
		return( -1 );
	}

	/* Generate!
	 */
	if( im_generate( out, 
		im_start_one, affinei_gen, im_stop_one, in, affine ) )
		return( -1 );

	return( 0 );
}
Beispiel #22
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 );
}