Exemplo n.º 1
0
static int
vips_resize_build( VipsObject *object )
{
	VipsResample *resample = VIPS_RESAMPLE( object );
	VipsResize *resize = (VipsResize *) object;

	VipsImage **t = (VipsImage **) 
		vips_object_local_array( object, 7 );

	VipsImage *in;
	int window_size;
	int int_shrink;
	int int_shrink_width;
	double residual;
	double sigma;

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

	if( !vips_object_argument_isset( object, "interpolate" ) ) {
		VipsInterpolate *interpolate;
		char *nick;

		if( vips_type_find( "VipsInterpolate", "bicubic" ) )
			nick = "bicubic";
		else
			nick = "bilinear";
		interpolate = vips_interpolate_new( nick );
		g_object_set( object, "interpolate", interpolate, NULL ); 
		VIPS_UNREF( interpolate ); 
	}

	in = resample->in;

	window_size = resize->interpolate ? 
		vips_interpolate_get_window_size( resize->interpolate ) : 2;

	/* If the factor is > 1.0, we need to zoom rather than shrink.
	 * Just set the int part to 1 in this case.
	 */
	int_shrink = resize->scale > 1.0 ? 1 : floor( 1.0 / resize->scale );

	/* We want to shrink by less for interpolators with larger windows.
	 */
	int_shrink = VIPS_MAX( 1,
		int_shrink / VIPS_MAX( 1, window_size / 2 ) );

	/* Size after int shrink.
	 */
	int_shrink_width = in->Xsize / int_shrink;

	/* Therefore residual scale factor is.
	 */
	residual = (in->Xsize * resize->scale) / int_shrink_width;

	/* A copy for enlarge resize.
	 */
	if( vips_shrink( in, &t[0], int_shrink, int_shrink, NULL ) )
		return( -1 );
	in = t[0];

	/* We want to make sure we read the image sequentially.
	 * However, the convolution we may be doing later will force us 
	 * into SMALLTILE or maybe FATSTRIP mode and that will break
	 * sequentiality.
	 *
	 * So ... read into a cache where tiles are scanlines, and make sure
	 * we keep enough scanlines to be able to serve a line of tiles.
	 *
	 * We use a threaded tilecache to avoid a deadlock: suppose thread1,
	 * evaluating the top block of the output, is delayed, and thread2, 
	 * evaluating the second block, gets here first (this can happen on 
	 * a heavily-loaded system). 
	 *
	 * With an unthreaded tilecache (as we had before), thread2 will get
	 * the cache lock and start evaling the second block of the shrink. 
	 * When it reaches the png reader it will stall until the first block 
	 * has been used ... but it never will, since thread1 will block on 
	 * this cache lock. 
	 */
	if( int_shrink > 1 ) { 
		int tile_width;
		int tile_height;
		int nlines;

		vips_get_tile_size( in, 
			&tile_width, &tile_height, &nlines );
		if( vips_tilecache( in, &t[6], 
			"tile_width", in->Xsize,
			"tile_height", 10,
			"max_tiles", 1 + (nlines * 2) / 10,
			"access", VIPS_ACCESS_SEQUENTIAL,
			"threaded", TRUE, 
			NULL ) )
			return( -1 );
		in = t[6];
	}

	/* If the final affine will be doing a large downsample, we can get 
	 * nasty aliasing on hard edges. Blur before affine to smooth this out.
	 *
	 * Don't blur for very small shrinks, blur with radius 1 for x1.5
	 * shrinks, blur radius 2 for x2.5 shrinks and above, etc.
	 */
	sigma = ((1.0 / residual) - 0.5) / 1.5;
	if( residual < 1.0 &&
		sigma > 0.1 ) { 
		if( vips_gaussblur( in, &t[2], sigma, NULL ) )
			return( -1 );
		in = t[2];
	}

	if( vips_affine( in, &t[3], residual, 0, 0, residual, 
		"interpolate", resize->interpolate,
		"idx", resize->idx,
		"idy", resize->idy,
		NULL ) )  
		return( -1 );
	in = t[3];

	/* If we are upsampling, don't sharpen.
	 */
	if( int_shrink > 1 ) { 
		t[5] = vips_image_new_matrixv( 3, 3,
			-1.0, -1.0, -1.0,
			-1.0, 32.0, -1.0,
			-1.0, -1.0, -1.0 );
		vips_image_set_double( t[5], "scale", 24 );

		if( vips_conv( in, &t[4], t[5], NULL ) ) 
			return( -1 );
		in = t[4];
	}

	if( vips_image_write( in, resample->out ) )
		return( -1 ); 

	return( 0 );
}
Exemplo n.º 2
0
static VipsImage *
thumbnail_shrink( VipsObject *process, VipsImage *in, 
	VipsInterpolate *interp, VipsImage *sharpen )
{
	VipsImage **t = (VipsImage **) vips_object_local_array( process, 10 );
	VipsInterpretation interpretation = linear_processing ?
		VIPS_INTERPRETATION_XYZ : VIPS_INTERPRETATION_sRGB; 

	int shrink; 
	double residual; 
	int tile_width;
	int tile_height;
	int nlines;

	/* RAD needs special unpacking.
	 */
	if( in->Coding == VIPS_CODING_RAD ) {
		vips_info( "vipsthumbnail", "unpacking Rad to float" );

		/* rad is scrgb.
		 */
		if( vips_rad2float( in, &t[0], NULL ) )
			return( NULL );
		in = t[0];
	}

	/* In linear mode, we import right at the start. 
	 *
	 * This is only going to work for images in device space. If you have
	 * an image in PCS which also has an attached profile, strange things
	 * will happen. 
	 */
	if( linear_processing &&
		in->Coding == VIPS_CODING_NONE &&
		(in->BandFmt == VIPS_FORMAT_UCHAR ||
		 in->BandFmt == VIPS_FORMAT_USHORT) &&
		(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || 
		 import_profile) ) {
		if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) )
			vips_info( "vipsthumbnail", 
				"importing with embedded profile" );
		else
			vips_info( "vipsthumbnail", 
				"importing with profile %s", import_profile );

		if( vips_icc_import( in, &t[1], 
			"input_profile", import_profile,
			"embedded", TRUE,
			"pcs", VIPS_PCS_XYZ,
			NULL ) )  
			return( NULL );

		in = t[1];
	}

	/* To the processing colourspace. This will unpack LABQ as well.
	 */
	vips_info( "vipsthumbnail", "converting to processing space %s",
		vips_enum_nick( VIPS_TYPE_INTERPRETATION, interpretation ) ); 
	if( vips_colourspace( in, &t[2], interpretation, NULL ) ) 
		return( NULL ); 
	in = t[2];

	shrink = calculate_shrink( in, &residual );

	vips_info( "vipsthumbnail", "integer shrink by %d", shrink );

	if( vips_shrink( in, &t[3], shrink, shrink, NULL ) ) 
		return( NULL );
	in = t[3];

	/* We want to make sure we read the image sequentially.
	 * However, the convolution we may be doing later will force us 
	 * into SMALLTILE or maybe FATSTRIP mode and that will break
	 * sequentiality.
	 *
	 * So ... read into a cache where tiles are scanlines, and make sure
	 * we keep enough scanlines to be able to serve a line of tiles.
	 *
	 * We use a threaded tilecache to avoid a deadlock: suppose thread1,
	 * evaluating the top block of the output, is delayed, and thread2, 
	 * evaluating the second block, gets here first (this can happen on 
	 * a heavily-loaded system). 
	 *
	 * With an unthreaded tilecache (as we had before), thread2 will get
	 * the cache lock and start evaling the second block of the shrink. 
	 * When it reaches the png reader it will stall until the first block 
	 * has been used ... but it never will, since thread1 will block on 
	 * this cache lock. 
	 */
	vips_get_tile_size( in, 
		&tile_width, &tile_height, &nlines );
	if( vips_tilecache( in, &t[4], 
		"tile_width", in->Xsize,
		"tile_height", 10,
		"max_tiles", (nlines * 2) / 10,
		"access", VIPS_ACCESS_SEQUENTIAL,
		"threaded", TRUE, 
		NULL ) ||
		vips_affine( t[4], &t[5], residual, 0, 0, residual, 
			"interpolate", interp,
			NULL ) )  
		return( NULL );
	in = t[5];

	vips_info( "vipsthumbnail", "residual scale by %g", residual );
	vips_info( "vipsthumbnail", "%s interpolation", 
		VIPS_OBJECT_GET_CLASS( interp )->nickname );

	/* Colour management.
	 *
	 * In linear mode, just export. In device space mode, do a combined
	 * import/export to transform to the target space.
	 */
	if( linear_processing ) {
		if( export_profile ||
			vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) {
			vips_info( "vipsthumbnail", 
				"exporting to device space with a profile" );
			if( vips_icc_export( in, &t[7], 
				"output_profile", export_profile,
				NULL ) )  
				return( NULL );
			in = t[7];
		}
		else {
			vips_info( "vipsthumbnail", "converting to sRGB" );
			if( vips_colourspace( in, &t[6], 
				VIPS_INTERPRETATION_sRGB, NULL ) ) 
				return( NULL ); 
			in = t[6];
		}
	}
	else if( export_profile &&
		(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) || 
		 import_profile) ) {
		if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) )
			vips_info( "vipsthumbnail", 
				"importing with embedded profile" );
		else
			vips_info( "vipsthumbnail", 
				"importing with profile %s", import_profile );

		vips_info( "vipsthumbnail", 
			"exporting with profile %s", export_profile );

		if( vips_icc_transform( in, &t[6], export_profile,
			"input_profile", import_profile,
			"embedded", TRUE,
			NULL ) )  
			return( NULL );

		in = t[6];
	}

	/* If we are upsampling, don't sharpen, since nearest looks dumb
	 * sharpened.
	 */
	if( shrink >= 1 && 
		residual <= 1.0 && 
		sharpen ) { 
		vips_info( "vipsthumbnail", "sharpening thumbnail" );
		if( vips_conv( in, &t[8], sharpen, NULL ) ) 
			return( NULL );
		in = t[8];
	}

	if( delete_profile &&
		vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) {
		vips_info( "vipsthumbnail", 
			"deleting profile from output image" );
		if( !vips_image_remove( in, VIPS_META_ICC_NAME ) ) 
			return( NULL );
	}

	return( in );
}
Exemplo n.º 3
0
static int
shrink_factor( IMAGE *in, IMAGE *out, 
	int shrink, double residual, VipsInterpolate *interp )
{
	IMAGE *t[9];
	VipsImage **s = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( out ), 1 );
	IMAGE *x;
	int tile_width;
	int tile_height;
	int nlines;

	if( im_open_local_array( out, t, 9, "thumbnail", "p" ) )
		return( -1 );
	x = in;

	/* Unpack the two coded formats we support to float for processing.
	 */
	if( x->Coding == IM_CODING_LABQ ) {
		if( verbose ) 
			printf( "unpacking LAB to RGB\n" );

		if( im_LabQ2disp( x, t[1], im_col_displays( 7 ) ) )
			return( -1 );
		x = t[1];
	}
	else if( x->Coding == IM_CODING_RAD ) {
		if( verbose ) 
			printf( "unpacking Rad to float\n" );

		if( im_rad2float( x, t[1] ) )
			return( -1 );
		x = t[1];
	}

	if( im_shrink( x, t[2], shrink, shrink ) )
		return( -1 );

	/* We want to make sure we read the image sequentially.
	 * However, the convolution we may be doing later will force us 
	 * into SMALLTILE or maybe FATSTRIP mode and that will break
	 * sequentiality.
	 *
	 * So ... read into a cache where tiles are scanlines, and make sure
	 * we keep enough scanlines to be able to serve a line of tiles.
	 */
	vips_get_tile_size( t[2], 
		&tile_width, &tile_height, &nlines );
	if( vips_tilecache( t[2], &s[0], 
		"tile_width", t[2]->Xsize,
		"tile_height", 10,
		"max_tiles", (nlines * 2) / 10,
		"strategy", VIPS_CACHE_SEQUENTIAL,
		NULL ) ||
		im_affinei_all( s[0], t[4], 
			interp, residual, 0, 0, residual, 0, 0 ) )
		return( -1 );
	x = t[4];

	/* If we are upsampling, don't sharpen, since nearest looks dumb
	 * sharpened.
	 */
	if( shrink > 1 && residual <= 1.0 && !nosharpen ) {
		if( verbose ) 
			printf( "sharpening thumbnail\n" );

		if( im_conv( x, t[5], sharpen_filter() ) )
			return( -1 );
		x = t[5];
	}

	/* Colour management: we can transform the image if we have an output
	 * profile and an input profile. The input profile can be in the
	 * image, or if there is no profile there, supplied by the user.
	 */
	if( export_profile &&
		(im_header_get_typeof( x, IM_META_ICC_NAME ) || 
		 import_profile) ) {
		if( im_header_get_typeof( x, IM_META_ICC_NAME ) ) {
			if( verbose ) 
				printf( "importing with embedded profile\n" );

			if( im_icc_import_embedded( x, t[6], 
				IM_INTENT_RELATIVE_COLORIMETRIC ) )
				return( -1 );
		}
		else {
			if( verbose ) 
				printf( "importing with profile %s\n",
					import_profile );

			if( im_icc_import( x, t[6], 
				import_profile, 
				IM_INTENT_RELATIVE_COLORIMETRIC ) )
				return( -1 );
		}

		if( verbose ) 
			printf( "exporting with profile %s\n", export_profile );

		if( im_icc_export_depth( t[6], t[7], 
			8, export_profile, 
			IM_INTENT_RELATIVE_COLORIMETRIC ) )
			return( -1 );

		x = t[7];
	}

	if( delete_profile ) {
		if( verbose )
			printf( "deleting profile from output image\n" );

		if( im_meta_get_typeof( x, IM_META_ICC_NAME ) &&
			!im_meta_remove( x, IM_META_ICC_NAME ) )
			return( -1 );
	}

	if( im_copy( x, out ) )
		return( -1 );

	return( 0 );
}