Пример #1
0
static int
vips_shrink_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop )
{
	VipsShrinkSequence *seq = (VipsShrinkSequence *) vseq;
	VipsShrink *shrink = (VipsShrink *) b;
	VipsRegion *ir = seq->ir;
	VipsRect *r = &or->valid;

	/* How do we chunk up the image? We don't want to prepare the whole of
	 * the input region corresponding to *r since it could be huge. 
	 *
	 * Each pixel of *r will depend on roughly mw x mh
	 * pixels, so we walk *r in chunks which map to the tile size.
	 *
	 * Make sure we can't ask for a zero step.
	 */
	int xstep = shrink->mw > VIPS__TILE_WIDTH ? 
		1 : VIPS__TILE_WIDTH / shrink->mw;
	int ystep = shrink->mh > VIPS__TILE_HEIGHT ? 
		1 : VIPS__TILE_HEIGHT / shrink->mh;

	int x, y;

#ifdef DEBUG
	printf( "vips_shrink_gen: generating %d x %d at %d x %d\n",
		r->width, r->height, r->left, r->top ); 
#endif /*DEBUG*/

	for( y = 0; y < r->height; y += ystep )  
		for( x = 0; x < r->width; x += xstep ) { 
			/* Clip the this rect against the demand size.
			 */
			int width = VIPS_MIN( xstep, r->width - x );
			int height = VIPS_MIN( ystep, r->height - y );

			VipsRect s;

			s.left = (r->left + x) * shrink->xshrink;
			s.top = (r->top + y) * shrink->yshrink;
			s.width = ceil( width * shrink->xshrink );
			s.height = ceil( height * shrink->yshrink );
#ifdef DEBUG
			printf( "shrink_gen: requesting %d x %d at %d x %d\n",
				s.width, s.height, s.left, s.top ); 
#endif /*DEBUG*/
			if( vips_region_prepare( ir, &s ) )
				return( -1 );

			vips_shrink_gen2( shrink, seq, 
				or, ir, 
				r->left + x, r->top + y, width, height );
		}

	return( 0 );
}
Пример #2
0
/* Return a ref to a window that encloses top/height.
 */
