int vips__csv_write( VipsImage *in, const char *filename, const char *separator ) { FILE *fp; VipsImage *memory; if( vips_check_mono( "vips2csv", in ) || vips_check_uncoded( "vips2csv", in ) || !(memory = vips_image_copy_memory( in )) ) return( -1 ); if( !(fp = vips__file_open_write( filename, TRUE )) ) { VIPS_UNREF( memory ); return( -1 ); } if( vips2csv( memory, fp, separator ) ) { fclose( fp ); VIPS_UNREF( memory ); return( -1 ); } fclose( fp ); VIPS_UNREF( memory ); return( 0 ); }
/* Write a VIPS image to PNG. */ static int write_vips( Write *write, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip ) { VipsImage *in = write->in; int bit_depth; int color_type; int interlace_type; int i, nb_passes; g_assert( in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT ); g_assert( in->Coding == VIPS_CODING_NONE ); g_assert( in->Bands > 0 && in->Bands < 5 ); /* Catch PNG errors. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); /* Check input image. If we are writing interlaced, we need to make 7 * passes over the image. We advertise ourselves as seq, so to ensure * we only suck once from upstream, switch to WIO. */ if( interlace ) { if( !(write->memory = vips_image_copy_memory( in )) ) return( -1 ); in = write->memory; } else { if( vips_image_pio_input( in ) ) return( -1 ); } if( compress < 0 || compress > 9 ) { vips_error( "vips2png", "%s", _( "compress should be in [0,9]" ) ); return( -1 ); } /* Set compression parameters. */ png_set_compression_level( write->pPng, compress ); /* Set row filter. */ png_set_filter( write->pPng, 0, filter ); bit_depth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16; switch( in->Bands ) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: vips_error( "vips2png", _( "can't save %d band image as png" ), in->Bands ); return( -1 ); } interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; png_set_IHDR( write->pPng, write->pInfo, in->Xsize, in->Ysize, bit_depth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); /* Set resolution. libpng uses pixels per meter. */ png_set_pHYs( write->pPng, write->pInfo, VIPS_RINT( in->Xres * 1000 ), VIPS_RINT( in->Yres * 1000 ), PNG_RESOLUTION_METER ); /* Set ICC Profile. */ if( profile && !strip ) { if( strcmp( profile, "none" ) != 0 ) { void *data; size_t length; if( !(data = vips__file_read_name( profile, VIPS_ICC_DIR, &length )) ) return( -1 ); #ifdef DEBUG printf( "write_vips: " "attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } } else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) && !strip ) { void *data; size_t length; if( vips_image_get_blob( in, VIPS_META_ICC_NAME, &data, &length ) ) return( -1 ); #ifdef DEBUG printf( "write_vips: attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } png_write_info( write->pPng, write->pInfo ); /* If we're an intel byte order CPU and this is a 16bit image, we need * to swap bytes. */ if( bit_depth > 8 && !vips_amiMSBfirst() ) png_set_swap( write->pPng ); if( interlace ) nb_passes = png_set_interlace_handling( write->pPng ); else nb_passes = 1; /* Write data. */ for( i = 0; i < nb_passes; i++ ) if( vips_sink_disc( in, write_png_block, write ) ) return( -1 ); /* The setjmp() was held by our background writer: reset it. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); png_write_end( write->pPng, write->pInfo ); return( 0 ); }
/* Write a VIPS image to PNG. */ static int write_vips( Write *write, int compress, int interlace, const char *profile, VipsForeignPngFilter filter, gboolean strip, gboolean palette, int colours, int Q, double dither ) { VipsImage *in = write->in; int bit_depth; int color_type; int interlace_type; int i, nb_passes; g_assert( in->BandFmt == VIPS_FORMAT_UCHAR || in->BandFmt == VIPS_FORMAT_USHORT ); g_assert( in->Coding == VIPS_CODING_NONE ); g_assert( in->Bands > 0 && in->Bands < 5 ); /* Catch PNG errors. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); /* Check input image. If we are writing interlaced, we need to make 7 * passes over the image. We advertise ourselves as seq, so to ensure * we only suck once from upstream, switch to WIO. */ if( interlace ) { if( !(write->memory = vips_image_copy_memory( in )) ) return( -1 ); in = write->memory; } else { if( vips_image_pio_input( in ) ) return( -1 ); } if( compress < 0 || compress > 9 ) { vips_error( "vips2png", "%s", _( "compress should be in [0,9]" ) ); return( -1 ); } /* Set compression parameters. */ png_set_compression_level( write->pPng, compress ); /* Set row filter. */ png_set_filter( write->pPng, 0, filter ); bit_depth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16; switch( in->Bands ) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: vips_error( "vips2png", _( "can't save %d band image as png" ), in->Bands ); return( -1 ); } #ifdef HAVE_IMAGEQUANT /* Enable image quantisation to paletted 8bpp PNG if colours is set. */ if( palette ) { g_assert( colours >= 2 && colours <= 256 ); bit_depth = 8; color_type = PNG_COLOR_TYPE_PALETTE; } #else if( palette ) g_warning( "%s", _( "ignoring palette (no quantisation support)" ) ); #endif /*HAVE_IMAGEQUANT*/ interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; png_set_IHDR( write->pPng, write->pInfo, in->Xsize, in->Ysize, bit_depth, color_type, interlace_type, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); /* Set resolution. libpng uses pixels per meter. */ png_set_pHYs( write->pPng, write->pInfo, VIPS_RINT( in->Xres * 1000 ), VIPS_RINT( in->Yres * 1000 ), PNG_RESOLUTION_METER ); /* Set ICC Profile. */ if( profile && !strip ) { if( strcmp( profile, "none" ) != 0 ) { void *data; size_t length; if( !(data = vips__file_read_name( profile, vips__icc_dir(), &length )) ) return( -1 ); #ifdef DEBUG printf( "write_vips: " "attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } } else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) && !strip ) { void *data; size_t length; if( vips_image_get_blob( in, VIPS_META_ICC_NAME, &data, &length ) ) return( -1 ); #ifdef DEBUG printf( "write_vips: attaching %zd bytes of ICC profile\n", length ); #endif /*DEBUG*/ png_set_iCCP( write->pPng, write->pInfo, "icc", PNG_COMPRESSION_TYPE_BASE, data, length ); } if( vips_image_get_typeof( in, VIPS_META_XMP_NAME ) ) { const char *str; if( vips_image_get_string( in, VIPS_META_XMP_NAME, &str ) ) return( -1 ); vips__png_set_text( write->pPng, write->pInfo, "XML:com.adobe.xmp", str ); } /* Set any "png-comment-xx-yyy" metadata items. */ if( vips_image_map( in, write_png_comment, write ) ) return( -1 ); #ifdef HAVE_IMAGEQUANT if( palette ) { VipsImage *im_index; VipsImage *im_palette; int palette_count; png_color *png_palette; png_byte *png_trans; int trans_count; if( vips__quantise_image( in, &im_index, &im_palette, colours, Q, dither ) ) return( -1 ); palette_count = im_palette->Xsize; g_assert( palette_count <= PNG_MAX_PALETTE_LENGTH ); png_palette = (png_color *) png_malloc( write->pPng, palette_count * sizeof( png_color ) ); png_trans = (png_byte *) png_malloc( write->pPng, palette_count * sizeof( png_byte ) ); trans_count = 0; for( i = 0; i < palette_count; i++ ) { VipsPel *p = (VipsPel *) VIPS_IMAGE_ADDR( im_palette, i, 0 ); png_color *col = &png_palette[i]; col->red = p[0]; col->green = p[1]; col->blue = p[2]; png_trans[i] = p[3]; if( p[3] != 255 ) trans_count = i + 1; #ifdef DEBUG printf( "write_vips: palette[%d] %d %d %d %d\n", i + 1, p[0], p[1], p[2], p[3] ); #endif /*DEBUG*/ } #ifdef DEBUG printf( "write_vips: attaching %d color palette\n", palette_count ); #endif /*DEBUG*/ png_set_PLTE( write->pPng, write->pInfo, png_palette, palette_count ); if( trans_count ) { #ifdef DEBUG printf( "write_vips: attaching %d alpha values\n", trans_count ); #endif /*DEBUG*/ png_set_tRNS( write->pPng, write->pInfo, png_trans, trans_count, NULL ); } png_free( write->pPng, (void *) png_palette ); png_free( write->pPng, (void *) png_trans ); VIPS_UNREF( im_palette ); VIPS_UNREF( write->memory ); write->memory = im_index; in = write->memory; } #endif /*HAVE_IMAGEQUANT*/ png_write_info( write->pPng, write->pInfo ); /* If we're an intel byte order CPU and this is a 16bit image, we need * to swap bytes. */ if( bit_depth > 8 && !vips_amiMSBfirst() ) png_set_swap( write->pPng ); if( interlace ) nb_passes = png_set_interlace_handling( write->pPng ); else nb_passes = 1; /* Write data. */ for( i = 0; i < nb_passes; i++ ) if( vips_sink_disc( in, write_png_block, write ) ) return( -1 ); /* The setjmp() was held by our background writer: reset it. */ if( setjmp( png_jmpbuf( write->pPng ) ) ) return( -1 ); png_write_end( write->pPng, write->pInfo ); return( 0 ); }
static int vips_histogram_build( VipsObject *object ) { VipsHistogram *histogram = VIPS_HISTOGRAM( object ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram ); VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; VipsImage **memory; VipsPel *outbuf; VipsPel **inbuf; int i; #ifdef DEBUG printf( "vips_histogram_build: " ); vips_object_print_name( object ); printf( "\n" ); #endif /*DEBUG*/ if( VIPS_OBJECT_CLASS( vips_histogram_parent_class )->build( object ) ) return( -1 ); g_assert( histogram->n > 0 ); /* Must be NULL-terminated. */ g_assert( !histogram->in[histogram->n] ); decode = (VipsImage **) vips_object_local_array( object, histogram->n ); format = (VipsImage **) vips_object_local_array( object, histogram->n ); band = (VipsImage **) vips_object_local_array( object, histogram->n ); size = (VipsImage **) vips_object_local_array( object, histogram->n ); memory = (VipsImage **) vips_object_local_array( object, histogram->n ); g_object_set( histogram, "out", vips_image_new(), NULL ); for( i = 0; i < histogram->n; i++ ) if( vips_image_decode( histogram->in[i], &decode[i] ) || vips_check_hist( class->nickname, decode[i] ) ) return( -1 ); /* Cast our input images up to a common format, bands and size. If * input_format is set, cast to a fixed input type. */ if( hclass->input_format != VIPS_FORMAT_NOTSET ) { for( i = 0; i < histogram->n; i++ ) if( vips_cast( decode[i], &format[i], hclass->input_format, NULL ) ) return( -1 ); } else { if( vips__formatalike_vec( decode, format, histogram->n ) ) return( -1 ); } if( vips__bandalike_vec( class->nickname, format, band, histogram->n, 1 ) || vips__hist_sizealike_vec( band, size, histogram->n ) ) return( -1 ); if( vips_image_pipeline_array( histogram->out, VIPS_DEMAND_STYLE_THINSTRIP, size ) ) return( -1 ); /* Need a copy of the inputs in memory. */ if( !(inbuf = VIPS_ARRAY( object, histogram->n + 1, VipsPel * )) ) return( -1 ); for( i = 0; i < histogram->n; i++ ) { if( !(memory[i] = vips_image_copy_memory( size[i] )) ) return( -1 ); inbuf[i] = VIPS_IMAGE_ADDR( memory[i], 0, 0 ); } inbuf[i] = NULL; /* Keep a copy of the memory images here for subclasses. */ histogram->ready = memory; histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->ready[0] ); histogram->out->Ysize = 1; if( hclass->format_table ) histogram->out->BandFmt = hclass->format_table[histogram->ready[0]->BandFmt]; histogram->out->Type = VIPS_INTERPRETATION_HISTOGRAM; if( !(outbuf = vips_malloc( object, VIPS_IMAGE_SIZEOF_LINE( histogram->out ))) ) return( -1 ); hclass->process( histogram, outbuf, inbuf, histogram->ready[0]->Xsize ); if( vips_image_write_line( histogram->out, 0, outbuf ) ) return( -1 ); return( 0 ); }