diff --git a/ChangeLog b/ChangeLog index 7415b14c..1a4a20f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,7 @@ - added --vips-leak flag - added VipsCopy - more VipsImage props +- added vips_image_write(), old one becomes vips_image_write_filename() 10/8/11 started 7.26.3 - don't use G_VALUE_COLLECT_INIT(), many platforms do not have a glib this diff --git a/TODO b/TODO index da44b6a7..37f7310c 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,22 @@ +- vips_image_write() uses im_copy() to send an image to a file + + but im_copy() now calls vips_copy(), which can't actually write to a + specific descriptor! + + vips_image_write() needs to do some behind-the-scenes magic, I'm not quite + sure what + + just vips_image_generate() with a pointer copy I think, basically + vipscopy without creating the output + + rename as vips_image_write_to_filename(), vips_image_write() should write to + a VipsImage + + im_add() etc. compat functions need to start calling vips_image_write() + instead of im_copy() + + + - vipscopy how would we do meta sets? diff --git a/libvips/conversion/im_copy.c b/libvips/conversion/im_copy.c index f37ee87a..793296e6 100644 --- a/libvips/conversion/im_copy.c +++ b/libvips/conversion/im_copy.c @@ -383,214 +383,3 @@ im_copy_native( IMAGE *in, IMAGE *out, gboolean is_msb_first ) else return( im_copy( in, out ) ); } - -/* Convert to a saveable format. - * - * im__saveable_t gives the general type of image - * we make: vanilla 1/3 bands (eg. PPM), with an optional alpha (eg. PNG), or - * with CMYK as an option (eg. JPEG). - * - * format_table[] says how to convert each input format. - * - * Need to im_close() the result IMAGE. - */ -IMAGE * -im__convert_saveable( IMAGE *in, - im__saveable_t saveable, int format_table[10] ) -{ - IMAGE *out; - - if( !(out = im_open( "convert-for-save", "p" )) ) - return( NULL ); - - /* If this is an IM_CODING_LABQ, we can go straight to RGB. - */ - if( in->Coding == IM_CODING_LABQ ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - static void *table = NULL; - - /* Make sure fast LabQ2disp tables are built. 7 is sRGB. - */ - if( !table ) - table = im_LabQ2disp_build_table( NULL, - im_col_displays( 7 ) ); - - if( !t || im_LabQ2disp_table( in, t, table ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - /* If this is an IM_CODING_RAD, we go to float RGB or XYZ. We should - * probably un-gamma-correct the RGB :( - */ - if( in->Coding == IM_CODING_RAD ) { - IMAGE *t; - - if( !(t = im_open_local( out, "conv:1", "p" )) || - im_rad2float( in, t ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - /* Get the bands right. - */ - if( in->Coding == IM_CODING_NONE ) { - if( in->Bands == 2 && saveable != IM__RGBA ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || im_extract_band( in, t, 0 ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - else if( in->Bands > 3 && saveable == IM__RGB ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || - im_extract_bands( in, t, 0, 3 ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - else if( in->Bands > 4 && - (saveable == IM__RGB_CMYK || saveable == IM__RGBA) ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || - im_extract_bands( in, t, 0, 4 ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - /* Else we have saveable IM__ANY and we don't chop bands down. - */ - } - - /* Interpret the Type field for colorimetric images. - */ - if( in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && - in->Type == IM_TYPE_LABS ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || im_LabS2LabQ( in, t ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - if( in->Coding == IM_CODING_LABQ ) { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || im_LabQ2Lab( in, t ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - if( in->Coding != IM_CODING_NONE ) { - im_close( out ); - return( NULL ); - } - - if( in->Bands == 3 && in->Type == IM_TYPE_LCH ) { - IMAGE *t[2]; - - if( im_open_local_array( out, t, 2, "conv-1", "p" ) || - im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || - im_LCh2Lab( t[0], t[1] ) ) { - im_close( out ); - return( NULL ); - } - - in = t[1]; - } - - if( in->Bands == 3 && in->Type == IM_TYPE_YXY ) { - IMAGE *t[2]; - - if( im_open_local_array( out, t, 2, "conv-1", "p" ) || - im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || - im_Yxy2XYZ( t[0], t[1] ) ) { - im_close( out ); - return( NULL ); - } - - in = t[1]; - } - - if( in->Bands == 3 && in->Type == IM_TYPE_UCS ) { - IMAGE *t[2]; - - if( im_open_local_array( out, t, 2, "conv-1", "p" ) || - im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || - im_UCS2XYZ( t[0], t[1] ) ) { - im_close( out ); - return( NULL ); - } - - in = t[1]; - } - - if( in->Bands == 3 && in->Type == IM_TYPE_LAB ) { - IMAGE *t[2]; - - if( im_open_local_array( out, t, 2, "conv-1", "p" ) || - im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || - im_Lab2XYZ( t[0], t[1] ) ) { - im_close( out ); - return( NULL ); - } - - in = t[1]; - } - - if( in->Bands == 3 && in->Type == IM_TYPE_XYZ ) { - IMAGE *t[2]; - - if( im_open_local_array( out, t, 2, "conv-1", "p" ) || - im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || - im_XYZ2disp( t[0], t[1], im_col_displays( 7 ) ) ) { - im_close( out ); - return( NULL ); - } - - in = t[1]; - } - - /* Cast to the output format. - */ - { - IMAGE *t = im_open_local( out, "conv:1", "p" ); - - if( !t || im_clip2fmt( in, t, format_table[in->BandFmt] ) ) { - im_close( out ); - return( NULL ); - } - - in = t; - } - - if( im_copy( in, out ) ) { - im_close( out ); - return( NULL ); - } - - return( out ); -} diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index d3f54978..46bf973c 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -986,3 +986,59 @@ im_demand_hint (IMAGE * im, VipsDemandStyle hint, ...) return (im_demand_hint_array (im, hint, ar)); } + +int +im_copy_set( IMAGE *in, IMAGE *out, + VipsType type, float xres, float yres, int xoffset, int yoffset ) +{ + return( vips_copy( in, out, + "interpretation", type, + "xres", xres, + "yres", yres, + "xoffset", xoffset, + "yoffset", yoffset, + NULL ) ); +} + +int +im_copy_morph( IMAGE *in, IMAGE *out, + int bands, VipsBandFmt bandfmt, VipsCoding coding ) +{ + return( vips_copy( in, out, + "bands", bands, + "format", bandfmt, + "coding", coding, + NULL ) ); +} + +int +im_copy( IMAGE *in, IMAGE *out ) +{ + return( im_copy_set( in, out, + in->Type, in->Xres, in->Yres, 0, 0 ) ); +} + +int +im_copy_swap( IMAGE *in, IMAGE *out ) +{ + return( vips_copy( in, out, "swap", TRUE, NULL ) ); +} + +int +im_copy_set_meta( IMAGE *in, IMAGE *out, const char *field, GValue *value ) +{ + if( im_copy( in, out ) ) + return( 1 ); + im_meta_set( out, field, value ); + + return( 0 ); +} + +int +im_copy_native( IMAGE *in, IMAGE *out, gboolean is_msb_first ) +{ + if( is_msb_first != im_amiMSBfirst() ) + return( im_copy_swap( in, out ) ); + else + return( im_copy( in, out ) ); +} diff --git a/libvips/format/im_vips2jpeg.c b/libvips/format/im_vips2jpeg.c index 190c2853..3dccd95e 100644 --- a/libvips/format/im_vips2jpeg.c +++ b/libvips/format/im_vips2jpeg.c @@ -144,6 +144,217 @@ im_vips2mimejpeg( IMAGE *in, int qfac ) #include #include +/* Convert to a saveable format. + * + * im__saveable_t gives the general type of image + * we make: vanilla 1/3 bands (eg. PPM), with an optional alpha (eg. PNG), or + * with CMYK as an option (eg. JPEG). + * + * format_table[] says how to convert each input format. + * + * Need to im_close() the result IMAGE. + */ +IMAGE * +im__convert_saveable( IMAGE *in, + im__saveable_t saveable, int format_table[10] ) +{ + IMAGE *out; + + if( !(out = im_open( "convert-for-save", "p" )) ) + return( NULL ); + + /* If this is an IM_CODING_LABQ, we can go straight to RGB. + */ + if( in->Coding == IM_CODING_LABQ ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + static void *table = NULL; + + /* Make sure fast LabQ2disp tables are built. 7 is sRGB. + */ + if( !table ) + table = im_LabQ2disp_build_table( NULL, + im_col_displays( 7 ) ); + + if( !t || im_LabQ2disp_table( in, t, table ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* If this is an IM_CODING_RAD, we go to float RGB or XYZ. We should + * probably un-gamma-correct the RGB :( + */ + if( in->Coding == IM_CODING_RAD ) { + IMAGE *t; + + if( !(t = im_open_local( out, "conv:1", "p" )) || + im_rad2float( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* Get the bands right. + */ + if( in->Coding == IM_CODING_NONE ) { + if( in->Bands == 2 && saveable != IM__RGBA ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_extract_band( in, t, 0 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + else if( in->Bands > 3 && saveable == IM__RGB ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || + im_extract_bands( in, t, 0, 3 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + else if( in->Bands > 4 && + (saveable == IM__RGB_CMYK || saveable == IM__RGBA) ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || + im_extract_bands( in, t, 0, 4 ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + /* Else we have saveable IM__ANY and we don't chop bands down. + */ + } + + /* Interpret the Type field for colorimetric images. + */ + if( in->Bands == 3 && in->BandFmt == IM_BANDFMT_SHORT && + in->Type == IM_TYPE_LABS ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_LabS2LabQ( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( in->Coding == IM_CODING_LABQ ) { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_LabQ2Lab( in, t ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( in->Coding != IM_CODING_NONE ) { + im_close( out ); + return( NULL ); + } + + if( in->Bands == 3 && in->Type == IM_TYPE_LCH ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_LCh2Lab( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_YXY ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_Yxy2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_UCS ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_UCS2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_LAB ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_Lab2XYZ( t[0], t[1] ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + if( in->Bands == 3 && in->Type == IM_TYPE_XYZ ) { + IMAGE *t[2]; + + if( im_open_local_array( out, t, 2, "conv-1", "p" ) || + im_clip2fmt( in, t[0], IM_BANDFMT_FLOAT ) || + im_XYZ2disp( t[0], t[1], im_col_displays( 7 ) ) ) { + im_close( out ); + return( NULL ); + } + + in = t[1]; + } + + /* Cast to the output format. + */ + { + IMAGE *t = im_open_local( out, "conv:1", "p" ); + + if( !t || im_clip2fmt( in, t, format_table[in->BandFmt] ) ) { + im_close( out ); + return( NULL ); + } + + in = t; + } + + if( im_copy( in, out ) ) { + im_close( out ); + return( NULL ); + } + + return( out ); +} + /* Define a new error handler for when we bomb out. */ typedef struct { diff --git a/libvips/include/vips/conversion.h b/libvips/include/vips/conversion.h index bc10f6b0..6e9c5e04 100644 --- a/libvips/include/vips/conversion.h +++ b/libvips/include/vips/conversion.h @@ -45,16 +45,6 @@ int vips_copy( VipsImage *in, VipsImage **out, ... ); DOUBLEMASK *im_vips2mask( VipsImage *in, const char *filename ); int im_mask2vips( DOUBLEMASK *in, VipsImage *out ); -int im_copy( VipsImage *in, VipsImage *out ); -int im_copy_set( VipsImage *in, VipsImage *out, - VipsInterpretation interpretation, - float xres, float yres, int xoffset, int yoffset ); -int im_copy_set_meta( VipsImage *in, VipsImage *out, - const char *field, GValue *value ); -int im_copy_morph( VipsImage *in, VipsImage *out, - int bands, VipsBandFormat format, VipsCoding coding ); -int im_copy_swap( VipsImage *in, VipsImage *out ); -int im_copy_native( VipsImage *in, VipsImage *out, gboolean is_msb_first ); int im_copy_file( VipsImage *in, VipsImage *out ); int im_clip2fmt( VipsImage *in, VipsImage *out, VipsBandFormat fmt ); diff --git a/libvips/include/vips/image.h b/libvips/include/vips/image.h index ff6b1805..9f51c95c 100644 --- a/libvips/include/vips/image.h +++ b/libvips/include/vips/image.h @@ -473,7 +473,8 @@ VipsImage *vips_image_new_from_memory( void *buffer, void vips_image_set_delete_on_close( VipsImage *image, gboolean delete_on_close ); VipsImage *vips_image_new_disc_temp( const char *format ); -int vips_image_write( VipsImage *image, const char *filename ); +int vips_image_write( VipsImage *image, VipsImage *out ); +int vips_image_write_filename( VipsImage *image, const char *filename ); gboolean vips_image_isMSBfirst( VipsImage *image ); gboolean vips_image_isfile( VipsImage *image ); diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 5644fb63..3a4e9178 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -526,6 +526,17 @@ int im_min( VipsImage *in, double *out ); int im_minpos( VipsImage *in, int *xpos, int *ypos, double *out ); int im_avg( VipsImage *in, double *out ); +int im_copy( VipsImage *in, VipsImage *out ); +int im_copy_set( VipsImage *in, VipsImage *out, + VipsInterpretation interpretation, + float xres, float yres, int xoffset, int yoffset ); +int im_copy_set_meta( VipsImage *in, VipsImage *out, + const char *field, GValue *value ); +int im_copy_morph( VipsImage *in, VipsImage *out, + int bands, VipsBandFormat format, VipsCoding coding ); +int im_copy_swap( VipsImage *in, VipsImage *out ); +int im_copy_native( VipsImage *in, VipsImage *out, gboolean is_msb_first ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index b07a7a45..00657f8a 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -1759,9 +1759,54 @@ vips_image_new_disc_temp( const char *format ) return( image ); } +static int +vips_image_write_gen( VipsRegion *or, + void *seq, void *a, void *b, gboolean *stop ) +{ + VipsRegion *ir = (VipsRegion *) seq; + VipsRect *r = &or->valid; + + /* Copy with pointers. + */ + if( vips_region_prepare( ir, r ) || + vips_region_region( or, ir, r, r->left, r->top ) ) + return( -1 ); + + return( 0 ); +} + /** * vips_image_write: * @image: image to write + * @out: write to this image + * + * A convenience function to write a #VipsImage to another #VipsImage. Unlike + * vips_copy(), you can specify the #VipsImage you want to write to. + * + * Returns: 0 on success, or -1 on error. + */ +int +vips_image_write( VipsImage *image, VipsImage *out ) +{ + if( vips_image_pio_input( image ) || + vips_image_pio_output( out ) ) + return( -1 ); + if( vips_image_copy_fields( out, image ) ) + return( -1 ); + vips_demand_hint( out, + VIPS_DEMAND_STYLE_THINSTRIP, image, NULL ); + + if( vips_image_generate( out, + vips_start_one, vips_image_write_gen, vips_stop_one, + copy->input, copy ) ) + return( -1 ); + + return( 0 ); +} + +/** + * vips_image_write_filename: + * @image: image to write * @filename: write to this file * * A convenience function to write a #VipsImage to a file. @@ -1769,7 +1814,7 @@ vips_image_new_disc_temp( const char *format ) * Returns: 0 on success, or -1 on error. */ int -vips_image_write( VipsImage *image, const char *filename ) +vips_image_write_filename( VipsImage *image, const char *filename ) { VipsImage *out; @@ -1777,7 +1822,7 @@ vips_image_write( VipsImage *image, const char *filename ) if( !(out = vips_image_new_mode( filename, "w" )) ) return( -1 ); - if( im_copy( image, out ) ) { + if( vips_image_write( image, out ) ) { g_object_unref( out ); return( -1 ); } @@ -2060,7 +2105,7 @@ vips_image_wio_input( VipsImage *image ) */ if( !(t1 = vips_image_new_mode( "wio_input", "t" )) ) return( -1 ); - if( im_copy( image, t1 ) ) { + if( vips_image_write( image, t1 ) ) { g_object_unref( t1 ); return( -1 ); }