VipsWindow *
vips_window_ref( IMAGE *im, int top, int height )
{
	VipsWindow *window;

	g_mutex_lock( im->sslock );

	if( !(window = vips_window_find( im, top, height )) ) {
		/* No existing window ... make a new one. Ask for a larger
		 * window than we strictly need. There's no point making tiny
		 * windows.
		 */
		int margin = VIPS_MIN( vips__window_margin_pixels,
			vips__window_margin_bytes / 
				VIPS_IMAGE_SIZEOF_LINE( im ) );

		top -= margin;
		height += margin * 2;

		top = VIPS_CLIP( 0, top, im->Ysize - 1 );
		height = VIPS_CLIP( 0, height, im->Ysize - top );

		if( !(window = vips_window_new( im, top, height )) ) {
			g_mutex_unlock( im->sslock );
			return( NULL );
		}
	}

	g_mutex_unlock( im->sslock );

	return( window );
}
Пример #3
0
static int
vips_shrink_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop )
{
	VipsShrinkSequence *seq = (VipsShrinkSequence *) vseq;
	VipsShrink *shrink = (VipsShrink *) b;
	VipsRegion *ir = seq->ir;
	VipsRect *r = &or->valid;

	/* How do we chunk up the image? We don't want to prepare the whole of
	 * the input region corresponding to *r since it could be huge. 
	 *
	 * Each pixel of *r will depend on roughly mw x mh
	 * pixels, so we walk *r in chunks which map to the tile size.
	 *
	 * Make sure we can't ask for a zero step.
	 *
	 * We don't chunk horizontally. We want "vips shrink x.jpg b.jpg 100
	 * 100" to run sequentially. If we chunk horizontally, we will fetch
	 * 100x100 lines from the top of the image, then 100x100 100 lines
	 * down, etc. for each thread, then when they've finished, fetch
	 * 100x100, 100 pixels across from the top of the image. This will
	 * break sequentiality. 
	 */
	int ystep = shrink->mh > VIPS__TILE_HEIGHT ? 
		1 : VIPS__TILE_HEIGHT / shrink->mh;

	int y;

#ifdef DEBUG
	printf( "vips_shrink_gen: generating %d x %d at %d x %d\n",
		r->width, r->height, r->left, r->top ); 
#endif /*DEBUG*/

	for( y = 0; y < r->height; y += ystep ) {
		/* Clip the this rect against the demand size.
		 */
		int height = VIPS_MIN( ystep, r->height - y );

		VipsRect s;

		s.left = r->left * shrink->xshrink;
		s.top = (r->top + y) * shrink->yshrink;
		s.width = ceil( r->width * shrink->xshrink );
		s.height = ceil( height * shrink->yshrink );
#ifdef DEBUG
		printf( "shrink_gen: requesting %d x %d at %d x %d\n",
			s.width, s.height, s.left, s.top ); 
#endif /*DEBUG*/
		if( vips_region_prepare( ir, &s ) )
			return( -1 );

		vips_shrink_gen2( shrink, seq, 
			or, ir, 
			r->left, r->top + y, r->width, height );
	}

	return( 0 );
}
Пример #4
0
static int
read_jpeg_generate( VipsRegion *or,
                    void *seq, void *a, void *b, gboolean *stop )
{
    VipsRect *r = &or->valid;
    ReadJpeg *jpeg = (ReadJpeg *) a;
    struct jpeg_decompress_struct *cinfo = &jpeg->cinfo;
    int sz = cinfo->output_width * cinfo->output_components;

    int y;

#ifdef DEBUG
    printf( "read_jpeg_generate: line %d, %d rows\n",
            r->top, r->height );
#endif /*DEBUG*/

    /* We're inside a tilecache where tiles are the full image width, so
     * this should always be true.
     */
    g_assert( r->left == 0 );
    g_assert( r->width == or->im->Xsize );
    g_assert( VIPS_RECT_BOTTOM( r ) <= or->im->Ysize );

    /* Tiles should always be on a 8-pixel boundary.
     */
    g_assert( r->top % 8 == 0 );

    /* Tiles should always be a strip in height, unless it's the final
     * strip.
     */
    g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) );

    /* Here for longjmp() from vips__new_error_exit().
     */
    if( setjmp( jpeg->eman.jmp ) )
        return( -1 );

    for( y = 0; y < r->height; y++ ) {
        JSAMPROW row_pointer[1];

        row_pointer[0] = (JSAMPLE *)
                         VIPS_REGION_ADDR( or, 0, r->top + y );

        jpeg_read_scanlines( cinfo, &row_pointer[0], 1 );

        if( jpeg->invert_pels ) {
            int x;

            for( x = 0; x < sz; x++ )
                row_pointer[0][x] = 255 - row_pointer[0][x];
        }
    }

    return( 0 );
}
Пример #5
0
static int
png2vips_generate( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
        VipsRect *r = &or->valid;
	Read *read = (Read *) a;

	int y;

#ifdef DEBUG
	printf( "png2vips_generate: line %d, %d rows\n", 
		r->top, r->height );
#endif /*DEBUG*/

	/* We're inside a tilecache where tiles are the full image width, so
	 * this should always be true.
	 */
	g_assert( r->left == 0 );
	g_assert( r->width == or->im->Xsize );
	g_assert( VIPS_RECT_BOTTOM( r ) <= or->im->Ysize );

	/* Tiles should always be a strip in height, unless it's the final
	 * strip.
	 */
	g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) ); 

	/* And check that y_pos is correct. It should be, since we are inside
	 * a vips_sequential().
	 */
	g_assert( r->top == read->y_pos ); 

	for( y = 0; y < r->height; y++ ) {
		png_bytep q = (png_bytep) VIPS_REGION_ADDR( or, 0, r->top + y );

		/* We need to catch and ignore errors from read_row().
		 */
		if( !setjmp( png_jmpbuf( read->pPng ) ) ) 
			png_read_row( read->pPng, q, NULL );
		else { 
#ifdef DEBUG
			printf( "png2vips_generate: png_read_row() failed, "
				"line %d\n", r->top + y ); 
			printf( "png2vips_generate: file %s\n", read->name );
			printf( "png2vips_generate: thread %p\n", 
				g_thread_self() );
#endif /*DEBUG*/
		}

		read->y_pos += 1;
	}

	return( 0 );
}
Пример #6
0
static int
vips__openslide_generate( VipsRegion *out, 
	void *seq, void *_rslide, void *unused, gboolean *stop )
{
	ReadSlide *rslide = _rslide;
	VipsRect *r = &out->valid;

	const char *error;
	int x, y;

	VIPS_DEBUG_MSG( "vips__openslide_generate: %dx%d @ %dx%d\n",
		r->width, r->height, r->left, r->top );

	/* Fill in tile-sized chunks. Some versions of OpenSlide can fail for
	 * very large requests.
	 */
	for( y = 0; y < r->height; y += TILE_HEIGHT ) 
		for( x = 0; x < r->width; x += TILE_WIDTH ) {
			int w = VIPS_MIN( TILE_WIDTH, r->width - x );
			int h = VIPS_MIN( TILE_HEIGHT, r->height - y );

			openslide_read_region( rslide->osr, 
				(uint32_t *) VIPS_REGION_ADDR( out, 
					r->left + x, r->top + y ),
				(r->left + x) * rslide->downsample, 
				(r->top + y) * rslide->downsample, 
				rslide->layer,
				w, h ); 
		}

	error = openslide_get_error( rslide->osr );
	if( error ) {
		vips_error( "openslide2vips", 
			_( "reading region: %s" ), error );

		return( -1 );
	}

	return( 0 );
}
Пример #7
0
/* Save an exif value to a string in a way that we can restore. We only bother
 * for the simple formats (that a client might try to change) though.
 *
 * Keep in sync with vips_exif_from_s() below.
 */
