static void vips_round_buffer( VipsArithmetic *arithmetic, VipsPel *out, VipsPel **in, int width ) { VipsRound *round = (VipsRound *) arithmetic; VipsImage *im = arithmetic->ready[0]; /* Complex just doubles the size. */ const int sz = width * im->Bands * (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); int x; switch( round->round ) { case VIPS_OPERATION_ROUND_RINT: SWITCH( VIPS_RINT ); break; case VIPS_OPERATION_ROUND_CEIL: SWITCH( VIPS_CEIL ); break; case VIPS_OPERATION_ROUND_FLOOR: SWITCH( VIPS_FLOOR ); break; default: g_assert_not_reached(); } }
static void vips_bandmean_buffer( VipsBandary *bandary, VipsPel *out, VipsPel **in, int width ) { VipsImage *im = bandary->ready[0]; const int bands = im->Bands; const int sz = width * (vips_band_format_iscomplex( im->BandFmt ) ? 2 : 1); int i, j; switch( vips_image_get_format( im ) ) { case VIPS_FORMAT_CHAR: SILOOP( signed char, int ); break; case VIPS_FORMAT_UCHAR: UILOOP( unsigned char, unsigned int ); break; case VIPS_FORMAT_SHORT: SILOOP( signed short, int ); break; case VIPS_FORMAT_USHORT: UILOOP( unsigned short, unsigned int ); break; case VIPS_FORMAT_INT: SILOOP( signed int, int ); break; case VIPS_FORMAT_UINT: UILOOP( unsigned int, unsigned int ); break; case VIPS_FORMAT_FLOAT: FLOOP( float ); break; case VIPS_FORMAT_DOUBLE: FLOOP( double ); break; case VIPS_FORMAT_COMPLEX: FLOOP( float ); break; case VIPS_FORMAT_DPCOMPLEX: FLOOP( double ); break; default: g_assert( 0 ); } }
const double relative_x = absolute_x - ix; const double relative_y = absolute_y - iy; /* * VIPS versions of Nicolas's pixel addressing values. */ const int lskip = VIPS_REGION_LSKIP( in ) / VIPS_IMAGE_SIZEOF_ELEMENT( in->im ); /* * Double the bands for complex images to account for the real and * imaginary parts being computed independently: */ const int actual_bands = in->im->Bands; const int bands = vips_band_format_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands; /* Confirm that absolute_x and absolute_y are >= 1, see above. */ g_assert( absolute_x >= 1.0 ); g_assert( absolute_y >= 1.0 ); switch( in->im->BandFmt ) { case VIPS_FORMAT_UCHAR: CALL( unsigned char, nosign ); break; case VIPS_FORMAT_CHAR: CALL( signed char, withsign ); break;
/* Make and init a Write. */ static Write * write_new( VipsImage *im, const char *filename, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, gboolean squash, gboolean miniswhite, VipsForeignTiffResunit resunit, double xres, double yres, gboolean bigtiff, gboolean rgbjpeg, gboolean properties, gboolean strip ) { Write *write; if( !(write = VIPS_NEW( im, Write )) ) return( NULL ); write->im = im; write->filename = vips_strdup( VIPS_OBJECT( im ), filename ); write->layer = NULL; write->tbuf = NULL; write->compression = get_compression( compression ); write->jpqual = Q; write->predictor = predictor; write->tile = tile; write->tilew = tile_width; write->tileh = tile_height; write->pyramid = pyramid; write->onebit = squash; write->miniswhite = miniswhite; write->icc_profile = vips_strdup( NULL, profile ); write->bigtiff = bigtiff; write->rgbjpeg = rgbjpeg; write->properties = properties; write->strip = strip; write->resunit = get_resunit( resunit ); write->xres = xres; write->yres = yres; /* In strip mode we use tileh to set rowsperstrip, and that does not * have the multiple-of-16 restriction. */ if( tile ) { if( (write->tilew & 0xf) != 0 || (write->tileh & 0xf) != 0 ) { vips_error( "vips2tiff", "%s", _( "tile size not a multiple of 16" ) ); return( NULL ); } } /* We can only pyramid LABQ and non-complex images. */ if( write->pyramid ) { if( im->Coding == VIPS_CODING_NONE && vips_band_format_iscomplex( im->BandFmt ) ) { vips_error( "vips2tiff", "%s", _( "can only pyramid LABQ and " "non-complex images" ) ); return( NULL ); } } /* Only 1-bit-ize 8 bit mono images. */ if( write->onebit && (im->Coding != VIPS_CODING_NONE || im->BandFmt != VIPS_FORMAT_UCHAR || im->Bands != 1) ) { vips_warn( "vips2tiff", "%s", _( "can only squash 1 band uchar images -- " "disabling squash" ) ); write->onebit = 0; } if( write->onebit && write->compression == COMPRESSION_JPEG ) { vips_warn( "vips2tiff", "%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) ); write->compression = COMPRESSION_NONE; } /* We can only MINISWHITE non-complex images of 1 or 2 bands. */ if( write->miniswhite && (im->Coding != VIPS_CODING_NONE || vips_band_format_iscomplex( im->BandFmt ) || im->Bands > 2) ) { vips_warn( "vips2tiff", "%s", _( "can only save non-complex greyscale images " "as miniswhite -- disabling miniswhite" ) ); write->miniswhite = FALSE; } /* Sizeof a line of bytes in the TIFF tile. */ if( im->Coding == VIPS_CODING_LABQ ) write->tls = write->tilew * 3; else if( write->onebit ) write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8; else write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew; /* Build the pyramid framework. */ write->layer = pyramid_new( write, NULL, im->Xsize, im->Ysize ); /* Fill all the layers. */ if( pyramid_fill( write ) ) { write_free( write ); return( NULL ); } if( tile ) write->tbuf = vips_malloc( NULL, TIFFTileSize( write->layer->tif ) ); else write->tbuf = vips_malloc( NULL, TIFFScanlineSize( write->layer->tif ) ); if( !write->tbuf ) { write_free( write ); return( NULL ); } return( write ); }
/* Write a TIFF header. width and height are the size of the VipsImage we are * writing (it may have been shrunk). */ static int write_tiff_header( Write *write, Layer *layer ) { TIFF *tif = layer->tif; int format; int orientation; /* Output base header fields. */ TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, layer->width ); TIFFSetField( tif, TIFFTAG_IMAGELENGTH, layer->height ); TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ); TIFFSetField( tif, TIFFTAG_COMPRESSION, write->compression ); if( write->compression == COMPRESSION_JPEG ) TIFFSetField( tif, TIFFTAG_JPEGQUALITY, write->jpqual ); if( write->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE ) TIFFSetField( tif, TIFFTAG_PREDICTOR, write->predictor ); /* Don't write mad resolutions (eg. zero), it confuses some programs. */ TIFFSetField( tif, TIFFTAG_RESOLUTIONUNIT, write->resunit ); TIFFSetField( tif, TIFFTAG_XRESOLUTION, VIPS_FCLIP( 0.01, write->xres, 1000000 ) ); TIFFSetField( tif, TIFFTAG_YRESOLUTION, VIPS_FCLIP( 0.01, write->yres, 1000000 ) ); if( !write->strip ) if( write_embed_profile( write, tif ) || write_embed_xmp( write, tif ) || write_embed_ipct( write, tif ) || write_embed_photoshop( write, tif ) || write_embed_imagedescription( write, tif ) ) return( -1 ); if( vips_image_get_typeof( write->im, VIPS_META_ORIENTATION ) && !vips_image_get_int( write->im, VIPS_META_ORIENTATION, &orientation ) ) TIFFSetField( tif, TIFFTAG_ORIENTATION, orientation ); /* And colour fields. */ if( write->im->Coding == VIPS_CODING_LABQ ) { TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 ); TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB ); } else if( write->onebit ) { TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 ); TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, write->miniswhite ? PHOTOMETRIC_MINISWHITE : PHOTOMETRIC_MINISBLACK ); } else { int photometric; /* Number of bands that have colour in .. other bands are saved * as alpha. */ int colour_bands; int alpha_bands; TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, write->im->Bands ); TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, vips_format_sizeof( write->im->BandFmt ) << 3 ); if( write->im->Bands < 3 ) { /* Mono or mono + alpha. */ photometric = write->miniswhite ? PHOTOMETRIC_MINISWHITE : PHOTOMETRIC_MINISBLACK; colour_bands = 1; } else { /* Could be: RGB, CMYK, LAB, perhaps with extra alpha. */ if( write->im->Type == VIPS_INTERPRETATION_LAB || write->im->Type == VIPS_INTERPRETATION_LABS ) { photometric = PHOTOMETRIC_CIELAB; colour_bands = 3; } else if( write->im->Type == VIPS_INTERPRETATION_CMYK && write->im->Bands >= 4 ) { photometric = PHOTOMETRIC_SEPARATED; TIFFSetField( tif, TIFFTAG_INKSET, INKSET_CMYK ); colour_bands = 4; } else if( write->compression == COMPRESSION_JPEG && write->im->Bands == 3 && write->im->BandFmt == VIPS_FORMAT_UCHAR && (!write->rgbjpeg && write->jpqual < 90) ) { /* This signals to libjpeg that it can do * YCbCr chrominance subsampling from RGB, not * that we will supply the image as YCbCr. */ photometric = PHOTOMETRIC_YCBCR; TIFFSetField( tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); colour_bands = 3; } else { /* Some kind of generic multi-band image .. * save the first three bands as RGB, the rest * as alpha. */ photometric = PHOTOMETRIC_RGB; colour_bands = 3; } } alpha_bands = VIPS_CLIP( 0, write->im->Bands - colour_bands, MAX_ALPHA ); if( alpha_bands > 0 ) { uint16 v[MAX_ALPHA]; int i; /* EXTRASAMPLE_UNASSALPHA means generic extra * alpha-like channels. ASSOCALPHA means pre-multipled * alpha only. */ for( i = 0; i < alpha_bands; i++ ) v[i] = EXTRASAMPLE_UNASSALPHA; TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, alpha_bands, v ); } TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric ); } /* Layout. */ if( write->tile ) { TIFFSetField( tif, TIFFTAG_TILEWIDTH, write->tilew ); TIFFSetField( tif, TIFFTAG_TILELENGTH, write->tileh ); } else TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, write->tileh ); if( layer->above ) /* Pyramid layer. */ TIFFSetField( tif, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); /* Sample format. */ format = SAMPLEFORMAT_UINT; if( vips_band_format_isuint( write->im->BandFmt ) ) format = SAMPLEFORMAT_UINT; else if( vips_band_format_isint( write->im->BandFmt ) ) format = SAMPLEFORMAT_INT; else if( vips_band_format_isfloat( write->im->BandFmt ) ) format = SAMPLEFORMAT_IEEEFP; else if( vips_band_format_iscomplex( write->im->BandFmt ) ) format = SAMPLEFORMAT_COMPLEXIEEEFP; TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, format ); return( 0 ); }
/** * vips_image_guess_interpretation: * @image: image to guess for * * Return the #VipsInterpretation for an image, guessing a sane value if * the set value looks crazy. * * Returns: a sensible #VipsInterpretation for the image. */ VipsInterpretation vips_image_guess_interpretation( const VipsImage *image ) { gboolean sane; sane = TRUE; /* Coding overrides interpretation. */ switch( image->Coding ) { case VIPS_CODING_LABQ: if( image->Type != VIPS_INTERPRETATION_LABQ ) sane = FALSE; break; case VIPS_CODING_RAD: if( image->Type != VIPS_INTERPRETATION_RGB ) sane = FALSE; break; default: break; } switch( image->Type ) { case VIPS_INTERPRETATION_MULTIBAND: if( image->Bands == 1 ) sane = FALSE; break; case VIPS_INTERPRETATION_B_W: /* Don't test bands, we allow bands after the first to be * unused extras, like alpha. */ break; case VIPS_INTERPRETATION_HISTOGRAM: if( image->Xsize > 1 && image->Ysize > 1 ) sane = FALSE; break; case VIPS_INTERPRETATION_FOURIER: if( !vips_band_format_iscomplex( image->BandFmt ) ) sane = FALSE; break; case VIPS_INTERPRETATION_XYZ: case VIPS_INTERPRETATION_LAB: case VIPS_INTERPRETATION_RGB: case VIPS_INTERPRETATION_CMC: case VIPS_INTERPRETATION_LCH: case VIPS_INTERPRETATION_sRGB: case VIPS_INTERPRETATION_HSV: case VIPS_INTERPRETATION_scRGB: case VIPS_INTERPRETATION_YXY: if( image->Bands < 3 ) sane = FALSE; break; case VIPS_INTERPRETATION_CMYK: if( image->Bands < 4 ) sane = FALSE; break; case VIPS_INTERPRETATION_LABQ: if( image->Coding != VIPS_CODING_LABQ ) sane = FALSE; break; case VIPS_INTERPRETATION_LABS: if( image->BandFmt != VIPS_FORMAT_SHORT ) sane = FALSE; break; case VIPS_INTERPRETATION_RGB16: if( image->BandFmt == VIPS_FORMAT_CHAR || image->BandFmt == VIPS_FORMAT_UCHAR || image->Bands < 3 ) sane = FALSE; break; case VIPS_INTERPRETATION_GREY16: if( image->BandFmt == VIPS_FORMAT_CHAR || image->BandFmt == VIPS_FORMAT_UCHAR ) sane = FALSE; break; case VIPS_INTERPRETATION_MATRIX: if( image->Bands != 1 ) sane = FALSE; break; default: g_assert_not_reached(); } if( sane ) return( vips_image_get_interpretation( image ) ); else return( vips_image_default_interpretation( image ) ); }