static int vips_replicate_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsReplicate *replicate = (VipsReplicate *) object; if( VIPS_OBJECT_CLASS( vips_replicate_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( replicate->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, replicate->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, replicate->in, NULL ); conversion->out->Xsize *= replicate->across; conversion->out->Ysize *= replicate->down; if( vips_image_generate( conversion->out, vips_start_one, vips_replicate_gen, vips_stop_one, replicate->in, replicate ) ) return( -1 ); return( 0 ); }
static int vips_sequential_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsSequential *sequential = (VipsSequential *) object; VIPS_DEBUG_MSG( "vips_sequential_build\n" ); if( VIPS_OBJECT_CLASS( vips_sequential_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( sequential->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, sequential->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_FATSTRIP, sequential->in, NULL ); if( vips_image_generate( conversion->out, vips_start_one, vips_sequential_generate, vips_stop_one, sequential->in, sequential ) ) return( -1 ); return( 0 ); }
static int vips_tile_cache_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsTileCache *cache = (VipsTileCache *) object; VIPS_DEBUG_MSG( "vips_tile_cache_build\n" ); if( VIPS_OBJECT_CLASS( vips_tile_cache_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( cache->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, cache->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_SMALLTILE, cache->in, NULL ); if( vips_image_generate( conversion->out, vips_start_one, vips_tile_cache_gen, vips_stop_one, cache->in, cache ) ) return( -1 ); return( 0 ); }
static int vips_sequential_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsSequential *sequential = (VipsSequential *) object; VipsImage *t; VIPS_DEBUG_MSG( "vips_sequential_build\n" ); if( VIPS_OBJECT_CLASS( vips_sequential_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( sequential->in ) ) return( -1 ); if( vips_linecache( sequential->in, &t, "tile_height", sequential->tile_height, "strategy", VIPS_CACHE_SEQUENTIAL, NULL ) ) return( -1 ); vips_object_local( object, t ); if( vips_image_copy_fields( conversion->out, t ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, t, NULL ); if( vips_image_generate( conversion->out, vips_start_one, vips_sequential_generate, vips_stop_one, t, sequential ) ) return( -1 ); return( 0 ); }
static int read_header( Read *read, VipsImage *out ) { vips_image_init_fields( out, read->config.input.width, read->config.input.height, read->config.input.has_alpha ? 4 : 3, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 ); vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); return( 0 ); }
static int vips_recomb_build( VipsObject *object ) { VipsConversion *conversion = (VipsConversion *) object; VipsRecomb *recomb = (VipsRecomb *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); if( VIPS_OBJECT_CLASS( vips_recomb_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( recomb->in ) || vips_check_uncoded( "VipsRecomb", recomb->in ) || vips_check_noncomplex( "VipsRecomb", recomb->in ) ) return( -1 ); if( vips_image_pio_input( recomb->m ) || vips_check_uncoded( "VipsRecomb", recomb->m ) || vips_check_noncomplex( "VipsRecomb", recomb->m ) || vips_check_mono( "VipsRecomb", recomb->m ) ) return( -1 ); if( recomb->in->Bands != recomb->m->Xsize ) { vips_error( "VipsRecomb", "%s", _( "bands in must equal matrix width" ) ); return( -1 ); } if( vips_cast( recomb->m, &t[0], VIPS_FORMAT_DOUBLE, NULL ) || vips_image_wio_input( t[0] ) ) return( -1 ); recomb->coeff = (double *) VIPS_IMAGE_ADDR( t[0], 0, 0 ); if( vips_image_copy_fields( conversion->out, recomb->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, recomb->in, NULL ); conversion->out->Bands = recomb->m->Ysize; if( vips_bandfmt_isint( recomb->in->BandFmt ) ) conversion->out->BandFmt = VIPS_FORMAT_FLOAT; if( vips_image_generate( conversion->out, vips_start_one, vips_recomb_gen, vips_stop_one, recomb->in, recomb ) ) return( -1 ); return( 0 ); }
static int vips_flip_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsFlip *flip = (VipsFlip *) object; VipsGenerateFn generate_fn; if( VIPS_OBJECT_CLASS( vips_flip_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( flip->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, flip->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, flip->in, NULL ); if( flip->direction == VIPS_DIRECTION_HORIZONTAL ) { generate_fn = vips_flip_horizontal_gen; conversion->out->Xoffset = flip->in->Xsize; conversion->out->Yoffset = 0; } else { generate_fn = vips_flip_vertical_gen; conversion->out->Xoffset = 0; conversion->out->Yoffset = flip->in->Ysize; } if( vips_image_generate( conversion->out, vips_start_one, generate_fn, vips_stop_one, flip->in, flip ) ) return( -1 ); return( 0 ); }
static int vips_black_build( VipsObject *object ) { VipsCreate *create = VIPS_CREATE( object ); VipsBlack *black = (VipsBlack *) object; if( VIPS_OBJECT_CLASS( vips_black_parent_class )->build( object ) ) return( -1 ); vips_image_init_fields( create->out, black->width, black->height, black->bands, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, black->bands == 1 ? VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_demand_hint( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); if( vips_image_generate( create->out, NULL, vips_black_gen, NULL, NULL, NULL ) ) return( -1 ); return( 0 ); }
static int read_csv( FILE *fp, VipsImage *out, int skip, int lines, const char *whitespace, const char *separator, gboolean read_image ) { int i; char whitemap[256]; char sepmap[256]; const char *p; fpos_t pos; int columns; int ch; double d; double *buf; int y; /* Make our char maps. */ for( i = 0; i < 256; i++ ) { whitemap[i] = 0; sepmap[i] = 0; } for( p = whitespace; *p; p++ ) whitemap[(int) *p] = 1; for( p = separator; *p; p++ ) sepmap[(int) *p] = 1; /* Skip first few lines. */ for( i = 0; i < skip; i++ ) if( !skip_line( fp ) ) { vips_error( "csv2vips", "%s", _( "end of file while skipping start" ) ); return( -1 ); } /* Parse the first line to get number of columns. Only bother checking * fgetpos() the first time we use it: assume it's working after this. */ if( fgetpos( fp, &pos ) ) { vips_error_system( errno, "csv2vips", "%s", _( "unable to seek" ) ); return( -1 ); } for( columns = 0; (ch = read_double( fp, whitemap, sepmap, skip + 1, columns + 1, &d )) == 0; columns++ ) ; fsetpos( fp, &pos ); if( columns == 0 ) { vips_error( "csv2vips", "%s", _( "empty line" ) ); return( -1 ); } /* If lines is -1, we have to scan the whole file to get the * number of lines out. */ if( lines == -1 ) { fgetpos( fp, &pos ); for( lines = 0; skip_line( fp ); lines++ ) ; fsetpos( fp, &pos ); } vips_image_init_fields( out, columns, lines, 1, VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, 1.0, 1.0 ); vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); /* Just reading the header? We are done. */ if( !read_image ) return( 0 ); if( !(buf = VIPS_ARRAY( out, VIPS_IMAGE_N_ELEMENTS( out ), double )) ) return( -1 ); for( y = 0; y < lines; y++ ) { int x; for( x = 0; x < columns; x++ ) { int lineno = y + skip + 1; int colno = x + 1; ch = read_double( fp, whitemap, sepmap, lineno, colno, &d ); if( ch == EOF ) { vips_error( "csv2vips", _( "unexpected EOF, line %d col %d" ), lineno, colno ); return( -1 ); } else if( ch == '\n' ) { vips_error( "csv2vips", _( "unexpected EOL, line %d col %d" ), lineno, colno ); return( -1 ); } else if( ch ) /* Parse error. */ return( -1 ); buf[x] = d; } if( vips_image_write_line( out, y, (VipsPel *) buf ) ) return( -1 ); /* Skip over the '\n' to the next line. */ skip_line( fp ); } return( 0 ); }
static int vips_copy_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsCopy *copy = (VipsCopy *) object; int i; if( VIPS_OBJECT_CLASS( vips_copy_parent_class )->build( object ) ) return( -1 ); if( vips_image_pio_input( copy->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, copy->in ) ) return( -1 ); vips_demand_hint( conversion->out, VIPS_DEMAND_STYLE_THINSTRIP, copy->in, NULL ); /* Use props to adjust header fields. */ for( i = 0; i < VIPS_NUMBER( vips_copy_names ); i++ ) { const char *name = vips_copy_names[i]; GParamSpec *pspec; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; if( vips_object_get_argument( object, name, &pspec, &argument_class, &argument_instance ) ) return( -1 ); if( argument_instance->assigned ) { GType type = G_PARAM_SPEC_VALUE_TYPE( pspec ); GValue value = { 0, }; g_value_init( &value, type ); g_object_get_property( G_OBJECT( object ), name, &value ); #ifdef VIPS_DEBUG { char *str; str = g_strdup_value_contents( &value ); printf( "vips_copy_build: %s = %s\n", name, str ); g_free( str ); } #endif /* VIPS_DEBUG */ g_object_set_property( G_OBJECT( conversion->out ), name, &value ); g_value_unset( &value ); } } if( vips_image_generate( conversion->out, vips_start_one, vips_copy_gen, vips_stop_one, copy->in, copy ) ) return( -1 ); return( 0 ); }
static int vips_fits_get_header( VipsFits *fits, VipsImage *out ) { int status; int bitpix; int width, height, bands, format, type; int keysexist; int i; status = 0; if( fits_get_img_paramll( fits->fptr, 10, &bitpix, &fits->naxis, fits->naxes, &status ) ) { vips_fits_error( status ); return( -1 ); } #ifdef VIPS_DEBUG VIPS_DEBUG_MSG( "naxis = %d\n", fits->naxis ); for( i = 0; i < fits->naxis; i++ ) VIPS_DEBUG_MSG( "%d) %lld\n", i, fits->naxes[i] ); #endif /*VIPS_DEBUG*/ width = 1; height = 1; bands = 1; switch( fits->naxis ) { /* If you add more dimensions here, adjust data read below. See also * the definition of MAX_DIMENSIONS above. */ case 10: case 9: case 8: case 7: case 6: case 5: case 4: for( i = fits->naxis; i > 3; i-- ) if( fits->naxes[i - 1] != 1 ) { vips_error( "fits", "%s", _( "dimensions above 3 " "must be size 1" ) ); return( -1 ); } case 3: bands = fits->naxes[2]; case 2: height = fits->naxes[1]; case 1: width = fits->naxes[0]; break; default: vips_error( "fits", _( "bad number of axis %d" ), fits->naxis ); return( -1 ); } /* Are we in one-band mode? */ if( fits->band_select != -1 ) bands = 1; /* Get image format. We want the 'raw' format of the image, our caller * can convert using the meta info if they want. */ for( i = 0; i < VIPS_NUMBER( fits2vips_formats ); i++ ) if( fits2vips_formats[i][0] == bitpix ) break; if( i == VIPS_NUMBER( fits2vips_formats ) ) { vips_error( "fits", _( "unsupported bitpix %d\n" ), bitpix ); return( -1 ); } format = fits2vips_formats[i][1]; fits->datatype = fits2vips_formats[i][2]; if( bands == 1 ) { if( format == VIPS_FORMAT_USHORT ) type = VIPS_INTERPRETATION_GREY16; else type = VIPS_INTERPRETATION_B_W; } else if( bands == 3 ) { if( format == VIPS_FORMAT_USHORT ) type = VIPS_INTERPRETATION_RGB16; else type = VIPS_INTERPRETATION_RGB; } else type = VIPS_INTERPRETATION_MULTIBAND; vips_image_init_fields( out, width, height, bands, format, VIPS_CODING_NONE, type, 1.0, 1.0 ); vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); /* Read all keys into meta. */ if( fits_get_hdrspace( fits->fptr, &keysexist, NULL, &status ) ) { vips_fits_error( status ); return( -1 ); } for( i = 0; i < keysexist; i++ ) { char record[81]; char vipsname[100]; if( fits_read_record( fits->fptr, i + 1, record, &status ) ) { vips_fits_error( status ); return( -1 ); } VIPS_DEBUG_MSG( "fits2vips: setting meta on vips image:\n" ); VIPS_DEBUG_MSG( " record == \"%s\"\n", record ); /* FITS lets keys repeat. For example, HISTORY appears many * times, each time with a fresh line of history attached. We * have to include the key index in the vips name we assign. */ vips_snprintf( vipsname, 100, "fits-%d", i ); vips_image_set_string( out, vipsname, record ); } return( 0 ); }
static int parse_header( Read *read ) { VipsImage *im = read->im; Image *image = read->image; Image *p; int i; #ifdef DEBUG printf( "parse_header: filename = %s\n", read->filename ); printf( "GetImageChannelDepth(AllChannels) = %d\n", GetImageChannelDepth( image, AllChannels, &image->exception ) ); printf( "GetImageDepth() = %ld\n", GetImageDepth( image, &image->exception ) ); printf( "image->depth = %u\n", image->depth ); printf( "GetImageType() = %d\n", GetImageType( image, &image->exception ) ); printf( "IsGrayImage() = %d\n", IsGrayImage( image, &image->exception ) ); printf( "IsMonochromeImage() = %d\n", IsMonochromeImage( image, &image->exception ) ); printf( "IsOpaqueImage() = %d\n", IsOpaqueImage( image, &image->exception ) ); #endif /*DEBUG*/ im->Xsize = image->columns; im->Ysize = image->rows; read->frame_height = image->rows; if( (im->Bands = get_bands( image )) < 0 ) return( -1 ); /* Depth can be 'fractional'. You'd think we should use * GetImageDepth() but that seems unreliable. 16-bit mono DICOM images * are reported as depth 1, for example. */ im->BandFmt = -1; if( image->depth >= 1 && image->depth <= 8 ) im->BandFmt = VIPS_FORMAT_UCHAR; if( image->depth >= 9 && image->depth <= 16 ) im->BandFmt = VIPS_FORMAT_USHORT; #ifdef UseHDRI if( image->depth == 32 ) im->BandFmt = VIPS_FORMAT_FLOAT; if( image->depth == 64 ) im->BandFmt = VIPS_FORMAT_DOUBLE; #else /*!UseHDRI*/ if( image->depth == 32 ) im->BandFmt = VIPS_FORMAT_UINT; #endif /*UseHDRI*/ if( im->BandFmt == -1 ) { vips_error( "magick2vips", _( "unsupported bit depth %d" ), (int) image->depth ); return( -1 ); } switch( image->colorspace ) { case GRAYColorspace: if( im->BandFmt == VIPS_FORMAT_USHORT ) im->Type = VIPS_INTERPRETATION_GREY16; else im->Type = VIPS_INTERPRETATION_B_W; break; case RGBColorspace: if( im->BandFmt == VIPS_FORMAT_USHORT ) im->Type = VIPS_INTERPRETATION_RGB16; else im->Type = VIPS_INTERPRETATION_RGB; break; case sRGBColorspace: if( im->BandFmt == VIPS_FORMAT_USHORT ) im->Type = VIPS_INTERPRETATION_RGB16; else im->Type = VIPS_INTERPRETATION_sRGB; break; case CMYKColorspace: im->Type = VIPS_INTERPRETATION_CMYK; break; default: vips_error( "magick2vips", _( "unsupported colorspace %d" ), (int) image->colorspace ); return( -1 ); } switch( image->units ) { case PixelsPerInchResolution: im->Xres = image->x_resolution / 25.4; im->Yres = image->y_resolution / 25.4; break; case PixelsPerCentimeterResolution: im->Xres = image->x_resolution / 10.0; im->Yres = image->y_resolution / 10.0; break; default: im->Xres = 1.0; im->Yres = 1.0; break; } /* Other fields. */ im->Coding = VIPS_CODING_NONE; vips_demand_hint( im, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); /* Three ways to loop over attributes / properties :-( */ #ifdef HAVE_RESETIMAGEPROPERTYITERATOR { char *key; /* This is the most recent imagemagick API, test for this first. */ ResetImagePropertyIterator( image ); while( (key = GetNextImageProperty( image )) ) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC( name_text ); vips_buf_appendf( &name, "magick-%s", key ); vips_image_set_string( im, vips_buf_all( &name ), GetImageProperty( image, key ) ); } } #elif defined(HAVE_RESETIMAGEATTRIBUTEITERATOR) { const ImageAttribute *attr; /* magick6.1-ish and later, deprecated in 6.5ish. */ ResetImageAttributeIterator( image ); while( (attr = GetNextImageAttribute( image )) ) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC( name_text ); vips_buf_appendf( &name, "magick-%s", attr->key ); vips_image_set_string( im, vips_buf_all( &name ), attr->value ); } } #else { const ImageAttribute *attr; /* GraphicsMagick is missing the iterator: we have to loop ourselves. * ->attributes is marked as private in the header, but there's no * getter so we have to access it directly. */ for( attr = image->attributes; attr; attr = attr->next ) { char name_text[256]; VipsBuf name = VIPS_BUF_STATIC( name_text ); vips_buf_appendf( &name, "magick-%s", attr->key ); vips_image_set_string( im, vips_buf_all( &name ), attr->value ); } } #endif /* Do we have a set of equal-sized frames? Append them. FIXME ... there must be an attribute somewhere from dicom read which says this is a volumetric image */ read->n_frames = 0; for( p = image; p; (p = GetNextImageInList( p )) ) { if( p->columns != (unsigned int) im->Xsize || p->rows != (unsigned int) im->Ysize || get_bands( p ) != im->Bands ) break; read->n_frames += 1; } if( p ) /* Nope ... just do the first image in the list. */ read->n_frames = 1; /* Record frame pointers. */ im->Ysize *= read->n_frames; if( !(read->frames = VIPS_ARRAY( NULL, read->n_frames, Image * )) ) return( -1 ); p = image; for( i = 0; i < read->n_frames; i++ ) { read->frames[i] = p; p = GetNextImageInList( p ); } return( 0 ); }
/* Read a png header. */ static int png2vips_header( Read *read, VipsImage *out ) { png_uint_32 width, height; int bit_depth, color_type; int interlace_type; png_uint_32 res_x, res_y; int unit_type; png_charp name; int compression_type; /* Well thank you, libpng. */ #if PNG_LIBPNG_VER < 10400 png_charp profile; #else png_bytep profile; #endif png_uint_32 proflen; int bands; VipsInterpretation interpretation; double Xres, Yres; if( setjmp( png_jmpbuf( read->pPng ) ) ) return( -1 ); png_get_IHDR( read->pPng, read->pInfo, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); /* png_get_channels() gives us 1 band for palette images ... so look * at colour_type for output bands. * * Ignore alpha, we detect that separately below. */ switch( color_type ) { case PNG_COLOR_TYPE_PALETTE: bands = 3; break; case PNG_COLOR_TYPE_GRAY_ALPHA: case PNG_COLOR_TYPE_GRAY: bands = 1; break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: bands = 3; break; default: vips_error( "png2vips", "%s", _( "unsupported color type" ) ); return( -1 ); } if( bit_depth > 8 ) { if( bands < 3 ) interpretation = VIPS_INTERPRETATION_GREY16; else interpretation = VIPS_INTERPRETATION_RGB16; } else { if( bands < 3 ) interpretation = VIPS_INTERPRETATION_B_W; else interpretation = VIPS_INTERPRETATION_sRGB; } /* Expand palette images. */ if( color_type == PNG_COLOR_TYPE_PALETTE ) png_set_palette_to_rgb( read->pPng ); /* Expand transparency. */ if( png_get_valid( read->pPng, read->pInfo, PNG_INFO_tRNS ) ) { png_set_tRNS_to_alpha( read->pPng ); bands += 1; } else if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA ) { /* Some images have no transparency chunk, but still set * color_type to alpha. */ bands += 1; } /* Expand <8 bit images to full bytes. */ if( color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8 ) png_set_expand_gray_1_2_4_to_8( read->pPng ); /* If we're an INTEL byte order machine and this is 16bits, we need * to swap bytes. */ if( bit_depth > 8 && !vips_amiMSBfirst() ) png_set_swap( read->pPng ); /* Get resolution. I'm not sure what we should do for UNKNOWN, since * vips is always pixels/mm. */ unit_type = PNG_RESOLUTION_METER; res_x = 1000; res_y = 1000; png_get_pHYs( read->pPng, read->pInfo, &res_x, &res_y, &unit_type ); switch( unit_type ) { case PNG_RESOLUTION_METER: Xres = res_x / 1000.0; Yres = res_y / 1000.0; break; default: Xres = res_x; Yres = res_y; break; } /* Set VIPS header. */ vips_image_init_fields( out, width, height, bands, bit_depth > 8 ? VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, interpretation, Xres, Yres ); /* Sequential mode needs thinstrip to work with things like * vips_shrink(). */ vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); /* Fetch the ICC profile. @name is useless, something like "icc" or * "ICC Profile" etc. Ignore it. * * @profile was png_charpp in libpngs < 1.5, png_bytepp is the * modern one. Ignore the warning, if any. */ if( png_get_iCCP( read->pPng, read->pInfo, &name, &compression_type, &profile, &proflen ) ) { void *profile_copy; #ifdef DEBUG printf( "png2vips_header: attaching %zd bytes of ICC profile\n", proflen ); printf( "png2vips_header: name = \"%s\"\n", name ); #endif /*DEBUG*/ if( !(profile_copy = vips_malloc( NULL, proflen )) ) return( -1 ); memcpy( profile_copy, profile, proflen ); vips_image_set_blob( out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_free, profile_copy, proflen ); } /* Sanity-check line size. */ png_read_update_info( read->pPng, read->pInfo ); if( png_get_rowbytes( read->pPng, read->pInfo ) != VIPS_IMAGE_SIZEOF_LINE( out ) ) { vips_error( "vipspng", "%s", _( "unable to read PNG header" ) ); 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( ReadJpeg *jpeg, VipsImage *out ) { struct jpeg_decompress_struct *cinfo = &jpeg->cinfo; jpeg_saved_marker_ptr p; VipsInterpretation interpretation; double xres, yres; /* Capture app2 sections here for assembly. */ void *app2_data[MAX_APP2_SECTIONS] = { 0 }; size_t app2_data_length[MAX_APP2_SECTIONS] = { 0 }; size_t 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 = jpeg->shrink; cinfo->scale_num = 1; jpeg_calc_output_dimensions( cinfo ); jpeg->invert_pels = FALSE; switch( cinfo->out_color_space ) { case JCS_GRAYSCALE: interpretation = VIPS_INTERPRETATION_B_W; break; case JCS_CMYK: interpretation = VIPS_INTERPRETATION_CMYK; /* Photoshop writes CMYK JPEG inverted :-( Maybe this is a * way to spot photoshop CMYK JPGs. */ if( cinfo->saw_Adobe_marker ) jpeg->invert_pels = TRUE; break; case JCS_RGB: default: interpretation = VIPS_INTERPRETATION_sRGB; break; } /* Get the jfif resolution. exif may overwrite this later. */ xres = 1.0; yres = 1.0; if( cinfo->saw_JFIF_marker && cinfo->X_density != 1U && cinfo->Y_density != 1U ) { #ifdef DEBUG printf( "read_jpeg_header: seen jfif _density %d, %d\n", cinfo->X_density, cinfo->Y_density ); #endif /*DEBUG*/ switch( cinfo->density_unit ) { case 1: /* Pixels per inch. */ xres = cinfo->X_density / 25.4; yres = cinfo->Y_density / 25.4; break; case 2: /* Pixels per cm. */ xres = cinfo->X_density / 10.0; yres = cinfo->Y_density / 10.0; break; default: vips_warn( "VipsJpeg", "%s", _( "unknown JFIF resolution unit" ) ); break; } #ifdef DEBUG printf( "read_jpeg_header: seen jfif resolution %g, %g p/mm\n", xres, yres ); #endif /*DEBUG*/ } /* Set VIPS header. */ vips_image_init_fields( out, cinfo->output_width, cinfo->output_height, cinfo->output_components, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, interpretation, xres, yres ); vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); /* Interlaced jpegs need lots of memory to read, so our caller needs * to know. */ (void) vips_image_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 ) { #ifdef DEBUG { printf( "read_jpeg_header: seen %d bytes of APP%d\n", p->data_length, p->marker - JPEG_APP0 ); for( i = 0; i < 10; i++ ) printf( "\t%d) '%c' (%d)\n", i, p->data[i], p->data[i] ); } #endif /*DEBUG*/ switch( p->marker ) { case JPEG_APP0 + 1: /* Possible EXIF or XMP data. */ if( p->data_length > 4 && vips_isprefix( "Exif", (char *) p->data ) ) { if( parse_exif( out, p->data, p->data_length ) || attach_blob( out, VIPS_META_EXIF_NAME, p->data, p->data_length ) ) return( -1 ); } if( p->data_length > 4 && vips_isprefix( "http", (char *) p->data ) && attach_blob( out, VIPS_META_XMP_NAME, p->data, p->data_length ) ) return( -1 ); break; case JPEG_APP0 + 2: /* Possible ICC profile. */ if( p->data_length > 14 && vips_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; case JPEG_APP0 + 13: /* Possible IPCT data block. */ if( p->data_length > 5 && vips_isprefix( "Photo", (char *) p->data ) && attach_blob( out, VIPS_META_IPCT_NAME, p->data, p->data_length ) ) return( -1 ); break; default: 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 %zd byte ICC profile\n", data_length ); #endif /*DEBUG*/ if( !(data = vips_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]; } vips_image_set_blob( out, VIPS_META_ICC_NAME, (VipsCallbackFn) vips_free, data, data_length ); } return( 0 ); }
static ReadSlide * readslide_new( const char *filename, VipsImage *out, int layer, const char *associated ) { ReadSlide *rslide; int64_t w, h; const char *background; const char * const *properties; rslide = VIPS_NEW( out, ReadSlide ); memset( rslide, 0, sizeof( *rslide ) ); g_signal_connect( out, "close", G_CALLBACK( readslide_destroy_cb ), rslide ); rslide->layer = layer; rslide->associated = g_strdup( associated ); rslide->osr = openslide_open( filename ); if( rslide->osr == NULL ) { vips_error( "openslide2vips", "%s", _( "failure opening slide" ) ); return( NULL ); } if( layer < 0 || layer >= openslide_get_layer_count( rslide->osr ) ) { vips_error( "openslide2vips", "%s", _( "invalid slide level" ) ); return( NULL ); } if( associated && check_associated_image( rslide->osr, associated ) ) return( NULL ); if( associated ) { openslide_get_associated_image_dimensions( rslide->osr, associated, &w, &h ); vips_image_set_string( out, "slide-associated-image", associated ); vips_demand_hint( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL ); } else { openslide_get_layer_dimensions( rslide->osr, layer, &w, &h ); rslide->downsample = openslide_get_layer_downsample( rslide->osr, layer ); vips_image_set_int( out, "slide-level", layer ); vips_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL ); } /* This tag is used by argb2rgba() to paint fully-transparent pixels. */ background = openslide_get_property_value( rslide->osr, OPENSLIDE_PROPERTY_NAME_BACKGROUND_COLOR ); if( background != NULL ) vips_image_set_int( out, VIPS_META_BACKGROUND_RGB, strtoul( background, NULL, 16 ) ); else vips_image_set_int( out, VIPS_META_BACKGROUND_RGB, 0xffffff ); if( w < 0 || h < 0 || rslide->downsample < 0 ) { vips_error( "openslide2vips", _( "getting dimensions: %s" ), openslide_get_error( rslide->osr ) ); return( NULL ); } if( w > INT_MAX || h > INT_MAX ) { vips_error( "openslide2vips", "%s", _( "image dimensions overflow int" ) ); return( NULL ); } vips_image_init_fields( out, w, h, 4, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_RGB, 1.0, 1.0 ); for( properties = openslide_get_property_names( rslide->osr ); *properties != NULL; properties++ ) vips_image_set_string( out, *properties, openslide_get_property_value( rslide->osr, *properties ) ); associated = g_strjoinv( ", ", (char **) openslide_get_associated_image_names( rslide->osr ) ); vips_image_set_string( out, "slide-associated-images", associated ); return( rslide ); }
static int vips_rot_build( VipsObject *object ) { VipsConversion *conversion = VIPS_CONVERSION( object ); VipsRot *rot = (VipsRot *) object; VipsGenerateFn generate_fn; VipsDemandStyle hint; if( VIPS_OBJECT_CLASS( vips_rot_parent_class )->build( object ) ) return( -1 ); if( rot->angle == VIPS_ANGLE_0 ) return( vips_image_write( rot->in, conversion->out ) ); if( vips_image_pio_input( rot->in ) ) return( -1 ); if( vips_image_copy_fields( conversion->out, rot->in ) ) return( -1 ); switch( rot->angle ) { case VIPS_ANGLE_90: generate_fn = vips_rot90_gen; hint = VIPS_DEMAND_STYLE_SMALLTILE; conversion->out->Xsize = rot->in->Ysize; conversion->out->Ysize = rot->in->Xsize; conversion->out->Xoffset = rot->in->Ysize; conversion->out->Yoffset = 0; break; case VIPS_ANGLE_180: generate_fn = vips_rot180_gen; hint = VIPS_DEMAND_STYLE_THINSTRIP; conversion->out->Xoffset = rot->in->Xsize; conversion->out->Yoffset = rot->in->Ysize; break; case VIPS_ANGLE_270: generate_fn = vips_rot270_gen; hint = VIPS_DEMAND_STYLE_SMALLTILE; conversion->out->Xsize = rot->in->Ysize; conversion->out->Ysize = rot->in->Xsize; conversion->out->Xoffset = 0; conversion->out->Yoffset = rot->in->Xsize; break; default: g_assert( 0 ); /* Keep -Wall happy. */ return( 0 ); } vips_demand_hint( conversion->out, hint, rot->in, NULL ); if( vips_image_generate( conversion->out, vips_start_one, generate_fn, vips_stop_one, rot->in, rot ) ) return( -1 ); return( 0 ); }