static void
vips_exif_to_s( ExifData *ed, ExifEntry *entry, VipsBuf *buf )
{
	unsigned long i;
	int iv;
	ExifRational rv;
	ExifSRational srv;
	char txt[256];

	if( entry->format == EXIF_FORMAT_ASCII )  {
		/* libexif does not null-terminate strings. Copy out and add
		 * the \0 ourselves.
		 */
		int len = VIPS_MIN( 254, entry->size ); 

		memcpy( txt, entry->data, len );
		txt[len] = '\0';
		vips_buf_appendf( buf, "%s ", txt );
	}
	else if( entry->components < 10 &&
		!vips_exif_get_int( ed, entry, 0, &iv ) ) {
		for( i = 0; i < entry->components; i++ ) {
			vips_exif_get_int( ed, entry, i, &iv );
			vips_buf_appendf( buf, "%d ", iv );
		}
	}
	else if( entry->components < 10 &&
		!vips_exif_get_rational( ed, entry, 0, &rv ) ) {
		for( i = 0; i < entry->components; i++ ) {
			vips_exif_get_rational( ed, entry, i, &rv );
			vips_buf_appendf( buf, "%u/%u ", 
				rv.numerator, rv.denominator );
		}
	}
	else if( entry->components < 10 &&
		!vips_exif_get_srational( ed, entry, 0, &srv ) ) {
		for( i = 0; i < entry->components; i++ ) {
			vips_exif_get_srational( ed, entry, i, &srv );
			vips_buf_appendf( buf, "%d/%d ", 
				srv.numerator, srv.denominator );
		}
	}
	else 
		vips_buf_appendf( buf, "%s ", 
			exif_entry_get_value( entry, txt, 256 ) );

	vips_buf_appendf( buf, "(%s, %s, %lu components, %d bytes)", 
		exif_entry_get_value( entry, txt, 256 ),
		exif_format_get_name( entry->format ),
		entry->components,
		entry->size );
}
Пример #8
0
/* Fetch a token. If it's a string token terminated by a '[', fetch up to the
 * matching ']' as well, for example ".jpg[Q=90]".
 *
 * Return NULL for end of tokens.
 */
