Beispiel #1
0
/* The inverse: take ink to a vec of double. Used in the vips7 compat
 * wrappers. Result valid while im is valid. 
 */
double *
vips__ink_to_vector( const char *domain, VipsImage *im, VipsPel *ink, int *n )
{
	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( im ), 6 );

	double *result;

#ifdef VIPS_DEBUG
	printf( "vips__ink_to_vector: starting\n" );
#endif /*VIPS_DEBUG*/

	/* Wrap a VipsImage around ink.
	 */
	t[0] = vips_image_new_from_memory( ink, 
		1, 1, VIPS_IMAGE_SIZEOF_PEL( im ), VIPS_FORMAT_UCHAR );
	if( vips_copy( t[0], &t[1], 
		"bands", im->Bands, 
		"format", im->BandFmt, 
		"coding", im->Coding, 
		"interpretation", im->Type, 
		NULL ) )
		return( NULL ); 

	/* The image may be coded .. unpack to double.
	 */
	if( vips_image_decode( t[1], &t[2] ) ||
		vips_cast( t[2], &t[3], VIPS_FORMAT_DOUBLE, NULL ) )
		return( NULL );

	/* To a mem buffer, then copy to out. 
	 */
	if( !(t[4] = vips_image_new_memory()) ||
		vips_image_write( t[3], t[4] ) )
		return( NULL ); 

	if( !(result = VIPS_ARRAY( im, t[4]->Bands, double )) )
		return( NULL ); 
	memcpy( result, t[4]->data, VIPS_IMAGE_SIZEOF_PEL( t[4] ) ); 
	*n = t[4]->Bands; 

#ifdef VIPS_DEBUG
{
	int i;

	printf( "vips__ink_to_vector:\n" );
	printf( "\tink = " ); 
	for( i = 0; i < n; i++ )
		printf( "%d ", ink[i] );
	printf( "\n" ); 

	printf( "\tvec = " ); 
	for( i = 0; i < *n; i++ )
		printf( "%d ", result[i] );
	printf( "\n" ); 
}
#endif /*VIPS_DEBUG*/

	return( result ); 
}
Beispiel #2
0
/* Make a new buffer.
 */
VipsBuffer *
vips_buffer_new( VipsImage *im, VipsRect *area )
{
	VipsBuffer *buffer;

	buffer = g_new( VipsBuffer, 1 );
	buffer->ref_count = 1;
	buffer->im = im;
	buffer->area = *area;
	buffer->done = FALSE;
	buffer->cache = NULL;
	buffer->bsize = (size_t) VIPS_IMAGE_SIZEOF_PEL( im ) * 
		area->width * area->height;
	if( !(buffer->buf = vips_tracked_malloc( buffer->bsize )) ) {
		vips_buffer_unref( buffer );
		return( NULL );
	}

#ifdef DEBUG
	printf( "** vips_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( vips__global_lock );
	vips__buffers_all = g_slist_prepend( vips__buffers_all, buffer );
	printf( "%d buffers in vips\n", g_slist_length( vips__buffers_all ) );
	g_mutex_unlock( vips__global_lock );
#endif /*DEBUG*/

	return( buffer );
}
Beispiel #3
0
/* Read a ppm/pgm file using mmap().
 */
static int
read_mmap( FILE *fp, const char *filename, int msb_first, VipsImage *out )
{
	const guint64 header_offset = ftell( fp );
	VipsImage *x = vips_image_new();
	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( x ), 3 );

	if( vips_rawload( filename, &t[0], 
			out->Xsize, out->Ysize, VIPS_IMAGE_SIZEOF_PEL( out ), 
			"offset", header_offset,
			NULL ) ||
		vips_copy( t[0], &t[1],
			"bands", out->Bands, 
			"format", out->BandFmt, 
			"coding", out->Coding, 
			NULL ) ||
		vips_copy( t[1], &t[2], 
			"swap", !vips_amiMSBfirst(), 
			NULL ) ||
		vips_image_write( t[2], out ) ) {
		g_object_unref( x );
		return( -1 );
	}
	g_object_unref( x );

	return( 0 );
}
Beispiel #4
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 #5
0
static int
buffer_move( VipsBuffer *buffer, VipsRect *area )
{
	VipsImage *im = buffer->im;
	size_t new_bsize;

	g_assert( buffer->ref_count == 1 );

	vips_buffer_undone( buffer );
	g_assert( !buffer->done );

	buffer->area = *area;

	new_bsize = (size_t) VIPS_IMAGE_SIZEOF_PEL( im ) * 
		area->width * area->height;
	if( buffer->bsize < new_bsize ||
		!buffer->buf ) {
		buffer->bsize = new_bsize;
		VIPS_FREEF( vips_tracked_free, buffer->buf );
		if( !(buffer->buf = vips_tracked_malloc( buffer->bsize )) ) 
			return( -1 );
	}

	return( 0 );
}
Beispiel #6
0
static int
vips_fits_write( VipsRegion *region, VipsRect *area, void *a )
{
	VipsFits *fits = (VipsFits *) a;
	VipsImage *image = fits->image;
	int es = VIPS_IMAGE_SIZEOF_ELEMENT( image );
	int ps = VIPS_IMAGE_SIZEOF_PEL( image );

	int status;
	int y, b, x, k;

	status = 0;

	VIPS_DEBUG_MSG( "vips_fits_write: "
		"writing left = %d, top = %d, width = %d, height = %d\n", 
		area->left, area->top, area->width, area->height );

	/* We need to write a band at a time. We can't bandsplit in vips,
	 * since vips_sink_disc() can't loop over many images at once, sadly.
	 */

	for( y = 0; y < area->height; y++ ) {
		VipsPel *p = VIPS_REGION_ADDR( region, 
			area->left, area->top + y );

		for( b = 0; b < image->Bands; b++ ) {
			VipsPel *p1, *q;
			long fpixel[3];

			p1 = p + b * es;
			q = fits->buffer;

			for( x = 0; x < area->width; x++ ) {
				for( k = 0; k < es; k++ ) 
					q[k] = p1[k];
				
				q += es;
				p1 += ps;
			}

			fpixel[0] = area->left + 1;
			fpixel[1] = area->top + y + 1;
			fpixel[2] = b + 1;

			/* No need to lock, write functions are single-threaded.
			 */

			if( fits_write_pix( fits->fptr, fits->datatype, 
				fpixel, area->width, fits->buffer, 
				&status ) ) {
				vips_fits_error( status );
				return( -1 );
			}
		}
	}

	return( 0 );
}
Beispiel #7
0
/* Paint the part of the region containing only whole pels.
 */
