Exemple #1
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 );
}
/* Convert n pels from signed short to IM_CODING_LABQ.
 */
static void
vips_LabS2LabQ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
{
	signed short *p = (signed short *) in[0];
	unsigned char *q = (unsigned char *) out;

	int i;

	for( i = 0; i < width; i++ ) {
		int l, a, b;
		unsigned char ext;

		/* Get LAB, rounding to 10, 11, 11. 
		 */
		l = p[0] + 16;
		l = VIPS_CLIP( 0, l, 32767 );
		l >>= 5;

		/* Make sure we round -ves in the right direction!
		 */
		a = p[1];
		if( a >= 0 )
			a += 16;
		else
			a -= 16;
		a = VIPS_CLIP( -32768, a, 32767 );
		a >>= 5;

		b = p[2];
		if( b >= 0 )
			b += 16;
		else
			b -= 16;
		b = VIPS_CLIP( -32768, b, 32767 );
		b >>= 5;

		p += 3;

		/* Extract top 8 bits.
		 */
		q[0] = l >> 2;
		q[1] = a >> 3;
		q[2] = b >> 3;

		/* Form extension byte.
		 */
		ext = (l << 6) & 0xc0;
		ext |= (a << 3) & 0x38;
		ext |= b & 0x7;
		q[3] = ext;

		q += 4;
	}
}
Exemple #3
0
/* Read an ascii ppm/pgm file.
 */
static int
read_ascii( FILE *fp, VipsImage *out )
{
	int x, y;
	VipsPel *buf;

	if( !(buf = VIPS_ARRAY( out, VIPS_IMAGE_SIZEOF_LINE( out ), VipsPel )) )
		return( -1 );

	for( y = 0; y < out->Ysize; y++ ) {
		for( x = 0; x < out->Xsize * out->Bands; x++ ) {
			int val;

			if( read_int( fp, &val ) )
				return( -1 );
			
			switch( out->BandFmt ) {
			case VIPS_FORMAT_UCHAR:
				buf[x] = VIPS_CLIP( 0, val, 255 );
				break;

			case VIPS_FORMAT_USHORT:
				((unsigned short *) buf)[x] = 
					VIPS_CLIP( 0, val, 65535 );
				break;

			case VIPS_FORMAT_UINT:
				((unsigned int *) buf)[x] = val;
				break;

			default:
				g_assert( 0 );
			}
		}

		if( vips_image_write_line( out, y, buf ) )
			return( -1 );
	}

	return( 0 );
}
Exemple #4
0
/* Scan the exif block on the image, if any, and make a set of vips metadata 
 * tags for what we find.
 */
int
vips__exif_parse( VipsImage *image )
{
	void *data;
	size_t length;
	ExifData *ed;
	VipsExifParams params;
	const char *str;

	if( !vips_image_get_typeof( image, VIPS_META_EXIF_NAME ) )
		return( 0 );
	if( vips_image_get_blob( image, VIPS_META_EXIF_NAME, &data, &length ) )
		return( -1 ); 
	if( !(ed = vips_exif_load_data_without_fix( data, length )) )
		return( -1 );

#ifdef DEBUG_VERBOSE
	show_tags( ed );
	show_values( ed );
#endif /*DEBUG_VERBOSE*/

	/* Look for resolution fields and use them to set the VIPS xres/yres 
	 * fields.
	 *
	 * If the fields are missing, set them from the image, which will have
	 * previously had them set from something like JFIF. 
	 */
	if( vips_image_resolution_from_exif( image, ed ) &&
		vips_exif_resolution_from_image( ed, image ) ) {
		exif_data_free( ed );
		return( -1 ); 
	}

	/* Make sure all required fields are there before we attach the vips
	 * metadata.
	 */
	exif_data_fix( ed );

	/* Attach informational fields for what we find.
	 */
	params.image = image;
	params.ed = ed;
	exif_data_foreach_content( ed, 
		(ExifDataForeachContentFunc) vips_exif_get_content, &params );

	vips_exif_get_thumbnail( image, ed );
	exif_data_free( ed );

	/* Orientation handling. ifd0 has the Orientation tag for the main
	 * image. 
	 */
	if( vips_image_get_typeof( image, "exif-ifd0-Orientation" ) != 0 &&
		!vips_image_get_string( image, 
			"exif-ifd0-Orientation", &str ) ) {
		int orientation;

		orientation = atoi( str );
		orientation = VIPS_CLIP( 1, orientation, 8 );
		vips_image_set_int( image, VIPS_META_ORIENTATION, orientation );
	}

	return( 0 );
}
/* Write a TIFF header. width and height are the size of the VipsImage we are
 * writing (it may have been shrunk).
 */