const char *
vips__token_segment( const char *p, VipsToken *token, 
	char *string, int size )
{
	const char *q;

	if( !(q = vips__token_must( p, token, string, size )) )
		return( NULL ); 

	/* If we stopped on [, read up to the matching ]. 
	 */
	if( *token == VIPS_TOKEN_STRING &&
		q[0] == '[' ) {
		VipsToken sub_token;
		char sub_string[VIPS_PATH_MAX];
		int depth;
		int i; 

		depth = 0;
		do {
			if( !(q = vips__token_must( q, &sub_token, 
				sub_string, VIPS_PATH_MAX )) )
				return( NULL ); 

			switch( sub_token ) {
			case VIPS_TOKEN_LEFT:
				depth += 1;
				break;

			case VIPS_TOKEN_RIGHT:
				depth -= 1;
				break;

			default:
				break;
			}
		} while( !(sub_token == VIPS_TOKEN_RIGHT && depth == 0) );

		i = VIPS_MIN( q - p, size );
		vips_strncpy( string, p, i + 1 );
	}

	return( q ); 
}
Пример #9
0
/* Write tileh scanlines, less for the last strip.
 */
static int
layer_write_strip( Write *write, Layer *layer, VipsRegion *strip )
{
	VipsImage *im = layer->image;
	VipsRect *area = &strip->valid;
	int height = VIPS_MIN( write->tileh, area->height ); 

	int y;

#ifdef DEBUG_VERBOSE
	printf( "Writing %d pixel strip at height %d to image %s\n",
		height, area->top, TIFFFileName( layer->tif ) );
#endif /*DEBUG_VERBOSE*/

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

		/* Any repacking necessary.
		 */
		if( im->Coding == VIPS_CODING_LABQ ) {
			LabQ2LabC( write->tbuf, p, im->Xsize );
			p = write->tbuf;
		}
		else if( im->BandFmt == VIPS_FORMAT_SHORT &&
			im->Type == VIPS_INTERPRETATION_LABS ) {
			LabS2Lab16( write->tbuf, p, im->Xsize );
			p = write->tbuf;
		}
		else if( write->onebit ) {
			eightbit2onebit( write, write->tbuf, p, im->Xsize );
			p = write->tbuf;
		}
		else if( (im->Bands == 1 || im->Bands == 2) && 
			write->miniswhite ) {
			invert_band0( write, write->tbuf, p, im->Xsize );
			p = write->tbuf;
		}

		if( TIFFWriteScanline( layer->tif, p, area->top + y, 0 ) < 0 ) 
			return( -1 );
	}

	return( 0 );
}
Пример #10
0
static int
vips_worley_distance( VipsWorley *worley, Cell cells[9], int x, int y )
{
	int distance;

	int i, j;

	distance = worley->cell_size * 1.5;

	for( i = 0; i < 9; i++ ) {
		Cell *cell = &cells[i];

		for( j = 0; j < cell->n_features; j++ ) {
			int d = vips_hypot( 
				x - cell->feature_x[j], 
				y - cell->feature_y[j] );

			distance = VIPS_MIN( distance, d );
		}
	}

	return( distance );
}
Пример #11
0
/* Calculate the shrink factors. 
 *
 * We shrink in two stages: first, a shrink with a block average. This can
 * only accurately shrink by integer factors. We then do a second shrink with
 * a supplied interpolator to get the exact size we want.
 */