static void
vips_zoom_paint_whole( VipsRegion *or, VipsRegion *ir, VipsZoom *zoom,
	const int left, const int right, const int top, const int bottom )
{
	const int ps = VIPS_IMAGE_SIZEOF_PEL( ir->im );
	const int ls = VIPS_REGION_LSKIP( or );
	const int rs = ps * (right - left);

	/* Transform to ir coordinates.
	 */
	const int ileft = left / zoom->xfac;
	const int iright = right / zoom->xfac;
	const int itop = top / zoom->yfac;
	const int ibottom = bottom / zoom->yfac;

	int x, y, z, i;

	/* We know this!
	 */
	g_assert( right > left && bottom > top && 
		right % zoom->xfac == 0 &&
		left % zoom->xfac == 0 &&
		top % zoom->yfac == 0 &&
		bottom % zoom->yfac == 0 );

	/* Loop over input, as we know we are all whole.
	 */
	for( y = itop; y < ibottom; y++ ) {
		VipsPel *p = VIPS_REGION_ADDR( ir, ileft, y );
		VipsPel *q = VIPS_REGION_ADDR( or, left, y * zoom->yfac );
		VipsPel *r;

		/* Expand the first line of pels.
		 */
		r = q;
		for( x = ileft; x < iright; x++ ) {
			/* Copy each pel xfac times.
			 */
			for( z = 0; z < zoom->xfac; z++ ) {
				for( i = 0; i < ps; i++ )
					r[i] = p[i];

				r += ps;
			}

			p += ps;
		}

		/* Copy the expanded line yfac-1 times.
		 */
		r = q + ls;
		for( z = 1; z < zoom->yfac; z++ ) {
			memcpy( r, q, rs );
			r += ls;
		}
	}
}
Beispiel #8
0
static int
vips_flip_horizontal_gen( VipsRegion *or, void *seq, void *a, void *b, 
	gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	VipsRect *r = &or->valid;
	VipsRect in;
	VipsPel *p, *q;
	int x, y, z;

	int le = r->left;
	int ri = VIPS_RECT_RIGHT(r);
	int to = r->top;
	int bo = VIPS_RECT_BOTTOM(r);

	int ps = VIPS_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 = VIPS_RECT_RIGHT( &in ) - 1;

	/* Ask for input we need.
	 */
	if( vips_region_prepare( ir, &in ) )
		return( -1 );

	/* Loop, copying and reversing lines.
	 */
	for( y = to; y < bo; y++ ) {
		p = VIPS_REGION_ADDR( ir, lastx, y );
		q = VIPS_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 #9
0
/* Generate an area of @or. @ir is large enough.
 */
static void
vips_shrink2_gen2( VipsShrink2 *shrink, VipsShrink2Sequence *seq,
                   VipsRegion *or, VipsRegion *ir,
                   int left, int top, int width, int height )
{
    VipsResample *resample = VIPS_RESAMPLE( shrink );
    const int bands = resample->in->Bands;
    const int sizeof_pixel = VIPS_IMAGE_SIZEOF_PEL( resample->in );
    const int ls = VIPS_REGION_LSKIP( ir ) /
                   VIPS_IMAGE_SIZEOF_ELEMENT( resample->in );

    int x, y, i;
    int x1, y1, b;

    for( y = 0; y < height; y++ ) {
        VipsPel *out = VIPS_REGION_ADDR( or, left, top + y );

        for( x = 0; x < width; x++ ) {
            int ix = (left + x) * shrink->xshrink;
            int iy = (top + y) * shrink->yshrink;
            VipsPel *in = VIPS_REGION_ADDR( ir, ix, iy );

            switch( resample->in->BandFmt ) {
            case VIPS_FORMAT_UCHAR:
                ISHRINK( unsigned char );
                break;
            case VIPS_FORMAT_CHAR:
                ISHRINK( char );
                break;
            case VIPS_FORMAT_USHORT:
                ISHRINK( unsigned short );
                break;
            case VIPS_FORMAT_SHORT:
                ISHRINK( short );
                break;
            case VIPS_FORMAT_UINT:
                ISHRINK( unsigned int );
                break;
            case VIPS_FORMAT_INT:
                ISHRINK( int );
                break;
            case VIPS_FORMAT_FLOAT:
                FSHRINK( float );
                break;
            case VIPS_FORMAT_DOUBLE:
                FSHRINK( double );
                break;

            default:
                g_assert( 0 );
            }

            out += sizeof_pixel;
        }
    }
}
Beispiel #10
0
/* Copy a single pixel sideways into a line of pixels.
 */
static void
vips_embed_copy_pixel( VipsEmbed *embed, VipsPel *q, VipsPel *p, int n )
{
	const int bs = VIPS_IMAGE_SIZEOF_PEL( embed->in );

	int x, b;

	for( x = 0; x < n; x++ )
		for( b = 0; b < bs; b++ )
			*q++ = p[b];
}
Beispiel #11
0
/* Swap 4- of bytes.
 */
static void
vips_byteswap_swap4( VipsPel *in, VipsPel *out, int width, VipsImage *im )
{
	guint32 *p = (guint32 *) in;
	guint32 *q = (guint32 *) out;
        int sz = (VIPS_IMAGE_SIZEOF_PEL( im ) * width) / 4;    

        int x;

        for( x = 0; x < sz; x++ ) 
		q[x] = GUINT32_SWAP_LE_BE( p[x] );
}
Beispiel #12
0
/* Swap 8- of bytes.
 */
static void
vips_copy_swap8( VipsPel *in, VipsPel *out, int width, VipsImage *im )
{
    guint64 *p = (guint64 *) in;
    guint64 *q = (guint64 *) out;
    int sz = (VIPS_IMAGE_SIZEOF_PEL( im ) * width) / 8;

    int x;

    for( x = 0; x < sz; x++ )
        q[x] = GUINT64_SWAP_LE_BE( p[x] );
}
Beispiel #13
0
static void
vips_bandjoin_buffer( VipsBandary *bandary, VipsPel *q, VipsPel **p, int width )
{
	VipsConversion *conversion = (VipsConversion *) bandary;
	VipsImage **in = bandary->ready;

	/* Output pel size.
	 */
	const int ops = VIPS_IMAGE_SIZEOF_PEL( conversion->out );

	int i;

	/* Loop for each input image. Scattered write is faster than
	 * scattered read.
	 */
	for( i = 0; i < bandary->n; i++ ) {
		/* Input pel size.
		 */
		int ips = VIPS_IMAGE_SIZEOF_PEL( in[i] );

		VipsPel * restrict p1;
		VipsPel * restrict q1;
		int x, z;

		q1 = q;
		p1 = p[i];

		for( x = 0; x < width; x++ ) {
			for( z = 0; z < ips; z++ )
				q1[z] = p1[z];

			p1 += ips;
			q1 += ops;
		}

		q += ips;
	}
}
Beispiel #14
0
/* Paint r of region or. It's a border area, lying entirely within 
 * embed->border[i]. p points to the top-left source pixel to fill with. 
 * plsk is the line stride.
 */
static void
vips_embed_paint_edge( VipsEmbed *embed, 
	VipsRegion *or, int i, VipsRect *r, VipsPel *p, int plsk )
{
	const int bs = VIPS_IMAGE_SIZEOF_PEL( embed->in );

	VipsRect todo;
	VipsPel *q;
	int y;

	VIPS_GATE_START( "vips_embed_paint_edge: work" );

	/* Pixels left to paint.
	 */
	todo = *r;

	/* Corner pieces ... copy the single pixel to paint the top line of
	 * todo, then use the line copier below to paint the rest of it.
	 */
	if( i > 3 ) {
		q = VIPS_REGION_ADDR( or, todo.left, todo.top );
		vips_embed_copy_pixel( embed, q, p, todo.width );

		p = q;
		todo.top += 1;
		todo.height -= 1;
	}

	if( i == 1 || i == 3 ) {
		/* Vertical line of pixels to copy.
		 */
		for( y = 0; y < todo.height; y++ ) {
			q = VIPS_REGION_ADDR( or, todo.left, todo.top + y );
			vips_embed_copy_pixel( embed, q, p, todo.width );
			p += plsk;
		}
	}
	else {
		/* Horizontal line of pixels to copy.
		 */
		for( y = 0; y < todo.height; y++ ) {
			q = VIPS_REGION_ADDR( or, todo.left, todo.top + y );
			memcpy( q, p, bs * todo.width );
		}
	}

	VIPS_GATE_STOP( "vips_embed_paint_edge: work" );
}
Beispiel #15
0
/* Fetch one pixel at a time ... good for very large shrinks.
 */
static int
vips_subsample_point_gen( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	VipsSubsample *subsample = (VipsSubsample *) b;
	VipsImage *in = (VipsImage *) a;
	VipsRect *r = &or->valid;
	int le = r->left;
	int ri = VIPS_RECT_RIGHT( r );
	int to = r->top;
	int bo = VIPS_RECT_BOTTOM(r);
	int ps = VIPS_IMAGE_SIZEOF_PEL( in );

	VipsRect s;
	int x, y;
	int k;

	/* Loop down the region.
	 */
	for( y = to; y < bo; y++ ) {
		VipsPel *q = VIPS_REGION_ADDR( or, le, y );
		VipsPel *p;

		/* Loop across the region, in owidth sized pieces.
		 */
		for( x = le; x < ri; x++ ) {
			/* Ask for input.
			 */
			s.left = x * subsample->xfac;
			s.top = y * subsample->yfac;
			s.width = 1;
			s.height = 1;
			if( vips_region_prepare( ir, &s ) )
				return( -1 );

			/* Append new pels to output.
			 */
			p = VIPS_REGION_ADDR( ir, s.left, s.top );
			for( k = 0; k < ps; k++ )
				q[k] = p[k];
			q += ps;
		}
	}

	return( 0 );
}
Beispiel #16
0
/* Copy rect from @from to @to.
 */
static void
copy_region( VipsRegion *from, VipsRegion *to, VipsRect *area )
{
	int y;

	/* Area should be inside both from and to.
	 */
	g_assert( vips_rect_includesrect( &from->valid, area ) );
	g_assert( vips_rect_includesrect( &to->valid, area ) );

	/* Loop down common area, copying.
	 */
	for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) {
		VipsPel *p = VIPS_REGION_ADDR( from, area->left, y );
		VipsPel *q = VIPS_REGION_ADDR( to, area->left, y );

		memcpy( q, p, VIPS_IMAGE_SIZEOF_PEL( from->im ) * area->width );
	}
}
Beispiel #17
0
/* Pack the pixels in @area from @in into a TIFF tile buffer.
 */
static void
pack2tiff( Write *write, Layer *layer, 
	VipsRegion *in, VipsRect *area, VipsPel *q )
{
	int y;

	/* JPEG compression can read outside the pixel area for edge tiles. It
	 * always compresses 8x8 blocks, so if the image width or height is
	 * not a multiple of 8, it can look beyond the pixels we will write.
	 *
	 * Black out the tile first to make sure these edge pixels are always
	 * zero.
	 */
	if( write->compression == COMPRESSION_JPEG &&
		(area->width < write->tilew || 
		 area->height < write->tileh) )
		memset( q, 0, TIFFTileSize( layer->tif ) );

	for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) {
		VipsPel *p = (VipsPel *) VIPS_REGION_ADDR( in, area->left, y );

		if( write->im->Coding == VIPS_CODING_LABQ )
			LabQ2LabC( q, p, area->width );
		else if( write->onebit ) 
			eightbit2onebit( write, q, p, area->width );
		else if( (in->im->Bands == 1 || in->im->Bands == 2) && 
			write->miniswhite ) 
			invert_band0( write, q, p, area->width );
		else if( write->im->BandFmt == VIPS_FORMAT_SHORT &&
			write->im->Type == VIPS_INTERPRETATION_LABS )
			LabS2Lab16( q, p, area->width );
		else
			memcpy( q, p, 
				area->width * 
				 VIPS_IMAGE_SIZEOF_PEL( write->im ) );

		q += write->tls;
	}
}
Beispiel #18
0
static int
write_ppm_line_ascii( VipsImage *in, FILE *fp, VipsPel *p )
{
	const int sk = VIPS_IMAGE_SIZEOF_PEL( in );
	int x, k;

	for( x = 0; x < in->Xsize; x++ ) {
		for( k = 0; k < in->Bands; k++ ) {
			switch( in->BandFmt ) {
			case VIPS_FORMAT_UCHAR:
				fprintf( fp, "%d ", p[k] );
				break;

			case VIPS_FORMAT_USHORT:
				fprintf( fp, "%d ", ((unsigned short *) p)[k] );
				break;

			case VIPS_FORMAT_UINT:
				fprintf( fp, "%d ", ((unsigned int *) p)[k] );
				break;

			default:
				g_assert( 0 );
			}
		}

		fprintf( fp, " " );

		p += sk;
	}

	if( !fprintf( fp, "\n" ) ) {
		vips_error( "vips2ppm", 
			"%s", _( "write error ... disc full?" ) );
		return( -1 );
	}

	return( 0 );
}
Beispiel #19
0
static int
vips_bandunfold_gen( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
	VipsBandunfold *bandunfold = (VipsBandunfold *) b;
	VipsRegion *ir = (VipsRegion *) seq;
	VipsImage *in = ir->im;
	VipsImage *out = or->im;
	VipsRect *r = &or->valid;
	int esize = VIPS_IMAGE_SIZEOF_ELEMENT( in );
	int psize = VIPS_IMAGE_SIZEOF_PEL( out );

	VipsRect need;
	int y;

	need.left = r->left / bandunfold->factor;
	need.top = r->top;
	need.width = (1 + r->width) / bandunfold->factor;
	need.height = r->height;
	if( vips_region_prepare( ir, &need ) )
		return( -1 );

	for( y = 0; y < r->height; y++ ) {
		VipsPel *p = VIPS_REGION_ADDR( ir, 
			r->left / bandunfold->factor, r->top + y ) + 
			(r->left % bandunfold->factor) * esize;
		VipsPel *q = VIPS_REGION_ADDR( or, r->left, r->top + y );

		/* We can't use vips_region_region() since we change pixel
		 * coordinates.
		 */
		memcpy( q, p, r->width * psize );
	}

	return( 0 );
}
Beispiel #20
0
/* Subsample a VipsRegion. We fetch in VIPS_MAX_WIDTH pixel-wide strips, 
 * left-to-right across the input.
 */