static int
write_tiff_header( Write *write, Layer *layer )
{
	TIFF *tif = layer->tif;

	int format; 
	int orientation; 

	/* Output base header fields.
	 */
	TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, layer->width );
	TIFFSetField( tif, TIFFTAG_IMAGELENGTH, layer->height );
	TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
	TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
	TIFFSetField( tif, TIFFTAG_COMPRESSION, write->compression );

	if( write->compression == COMPRESSION_JPEG ) 
		TIFFSetField( tif, TIFFTAG_JPEGQUALITY, write->jpqual );

	if( write->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE ) 
		TIFFSetField( tif, TIFFTAG_PREDICTOR, write->predictor );

	/* Don't write mad resolutions (eg. zero), it confuses some programs.
	 */
	TIFFSetField( tif, TIFFTAG_RESOLUTIONUNIT, write->resunit );
	TIFFSetField( tif, TIFFTAG_XRESOLUTION, 
		VIPS_FCLIP( 0.01, write->xres, 1000000 ) );
	TIFFSetField( tif, TIFFTAG_YRESOLUTION, 
		VIPS_FCLIP( 0.01, write->yres, 1000000 ) );

	if( !write->strip ) 
		if( write_embed_profile( write, tif ) ||
			write_embed_xmp( write, tif ) ||
			write_embed_ipct( write, tif ) ||
			write_embed_photoshop( write, tif ) ||
			write_embed_imagedescription( write, tif ) )
			return( -1 ); 

	if( vips_image_get_typeof( write->im, VIPS_META_ORIENTATION ) &&
		!vips_image_get_int( write->im, 
			VIPS_META_ORIENTATION, &orientation ) )
		TIFFSetField( tif, TIFFTAG_ORIENTATION, orientation );

	/* And colour fields.
	 */
	if( write->im->Coding == VIPS_CODING_LABQ ) {
		TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 );
		TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 );
		TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
	}
	else if( write->onebit ) {
		TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 );
		TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 );
		TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, 
			write->miniswhite ? 
				PHOTOMETRIC_MINISWHITE :  
				PHOTOMETRIC_MINISBLACK ); 
	}
	else {
		int photometric;

		/* Number of bands that have colour in .. other bands are saved
		 * as alpha.
		 */
		int colour_bands;

		int alpha_bands;

		TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, write->im->Bands );
		TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 
			vips_format_sizeof( write->im->BandFmt ) << 3 );

		if( write->im->Bands < 3 ) {
			/* Mono or mono + alpha.
			 */
			photometric = write->miniswhite ? 
				PHOTOMETRIC_MINISWHITE :  
				PHOTOMETRIC_MINISBLACK;
			colour_bands = 1;
		}
		else {
			/* Could be: RGB, CMYK, LAB, perhaps with extra alpha.
			 */
			if( write->im->Type == VIPS_INTERPRETATION_LAB || 
				write->im->Type == VIPS_INTERPRETATION_LABS ) {
				photometric = PHOTOMETRIC_CIELAB;
				colour_bands = 3;
			}
			else if( write->im->Type == VIPS_INTERPRETATION_CMYK &&
				write->im->Bands >= 4 ) {
				photometric = PHOTOMETRIC_SEPARATED;
				TIFFSetField( tif, 
					TIFFTAG_INKSET, INKSET_CMYK );
				colour_bands = 4;
			}
			else if( write->compression == COMPRESSION_JPEG &&
				write->im->Bands == 3 &&
				write->im->BandFmt == VIPS_FORMAT_UCHAR &&
				(!write->rgbjpeg && write->jpqual < 90) ) { 
				/* This signals to libjpeg that it can do
				 * YCbCr chrominance subsampling from RGB, not
				 * that we will supply the image as YCbCr.
				 */
				photometric = PHOTOMETRIC_YCBCR;
				TIFFSetField( tif, TIFFTAG_JPEGCOLORMODE, 
					JPEGCOLORMODE_RGB );
				colour_bands = 3;
			}
			else {
				/* Some kind of generic multi-band image ..
				 * save the first three bands as RGB, the rest
				 * as alpha.
				 */
				photometric = PHOTOMETRIC_RGB;
				colour_bands = 3;
			}
		}

		alpha_bands = VIPS_CLIP( 0, 
			write->im->Bands - colour_bands, MAX_ALPHA );
		if( alpha_bands > 0 ) { 
			uint16 v[MAX_ALPHA];
			int i;

			/* EXTRASAMPLE_UNASSALPHA means generic extra
			 * alpha-like channels. ASSOCALPHA means pre-multipled
			 * alpha only. 
			 */
			for( i = 0; i < alpha_bands; i++ )
				v[i] = EXTRASAMPLE_UNASSALPHA;
			TIFFSetField( tif, 
				TIFFTAG_EXTRASAMPLES, alpha_bands, v );
		}

		TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
	}

	/* Layout.
	 */
	if( write->tile ) {
		TIFFSetField( tif, TIFFTAG_TILEWIDTH, write->tilew );
		TIFFSetField( tif, TIFFTAG_TILELENGTH, write->tileh );
	}
	else
		TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, write->tileh );

	if( layer->above ) 
		/* Pyramid layer.
		 */
		TIFFSetField( tif, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE );

	/* Sample format.
	 */
	format = SAMPLEFORMAT_UINT;
	if( vips_band_format_isuint( write->im->BandFmt ) )
		format = SAMPLEFORMAT_UINT;
	else if( vips_band_format_isint( write->im->BandFmt ) )
		format = SAMPLEFORMAT_INT;
	else if( vips_band_format_isfloat( write->im->BandFmt ) )
		format = SAMPLEFORMAT_IEEEFP;
	else if( vips_band_format_iscomplex( write->im->BandFmt ) )
		format = SAMPLEFORMAT_COMPLEXIEEEFP;
	TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, format );

	return( 0 );
}
Exemple #6
0
static int
vips_smartcrop_attention( VipsSmartcrop *smartcrop, 
	VipsImage *in, int *left, int *top )
{
	/* From smartcrop.js.
	 */
	static double skin_vector[] = {-0.78, -0.57, -0.44};
	static double ones[] = {1.0, 1.0, 1.0};

	VipsImage **t = (VipsImage **) 
		vips_object_local_array( VIPS_OBJECT( smartcrop ), 24 );

	double hscale;
	double vscale;
	double sigma;
	double max;
	int x_pos;
	int y_pos;

	/* The size we shrink to gives the precision with which we can place
	 * the crop
	 */
	hscale = 32.0 / in->Xsize;
	vscale = 32.0 / in->Ysize;
	sigma = VIPS_MAX( sqrt( pow( smartcrop->width * hscale, 2 ) +
		pow( smartcrop->height * vscale, 2 ) ) / 10, 1.0 );
	if ( vips_resize( in, &t[17], hscale,
		"vscale", vscale,
		NULL ) )
		return( -1 );

	/* Simple edge detect.
	 */
	if( !(t[21] = vips_image_new_matrixv( 3, 3,
		 0.0, -1.0,  0.0, 
		-1.0,  4.0, -1.0, 
		 0.0, -1.0,  0.0 )) )
		return( -1 );

	/* Convert to XYZ and just use the first three bands.
	 */
	if( vips_colourspace( t[17], &t[0], VIPS_INTERPRETATION_XYZ, NULL ) ||
		vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) )
		return( -1 );

	/* Edge detect on Y. 
	 */
	if( vips_extract_band( t[1], &t[2], 1, NULL ) ||
		vips_conv( t[2], &t[3], t[21], 
			"precision", VIPS_PRECISION_INTEGER,
			NULL ) ||
		vips_linear1( t[3], &t[4], 5.0, 0.0, NULL ) ||
		vips_abs( t[4], &t[14], NULL ) )
		return( -1 );

	/* Look for skin colours. Taken from smartcrop.js.
	 */
	if( 
		/* Normalise to magnitude of colour in XYZ.
		 */
		pythagoras( smartcrop, t[1], &t[5] ) ||
		vips_divide( t[1], t[5], &t[6], NULL ) ||

		/* Distance from skin point.
		 */
		vips_linear( t[6], &t[7], ones, skin_vector, 3, NULL ) ||
		pythagoras( smartcrop, t[7], &t[8] ) ||

		/* Rescale to 100 - 0 score.
		 */
		vips_linear1( t[8], &t[9], -100.0, 100.0, NULL ) ||

		/* Ignore dark areas.
		 */
		vips_more_const1( t[2], &t[10], 5.0, NULL ) ||
		!(t[11] = vips_image_new_from_image1( t[10], 0.0 )) ||
		vips_ifthenelse( t[10], t[9], t[11], &t[15], NULL ) )
		return( -1 );

	/* Look for saturated areas.
	 */
	if( vips_colourspace( t[1], &t[12], 
		VIPS_INTERPRETATION_LAB, NULL ) ||
		vips_extract_band( t[12], &t[13], 1, NULL ) ||
		vips_ifthenelse( t[10], t[13], t[11], &t[16], NULL ) )
		return( -1 );

	/* Sum, blur and find maxpos.
	 *
	 * The amount of blur is related to the size of the crop
	 * area: how large an area we want to consider for the scoring
	 * function.
	 */

	if( vips_sum( &t[14], &t[18], 3, NULL ) ||
		vips_gaussblur( t[18], &t[19], sigma, NULL ) ||
		vips_max( t[19], &max, "x", &x_pos, "y", &y_pos, NULL ) )
		return( -1 ); 

	/* Centre the crop over the max.
	 */
	*left = VIPS_CLIP( 0, 
		x_pos / hscale - smartcrop->width / 2, 
		in->Xsize - smartcrop->width );
	*top = VIPS_CLIP( 0, 
		y_pos / vscale - smartcrop->height / 2, 
		in->Ysize - smartcrop->height ); 

	return( 0 ); 
}
static void inline
bicubic_signed_int32_tab( void *pout, const VipsPel *pin,
	const int bands, const int lskip,
	const double *cx, const double *cy )
{
	T* restrict out = (T *) pout;
	const T* restrict in = (T *) pin;

	const int b1 = bands;
	const int b2 = b1 + b1;
	const int b3 = b1 + b2;

	const int l1 = lskip / sizeof( T );
	const int l2 = l1 + l1;
	const int l3 = l1 + l2;

        const int l1_plus_b1 = l1 + b1;
        const int l1_plus_b2 = l1 + b2;
        const int l1_plus_b3 = l1 + b3;
        const int l2_plus_b1 = l2 + b1;
        const int l2_plus_b2 = l2 + b2;
        const int l2_plus_b3 = l2 + b3;
        const int l3_plus_b1 = l3 + b1;
        const int l3_plus_b2 = l3 + b2;
        const int l3_plus_b3 = l3 + b3;

	for( int z = 0; z < bands; z++ ) {
		const T uno_one = in[0];
		const T uno_two = in[b1];
		const T uno_thr = in[b2];
		const T uno_fou = in[b3];

		const T dos_one = in[l1];
		const T dos_two = in[l1_plus_b1];
		const T dos_thr = in[l1_plus_b2];
		const T dos_fou = in[l1_plus_b3];

		const T tre_one = in[l2];
		const T tre_two = in[l2_plus_b1];
		const T tre_thr = in[l2_plus_b2];
		const T tre_fou = in[l2_plus_b3];

		const T qua_one = in[l3];
		const T qua_two = in[l3_plus_b1];
		const T qua_thr = in[l3_plus_b2];
		const T qua_fou = in[l3_plus_b3];

		double bicubic = bicubic_float<double>(
			uno_one, uno_two, uno_thr, uno_fou,
			dos_one, dos_two, dos_thr, dos_fou,
			tre_one, tre_two, tre_thr, tre_fou,
			qua_one, qua_two, qua_thr, qua_fou,
			cx, cy );

		bicubic = VIPS_CLIP( min_value, bicubic, max_value ); 

		out[z] = bicubic;

		in += 1;
	}
}