static int
calculate_shrink( int width, int height, double *residual )
{
	/* Calculate the horizontal and vertical shrink we'd need to fit the
	 * image to the bounding box, and pick the biggest.
	 *
	 * In crop mode we aim to fill the bounding box, so we must use the
	 * smaller axis.
	 */
	double horizontal = (double) width / thumbnail_width;
	double vertical = (double) height / thumbnail_height;
	double factor = crop_image ?
		VIPS_MIN( horizontal, vertical ) : 
		VIPS_MAX( horizontal, vertical ); 

	/* If the shrink factor is <= 1.0, we need to zoom rather than shrink.
	 * Just set the factor to 1 in this case.
	 */
	double factor2 = factor < 1.0 ? 1.0 : factor;

	/* Int component of shrink.
	 */
	int shrink = floor( factor2 );

	if( residual ) {
		/* Width after int shrink.
		 */
		int iwidth = width / shrink;

		/* Therefore residual scale factor is.
		 */
		*residual = (width / factor) / iwidth; 
	}

	return( shrink );
}
Пример #12
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 );
}
Пример #13
0
/* Zoom a VipsRegion.
 */
static int
vips_zoom_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
{
	VipsRegion *ir = (VipsRegion *) seq;
	VipsZoom *zoom = (VipsZoom *) b;

	/* Output area we are building.
	 */
	const VipsRect *r = &or->valid;
	const int ri = VIPS_RECT_RIGHT( r );
	const int bo = VIPS_RECT_BOTTOM(r);

	VipsRect s;
	int left, right, top, bottom;
	int width, height;

	/* Area of input we need. We have to round out, as we may have
	 * part-pixels all around the edges.
	 */
	left = ROUND_DOWN( r->left, zoom->xfac );
	right = ROUND_UP( ri, zoom->xfac );
	top = ROUND_DOWN( r->top, zoom->yfac );
	bottom = ROUND_UP( bo, zoom->yfac );
	width = right - left;
	height = bottom - top;
	s.left = left / zoom->xfac;
	s.top = top / zoom->yfac;
	s.width = width / zoom->xfac;
	s.height = height / zoom->yfac;
	if( vips_region_prepare( ir, &s ) )
		return( -1 );
	
	/* Find the part of the output (if any) which uses only whole pels.
	 */
	left = ROUND_UP( r->left, zoom->xfac );
	right = ROUND_DOWN( ri, zoom->xfac );
	top = ROUND_UP( r->top, zoom->yfac );
	bottom = ROUND_DOWN( bo, zoom->yfac );
	width = right - left;
	height = bottom - top;

	/* Stage 1: we just paint the whole pels in the centre of the region.
	 * As we know they are not clipped, we can do it quickly.
	 */
	if( width > 0 && height > 0 ) 
		vips_zoom_paint_whole( or, ir, zoom, left, right, top, bottom );

	/* Just fractional pixels left. Paint in the top, left, right and
	 * bottom parts.
	 */
	if( top - r->top > 0 ) 
		/* Some top pixels.
		 */
		vips_zoom_paint_part( or, ir, zoom, 
			r->left, ri, r->top, VIPS_MIN( top, bo ) );
	if( left - r->left > 0 && height > 0 )
		/* Left pixels.
		 */
		vips_zoom_paint_part( or, ir, zoom, 
			r->left, VIPS_MIN( left, ri ), top, bottom );
	if( ri - right > 0 && height > 0 )
		/* Right pixels.
		 */
		vips_zoom_paint_part( or, ir, zoom, 
			VIPS_MAX( right, r->left ), ri, top, bottom );
	if( bo - bottom > 0 && height >= 0 )
		/* Bottom pixels.
		 */
		vips_zoom_paint_part( or, ir, zoom, 
			r->left, ri, VIPS_MAX( bottom, r->top ), bo );

	return( 0 );
}
Пример #14
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;
	}
}
Пример #15
0
static int
png2vips_generate( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
        VipsRect *r = &or->valid;
	Read *read = (Read *) a;

	int y;

#ifdef DEBUG
	printf( "png2vips_generate: line %d, %d rows\n", r->top, r->height );
	printf( "png2vips_generate: y_top = %d\n", read->y_pos );
#endif /*DEBUG*/

	/* We're inside a tilecache where tiles are the full image width, so
	 * this should always be true.
	 */
	g_assert( r->left == 0 );
	g_assert( r->width == or->im->Xsize );
	g_assert( VIPS_RECT_BOTTOM( r ) <= or->im->Ysize );

	/* Tiles should always be a strip in height, unless it's the final
	 * strip.
	 */
	g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) ); 

	/* And check that y_pos is correct. It should be, since we are inside
	 * a vips_sequential().
	 */
	if( r->top != read->y_pos ) {
		vips_error( "vipspng", 
			_( "out of order read at line %d" ), read->y_pos );
		return( -1 );
	}

	for( y = 0; y < r->height; y++ ) {
		png_bytep q = (png_bytep) VIPS_REGION_ADDR( or, 0, r->top + y );

		/* We need to catch and ignore errors from read_row().
		 */
		if( !setjmp( png_jmpbuf( read->pPng ) ) ) 
			png_read_row( read->pPng, q, NULL );
		else { 
#ifdef DEBUG
			printf( "png2vips_generate: png_read_row() failed, "
				"line %d\n", r->top + y ); 
			printf( "png2vips_generate: file %s\n", read->name );
			printf( "png2vips_generate: thread %p\n", 
				g_thread_self() );
#endif /*DEBUG*/
		}

		read->y_pos += 1;
	}

	/* Turn errors back on. png_read_end() can trigger them too.
	 */
	if( setjmp( png_jmpbuf( read->pPng ) ) ) 
		return( -1 );

	/* We need to shut down the reader immediately at the end of read or
	 * we won't detach ready for the next image.
	 */
	if( read->y_pos >= read->out->Ysize ) {
		png_read_end( read->pPng, NULL ); 
		read_destroy( read );
	}

	return( 0 );
}
Пример #16
0
/* Entropy-style smartcrop. Repeatedly discard low interest areas. This should
 * be faster for very large images. 
 */