static int
vips_subsample_line_gen( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	VipsSubsample *subsample = (VipsSubsample *) b;
	VipsImage *in = (VipsImage *) a;
	VipsRect *r = &or->valid;
	int le = r->left;
	int ri = VIPS_RECT_RIGHT( r );
	int to = r->top;
	int bo = VIPS_RECT_BOTTOM( r );
	int ps = VIPS_IMAGE_SIZEOF_PEL( in );
	int owidth = VIPS_MAX_WIDTH / subsample->xfac;

	VipsRect s;
	int x, y;
	int z, k;

	/* Loop down the region.
	 */
	for( y = to; y < bo; y++ ) {
		VipsPel *q = VIPS_REGION_ADDR( or, le, y );
		VipsPel *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 = VIPS_MIN( owidth, ri - x );

			/* Ask for this many from input ... can save a 
			 * little here!
			 */
			int iw = ow * subsample->xfac - (subsample->xfac - 1);

			/* Ask for input.
			 */
			s.left = x * subsample->xfac;
			s.top = y * subsample->yfac;
			s.width = iw;
			s.height = 1;
			if( vips_region_prepare( ir, &s ) )
				return( -1 );

			/* Append new pels to output.
			 */
			p = VIPS_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 * subsample->xfac;
			}
		}
	}

	return( 0 );
}
Beispiel #21
0
static int
vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	const VipsAffine *affine = (VipsAffine *) b;
	const VipsImage *in = (VipsImage *) a;
	const int window_size = 
		vips_interpolate_get_window_size( affine->interpolate );
	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 VipsRect *r = &or->valid;
	const int le = r->left;
	const int ri = VIPS_RECT_RIGHT( r );
	const int to = r->top;
	const int bo = VIPS_RECT_BOTTOM( r );

	const VipsRect *iarea = &affine->trn.iarea;
	const VipsRect *oarea = &affine->trn.oarea;

	int ps = VIPS_IMAGE_SIZEOF_PEL( in );
	int x, y, z;
	
	VipsRect 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.
	 */
	vips__transform_invert_rect( &affine->trn, &want, &need );

	/* That does round-to-nearest, because it has to stop rounding errors
	 * growing images unexpectedly. We need round-down, so we must
	 * add half a pixel along the left and top. But we are int :( so add 1
	 * pixel. 
	 *
	 * Add an extra line along the right and bottom as well, for rounding.
	 */
	vips_rect_marginadjust( &need, 1 );

	/* Now go to space (2) above.
	 */
	need.left += iarea->left;
	need.top += iarea->top;

	/* Add a border for interpolation. 
	 */
	need.width += window_size - 1;
	need.height += window_size - 1;
	need.left -= window_offset; 
	need.top -= window_offset;

	/* Clip against the size of (2).
	 */
	image.left = 0;
	image.top = 0;
	image.width = in->Xsize;
	image.height = in->Ysize;
	vips_rect_intersectrect( &need, &image, &clipped );

	/* Outside input image? All black.
	 */
	if( vips_rect_isempty( &clipped ) ) {
		vips_region_black( or );
		return( 0 );
	}

	/* We do need some pixels from the input image to make our output -
	 * ask for them.
	 */
	if( vips_region_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.odx;
		const double oy = y + oarea->top - affine->trn.ody;

		/* Continuous cods in input space.
		 */
		double ix, iy;

		VipsPel *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;

		/* And the input offset.
		 */
		ix -= affine->trn.idx;
		iy -= affine->trn.idy;

		q = VIPS_REGION_ADDR( or, le, y );

		for( x = le; x < ri; x++ ) {
			int fx, fy; 	

			fx = FAST_PSEUDO_FLOOR( ix );
			fy = FAST_PSEUDO_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 #22
0
static int
vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	const VipsAffine *affine = (VipsAffine *) b;
	const VipsImage *in = (VipsImage *) a;
	const int window_size = 
		vips_interpolate_get_window_size( affine->interpolate );
	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 VipsRect *r = &or->valid;
	const int le = r->left;
	const int ri = VIPS_RECT_RIGHT( r );
	const int to = r->top;
	const int bo = VIPS_RECT_BOTTOM( r );

	const VipsRect *iarea = &affine->trn.iarea;
	const VipsRect *oarea = &affine->trn.oarea;

	int ps = VIPS_IMAGE_SIZEOF_PEL( in );
	int x, y, z;
	
	VipsRect image, want, need, clipped;

#ifdef DEBUG_VERBOSE
	printf( "vips_affine_gen: "
		"generating left=%d, top=%d, width=%d, height=%d\n", 
		r->left,
		r->top,
		r->width,
		r->height );
#endif /*DEBUG_VERBOSE*/

	/* We are generating this chunk of the transformed image. This takes
	 * us to space 4.
	 */
	want = *r;
	want.left += oarea->left;
	want.top += oarea->top;

	/* Find the area of the input image we need. This takes us to space 3. 
	 */
	vips__transform_invert_rect( &affine->trn, &want, &need );

	/* That does round-to-nearest, because it has to stop rounding errors
	 * growing images unexpectedly. We need round-down, so we must
	 * add half a pixel along the left and top. But we are int :( so add 1
	 * pixel. 
	 *
	 * Add an extra line along the right and bottom as well, for rounding.
	 */
	vips_rect_marginadjust( &need, 1 );

	/* We need to fetch a larger area for the interpolator.
	 */
	need.left -= window_offset;
	need.top -= window_offset;
	need.width += window_size - 1;
	need.height += window_size - 1;

	/* Now go to space 2, the expanded input image. This is the one we
	 * read pixels from. 
	 */
	need.left += window_offset;
	need.top += window_offset;

	/* Clip against the size of (2).
	 */
	image.left = 0;
	image.top = 0;
	image.width = in->Xsize;
	image.height = in->Ysize;
	vips_rect_intersectrect( &need, &image, &clipped );

#ifdef DEBUG_VERBOSE
	printf( "vips_affine_gen: "
		"preparing left=%d, top=%d, width=%d, height=%d\n", 
		clipped.left,
		clipped.top,
		clipped.width,
		clipped.height );
#endif /*DEBUG_VERBOSE*/

	if( vips_rect_isempty( &clipped ) ) {
		vips_region_black( or );
		return( 0 );
	}
	if( vips_region_prepare( ir, &clipped ) )
		return( -1 );

	VIPS_GATE_START( "vips_affine_gen: work" ); 

	/* Resample! x/y loop over pixels in the output image (5).
	 */
	for( y = to; y < bo; y++ ) {
		/* Input clipping rectangle. We offset this so we can clip in
		 * space 2. 
		 */
		const int ile = iarea->left + window_offset;
		const int ito = iarea->top + window_offset;
		const int iri = ile + iarea->width;
		const int ibo = ito + 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.odx;
		const double oy = y + oarea->top - affine->trn.ody;

		/* Continuous cods in input space.
		 */
		double ix, iy;

		VipsPel *q;

		/* To (3).
		 */
		ix = affine->trn.ia * ox + affine->trn.ib * oy;
		iy = affine->trn.ic * ox + affine->trn.id * oy;

		/* And the input offset in (3). 
		 */
		ix -= affine->trn.idx;
		iy -= affine->trn.idy;

		/* Finally to 2. 
		 */
		ix += window_offset;
		iy += window_offset;

		q = VIPS_REGION_ADDR( or, le, y );

		for( x = le; x < ri; x++ ) {
			int fx, fy; 	

			fx = FAST_PSEUDO_FLOOR( ix );
			fy = FAST_PSEUDO_FLOOR( iy );

			/* Clip against iarea.
			 */
			if( fx >= ile &&
				fx < iri &&
				fy >= ito &&
				fy < ibo ) {
				/* Verify that we can read the whole stencil.
				 * With DEBUG on this will range-check.
				 */
				g_assert( VIPS_REGION_ADDR( ir, 
					(int) ix - window_offset,
					(int) iy - window_offset ) );
				g_assert( VIPS_REGION_ADDR( ir, 
					(int) ix - window_offset + 
						window_size - 1,
					(int) iy - window_offset + 
						window_size - 1 ) );

				interpolate( affine->interpolate, 
					q, ir, ix, iy );
			}
			else {
				for( z = 0; z < ps; z++ ) 
					q[z] = 0;
			}

			ix += ddx;
			iy += ddy;
			q += ps;
		}
	}

	VIPS_GATE_STOP( "vips_affine_gen: work" ); 

	return( 0 );
}
Beispiel #23
0
/* Make a pair of vector constants into a set of formatted pixels. bands can
 * be 3 while n is 1, meaning expand the constant to the number of bands. 
 * imag can be NULL, meaning all zero for the imaginary component.
 */
VipsPel *
vips__vector_to_pels( const char *domain, 
	int bands, VipsBandFormat format, VipsCoding coding, 
	double *real, double *imag, int n )
{
	/* Run our pipeline relative to this.
	 */
	VipsImage *context = vips_image_new(); 

	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( context ), 8 );

	VipsImage *in;
	double *ones;
	VipsPel *result;
	int i;

#ifdef VIPS_DEBUG
	printf( "vips__vector_to_pels: starting\n" );
#endif /*VIPS_DEBUG*/

	ones = VIPS_ARRAY( context, n, double );
	for( i = 0; i < n; i++ )
		ones[i] = 1.0;

	/* Make the real and imaginary parts.
	 */
	if( vips_black( &t[0], 1, 1, "bands", bands, NULL ) ||
		vips_linear( t[0], &t[1], ones, real, n, NULL ) ) {
		g_object_unref( context );
		return( NULL );
	}
	in = t[1];

	if( imag ) { 
		if( vips_black( &t[2], 1, 1, "bands", bands, NULL ) ||
			vips_linear( t[2], &t[3], ones, imag, n, NULL ) ||
			vips_complexform( in, t[3], &t[4], NULL ) ) {
			g_object_unref( context );
			return( NULL );
		}
		in = t[4];
	}

	/* Cast to the output type and coding. 
	 */
	if( vips_cast( in, &t[5], format, NULL ) ||
		vips_image_encode( t[5], &t[6], coding ) ) {
		g_object_unref( context );
		return( NULL );
	}
	in = t[6];

	/* Write to memory, copy to output buffer. 
	 */
	if( !(t[7] = vips_image_new_memory()) ||
		vips_image_write( in, t[7] ) ) {
		g_object_unref( context );
		return( NULL );
	}
	in = t[7];

	if( !(result = 
		VIPS_ARRAY( NULL, VIPS_IMAGE_SIZEOF_PEL( in ), VipsPel )) ) {
		g_object_unref( context );
		return( NULL );
	}

	memcpy( result, in->data, VIPS_IMAGE_SIZEOF_PEL( in ) ); 

#ifdef VIPS_DEBUG
{
	int i;

	printf( "vips__vector_to_ink:\n" );
	printf( "\t(real, imag) = " ); 
	for( i = 0; i < n; i++ )
		printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 );
	printf( "\n" ); 
	printf( "\tink = " ); 
	for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( in ); i++ )
		printf( "%d ", result[i] );
	printf( "\n" ); 
}
#endif /*VIPS_DEBUG*/

	g_object_unref( context );

	return( result ); 
}
Beispiel #24
0
static int
vips_ifthenelse_gen( VipsRegion *or, void *seq, void *client1, void *client2,
	gboolean *stop )
{
	VipsRegion **ir = (VipsRegion **) seq;
	VipsIfthenelse *ifthenelse = (VipsIfthenelse *) client2;
	VipsRect *r = &or->valid;
	int le = r->left;
	int to = r->top;
	int bo = VIPS_RECT_BOTTOM( r );

	VipsImage *c = ir[2]->im;
	VipsImage *a = ir[0]->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 = VIPS_IMAGE_SIZEOF_PEL( a );
		width = r->width;
	}
	else {
		/* Copying ELEMENT sized-units with an n-band conditional.
		 */
		size = VIPS_IMAGE_SIZEOF_ELEMENT( a );
		width = r->width * a->Bands;
	}

	if( vips_region_prepare( ir[2], 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 *) VIPS_REGION_ADDR( ir[2], le, to )) == 0;
	alln0 = *((PEL *) VIPS_REGION_ADDR( ir[2], le, to )) != 0;
	for( y = to; y < bo; y++ ) {
		PEL *p = (PEL *) VIPS_REGION_ADDR( ir[2], 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( vips_region_prepare( ir[0], r ) ||
			vips_region_region( or, ir[0], r, r->left, r->top ) )
			return( -1 );
	}
	else if( all0 ) {
		/* All zero. Point or at the else image.
		 */
		if( vips_region_prepare( ir[1], r ) ||
			vips_region_region( or, ir[1], r, r->left, r->top ) )
			return( -1 );
	}
	else {
		/* Mix of set and clear ... ask for both then and else parts 
		 * and interleave.
		 */
		if( vips_region_prepare( ir[0], r ) || 
			vips_region_prepare( ir[1], r ) ) 
			return( -1 );

		for( y = to; y < bo; y++ ) {
			PEL *ap = (PEL *) VIPS_REGION_ADDR( ir[0], le, y );
			PEL *bp = (PEL *) VIPS_REGION_ADDR( ir[1], le, y );
			PEL *cp = (PEL *) VIPS_REGION_ADDR( ir[2], le, y );
			PEL *q = (PEL *) VIPS_REGION_ADDR( or, le, y );

			if( ifthenelse->blend ) {
				if( c->Bands == 1 ) 
					vips_blend1_buffer( q, 
						cp, ap, bp, r->width, a );
				else
					vips_blendn_buffer( q, 
						cp, ap, bp, r->width, a );
			}
			else {
				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 );
}
Beispiel #25
0
/* This can work inplace, ie. in == out is allowed.
 */
static void
vips_rot45_rot45( VipsImage *out, VipsImage *in )
{
	size_t ps = VIPS_IMAGE_SIZEOF_PEL( in ); 
	VipsPel *temp = VIPS_ARRAY( in, ps, VipsPel ); 
	int size = in->Xsize; 
	int size_2 = size / 2;

	int x, y;

	g_assert( in->Xsize == in->Ysize ); 
	g_assert( out->Xsize == out->Ysize ); 
	g_assert( in->Xsize == out->Xsize ); 
	g_assert( in->Xsize % 2 == 1 );

	/* Split the square into 8 triangles. Loop over the top-left one,
	 * reflect to index the others.
	 *
	 * 	1 1 2 2 3
	 * 	8 1 2 3 3
	 * 	8 8 x 4 4
	 * 	7 7 6 5 4
	 * 	7 6 6 5 5 
	 *
	 * do the centre separately.
	 */

	for( y = 0; y < size_2; y++ )  
		for( x = y; x < size_2; x++ ) {
			/* Save 1, it goes into 2 at the end.
			 */
			POINT_TO_TEMP( temp, x, y ); 

			/* Fill 1 from 8.
			 */
			ASSIGN( x, y, 
				y, size_2 - (x - y) );

			/* 8 from 7.
			 */
			ASSIGN( y, size_2 - (x - y),
				y, (size - 1) - x ); 

			/* 7 from 6.
			 */
			ASSIGN( y, (size - 1) - x,
				size_2 - (x - y), (size - 1) - y );

			/* 6 from 5.
			 */
			ASSIGN( size_2 - (x - y), (size - 1) - y,
				(size - 1) - x, (size - 1) - y ); 

			/* 5 from 4. 
			 */
			ASSIGN( (size - 1) - x, (size - 1) - y,
				(size - 1) - y, (x - y) + size_2 );

			/* 4 from 3. 
			 */
			ASSIGN( (size - 1) - y, (x - y) + size_2,
				(size - 1) - y, x );

			/* 3 from 2.
			 */
			ASSIGN( (size - 1) - y, x,
				(x - y) + size_2, y );

			/* 2 from saved 1. 
			 */
			TEMP_TO_POINT( (x - y) + size_2, y, temp ); 
		}

	/* Centre.
	 */
	ASSIGN( size_2, size_2, size_2, size_2 ); 
}
Beispiel #26
0
static int
vips_quadratic_gen( VipsRegion *or, void *vseq, 
	void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) vseq;
	VipsQuadratic *quadratic = (VipsQuadratic *) b;
	VipsResample *resample = VIPS_RESAMPLE( quadratic );
	VipsInterpolateMethod interpolate_fn = 
		vips_interpolate_get_method( quadratic->interpolate );

	/* @in is the enlarged image (borders on, after vips_embed()). Use
	 * @resample->in for the original, not-expanded image. 
	 */
	const VipsImage *in = (VipsImage *) a;

	const int ps = VIPS_IMAGE_SIZEOF_PEL( in );

	double *vec = (double *) VIPS_IMAGE_ADDR( quadratic->mat, 0, 0 );

	int clip_width = resample->in->Xsize;
	int clip_height = resample->in->Ysize;

	int xlow = or->valid.left;
	int ylow = or->valid.top;
	int xhigh = VIPS_RECT_RIGHT( &or->valid );
	int yhigh = VIPS_RECT_BOTTOM( &or->valid );

	VipsPel *q;

	int xo, yo;		/* output coordinates, dstimage */
	int z;
	double fxi, fyi; 	/* input coordinates */
	double dx, dy;        	/* xo derivative of input coord. */
	double ddx, ddy;      	/* 2nd xo derivative of input coord. */

	VipsRect image;

	image.left = 0;
	image.top = 0;
	image.width = in->Xsize;
	image.height = in->Ysize;
	if( vips_region_image( ir, &image ) )
		return( -1 );

	for( yo = ylow; yo < yhigh; yo++ ) {
		fxi = xlow + vec[0];                /* order 0 */
		fyi = yo + vec[1];    
		dx = 1.0;
		dy = 0.0;

		switch( quadratic->order ) {
		case 3: 
			fxi += vec[10] * yo * yo + vec[8] * xlow * xlow;
			fyi += vec[11] * yo * yo + vec[9] * xlow * xlow;
			dx += vec[8];
			ddx = vec[8] * 2.0;
			dy += vec[9];
			ddy = vec[9] * 2.0;

		case 2: 
			fxi += vec[6] * xlow * yo;
			fyi += vec[7] * xlow * yo;
			dx += vec[6] * yo;
			dy += vec[7] * yo;

		case 1: 
			fxi += vec[4] * yo + vec[2] * xlow;
			fyi += vec[5] * yo + vec[3] * xlow;
			dx += vec[2];
			dy += vec[3];

		case 0: 
			/* See above for order 0.
			 */
			break;

		default:
		    	g_assert( 0 );
		    	return(-7);
		}

		q = VIPS_REGION_ADDR( or, xlow, yo );

		for( xo = xlow; xo < xhigh; xo++ ) {
			int xi, yi; 	

			xi = fxi;
			yi = fyi;

			/* Clipping! 
			 */
			if( xi < 0 || 
				yi < 0 || 
				xi >= clip_width || 
				yi >= clip_height ) {
				for( z = 0; z < ps; z++ ) 
					q[z] = 0;
			}
			else 
				interpolate_fn( quadratic->interpolate, 
					q, ir, fxi, fyi );

			q += ps;

			fxi += dx;
			fyi += dy;

			if( quadratic->order > 2 ) {
				dx += ddx;
				dy += ddy;
			}
		}
	}

	return( 0 );
}
Beispiel #27
0
/* Paint the part of the region containing only part-pels.
 */
static void
vips_zoom_paint_part( VipsRegion *or, VipsRegion *ir, VipsZoom *zoom,
	const int left, const int right, const int top, const int bottom )
{
	const int ps = VIPS_IMAGE_SIZEOF_PEL( ir->im );
	const int ls = VIPS_REGION_LSKIP( or );
	const int rs = ps * (right - left);

	/* Start position in input.
	 */
	const int ix = left / zoom->xfac;
	const int iy = top / zoom->yfac;

	/* Pels down to yfac boundary, pels down to bottom. Do the smallest of
	 * these for first y loop.
	 */
	const int ptbound = (iy + 1) * zoom->yfac - top;
	const int ptbot = bottom - top;

	int yt = VIPS_MIN( ptbound, ptbot );

	int x, y, z, i;

	/* Only know this.
	 */
	g_assert( right - left >= 0 && bottom - top >= 0 );

	/* Have to loop over output.
	 */
	for( y = top; y < bottom; ) {
		VipsPel *p = VIPS_REGION_ADDR( ir, ix, y / zoom->yfac );
		VipsPel *q = VIPS_REGION_ADDR( or, left, y );
		VipsPel *r;

		/* Output pels until we jump the input pointer.
		 */
		int xt = (ix + 1) * zoom->xfac - left;

		/* Loop for this output line.
		 */
		r = q;
		for( x = left; x < right; x++ ) {
			/* Copy 1 pel.
			 */
			for( i = 0; i < ps; i++ )
				r[i] = p[i];
			r += ps;

			/* Move input if on boundary.
			 */
			--xt;
			if( xt == 0 ) {
				xt = zoom->xfac;
				p += ps;
			}
		}

		/* Repeat that output line until the bottom of this pixel
		 * boundary, or we hit bottom.
		 */
		r = q + ls;
		for( z = 1; z < yt; z++ ) {
			memcpy( r, q, rs );
			r += ls;
		}

		/* Move y on by the number of lines we wrote.
		 */
		y += yt;

		/* Reset yt for next iteration.
		 */
		yt = zoom->yfac;
	}
}
Beispiel #28
0
/* Make and init a Write.
 */
static Write *
write_new( VipsImage *im, const char *filename,
	VipsForeignTiffCompression compression, int Q, 
		VipsForeignTiffPredictor predictor,
	char *profile,
	gboolean tile, int tile_width, int tile_height,
	gboolean pyramid,
	gboolean squash,
	gboolean miniswhite,
	VipsForeignTiffResunit resunit, double xres, double yres,
	gboolean bigtiff,
	gboolean rgbjpeg,
	gboolean properties,
	gboolean strip )
{
	Write *write;

	if( !(write = VIPS_NEW( im, Write )) )
		return( NULL );
	write->im = im;
	write->filename = vips_strdup( VIPS_OBJECT( im ), filename );
	write->layer = NULL;
	write->tbuf = NULL;
	write->compression = get_compression( compression );
	write->jpqual = Q;
	write->predictor = predictor;
	write->tile = tile;
	write->tilew = tile_width;
	write->tileh = tile_height;
	write->pyramid = pyramid;
	write->onebit = squash;
	write->miniswhite = miniswhite;
	write->icc_profile = vips_strdup( NULL, profile );
	write->bigtiff = bigtiff;
	write->rgbjpeg = rgbjpeg;
	write->properties = properties;
	write->strip = strip;

	write->resunit = get_resunit( resunit );
	write->xres = xres;
	write->yres = yres;

	/* In strip mode we use tileh to set rowsperstrip, and that does not
	 * have the multiple-of-16 restriction.
	 */
	if( tile ) { 
		if( (write->tilew & 0xf) != 0 || 
			(write->tileh & 0xf) != 0 ) {
			vips_error( "vips2tiff", 
				"%s", _( "tile size not a multiple of 16" ) );
			return( NULL );
		}
	}

	/* We can only pyramid LABQ and non-complex images. 
	 */
	if( write->pyramid ) {
		if( im->Coding == VIPS_CODING_NONE && 
			vips_band_format_iscomplex( im->BandFmt ) ) {
			vips_error( "vips2tiff", 
				"%s", _( "can only pyramid LABQ and "
				"non-complex images" ) );
			return( NULL );
		}
	}

	/* Only 1-bit-ize 8 bit mono images.
	 */
	if( write->onebit &&
		(im->Coding != VIPS_CODING_NONE || 
			im->BandFmt != VIPS_FORMAT_UCHAR ||
			im->Bands != 1) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only squash 1 band uchar images -- "
				"disabling squash" ) );
		write->onebit = 0;
	}

	if( write->onebit && 
		write->compression == COMPRESSION_JPEG ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) );
		write->compression = COMPRESSION_NONE;
	}
 
	/* We can only MINISWHITE non-complex images of 1 or 2 bands.
	 */
	if( write->miniswhite &&
		(im->Coding != VIPS_CODING_NONE || 
			vips_band_format_iscomplex( im->BandFmt ) ||
			im->Bands > 2) ) {
		vips_warn( "vips2tiff", 
			"%s", _( "can only save non-complex greyscale images "
				"as miniswhite -- disabling miniswhite" ) );
		write->miniswhite = FALSE;
	}

	/* Sizeof a line of bytes in the TIFF tile.
	 */
	if( im->Coding == VIPS_CODING_LABQ )
		write->tls = write->tilew * 3;
	else if( write->onebit )
		write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8;
	else
		write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew;

	/* Build the pyramid framework.
	 */
	write->layer = pyramid_new( write, NULL, im->Xsize, im->Ysize );

	/* Fill all the layers.
	 */
	if( pyramid_fill( write ) ) {
		write_free( write );
		return( NULL );
	}

	if( tile ) 
		write->tbuf = vips_malloc( NULL, 
			TIFFTileSize( write->layer->tif ) );
	else
		write->tbuf = vips_malloc( NULL, 
			TIFFScanlineSize( write->layer->tif ) );
	if( !write->tbuf ) {
		write_free( write );
		return( NULL );
	}

	return( write );
}
Beispiel #29
0
static int
vips_mapim_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
{
	VipsRect *r = &or->valid;
	VipsRegion **ir = (VipsRegion **) seq;
	const VipsImage **in_array = (const VipsImage **) a;
	const VipsMapim *mapim = (VipsMapim *) b; 
	const VipsResample *resample = VIPS_RESAMPLE( mapim );
	const VipsImage *in = in_array[0];
	const int window_size = 
		vips_interpolate_get_window_size( mapim->interpolate );
	const int window_offset = 
		vips_interpolate_get_window_offset( mapim->interpolate );
	const VipsInterpolateMethod interpolate = 
		vips_interpolate_get_method( mapim->interpolate );
	const int ps = VIPS_IMAGE_SIZEOF_PEL( in );
	const int clip_width = resample->in->Xsize;
	const int clip_height = resample->in->Ysize;

	VipsRect bounds, image, clipped;
	int x, y, z;
	
#ifdef DEBUG_VERBOSE
	printf( "vips_mapim_gen: "
		"generating left=%d, top=%d, width=%d, height=%d\n", 
		r->left,
		r->top,
		r->width,
		r->height );
#endif /*DEBUG_VERBOSE*/

	/* Fetch the chunk of the mapim image we need, and find the max/min in
	 * x and y.
	 */
	if( vips_region_prepare( ir[1], r ) )
		return( -1 );

	VIPS_GATE_START( "vips_mapim_gen: work" ); 

	vips_mapim_region_minmax( ir[1], r, &bounds ); 

	VIPS_GATE_STOP( "vips_mapim_gen: work" ); 

	/* The bounding box of that area is what we will need from @in. Add
	 * enough for the interpolation stencil as well.
	 * 
	 */
	bounds.width += window_size - 1;
	bounds.height += window_size - 1;

	/* Clip against the expanded image.
	 */
	image.left = 0;
	image.top = 0;
	image.width = in->Xsize;
	image.height = in->Ysize;
	vips_rect_intersectrect( &bounds, &image, &clipped );

#ifdef DEBUG_VERBOSE
	printf( "vips_mapim_gen: "
		"preparing left=%d, top=%d, width=%d, height=%d\n", 
		clipped.left,
		clipped.top,
		clipped.width,
		clipped.height );
#endif /*DEBUG_VERBOSE*/

	if( vips_rect_isempty( &clipped ) ) {
		vips_region_black( or );
		return( 0 );
	}
	if( vips_region_prepare( ir[0], &clipped ) )
		return( -1 );

	VIPS_GATE_START( "vips_mapim_gen: work" ); 

	/* Resample! x/y loop over pixels in the output image (5).
	 */
	for( y = 0; y < r->height; y++ ) {
		VipsPel * restrict p = 
			VIPS_REGION_ADDR( ir[1], r->left, y + r->top );
		VipsPel * restrict q = 
			VIPS_REGION_ADDR( or, r->left, y + r->top );

		switch( ir[1]->im->BandFmt ) {
		case VIPS_FORMAT_UCHAR: 	
			ULOOKUP( unsigned char ); break; 
		case VIPS_FORMAT_CHAR: 	
			LOOKUP( signed char ); break; 
		case VIPS_FORMAT_USHORT: 
			ULOOKUP( unsigned short ); break; 
		case VIPS_FORMAT_SHORT: 	
			LOOKUP( signed short ); break; 
		case VIPS_FORMAT_UINT: 	
			ULOOKUP( unsigned int ); break; 
		case VIPS_FORMAT_INT: 	
			LOOKUP( signed int ); break; 

		case VIPS_FORMAT_FLOAT: 		
		case VIPS_FORMAT_COMPLEX: 
			LOOKUP( float ); break; 
			break;

		case VIPS_FORMAT_DOUBLE:	
		case VIPS_FORMAT_DPCOMPLEX: 
			LOOKUP( double ); break;

		default:
			g_assert_not_reached();
		}
	}

	VIPS_GATE_STOP( "vips_mapim_gen: work" ); 

	return( 0 );
}
Beispiel #30
0
/* Calculate a pixel for an image from a vec of double. Valid while im is
 * valid. imag can be NULL, meaning all zero for the imaginary component.
 */
