/* And orientation. */ static int vips_exif_set_orientation( ExifData *ed, VipsImage *im ) { int orientation; /* We set the tag, even if it's been deleted, since it's a required * field. */ if( !vips_image_get_typeof( im, VIPS_META_ORIENTATION ) || vips_image_get_int( im, VIPS_META_ORIENTATION, &orientation ) ) orientation = 1; VIPS_DEBUG_MSG( "set_exif_orientation: %d\n", orientation ); vips_exif_set_tag( ed, 0, EXIF_TAG_ORIENTATION, vips_exif_set_int, (void *) &orientation ); return( 0 ); }
/* 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 ); }