Ejemplo n.º 1
0
static VALUE
writer_meta_set(VALUE obj, const char* name, VALUE str)
{
    GetImg(obj, data, im);

	size_t len = RSTRING_LEN(str);
    void *buf = malloc(len);
    memcpy(buf, RSTRING_PTR(str), len);

    if (im_meta_set_blob(im, name, (im_callback_fn)xfree, buf, len)) {
        xfree(buf);
        vips_lib_error();
    }

    return str;
}
Ejemplo n.º 2
0
static int
attach_thumbnail( IMAGE *im, ExifData *ed )
{
	if( ed->size > 0 ) {
		char *thumb_copy;

		thumb_copy = im_malloc( NULL, ed->size );      
		memcpy( thumb_copy, ed->data, ed->size );

		if( im_meta_set_blob( im, "jpeg-thumbnail-data", 
			(im_callback_fn) im_free, thumb_copy, ed->size ) ) {
			im_free( thumb_copy );
			return( -1 );
		}
	}

	return( 0 );
}
Ejemplo n.º 3
0
/* Read a cinfo to a VIPS image. Set invert_pels if the pixel reader needs to
 * do 255-pel.
 */
static int
read_jpeg_header( struct jpeg_decompress_struct *cinfo, 
	IMAGE *out, gboolean *invert_pels, int shrink )
{
	jpeg_saved_marker_ptr p;
	int type;

	/* Capture app2 sections here for assembly.
	 */
	void *app2_data[MAX_APP2_SECTIONS] = { 0 };
	int app2_data_length[MAX_APP2_SECTIONS] = { 0 };
	int data_length;
	int i;

	/* Read JPEG header. libjpeg will set out_color_space sanely for us 
	 * for YUV YCCK etc.
	 */
	jpeg_read_header( cinfo, TRUE );
	cinfo->scale_denom = shrink;
	cinfo->scale_num = 1;
	jpeg_calc_output_dimensions( cinfo );

	*invert_pels = FALSE;
	switch( cinfo->out_color_space ) {
	case JCS_GRAYSCALE:
		type = IM_TYPE_B_W;
		break;

	case JCS_CMYK:
		type = IM_TYPE_CMYK;
		/* Photoshop writes CMYK JPEG inverted :-( Maybe this is a
		 * way to spot photoshop CMYK JPGs.
		 */
		if( cinfo->saw_Adobe_marker ) 
			*invert_pels = TRUE;
		break;

	case JCS_RGB:
	default:
		type = IM_TYPE_sRGB;
		break;
	}

	/* Set VIPS header.
	 */
	im_initdesc( out,
		 cinfo->output_width, cinfo->output_height,
		 cinfo->output_components,
		 IM_BBITS_BYTE, IM_BANDFMT_UCHAR, IM_CODING_NONE, type,
		 1.0, 1.0, 0, 0 );

	/* Interlaced jpegs need lots of memory to read, so our caller needs
	 * to know.
	 */
	(void) im_meta_set_int( out, "jpeg-multiscan", 
		jpeg_has_multiple_scans( cinfo ) );

	/* Look for EXIF and ICC profile.
	 */
	for( p = cinfo->marker_list; p; p = p->next ) {
		switch( p->marker ) {
		case JPEG_APP0 + 1:
			/* EXIF data.
			 */
#ifdef DEBUG
			printf( "read_jpeg_header: seen %d bytes of APP1\n",
				p->data_length );
#endif /*DEBUG*/
			if( read_exif( out, p->data, p->data_length ) )
				return( -1 );
			break;

		case JPEG_APP0 + 2:
			/* ICC profile.
			 */
#ifdef DEBUG
			printf( "read_jpeg_header: seen %d bytes of APP2\n",
				p->data_length );
#endif /*DEBUG*/

			if( p->data_length > 14 &&
				im_isprefix( "ICC_PROFILE", 
					(char *) p->data ) ) {
				/* cur_marker numbers from 1, according to
				 * spec.
				 */
				int cur_marker = p->data[12] - 1;

				if( cur_marker >= 0 &&
					cur_marker < MAX_APP2_SECTIONS ) {
					app2_data[cur_marker] = p->data + 14;
					app2_data_length[cur_marker] = 
						p->data_length - 14;
				}
			}
			break;

		default:
#ifdef DEBUG
			printf( "read_jpeg_header: seen %d bytes of data\n",
				p->data_length );
#endif /*DEBUG*/
			break;
		}
	}

	/* Assemble ICC sections.
	 */
	data_length = 0;
	for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ )
		data_length += app2_data_length[i];
	if( data_length ) {
		unsigned char *data;
		int p;

#ifdef DEBUG
		printf( "read_jpeg_header: assembled %d byte ICC profile\n",
			data_length );
#endif /*DEBUG*/

		if( !(data = im_malloc( NULL, data_length )) ) 
			return( -1 );

		p = 0;
		for( i = 0; i < MAX_APP2_SECTIONS && app2_data[i]; i++ ) {
			memcpy( data + p, app2_data[i], app2_data_length[i] );
			p += app2_data_length[i];
		}

		if( im_meta_set_blob( out, IM_META_ICC_NAME, 
			(im_callback_fn) im_free, data, data_length ) ) {
			im_free( data );
			return( -1 );
		}
	}

	return( 0 );
}
Ejemplo n.º 4
0
static int
read_exif( IMAGE *im, void *data, int data_length )
{
	char *data_copy;

	/* Horrifyingly, some JPEGs have several APP1 sections. We must only
	 * use the first one that starts "Exif.."
	 */
	if( ((char *) data)[0] != 'E' ||
		((char *) data)[1] != 'x' ||
		((char *) data)[2] != 'i' ||
		((char *) data)[3] != 'f' )
		return( 0 );
	if( im_header_get_typeof( im, IM_META_EXIF_NAME ) ) 
		return( 0 );

	/* Always attach a copy of the unparsed exif data.
	 */
	if( !(data_copy = im_malloc( NULL, data_length )) )
		return( -1 );
	memcpy( data_copy, data, data_length );
	if( im_meta_set_blob( im, IM_META_EXIF_NAME, 
		(im_callback_fn) im_free, data_copy, data_length ) ) {
		im_free( data_copy );
		return( -1 );
	}

#ifdef HAVE_EXIF
{
	ExifData *ed;

	if( !(ed = exif_data_new_from_data( data, data_length )) )
		return( -1 );

	if( ed->size > 0 ) {
#ifdef DEBUG_VERBOSE
		show_tags( ed );
		show_values( ed );
#endif /*DEBUG_VERBOSE*/

		/* Attach informational fields for what we find.

			FIXME ... better to have this in the UI layer?

			Or we could attach non-human-readable tags here (int, 
			double etc) and then move the human stuff to the UI 
			layer?

		 */
		exif_data_foreach_content( ed, 
			(ExifDataForeachContentFunc) attach_exif_content, im );

		/* Look for resolution fields and use them to set the VIPS 
		 * xres/yres fields.
		 */
		set_vips_resolution( im, ed );

		attach_thumbnail( im, ed );
	}

	exif_data_free( ed );
}
#endif /*HAVE_EXIF*/

	return( 0 );
}