VipsPel *
vips__vector_to_ink( const char *domain, 
	VipsImage *im, double *real, double *imag, int n )
{
	/* Run our pipeline relative to this.
	 */
	VipsImage *context = vips_image_new(); 

	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( context ), 6 );

	VipsBandFormat format;
	int bands; 
	double *ones;
	VipsPel *result;
	int i;

#ifdef VIPS_DEBUG
	printf( "vips__vector_to_ink: starting\n" );
#endif /*VIPS_DEBUG*/

	vips_image_decode_predict( im, &bands, &format );
	ones = VIPS_ARRAY( im, n, double );
	for( i = 0; i < n; i++ )
		ones[i] = 1.0;

	/* Cast vec to match the decoded image.
	 */
	if( vips_black( &t[1], 1, 1, "bands", bands, NULL ) ||
		vips_linear( t[1], &t[2], ones, real, n, NULL ) || 
		vips_cast( t[2], &t[3], format, NULL ) ) {
		g_object_unref( context );
		return( NULL );
	}

	/* And now recode the vec to match the original im.
	 */
	if( vips_image_encode( t[3], &t[4], im->Coding ) || 
		!(t[5] = vips_image_new_memory()) ||
		vips_image_write( t[4], t[5] ) ) {
		g_object_unref( context );
		return( NULL );
	}

	if( !(result = 
		VIPS_ARRAY( im, VIPS_IMAGE_SIZEOF_PEL( t[5] ), VipsPel )) ) {
		g_object_unref( context );
		return( NULL );
	}

	g_assert( VIPS_IMAGE_SIZEOF_PEL( t[5] ) == 
		VIPS_IMAGE_SIZEOF_PEL( im ) ); 

	memcpy( result, t[5]->data, VIPS_IMAGE_SIZEOF_PEL( im ) ); 

	g_object_unref( context );

#ifdef VIPS_DEBUG
{
	int i;

	printf( "vips__vector_to_ink:\n" );
	printf( "\t(real, imag) = " ); 
	for( i = 0; i < n; i++ )
		printf( "(%g, %g) ", real[i], imag ? imag[i] : 0 );
	printf( "\n" ); 
	printf( "\tink = " ); 
	for( i = 0; i < VIPS_IMAGE_SIZEOF_PEL( im ); i++ )
		printf( "%d ", result[i] );
	printf( "\n" ); 
}
#endif /*VIPS_DEBUG*/

	return( result ); 
}