libvips/libvips/foreign/vips2tiff.c

1657 lines
39 KiB
C

/* TIFF PARTS:
* Copyright (c) 1988, 1990 by Sam Leffler.
* All rights reserved.
*
* This file is provided for unrestricted use provided that this
* legend is included on all tape media and as a part of the
* software program in whole or part. Users may copy, modify or
* distribute this file at will.
*
* MODIFICATION FOR VIPS Copyright 1991, K.Martinez
*
* software may be distributed FREE, with these copyright notices
* no responsibility/warantee is implied or given
*
*
* Modified and added im_LabQ2LabC() function. It can write IM_TYPE_LABQ image
* in vips format to LAB in tiff format.
* Copyright 1994 Ahmed Abbood.
*
* 19/9/95 JC
* - calls TIFFClose() more reliably
* - tidied up
* 12/4/97 JC
* - thrown away and rewritten for TIFF 6 lib
* 22/4/97 JC
* - writes a pyramid!
* - to separate TIFF files tho'
* 23/4/97 JC
* - does 2nd gather pass to put pyramid into a single TIFF file
* - ... and shrinks IM_CODING_LABQ too
* 26/10/98 JC
* - binary open for stupid systems
* 7/6/99 JC
* - 16bit TIFF write too
* 9/7/99 JC
* - ZIP tiff added
* 11/5/00 JC
* - removed TIFFmalloc/TIFFfree
* 5/8/00 JC
* - mode string now part of filename
* 23/4/01 JC
* - HAVE_TIFF turns on TIFFness
* 19/3/02 ruven
* - pyramid stops at tile size, not 64x64
* 29/4/02 JC
* - write any number of bands (but still with photometric RGB, so not
* very useful)
* 10/9/02 JC
* - oops, handle TIFF errors better
* - now writes CMYK correctly
* 13/2/03 JC
* - tries not to write mad resolutions
* 7/5/03 JC
* - only write CMYK if Type == CMYK
* - writes EXTRASAMPLES ALPHA for bands == 2 or 4 (if we're writing RGB)
* 17/11/03 JC
* - write float too
* 28/11/03 JC
* - read via a "p" so we work from mmap window images
* - uses threadgroups for speedup
* 9/3/04 JC
* - 1 bit write mode added
* 5/4/04
* - better handling of edge tiles (thanks Ruven)
* 18/5/04 Andrey Kiselev
* - added res_inch/res_cm option
* 20/5/04 JC
* - allow single res number too
* 19/7/04
* - write several scanlines at once, good speed up for some cases
* 22/9/04
* - got rid of wrapper image so nip gets progress feedback
* - fixed tiny read-beyond-buffer issue for edge tiles
* 7/10/04
* - added ICC profile embedding
* 13/12/04
* - can now pyramid any non-complex type (thanks Ruven)
* 27/1/05
* - added ccittfax4 as a compression option
* 9/3/05
* - set PHOTOMETRIC_CIELAB for vips TYPE_LAB images ... so we can write
* float LAB as well as float RGB
* - also LABS images
* 22/6/05
* - 16 bit LAB write was broken
* 9/9/05
* - write any icc profile from meta
* 3/3/06
* - raise tile buffer limit (thanks Ruven)
* 11/11/06
* - set ORIENTATION_TOPLEFT (thanks Josef)
* 18/7/07 Andrey Kiselev
* - remove "b" option on TIFFOpen()
* - support TIFFTAG_PREDICTOR types for lzw and deflate compression
* 3/11/07
* - use im_wbuffer() for background writes
* 15/2/08
* - set TIFFTAG_JPEGQUALITY explicitly when we copy TIFF files, since
* libtiff doesn't keep this in the header (thanks Joe)
* 20/2/08
* - use tiff error handler from im_tiff2vips.c
* 27/2/08
* - don't try to copy icc profiles when building pyramids (thanks Joe)
* 9/4/08
* - use IM_META_RESOLUTION_UNIT to set default resunit
* 17/4/08
* - allow CMYKA (thanks Doron)
* 5/9/08
* - trigger eval callbacks during tile write
* 4/2/10
* - gtkdoc
* 26/2/10
* - option to turn on bigtiff output
* 16/4/10
* - use vips_sink_*() instead of threadgroup and friends
* 22/6/10
* - make no-owner regions for the tile cache, since we share these
* between threads
* 12/7/11
* - use im__temp_name() for intermediates rather than polluting the
* output directory
* 5/9/11
* - enable YCbCr compression for jpeg write
* 23/11/11
* - set reduced-resolution subfile type on pyramid layers
* 2/12/11
* - make into a simple function call ready to be wrapped as a new-style
* VipsForeign class
* 21/3/12
* - bump max layer buffer up
* 2/6/12
* - copy jpeg pyramid in gather in RGB mode ... tiff4 doesn't do ycbcr
* mode
* 7/8/12
* - be more cautious enabling YCbCr mode
* 24/9/13
* - support many more vips formats, eg. complex, 32-bit int, any number
* of bands, etc., see the tiff loader
* 26/1/14
* - add RGB as well as YCbCr write
* 20/11/14
* - cache input in tile write mode to keep us sequential
* 3/12/14
* - embed XMP in output
* 10/12/14
* - zero out edge tile buffers before jpeg write, thanks iwbh15
* 19/1/15
* - disable chroma subsample if Q >= 90
* 13/2/15
* - append later layers, don't copy the base image
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG_VERBOSE
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#ifdef HAVE_TIFF
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <string.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include <tiffio.h>
#include "tiff.h"
/* FIXME ... this is not the best way to organise a pyramid builder, dzsave is
* much better.
*
* Rip out all the PyramidTile stuff and redo dzsave-style. We could scrap the
* input cache as well.
*/
/* Max no of tiles we buffer in a layer. Enough to buffer a line of 64x64
* tiles on a 100k pixel across image.
*/
#define MAX_LAYER_BUFFER (10000)
/* Bits we OR together for quadrants in a tile.
*/
typedef enum pyramid_bits {
PYR_TL = 1, /* Top-left etc. */
PYR_TR = 2,
PYR_BL = 4,
PYR_BR = 8,
PYR_ALL = 15,
PYR_NONE = 0
} PyramidBits;
/* A tile in our pyramid.
*/
typedef struct pyramid_tile {
VipsRegion *tile;
PyramidBits bits;
} PyramidTile;
/* A layer in the pyramid.
*/
typedef struct pyramid_layer {
/* Parameters.
*/
struct tiff_write *tw; /* Main TIFF write struct */
int width, height; /* Layer size */
int sub; /* Subsample factor for this layer */
char *lname; /* Name of this TIFF file */
TIFF *tif; /* TIFF file we write this layer to */
VipsPel *tbuf; /* TIFF output buffer */
PyramidTile tiles[MAX_LAYER_BUFFER];
struct pyramid_layer *below; /* Tiles go to here */
struct pyramid_layer *above; /* Tiles come from here */
} PyramidLayer;
/* A TIFF image in the process of being written.
*/
typedef struct tiff_write {
VipsImage *im; /* Original input image */
char *name; /* Final name we write to */
/* Read from im with these.
*/
VipsRegion *reg;
char *bname; /* Name for base layer */
TIFF *tif; /* Image we write to */
PyramidLayer *layer; /* Top of pyramid, if in use */
VipsPel *tbuf; /* TIFF output buffer */
int tls; /* Tile line size */
int compression; /* Compression type */
int jpqual; /* JPEG q-factor */
int predictor; /* Predictor value */
int tile; /* Tile or not */
int tilew, tileh; /* Tile size */
int pyramid; /* Write pyramid */
int onebit; /* Write as 1-bit TIFF */
int resunit; /* Resolution unit (inches or cm) */
double xres; /* Resolution in X */
double yres; /* Resolution in Y */
char *icc_profile; /* Profile to embed */
int bigtiff; /* True for bigtiff write */
int rgbjpeg; /* True for RGB not YCbCr */
GMutex *write_lock; /* Lock TIFF*() calls with this */
VipsImage *cache; /* Cache a chunk of input */
} TiffWrite;
/* Open TIFF for output.
*/
static TIFF *
tiff_openout( TiffWrite *tw, const char *name )
{
TIFF *tif;
const char *mode = tw->bigtiff ? "w8" : "w";
#ifdef DEBUG
printf( "TIFFOpen( \"%s\", \"%s\" )\n", name, mode );
#endif /*DEBUG*/
if( !(tif = TIFFOpen( name, mode )) ) {
vips_error( "vips2tiff",
_( "unable to open \"%s\" for output" ), name );
return( NULL );
}
return( tif );
}
/* Open TIFF for input.
*/
static TIFF *
tiff_openin( const char *name )
{
TIFF *tif;
if( !(tif = TIFFOpen( name, "r" )) ) {
vips_error( "vips2tiff",
_( "unable to open \"%s\" for input" ), name );
return( NULL );
}
return( tif );
}
/* Convert VIPS LabQ to TIFF LAB. Just take the first three bands.
*/
static void
LabQ2LabC( VipsPel *q, VipsPel *p, int n )
{
int x;
for( x = 0; x < n; x++ ) {
/* Get most significant 8 bits of lab.
*/
q[0] = p[0];
q[1] = p[1];
q[2] = p[2];
p += 4;
q += 3;
}
}
/* Pack 8 bit VIPS to 1 bit TIFF.
*/
static void
eightbit2onebit( VipsPel *q, VipsPel *p, int n )
{
int x;
VipsPel bits;
bits = 0;
for( x = 0; x < n; x++ ) {
bits <<= 1;
if( p[x] )
bits |= 1;
if( (x & 0x7) == 0x7 ) {
*q++ = bits;
bits = 0;
}
}
/* Any left-over bits? Need to be left-aligned.
*/
if( (x & 0x7) != 0 )
*q++ = bits << (8 - (x & 0x7));
}
/* Convert VIPS LABS to TIFF 16 bit LAB.
*/
static void
LabS2Lab16( VipsPel *q, VipsPel *p, int n )
{
int x;
short *p1 = (short *) p;
unsigned short *q1 = (unsigned short *) q;
for( x = 0; x < n; x++ ) {
/* TIFF uses unsigned 16 bit ... move zero, scale up L.
*/
q1[0] = (int) p1[0] << 1;
q1[1] = p1[1];
q1[2] = p1[2];
p1 += 3;
q1 += 3;
}
}
/* Pack a VIPS region into a TIFF tile buffer.
*/
static void
pack2tiff( TiffWrite *tw, VipsRegion *in, VipsPel *q, VipsRect *area )
{
int y;
/* JPEG compression can read outside the pixel area for edge tiles. It
* always compresses 8x8 blocks, so if the image width or height is
* not a multiple of 8, it can look beyond the pixels we will write.
*
* Black out the tile first to make sure these edge pixels are always
* zero.
*/
if( tw->compression == COMPRESSION_JPEG &&
(area->width < tw->tilew ||
area->height < tw->tileh) )
memset( q, 0, TIFFTileSize( tw->tif ) );
for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) {
VipsPel *p = (VipsPel *) VIPS_REGION_ADDR( in, area->left, y );
if( in->im->Coding == VIPS_CODING_LABQ )
LabQ2LabC( q, p, area->width );
else if( tw->onebit )
eightbit2onebit( q, p, area->width );
else if( in->im->BandFmt == VIPS_FORMAT_SHORT &&
in->im->Type == VIPS_INTERPRETATION_LABS )
LabS2Lab16( q, p, area->width );
else
memcpy( q, p,
area->width * VIPS_IMAGE_SIZEOF_PEL( in->im ) );
q += tw->tls;
}
}
/* Embed an ICC profile from a file.
*/
static int
embed_profile_file( TIFF *tif, const char *profile )
{
char *buffer;
size_t length;
if( !(buffer = vips__file_read_name( profile, VIPS_ICC_DIR, &length )) )
return( -1 );
TIFFSetField( tif, TIFFTAG_ICCPROFILE, length, buffer );
vips_free( buffer );
#ifdef DEBUG
printf( "vips2tiff: attached profile \"%s\"\n", profile );
#endif /*DEBUG*/
return( 0 );
}
/* Embed an ICC profile from VipsImage metadata.
*/
static int
embed_profile_meta( TIFF *tif, VipsImage *im )
{
void *data;
size_t data_length;
if( vips_image_get_blob( im, VIPS_META_ICC_NAME, &data, &data_length ) )
return( -1 );
TIFFSetField( tif, TIFFTAG_ICCPROFILE, data_length, data );
#ifdef DEBUG
printf( "vips2tiff: attached profile from meta\n" );
#endif /*DEBUG*/
return( 0 );
}
static int
embed_profile( TiffWrite *tw, TIFF *tif )
{
if( tw->icc_profile &&
strcmp( tw->icc_profile, "none" ) != 0 &&
embed_profile_file( tif, tw->icc_profile ) )
return( -1 );
if( !tw->icc_profile &&
vips_image_get_typeof( tw->im, VIPS_META_ICC_NAME ) &&
embed_profile_meta( tif, tw->im ) )
return( -1 );
return( 0 );
}
/* Embed any XMP metadata.
*/
static int
embed_xmp( TiffWrite *tw, TIFF *tif )
{
void *data;
size_t data_length;
if( !vips_image_get_typeof( tw->im, VIPS_META_XMP_NAME ) )
return( 0 );
if( vips_image_get_blob( tw->im, VIPS_META_XMP_NAME,
&data, &data_length ) )
return( -1 );
TIFFSetField( tif, TIFFTAG_XMLPACKET, data_length, data );
#ifdef DEBUG
printf( "vips2tiff: attached XMP from meta\n" );
#endif /*DEBUG*/
return( 0 );
}
/* Write a TIFF header. width and height are the size of the VipsImage we are
* writing (may have been shrunk!).
*/
static int
write_tiff_header( TiffWrite *tw, TIFF *tif, int width, int height )
{
uint16 v[1];
int format;
/* Output base header fields.
*/
TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, width );
TIFFSetField( tif, TIFFTAG_IMAGELENGTH, height );
TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT );
TIFFSetField( tif, TIFFTAG_COMPRESSION, tw->compression );
if( tw->compression == COMPRESSION_JPEG )
TIFFSetField( tif, TIFFTAG_JPEGQUALITY, tw->jpqual );
if( tw->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE )
TIFFSetField( tif, TIFFTAG_PREDICTOR, tw->predictor );
/* Don't write mad resolutions (eg. zero), it confuses some programs.
*/
TIFFSetField( tif, TIFFTAG_RESOLUTIONUNIT, tw->resunit );
TIFFSetField( tif, TIFFTAG_XRESOLUTION,
VIPS_CLIP( 0.01, tw->xres, 1000000 ) );
TIFFSetField( tif, TIFFTAG_YRESOLUTION,
VIPS_CLIP( 0.01, tw->yres, 1000000 ) );
if( embed_profile( tw, tif ) )
return( -1 );
if( embed_xmp( tw, tif ) )
return( -1 );
/* And colour fields.
*/
if( tw->im->Coding == VIPS_CODING_LABQ ) {
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 3 );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 8 );
TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
}
else if( tw->onebit ) {
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, 1 );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, 1 );
TIFFSetField( tif,
TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
}
else {
int photometric;
TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, tw->im->Bands );
TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE,
vips_format_sizeof( tw->im->BandFmt ) << 3 );
switch( tw->im->Bands ) {
case 1:
case 2:
photometric = PHOTOMETRIC_MINISBLACK;
if( tw->im->Bands == 2 ) {
v[0] = EXTRASAMPLE_ASSOCALPHA;
TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v );
}
break;
case 3:
case 4:
/* could be: RGB, RGBA, CMYK, LAB, LABA, generic
* multi-band image.
*/
if( tw->im->Type == VIPS_INTERPRETATION_LAB ||
tw->im->Type == VIPS_INTERPRETATION_LABS )
photometric = PHOTOMETRIC_CIELAB;
else if( tw->im->Type == VIPS_INTERPRETATION_CMYK ) {
photometric = PHOTOMETRIC_SEPARATED;
TIFFSetField( tif,
TIFFTAG_INKSET, INKSET_CMYK );
}
else if( tw->compression == COMPRESSION_JPEG &&
tw->im->Bands == 3 &&
tw->im->BandFmt == VIPS_FORMAT_UCHAR &&
(!tw->rgbjpeg && tw->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 );
}
else
photometric = PHOTOMETRIC_RGB;
if( tw->im->Type != VIPS_INTERPRETATION_CMYK &&
tw->im->Bands == 4 ) {
v[0] = EXTRASAMPLE_ASSOCALPHA;
TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v );
}
break;
case 5:
/* Only CMYKA
*/
photometric = PHOTOMETRIC_SEPARATED;
TIFFSetField( tif, TIFFTAG_INKSET, INKSET_CMYK );
v[0] = EXTRASAMPLE_ASSOCALPHA;
TIFFSetField( tif, TIFFTAG_EXTRASAMPLES, 1, v );
break;
default:
/* Who knows. Just call it RGB.
*/
photometric = PHOTOMETRIC_RGB;
break;
}
TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric );
}
/* Layout.
*/
if( tw->tile ) {
TIFFSetField( tif, TIFFTAG_TILEWIDTH, tw->tilew );
TIFFSetField( tif, TIFFTAG_TILELENGTH, tw->tileh );
}
else
TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, 16 );
if( tif != tw->tif ) {
/* Pyramid layer.
*/
TIFFSetField( tif, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE );
}
/* Sample format.
*/
format = SAMPLEFORMAT_UINT;
if( vips_band_format_isuint( tw->im->BandFmt ) )
format = SAMPLEFORMAT_UINT;
else if( vips_band_format_isint( tw->im->BandFmt ) )
format = SAMPLEFORMAT_INT;
else if( vips_band_format_isfloat( tw->im->BandFmt ) )
format = SAMPLEFORMAT_IEEEFP;
else if( vips_band_format_iscomplex( tw->im->BandFmt ) )
format = SAMPLEFORMAT_COMPLEXIEEEFP;
TIFFSetField( tif, TIFFTAG_SAMPLEFORMAT, format );
return( 0 );
}
/* Free a pyramid layer.
*/
static void
free_layer( PyramidLayer *layer )
{
int i;
for( i = 0; i < MAX_LAYER_BUFFER; i++ )
VIPS_FREEF( g_object_unref, layer->tiles[i].tile );
/* And close the TIFF file we are writing to.
*/
VIPS_FREEF( vips_free, layer->tbuf );
VIPS_FREEF( TIFFClose, layer->tif );
}
/* Free an entire pyramid.
*/
static void
free_pyramid( PyramidLayer *layer )
{
if( layer->below )
free_pyramid( layer->below );
free_layer( layer );
}
/* Build a pyramid. w & h are size of layer above this layer. Write new layer
* struct into *zap, return 0/-1 for success/fail.
*/
static int
build_pyramid( TiffWrite *tw, PyramidLayer *above,
PyramidLayer **zap, int w, int h )
{
PyramidLayer *layer = VIPS_NEW( tw->im, PyramidLayer );
int i;
if( !layer )
return( -1 );
layer->tw = tw;
layer->width = w / 2;
layer->height = h / 2;
if( !above )
/* Top of pyramid.
*/
layer->sub = 2;
else
layer->sub = above->sub * 2;
layer->lname = NULL;
layer->tif = NULL;
layer->tbuf = NULL;
for( i = 0; i < MAX_LAYER_BUFFER; i++ ) {
layer->tiles[i].tile = NULL;
layer->tiles[i].bits = PYR_NONE;
}
layer->below = NULL;
layer->above = above;
/* Save layer, to make sure it gets freed properly.
*/
*zap = layer;
if( layer->width > tw->tilew ||
layer->height > tw->tileh )
if( build_pyramid( tw, layer,
&layer->below, layer->width, layer->height ) )
return( -1 );
if( !(layer->lname = vips__temp_name( "%s.tif" )) )
return( -1 );
/* Make output image.
*/
if( !(layer->tif = tiff_openout( tw, layer->lname )) )
return( -1 );
/* Write the TIFF header for this layer.
*/
if( write_tiff_header( tw, layer->tif, layer->width, layer->height ) )
return( -1 );
if( !(layer->tbuf = vips_malloc( NULL, TIFFTileSize( layer->tif ) )) )
return( -1 );
return( 0 );
}
/* Pick a new tile to write to in this layer. Either reuse a tile we have
* previously filled, or make a new one.
*/
static int
find_new_tile( PyramidLayer *layer )
{
int i;
/* Existing buffer we have finished with?
*/
for( i = 0; i < MAX_LAYER_BUFFER; i++ )
if( layer->tiles[i].bits == PYR_ALL )
return( i );
/* Have to make a new one.
*/
for( i = 0; i < MAX_LAYER_BUFFER; i++ )
if( !layer->tiles[i].tile ) {
if( !(layer->tiles[i].tile =
vips_region_new( layer->tw->im )) )
return( -1 );
return( i );
}
/* Out of space!
*/
vips_error( "vips2tiff",
"%s", _( "layer buffer exhausted -- "
"try making TIFF output tiles smaller" ) );
return( -1 );
}
/* Find a tile in the layer buffer - if it's not there, make a new one.
*/
static int
find_tile( PyramidLayer *layer, VipsRect *pos )
{
int i;
VipsRect quad;
VipsRect image;
VipsRect inter;
/* Do we have a VipsRegion for this position?
*/
for( i = 0; i < MAX_LAYER_BUFFER; i++ ) {
VipsRegion *reg = layer->tiles[i].tile;
if( reg && reg->valid.left == pos->left &&
reg->valid.top == pos->top )
return( i );
}
/* Make a new one.
*/
if( (i = find_new_tile( layer )) < 0 )
return( -1 );
if( vips_region_buffer( layer->tiles[i].tile, pos ) )
return( -1 );
vips__region_no_ownership( layer->tiles[i].tile );
layer->tiles[i].bits = PYR_NONE;
/* Do any quadrants of this tile fall entirely outside the image?
* If they do, set their bits now.
*/
quad.width = layer->tw->tilew / 2;
quad.height = layer->tw->tileh / 2;
image.left = 0;
image.top = 0;
image.width = layer->width;
image.height = layer->height;
quad.left = pos->left;
quad.top = pos->top;
vips_rect_intersectrect( &quad, &image, &inter );
if( vips_rect_isempty( &inter ) )
layer->tiles[i].bits |= PYR_TL;
quad.left = pos->left + quad.width;
quad.top = pos->top;
vips_rect_intersectrect( &quad, &image, &inter );
if( vips_rect_isempty( &inter ) )
layer->tiles[i].bits |= PYR_TR;
quad.left = pos->left;
quad.top = pos->top + quad.height;
vips_rect_intersectrect( &quad, &image, &inter );
if( vips_rect_isempty( &inter ) )
layer->tiles[i].bits |= PYR_BL;
quad.left = pos->left + quad.width;
quad.top = pos->top + quad.height;
vips_rect_intersectrect( &quad, &image, &inter );
if( vips_rect_isempty( &inter ) )
layer->tiles[i].bits |= PYR_BR;
return( i );
}
/* Shrink a region by a factor of two, writing the result to a specified
* offset in another region. VIPS_CODING_LABQ only.
*/
static void
shrink_region_labpack( VipsRegion *from, VipsRect *area,
VipsRegion *to, int xoff, int yoff )
{
int ls = VIPS_REGION_LSKIP( from );
VipsRect *t = &to->valid;
int x, y;
VipsRect out;
/* Calculate output size and position.
*/
out.left = t->left + xoff;
out.top = t->top + yoff;
out.width = area->width / 2;
out.height = area->height / 2;
/* Shrink ... ignore the extension byte for speed.
*/
for( y = 0; y < out.height; y++ ) {
VipsPel *p = VIPS_REGION_ADDR( from,
area->left, area->top + y * 2 );
VipsPel *q = VIPS_REGION_ADDR( to, out.left, out.top + y );
for( x = 0; x < out.width; x++ ) {
signed char *sp = (signed char *) p;
unsigned char *up = (unsigned char *) p;
int l = up[0] + up[4] +
up[ls] + up[ls + 4];
int a = sp[1] + sp[5] +
sp[ls + 1] + sp[ls + 5];
int b = sp[2] + sp[6] +
sp[ls + 2] + sp[ls + 6];
q[0] = l >> 2;
q[1] = a >> 2;
q[2] = b >> 2;
q[3] = 0;
q += 4;
p += 8;
}
}
}
#define SHRINK_TYPE_INT( TYPE ) \
for( x = 0; x < out.width; x++ ) { \
TYPE *tp = (TYPE *) p; \
TYPE *tp1 = (TYPE *) (p + ls); \
TYPE *tq = (TYPE *) q; \
\
for( z = 0; z < nb; z++ ) { \
int tot = tp[z] + tp[z + nb] + \
tp1[z] + tp1[z + nb]; \
\
tq[z] = tot >> 2; \
} \
\
/* Move on two pels in input. \
*/ \
p += ps << 1; \
q += ps; \
}
#define SHRINK_TYPE_FLOAT( TYPE ) \
for( x = 0; x < out.width; x++ ) { \
TYPE *tp = (TYPE *) p; \
TYPE *tp1 = (TYPE *) (p + ls); \
TYPE *tq = (TYPE *) q; \
\
for( z = 0; z < nb; z++ ) { \
double tot = (double) tp[z] + tp[z + nb] + \
tp1[z] + tp1[z + nb]; \
\
tq[z] = tot / 4; \
} \
\
/* Move on two pels in input. \
*/ \
p += ps << 1; \
q += ps; \
}
/* Shrink a region by a factor of two, writing the result to a specified
* offset in another region. n-band, non-complex.
*/
static void
shrink_region( VipsRegion *from, VipsRect *area,
VipsRegion *to, int xoff, int yoff )
{
int ls = VIPS_REGION_LSKIP( from );
int ps = VIPS_IMAGE_SIZEOF_PEL( from->im );
int nb = from->im->Bands;
VipsRect *t = &to->valid;
int x, y, z;
VipsRect out;
/* Calculate output size and position.
*/
out.left = t->left + xoff;
out.top = t->top + yoff;
out.width = area->width / 2;
out.height = area->height / 2;
for( y = 0; y < out.height; y++ ) {
VipsPel *p = VIPS_REGION_ADDR( from,
area->left, area->top + y * 2 );
VipsPel *q = VIPS_REGION_ADDR( to,
out.left, out.top + y );
/* Process this line of pels.
*/
switch( from->im->BandFmt ) {
case VIPS_FORMAT_UCHAR:
SHRINK_TYPE_INT( unsigned char ); break;
case VIPS_FORMAT_CHAR:
SHRINK_TYPE_INT( signed char ); break;
case VIPS_FORMAT_USHORT:
SHRINK_TYPE_INT( unsigned short ); break;
case VIPS_FORMAT_SHORT:
SHRINK_TYPE_INT( signed short ); break;
case VIPS_FORMAT_UINT:
SHRINK_TYPE_INT( unsigned int ); break;
case VIPS_FORMAT_INT:
SHRINK_TYPE_INT( signed int ); break;
case VIPS_FORMAT_FLOAT:
SHRINK_TYPE_FLOAT( float ); break;
case VIPS_FORMAT_DOUBLE:
SHRINK_TYPE_FLOAT( double ); break;
default:
g_assert( 0 );
}
}
}
/* Write a tile from a layer.
*/
static int
save_tile( TiffWrite *tw,
TIFF *tif, VipsPel *tbuf, VipsRegion *reg, VipsRect *area )
{
/* Have to repack pixels.
*/
pack2tiff( tw, reg, tbuf, area );
#ifdef DEBUG_VERBOSE
printf( "Writing %dx%d pixels at position %dx%d to image %s\n",
tw->tilew, tw->tileh, area->left, area->top,
TIFFFileName( tif ) );
#endif /*DEBUG_VERBOSE*/
/* Write to TIFF! easy.
*/
if( TIFFWriteTile( tif, tbuf, area->left, area->top, 0, 0 ) < 0 ) {
vips_error( "vips2tiff", "%s", _( "TIFF write tile failed" ) );
return( -1 );
}
return( 0 );
}
/* A new tile has arrived! Shrink into this layer, if we fill a region, write
* it and recurse.
*/
static int
new_tile( PyramidLayer *layer, VipsRegion *tile, VipsRect *area )
{
TiffWrite *tw = layer->tw;
int xoff, yoff;
int t, ri, bo;
VipsRect out, new;
PyramidBits bit;
/* Calculate pos and size of new pixels we make inside this layer.
*/
new.left = area->left / 2;
new.top = area->top / 2;
new.width = area->width / 2;
new.height = area->height / 2;
/* Has size fallen to zero? Can happen if this is a one-pixel-wide
* strip.
*/
if( vips_rect_isempty( &new ) )
return( 0 );
/* Offset into this tile ... ie. which quadrant we are writing.
*/
xoff = new.left % layer->tw->tilew;
yoff = new.top % layer->tw->tileh;
/* Calculate pos for tile we shrink into in this layer.
*/
out.left = new.left - xoff;
out.top = new.top - yoff;
/* Clip against edge of image.
*/
ri = VIPS_MIN( layer->width, out.left + layer->tw->tilew );
bo = VIPS_MIN( layer->height, out.top + layer->tw->tileh );
out.width = ri - out.left;
out.height = bo - out.top;
if( (t = find_tile( layer, &out )) < 0 )
return( -1 );
/* Shrink into place.
*/
if( tw->im->Coding == VIPS_CODING_NONE )
shrink_region( tile, area,
layer->tiles[t].tile, xoff, yoff );
else
shrink_region_labpack( tile, area,
layer->tiles[t].tile, xoff, yoff );
/* Set that bit.
*/
if( xoff )
if( yoff )
bit = PYR_BR;
else
bit = PYR_TR;
else
if( yoff )
bit = PYR_BL;
else
bit = PYR_TL;
if( layer->tiles[t].bits & bit ) {
vips_error( "vips2tiff",
"%s", _( "internal error #9876345" ) );
return( -1 );
}
layer->tiles[t].bits |= bit;
if( layer->tiles[t].bits == PYR_ALL ) {
/* Save this complete tile.
*/
if( save_tile( tw, layer->tif, layer->tbuf,
layer->tiles[t].tile, &layer->tiles[t].tile->valid ) )
return( -1 );
/* And recurse down the pyramid!
*/
if( layer->below &&
new_tile( layer->below,
layer->tiles[t].tile,
&layer->tiles[t].tile->valid ) )
return( -1 );
}
return( 0 );
}
/* Write as tiles. This is called by vips_sink_tile() for every tile
* generated.
*/
static int
write_tif_tile( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop )
{
TiffWrite *tw = (TiffWrite *) a;
g_mutex_lock( tw->write_lock );
/* Write to TIFF.
*/
if( save_tile( tw, tw->tif, tw->tbuf, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
/* Is there a pyramid? Write to that too.
*/
if( tw->layer &&
new_tile( tw->layer, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
g_mutex_unlock( tw->write_lock );
return( 0 );
}
/* Write as tiles.
*/
static int
write_tif_tilewise( TiffWrite *tw )
{
VipsImage *im = tw->im;
/* Double check: buffers should match in size, except for onebit and
* labq modes.
*/
{
size_t vips_tile_size =
VIPS_IMAGE_SIZEOF_PEL( im ) * tw->tilew * tw->tileh;
if( tw->im->Coding != VIPS_CODING_LABQ &&
!tw->onebit &&
TIFFTileSize( tw->tif ) != vips_tile_size ) {
vips_error( "vips2tiff",
"%s", _( "unsupported image format" ) );
return( -1 );
}
}
g_assert( !tw->tbuf );
if( !(tw->tbuf = vips_malloc( NULL, TIFFTileSize( tw->tif ) )) )
return( -1 );
g_assert( !tw->write_lock );
tw->write_lock = vips_g_mutex_new();
/* Write pyramid too? Only bother if bigger than tile size.
*/
if( tw->pyramid &&
(im->Xsize > tw->tilew || im->Ysize > tw->tileh) &&
build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) )
return( -1 );
if( vips_sink_tile( im, tw->tilew, tw->tileh,
NULL, write_tif_tile, NULL, tw, NULL ) )
return( -1 );
return( 0 );
}
static int
write_tif_block( VipsRegion *region, VipsRect *area, void *a )
{
TiffWrite *tw = (TiffWrite *) a;
VipsImage *im = tw->im;
int y;
for( y = 0; y < area->height; y++ ) {
VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + y );
/* Any repacking necessary.
*/
if( im->Coding == VIPS_CODING_LABQ ) {
LabQ2LabC( tw->tbuf, p, im->Xsize );
p = tw->tbuf;
}
else if( im->BandFmt == VIPS_FORMAT_SHORT &&
im->Type == VIPS_INTERPRETATION_LABS ) {
LabS2Lab16( tw->tbuf, p, im->Xsize );
p = tw->tbuf;
}
else if( tw->onebit ) {
eightbit2onebit( tw->tbuf, p, im->Xsize );
p = tw->tbuf;
}
if( TIFFWriteScanline( tw->tif, p, area->top + y, 0 ) < 0 )
return( -1 );
}
return( 0 );
}
/* Write as scan-lines.
*/
static int
write_tif_stripwise( TiffWrite *tw )
{
g_assert( !tw->tbuf );
/* Double check: buffers should match in size, except for onebit and
* labq modes.
*/
if( tw->im->Coding != VIPS_CODING_LABQ &&
!tw->onebit &&
TIFFScanlineSize( tw->tif ) !=
VIPS_IMAGE_SIZEOF_LINE( tw->im ) ) {
vips_error( "vips2tiff",
"%s", _( "unsupported image format" ) );
return( -1 );
}
if( !(tw->tbuf = vips_malloc( NULL, TIFFScanlineSize( tw->tif ) )) )
return( -1 );
if( vips_sink_disc( tw->im, write_tif_block, tw ) )
return( -1 );
return( 0 );
}
/* Delete any temp files we wrote.
*/
static void
delete_files( TiffWrite *tw )
{
PyramidLayer *layer;
if( tw->bname ) {
#ifndef DEBUG
unlink( tw->bname );
#else
printf( "delete_files: leaving %s\n", tw->bname );
#endif /*DEBUG*/
tw->bname = NULL;
}
for( layer = tw->layer; layer; layer = layer->below )
if( layer->lname ) {
#ifndef DEBUG
unlink( layer->lname );
#else
printf( "delete_files: leaving %s\n", layer->lname );
#endif /*DEBUG*/
layer->lname = NULL;
}
}
/* Free a TiffWrite.
*/
static void
free_tiff_write( TiffWrite *tw )
{
delete_files( tw );
VIPS_FREEF( TIFFClose, tw->tif );
VIPS_FREEF( vips_free, tw->tbuf );
VIPS_FREEF( vips_g_mutex_free, tw->write_lock );
VIPS_FREEF( free_pyramid, tw->layer );
VIPS_UNREF( tw->cache );
VIPS_FREEF( vips_free, tw->icc_profile );
}
/* Round N down to P boundary.
*/
#define ROUND_DOWN(N,P) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) ))
static int
get_compression( VipsForeignTiffCompression compression )
{
switch( compression ) {
case VIPS_FOREIGN_TIFF_COMPRESSION_NONE:
return( COMPRESSION_NONE );
case VIPS_FOREIGN_TIFF_COMPRESSION_JPEG:
return( COMPRESSION_JPEG );
case VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE:
return( COMPRESSION_ADOBE_DEFLATE );
case VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS:
return( COMPRESSION_PACKBITS );
case VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4:
return( COMPRESSION_CCITTFAX4 );
case VIPS_FOREIGN_TIFF_COMPRESSION_LZW:
return( COMPRESSION_LZW );
default:
g_assert( 0 );
}
/* Keep -Wall happy.
*/
return( -1 );
}
static int
get_resunit( VipsForeignTiffResunit resunit )
{
switch( resunit ) {
case VIPS_FOREIGN_TIFF_RESUNIT_CM:
return( RESUNIT_CENTIMETER );
case VIPS_FOREIGN_TIFF_RESUNIT_INCH:
return( RESUNIT_INCH );
default:
g_assert( 0 );
}
/* Keep -Wall happy.
*/
return( -1 );
}
/* Make and init a TiffWrite.
*/
static TiffWrite *
make_tiff_write( 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,
VipsForeignTiffResunit resunit, double xres, double yres,
gboolean bigtiff,
gboolean rgbjpeg )
{
TiffWrite *tw;
if( !(tw = VIPS_NEW( im, TiffWrite )) )
return( NULL );
tw->im = im;
tw->name = vips_strdup( VIPS_OBJECT( im ), filename );
tw->bname = NULL;
tw->tif = NULL;
tw->layer = NULL;
tw->tbuf = NULL;
tw->compression = get_compression( compression );
tw->jpqual = Q;
tw->predictor = predictor;
tw->tile = tile;
tw->tilew = tile_width;
tw->tileh = tile_height;
tw->pyramid = pyramid;
tw->onebit = squash;
tw->icc_profile = profile;
tw->bigtiff = bigtiff;
tw->rgbjpeg = rgbjpeg;
tw->write_lock = NULL;
tw->cache = NULL;
tw->resunit = get_resunit( resunit );
tw->xres = xres;
tw->yres = yres;
if( (tw->tilew & 0xf) != 0 ||
(tw->tileh & 0xf) != 0 ) {
vips_error( "vips2tiff",
"%s", _( "tile size not a multiple of 16" ) );
return( NULL );
}
if( !tw->tile && tw->pyramid ) {
vips_warn( "vips2tiff",
"%s", _( "can't have strip pyramid -- "
"enabling tiling" ) );
tw->tile = 1;
}
/* We can only pyramid LABQ and non-complex images.
*/
if( tw->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( tw->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" ) );
tw->onebit = 0;
}
if( tw->onebit &&
tw->compression == COMPRESSION_JPEG ) {
vips_warn( "vips2tiff",
"%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) );
tw->compression = COMPRESSION_NONE;
}
/* Sizeof a line of bytes in the TIFF tile.
*/
if( im->Coding == VIPS_CODING_LABQ )
tw->tls = tw->tilew * 3;
else if( tw->onebit )
tw->tls = ROUND_UP( tw->tilew, 8 ) / 8;
else
tw->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * tw->tilew;
/* If we will be writing tiles, we need to cache tileh lines of the
* input, since we say we're sequential.
*/
if( tw->tile ) {
if( vips_tilecache( tw->im, &tw->cache,
"tile_width", tw->im->Xsize,
"tile_height", 1,
"max_tiles", 2 * tw->tileh,
"threaded", TRUE,
NULL ) )
return( NULL );
tw->im = tw->cache;
}
return( tw );
}
/* Copy fields.
*/
#define CopyField( tag, v ) \
if( TIFFGetField( in, tag, &v ) ) TIFFSetField( out, tag, v )
/* Copy a TIFF file ... we know we wrote it, so just copy the tags we know
* we might have set.
*/
static int
tiff_copy( TiffWrite *tw, TIFF *out, TIFF *in )
{
uint32 i32;
uint16 i16;
float f;
tdata_t buf;
ttile_t tile;
ttile_t n;
/* All the fields we might have set.
*/
CopyField( TIFFTAG_IMAGEWIDTH, i32 );
CopyField( TIFFTAG_IMAGELENGTH, i32 );
CopyField( TIFFTAG_PLANARCONFIG, i16 );
CopyField( TIFFTAG_ORIENTATION, i16 );
CopyField( TIFFTAG_XRESOLUTION, f );
CopyField( TIFFTAG_YRESOLUTION, f );
CopyField( TIFFTAG_RESOLUTIONUNIT, i16 );
CopyField( TIFFTAG_COMPRESSION, i16 );
CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 );
CopyField( TIFFTAG_BITSPERSAMPLE, i16 );
CopyField( TIFFTAG_PHOTOMETRIC, i16 );
CopyField( TIFFTAG_TILEWIDTH, i32 );
CopyField( TIFFTAG_TILELENGTH, i32 );
CopyField( TIFFTAG_ROWSPERSTRIP, i32 );
CopyField( TIFFTAG_SUBFILETYPE, i32 );
if( tw->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE )
TIFFSetField( out, TIFFTAG_PREDICTOR, tw->predictor );
/* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it.
* Set explicitly from TiffWrite.
*/
if( tw->compression == COMPRESSION_JPEG ) {
TIFFSetField( out, TIFFTAG_JPEGQUALITY, tw->jpqual );
/* Only for three-band, 8-bit images.
*/
if( tw->im->Bands == 3 &&
tw->im->BandFmt == VIPS_FORMAT_UCHAR ) {
/* Enable rgb->ycbcr conversion in the jpeg write.
*/
if( !tw->rgbjpeg &&
tw->jpqual < 90 )
TIFFSetField( out,
TIFFTAG_JPEGCOLORMODE,
JPEGCOLORMODE_RGB );
/* And we want ycbcr expanded to rgb on read. Otherwise
* TIFFTileSize() will give us the size of a chrominance
* subsampled tile.
*/
TIFFSetField( in,
TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
}
}
/* We can't copy profiles or xmp :( Set again from TiffWrite.
*/
if( embed_profile( tw, out ) )
return( -1 );
if( embed_xmp( tw, out ) )
return( -1 );
buf = vips_malloc( NULL, TIFFTileSize( in ) );
n = TIFFNumberOfTiles( in );
for( tile = 0; tile < n; tile++ ) {
tsize_t len;
/* It'd be good to use TIFFReadRawTile()/TIFFWriteRawTile()
* here to save compression/decompression, but sadly it seems
* not to work :-( investigate at some point.
*/
len = TIFFReadEncodedTile( in, tile, buf, -1 );
if( len < 0 ||
TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) {
vips_free( buf );
return( -1 );
}
}
vips_free( buf );
return( 0 );
}
/* Append all of the lower layers we wrote to the output.
*/
static int
gather_pyramid( TiffWrite *tw )
{
PyramidLayer *layer;
for( layer = tw->layer; layer; layer = layer->below ) {
TIFF *in;
#ifdef DEBUG
printf( "Appending layer %s ...\n", layer->lname );
#endif /*DEBUG*/
if( !(in = tiff_openin( layer->lname )) )
return( -1 );
if( tiff_copy( tw, tw->tif, in ) ) {
TIFFClose( in );
return( -1 );
}
TIFFClose( in );
if( !TIFFWriteDirectory( tw->tif ) )
return( -1 );
}
return( 0 );
}
int
vips__tiff_write( VipsImage *in, const char *filename,
VipsForeignTiffCompression compression, int Q,
VipsForeignTiffPredictor predictor,
char *profile,
gboolean tile, int tile_width, int tile_height,
gboolean pyramid,
gboolean squash,
VipsForeignTiffResunit resunit, double xres, double yres,
gboolean bigtiff,
gboolean rgbjpeg )
{
TiffWrite *tw;
int res;
#ifdef DEBUG
printf( "tiff2vips: libtiff version is \"%s\"\n", TIFFGetVersion() );
#endif /*DEBUG*/
vips__tiff_init();
/* Check input image.
*/
if( vips_check_coding_known( "vips2tiff", in ) )
return( -1 );
/* Make output image.
*/
if( !(tw = make_tiff_write( in, filename,
compression, Q, predictor, profile,
tile, tile_width, tile_height, pyramid, squash,
resunit, xres, yres, bigtiff, rgbjpeg )) )
return( -1 );
if( !(tw->tif = tiff_openout( tw, tw->name )) ) {
free_tiff_write( tw );
return( -1 );
}
/* Write the TIFF header for the full-res file.
*/
if( write_tiff_header( tw, tw->tif, in->Xsize, in->Ysize ) ) {
free_tiff_write( tw );
return( -1 );
}
if( tw->tile )
res = write_tif_tilewise( tw );
else
res = write_tif_stripwise( tw );
if( res ) {
free_tiff_write( tw );
return( -1 );
}
if( !TIFFWriteDirectory( tw->tif ) )
return( -1 );
/* Free pyramid resources ... this will TIFFClose() the smaller layers
* ready for us to read from them again.
*/
if( tw->layer )
free_pyramid( tw->layer );
/* Append smaller layers to the main file.
*/
if( tw->pyramid &&
gather_pyramid( tw ) ) {
free_tiff_write( tw );
return( -1 );
}
free_tiff_write( tw );
return( 0 );
}
#endif /*HAVE_TIFF*/