static int
vips_smartcrop_entropy( VipsSmartcrop *smartcrop, 
	VipsImage *in, int *left, int *top )
{
	int max_slice_size;
	int width;
	int height;

	*left = 0;
	*top = 0;
	width = in->Xsize;
	height = in->Ysize;

	/* How much do we trim by each iteration? Aim for 8 steps in the axis
	 * that needs trimming most.
	 */
	max_slice_size = VIPS_MAX( 
		ceil( (width - smartcrop->width) / 8.0 ),
		ceil( (height - smartcrop->height) / 8.0 ) );

	/* Repeatedly take a slice off width and height until we 
	 * reach the target.
	 */
	while( width > smartcrop->width || 
		height > smartcrop->height ) {
		const int slice_width = 
			VIPS_MIN( width - smartcrop->width, max_slice_size );
		const int slice_height = 
			VIPS_MIN( height - smartcrop->height, max_slice_size );

		if( slice_width > 0 ) { 
			double left_score;
			double right_score;

			if( vips_smartcrop_score( smartcrop, in, 
				*left, *top, 
				slice_width, height, &left_score ) )
				return( -1 );

			if( vips_smartcrop_score( smartcrop, in, 
				*left + width - slice_width, *top, 
				slice_width, height, &right_score ) )
				return( -1 ); 

			width -= slice_width;
			if( left_score < right_score ) 
				*left += slice_width;
		}

		if( slice_height > 0 ) { 
			double top_score;
			double bottom_score;

			if( vips_smartcrop_score( smartcrop, in, 
				*left, *top, 
				width, slice_height, &top_score ) )
				return( -1 );

			if( vips_smartcrop_score( smartcrop, in, 
				*left, *top + height - slice_height, 
				width, slice_height, &bottom_score ) )
				return( -1 ); 

			height -= slice_height;
			if( top_score < bottom_score ) 
				*top += slice_height;
		}
	}

	return( 0 );
}
Пример #17
0
static int
vips_join_build( VipsObject *object )
{
	VipsConversion *conversion = VIPS_CONVERSION( object );
	VipsJoin *join = (VipsJoin *) object;

	int x, y;
	VipsImage *t;

	if( VIPS_OBJECT_CLASS( vips_join_parent_class )->build( object ) )
		return( -1 );

	switch( join->direction ) {
	case VIPS_DIRECTION_HORIZONTAL:
		x = join->in1->Xsize + join->shim;

		switch( join->align ) {
		case VIPS_ALIGN_LOW:
			y = 0;
			break;

		case VIPS_ALIGN_CENTRE:
			y = join->in1->Ysize / 2 - join->in2->Ysize / 2;
			break;

		case VIPS_ALIGN_HIGH:
			y = join->in1->Ysize - join->in2->Ysize;
			break;

		default:
			g_assert( 0 );

			/* Keep -Wall happy.
			 */
			return( 0 );
		}

		break;

	case VIPS_DIRECTION_VERTICAL:
		y = join->in1->Ysize + join->shim;

		switch( join->align ) {
		case VIPS_ALIGN_LOW:
			x = 0;
			break;

		case VIPS_ALIGN_CENTRE:
			x = join->in1->Xsize / 2 - join->in2->Xsize / 2;
			break;

		case VIPS_ALIGN_HIGH:
			x = join->in1->Xsize - join->in2->Xsize;
			break;

		default:
			g_assert( 0 );

			/* Keep -Wall happy.
			 */
			return( 0 );
		}

		break;

	default:
		g_assert( 0 );

		/* Keep -Wall happy.
		 */
		return( 0 );
	}

	if( vips_insert( join->in1, join->in2, &t, x, y,
		"expand", TRUE,
		"background", join->background,
		NULL ) )
		return( -1 );

	if( !join->expand ) {
		VipsImage *t2;
		int left, top, width, height;

		switch( join->direction ) {
		case VIPS_DIRECTION_HORIZONTAL:
			left = 0;
			top = VIPS_MAX( 0, y ) - y;
			width = t->Xsize;
			height = VIPS_MIN( join->in1->Ysize, join->in2->Ysize );
			break;

		case VIPS_DIRECTION_VERTICAL:
			left = VIPS_MAX( 0, x ) - x;
			top = 0;
			width = VIPS_MIN( join->in1->Xsize, join->in2->Xsize );
			height = t->Ysize; 
			break;

		default:
			g_assert( 0 );

			/* Keep -Wall happy.
			 */
			return( 0 );
		}

		if( vips_extract_area( t, &t2, 
			left, top, width, height, NULL ) ) {
			g_object_unref( t );
			return( -1 );
		}
		g_object_unref( t );

		t = t2;
	}

	if( vips_image_write( t, conversion->out ) ) {
		g_object_unref( t );
		return( -1 );
	}
	g_object_unref( t );

	return( 0 );
}
Пример #18
0
/* Break a command-line argument into tokens separated by whitespace. 
 *
 * Strings can't be adjacent, so "hello world" (without quotes) is a single 
 * string.  Strings are written (with \" escaped) into @string. If the string
 * is larger than @size, it is silently null-termionated and truncated. 
 *
 * Return NULL for end of tokens.
 */
