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; }
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 ); }
/* 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 ); }
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 ); }