const char *
vips__token_get( const char *p, VipsToken *token, char *string, int size )
{
	const char *q;
	int ch;
	int n;
	int i;

	/* Parse this token with p.
	 */
	if( !p )
		return( NULL );

	/* Skip initial whitespace.
	 */
        p += strspn( p, " \t\n\r" );
	if( !p[0] )
		return( NULL );

	switch( (ch = p[0]) ) {
	case '{':
	case '[':
	case '(':
	case '<':
		*token = VIPS_TOKEN_LEFT;
		p += 1;
		break;

	case ')':
	case ']':
	case '}':
	case '>':
		*token = VIPS_TOKEN_RIGHT;
		p += 1;
		break;

	case '=':
		*token = VIPS_TOKEN_EQUALS;
		p += 1;
		break;

	case ',':
		*token = VIPS_TOKEN_COMMA;
		p += 1;
		break;

	case '"':
	case '\'':
		/* Parse a quoted string. Copy up to ", interpret any \",
		 * error if no closing ".
		 */
		*token = VIPS_TOKEN_STRING;

		do {
			/* Number of characters until the next quote
			 * character or end of string.
			 */
			if( (q = strchr( p + 1, ch )) )
				n = q - p + 1;
			else
				n = strlen( p + 1 );

			/* How much can we copy to the buffer?
			 */
			i = VIPS_MIN( n, size );
			vips_strncpy( string, p + 1, i );

			/* We might have stopped at an escaped quote. If the
			 * string was not truncated, swap the preceding 
			 * backslash for a quote.
			 */
			if( p[n + 1] == ch && p[n] == '\\' && i == n )
				string[i - 1] = ch;

			string += i;
			size -= i;
			p += n + 1;
		} while( p[0] && p[-1] == '\\' );

		p += 1;

		break;

	default:
		/* It's an unquoted string: read up to the next non-string
		 * character. We don't allow two strings next to each other,
		 * so the next break must be bracket, equals, comma.
		 */
		*token = VIPS_TOKEN_STRING;
		n = strcspn( p, "<[{()}]>=," );
		i = VIPS_MIN( n, size );
		vips_strncpy( string, p, i + 1 );
		p += n;

		/* We remove leading whitespace, so we trim trailing
		 * whitespace from unquoted strings too. Only if the string
		 * hasn't been truncated.
		 */
		if( i == n ) 
			while( i > 0 && isspace( string[i - 1] ) ) {
				string[i - 1] = '\0';
				i--;
			}

		break;
	}

	return( p );
}
Пример #19
0
static int
png2vips_generate( VipsRegion *or, 
	void *seq, void *a, void *b, gboolean *stop )
{
        VipsRect *r = &or->valid;
	Read *read = (Read *) a;

	int y;

#ifdef DEBUG
	printf( "png2vips_generate: line %d, %d rows\n", r->top, r->height );
	printf( "png2vips_generate: y_top = %d\n", read->y_pos );
#endif /*DEBUG*/

	/* We're inside a tilecache where tiles are the full image width, so
	 * this should always be true.
	 */
	g_assert( r->left == 0 );
	g_assert( r->width == or->im->Xsize );
	g_assert( VIPS_RECT_BOTTOM( r ) <= or->im->Ysize );

	/* Tiles should always be a strip in height, unless it's the final
	 * strip.
	 */
	g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) ); 

	/* And check that y_pos is correct. It should be, since we are inside
	 * a vips_sequential().
	 */
	if( r->top != read->y_pos ) {
		vips_error( "vipspng", 
			_( "out of order read at line %d" ), read->y_pos );
		return( -1 );
	}

	for( y = 0; y < r->height; y++ ) {
		png_bytep q = (png_bytep) VIPS_REGION_ADDR( or, 0, r->top + y );

		/* We need to catch errors from read_row().
		 */
		if( !setjmp( png_jmpbuf( read->pPng ) ) ) 
			png_read_row( read->pPng, q, NULL );
		else { 
			/* We've failed to read some pixels. Knock this 
			 * operation out of cache. 
			 */
			vips_foreign_load_invalidate( read->out );

#ifdef DEBUG
			printf( "png2vips_generate: png_read_row() failed, "
				"line %d\n", r->top + y ); 
			printf( "png2vips_generate: file %s\n", read->name );
			printf( "png2vips_generate: thread %p\n", 
				g_thread_self() );
#endif /*DEBUG*/

			/* And bail if fail is on. We have to add an error
			 * message, since the handler we install just does
			 * g_warning().
			 */
			if( read->fail ) {
				vips_error( "vipspng", 
					"%s", _( "libpng read error" ) ); 
				return( -1 );
			}
		}

		read->y_pos += 1;
	}

	/* Catch errors from png_read_end(). This can fail on a truncated
	 * file. 
	 */
	if( setjmp( png_jmpbuf( read->pPng ) ) ) {
		if( read->fail ) {
			vips_error( "vipspng", "%s", _( "libpng read error" ) ); 
			return( -1 );
		}

		return( 0 );
	}

	/* We need to shut down the reader immediately at the end of read or
	 * we won't detach ready for the next image.
	 */
	if( read->y_pos >= read->out->Ysize ) {
		png_read_end( read->pPng, NULL ); 
		read_destroy( read );
	}

	return( 0 );
}