add subifd support to the TIFF writer
A new subifd switch enables the writing of pyramids layers into subifds (rather than the default successive pages). This switch is enabled automatically for multi-page pyramids. seems to work in quick tests
This commit is contained in:
parent
6a8f128831
commit
a2d196b736
@ -193,6 +193,8 @@
|
|||||||
* - write XYZ images as logluv
|
* - write XYZ images as logluv
|
||||||
* 7/2/20 [jclavoie-jive]
|
* 7/2/20 [jclavoie-jive]
|
||||||
* - add PAGENUMBER support
|
* - add PAGENUMBER support
|
||||||
|
* 23/5/20
|
||||||
|
* - add support for subifd pyramid layers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -247,6 +249,13 @@
|
|||||||
#include "pforeign.h"
|
#include "pforeign.h"
|
||||||
#include "tiff.h"
|
#include "tiff.h"
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* - have a layout enum rather than a bool
|
||||||
|
* - revise docs
|
||||||
|
* - revise tests
|
||||||
|
*/
|
||||||
|
|
||||||
/* Max number of alpha channels we allow.
|
/* Max number of alpha channels we allow.
|
||||||
*/
|
*/
|
||||||
#define MAX_ALPHA (64)
|
#define MAX_ALPHA (64)
|
||||||
@ -396,40 +405,62 @@ embed_profile_meta( TIFF *tif, VipsImage *im )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static Layer *
|
static void
|
||||||
wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
|
wtiff_layer_init( Wtiff *wtiff, Layer **layer, Layer *above,
|
||||||
|
int width, int height )
|
||||||
{
|
{
|
||||||
Layer *layer;
|
if( !*layer ) {
|
||||||
|
*layer = VIPS_NEW( wtiff->ready, Layer );
|
||||||
layer = VIPS_NEW( wtiff->ready, Layer );
|
(*layer)->wtiff = wtiff;
|
||||||
layer->wtiff = wtiff;
|
(*layer)->width = width;
|
||||||
layer->width = width;
|
(*layer)->height = height;
|
||||||
layer->height = height;
|
|
||||||
|
|
||||||
if( !above )
|
if( !above )
|
||||||
/* Top of pyramid.
|
/* Top of pyramid.
|
||||||
*/
|
*/
|
||||||
layer->sub = 1;
|
(*layer)->sub = 1;
|
||||||
else
|
else
|
||||||
layer->sub = above->sub * 2;
|
(*layer)->sub = above->sub * 2;
|
||||||
|
|
||||||
layer->lname = NULL;
|
(*layer)->lname = NULL;
|
||||||
layer->buf = NULL;
|
(*layer)->buf = NULL;
|
||||||
layer->len = 0;
|
(*layer)->len = 0;
|
||||||
layer->tif = NULL;
|
(*layer)->tif = NULL;
|
||||||
layer->image = NULL;
|
(*layer)->image = NULL;
|
||||||
layer->write_y = 0;
|
(*layer)->write_y = 0;
|
||||||
layer->y = 0;
|
(*layer)->y = 0;
|
||||||
layer->strip = NULL;
|
(*layer)->strip = NULL;
|
||||||
layer->copy = NULL;
|
(*layer)->copy = NULL;
|
||||||
|
|
||||||
layer->below = NULL;
|
(*layer)->below = NULL;
|
||||||
layer->above = above;
|
(*layer)->above = above;
|
||||||
|
|
||||||
|
/* The name for the top layer is the output filename.
|
||||||
|
*
|
||||||
|
* We need lname to be freed automatically: it has to stay
|
||||||
|
* alive until after wtiff_gather().
|
||||||
|
*/
|
||||||
|
if( wtiff->filename ) {
|
||||||
|
if( !above )
|
||||||
|
(*layer)->lname = vips_strdup(
|
||||||
|
VIPS_OBJECT( wtiff->ready ),
|
||||||
|
wtiff->filename );
|
||||||
|
else {
|
||||||
|
char *lname;
|
||||||
|
|
||||||
|
lname = vips__temp_name( "%s.tif" );
|
||||||
|
(*layer)->lname = vips_strdup(
|
||||||
|
VIPS_OBJECT( wtiff->ready ),
|
||||||
|
lname );
|
||||||
|
g_free( lname );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
printf( "wtiff_layer_new: sub = %d, width = %d, height = %d\n",
|
|
||||||
layer->sub, width, height );
|
|
||||||
*/
|
*/
|
||||||
|
printf( "wtiff_layer_init: sub = %d, width = %d, height = %d\n",
|
||||||
|
(*layer)->sub, width, height );
|
||||||
|
}
|
||||||
|
|
||||||
if( wtiff->pyramid ) {
|
if( wtiff->pyramid ) {
|
||||||
int limitw, limith;
|
int limitw, limith;
|
||||||
@ -459,34 +490,13 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height )
|
|||||||
* Very tall or wide images might end up with a smallest layer
|
* Very tall or wide images might end up with a smallest layer
|
||||||
* larger than one tile.
|
* larger than one tile.
|
||||||
*/
|
*/
|
||||||
if( (layer->width > limitw ||
|
if( ((*layer)->width > limitw ||
|
||||||
layer->height > limith) &&
|
(*layer)->height > limith) &&
|
||||||
layer->width > 1 &&
|
(*layer)->width > 1 &&
|
||||||
layer->height > 1 )
|
(*layer)->height > 1 )
|
||||||
layer->below = wtiff_layer_new( wtiff, layer,
|
wtiff_layer_init( wtiff, &(*layer)->below, *layer,
|
||||||
width / 2, height / 2 );
|
width / 2, height / 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The name for the top layer is the output filename.
|
|
||||||
*
|
|
||||||
* We need lname to be freed automatically: it has to stay
|
|
||||||
* alive until after wtiff_gather().
|
|
||||||
*/
|
|
||||||
if( wtiff->filename ) {
|
|
||||||
if( !above )
|
|
||||||
layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
|
|
||||||
wtiff->filename );
|
|
||||||
else {
|
|
||||||
char *lname;
|
|
||||||
|
|
||||||
lname = vips__temp_name( "%s.tif" );
|
|
||||||
layer->lname = vips_strdup( VIPS_OBJECT( wtiff->ready ),
|
|
||||||
lname );
|
|
||||||
g_free( lname );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return( layer );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -846,7 +856,10 @@ wtiff_allocate_layers( Wtiff *wtiff )
|
|||||||
{
|
{
|
||||||
Layer *layer;
|
Layer *layer;
|
||||||
|
|
||||||
|
g_assert( wtiff->layer );
|
||||||
|
|
||||||
for( layer = wtiff->layer; layer; layer = layer->below ) {
|
for( layer = wtiff->layer; layer; layer = layer->below ) {
|
||||||
|
if( !layer->image ) {
|
||||||
layer->image = vips_image_new();
|
layer->image = vips_image_new();
|
||||||
if( vips_image_pipelinev( layer->image,
|
if( vips_image_pipelinev( layer->image,
|
||||||
VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL ) )
|
VIPS_DEMAND_STYLE_ANY, wtiff->ready, NULL ) )
|
||||||
@ -857,29 +870,42 @@ wtiff_allocate_layers( Wtiff *wtiff )
|
|||||||
layer->strip = vips_region_new( layer->image );
|
layer->strip = vips_region_new( layer->image );
|
||||||
layer->copy = vips_region_new( layer->image );
|
layer->copy = vips_region_new( layer->image );
|
||||||
|
|
||||||
/* The regions will get used in the bg thread callback, so
|
/* The regions will get used in the bg thread callback,
|
||||||
* make sure we don't own them.
|
* so make sure we don't own them.
|
||||||
*/
|
*/
|
||||||
vips__region_no_ownership( layer->strip );
|
vips__region_no_ownership( layer->strip );
|
||||||
vips__region_no_ownership( layer->copy );
|
vips__region_no_ownership( layer->copy );
|
||||||
|
|
||||||
if( wtiff_layer_rewind( wtiff, layer ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
if( layer->lname )
|
if( layer->lname )
|
||||||
layer->tif = vips__tiff_openout(
|
layer->tif = vips__tiff_openout(
|
||||||
layer->lname, wtiff->bigtiff );
|
layer->lname, wtiff->bigtiff );
|
||||||
else {
|
else {
|
||||||
layer->tif = vips__tiff_openout_buffer( wtiff->ready,
|
layer->tif = vips__tiff_openout_buffer(
|
||||||
wtiff->bigtiff, &layer->buf, &layer->len );
|
wtiff->ready, wtiff->bigtiff,
|
||||||
|
&layer->buf, &layer->len );
|
||||||
}
|
}
|
||||||
if( !layer->tif )
|
if( !layer->tif )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( wtiff_layer_rewind( wtiff, layer ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
if( wtiff_write_header( wtiff, layer ) )
|
if( wtiff_write_header( wtiff, layer ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !wtiff->tbuf ) {
|
||||||
|
if( wtiff->tile )
|
||||||
|
wtiff->tbuf = vips_malloc( NULL,
|
||||||
|
TIFFTileSize( wtiff->layer->tif ) );
|
||||||
|
else
|
||||||
|
wtiff->tbuf = vips_malloc( NULL,
|
||||||
|
TIFFScanlineSize( wtiff->layer->tif ) );
|
||||||
|
if( !wtiff->tbuf )
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1099,28 +1125,6 @@ wtiff_new( VipsImage *input, const char *filename,
|
|||||||
wtiff->toilet_roll = TRUE;
|
wtiff->toilet_roll = TRUE;
|
||||||
wtiff->image_height = wtiff->page_height;
|
wtiff->image_height = wtiff->page_height;
|
||||||
wtiff->n_pages = wtiff->ready->Ysize / wtiff->page_height;
|
wtiff->n_pages = wtiff->ready->Ysize / wtiff->page_height;
|
||||||
|
|
||||||
/* We can't pyramid toilet roll images.
|
|
||||||
*/
|
|
||||||
if( wtiff->pyramid ) {
|
|
||||||
g_warning( "%s",
|
|
||||||
_( "can't pyramid multi page images --- "
|
|
||||||
"disabling pyramid" ) );
|
|
||||||
wtiff->pyramid = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* In strip mode we use tileh to set rowsperstrip, and that does not
|
|
||||||
* have the multiple-of-16 restriction.
|
|
||||||
*/
|
|
||||||
if( tile ) {
|
|
||||||
if( (wtiff->tilew & 0xf) != 0 ||
|
|
||||||
(wtiff->tileh & 0xf) != 0 ) {
|
|
||||||
wtiff_free( wtiff );
|
|
||||||
vips_error( "vips2tiff",
|
|
||||||
"%s", _( "tile size not a multiple of 16" ) );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We can only pyramid LABQ and non-complex images.
|
/* We can only pyramid LABQ and non-complex images.
|
||||||
@ -1136,6 +1140,41 @@ wtiff_new( VipsImage *input, const char *filename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Pyramid images must be tiled.
|
||||||
|
*/
|
||||||
|
if( wtiff->pyramid &&
|
||||||
|
!wtiff->tile )
|
||||||
|
wtiff->tile = TRUE;
|
||||||
|
|
||||||
|
/* Multi-page pyramids must be in subifd mode.
|
||||||
|
*/
|
||||||
|
if( wtiff->pyramid &&
|
||||||
|
wtiff->toilet_roll )
|
||||||
|
wtiff->subifd = TRUE;
|
||||||
|
|
||||||
|
/* If compression is off and we're writing a >4gb image, automatically
|
||||||
|
* enable bigtiff.
|
||||||
|
*
|
||||||
|
* This won't always work. If the image data is just under 4gb but
|
||||||
|
* there's a lot of metadata, we could be pushed over the 4gb limit.
|
||||||
|
*/
|
||||||
|
if( wtiff->compression == COMPRESSION_NONE &&
|
||||||
|
VIPS_IMAGE_SIZEOF_IMAGE( wtiff->ready ) > UINT_MAX )
|
||||||
|
wtiff->bigtiff = TRUE;
|
||||||
|
|
||||||
|
/* In strip mode we use tileh to set rowsperstrip, and that does not
|
||||||
|
* have the multiple-of-16 restriction.
|
||||||
|
*/
|
||||||
|
if( wtiff->tile ) {
|
||||||
|
if( (wtiff->tilew & 0xf) != 0 ||
|
||||||
|
(wtiff->tileh & 0xf) != 0 ) {
|
||||||
|
wtiff_free( wtiff );
|
||||||
|
vips_error( "vips2tiff",
|
||||||
|
"%s", _( "tile size not a multiple of 16" ) );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Can only squash 8 bit mono. 3-band float should have been squashed
|
/* Can only squash 8 bit mono. 3-band float should have been squashed
|
||||||
* above.
|
* above.
|
||||||
*/
|
*/
|
||||||
@ -1193,42 +1232,6 @@ wtiff_new( VipsImage *input, const char *filename,
|
|||||||
wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) *
|
wtiff->tls = VIPS_IMAGE_SIZEOF_PEL( wtiff->ready ) *
|
||||||
wtiff->tilew;
|
wtiff->tilew;
|
||||||
|
|
||||||
/* If compression is off and we're writing a >4gb image, automatically
|
|
||||||
* enable bigtiff.
|
|
||||||
*
|
|
||||||
* This won't always work. If the image data is just under 4gb but
|
|
||||||
* there's a lot of metadata, we could be pushed over the 4gb limit.
|
|
||||||
*/
|
|
||||||
if( wtiff->compression == COMPRESSION_NONE &&
|
|
||||||
VIPS_IMAGE_SIZEOF_IMAGE( wtiff->ready ) > UINT_MAX &&
|
|
||||||
!wtiff->bigtiff ) {
|
|
||||||
g_warning( "%s", _( "image over 4gb, enabling bigtiff" ) );
|
|
||||||
wtiff->bigtiff = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build the pyramid framework.
|
|
||||||
*/
|
|
||||||
wtiff->layer = wtiff_layer_new( wtiff, NULL,
|
|
||||||
wtiff->ready->Xsize, wtiff->image_height );
|
|
||||||
|
|
||||||
/* Fill all the layers.
|
|
||||||
*/
|
|
||||||
if( wtiff_allocate_layers( wtiff ) ) {
|
|
||||||
wtiff_free( wtiff );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( tile )
|
|
||||||
wtiff->tbuf = vips_malloc( NULL,
|
|
||||||
TIFFTileSize( wtiff->layer->tif ) );
|
|
||||||
else
|
|
||||||
wtiff->tbuf = vips_malloc( NULL,
|
|
||||||
TIFFScanlineSize( wtiff->layer->tif ) );
|
|
||||||
if( !wtiff->tbuf ) {
|
|
||||||
wtiff_free( wtiff );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( wtiff );
|
return( wtiff );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1876,8 +1879,8 @@ wtiff_gather( Wtiff *wtiff )
|
|||||||
TIFF *in;
|
TIFF *in;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "Appending layer %s ...\n", layer->lname );
|
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
printf( "appending layer %s ...\n", layer->lname );
|
||||||
|
|
||||||
if( layer->lname ) {
|
if( layer->lname ) {
|
||||||
if( !(source = vips_source_new_from_file(
|
if( !(source = vips_source_new_from_file(
|
||||||
@ -1911,77 +1914,64 @@ wtiff_gather( Wtiff *wtiff )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Three types of write: single image, multipage and pyramid.
|
/* Write one page from our input image, optionally pyramiding it.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
wtiff_write_image( Wtiff *wtiff )
|
wtiff_write_page( Wtiff *wtiff, VipsImage *page )
|
||||||
{
|
{
|
||||||
if( wtiff->toilet_roll ) {
|
|
||||||
int y;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "wtiff_write_image: toilet-roll mode\n" );
|
printf( "wtiff_write_page:\n" );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
y = 0;
|
/* Init the pyramid framework for this page. This will just make a
|
||||||
for(;;) {
|
* single layer if we're not pyramiding.
|
||||||
VipsImage *page;
|
*/
|
||||||
|
wtiff_layer_init( wtiff, &wtiff->layer, NULL,
|
||||||
|
page->Xsize, page->Ysize );
|
||||||
|
|
||||||
if( vips_crop( wtiff->ready, &page,
|
/* Fill all the layers and write the TIFF headers.
|
||||||
0, y, wtiff->ready->Xsize, wtiff->page_height,
|
*/
|
||||||
NULL ) )
|
if( wtiff_allocate_layers( wtiff ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
if( vips_sink_disc( page, write_strip, wtiff ) ) {
|
|
||||||
g_object_unref( page );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
g_object_unref( page );
|
|
||||||
|
|
||||||
wtiff->page_number += 1;
|
/* In ifd mode, we write the pyramid layers as subdirectories of this
|
||||||
y += wtiff->page_height;
|
* page.
|
||||||
if( y >= wtiff->ready->Ysize )
|
*/
|
||||||
break;
|
if( wtiff->subifd ) {
|
||||||
|
|
||||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) ||
|
|
||||||
wtiff_layer_rewind( wtiff,
|
|
||||||
wtiff->layer ) ||
|
|
||||||
wtiff_write_header( wtiff,
|
|
||||||
wtiff->layer ) )
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( wtiff->pyramid &&
|
|
||||||
wtiff->subifd ) {
|
|
||||||
int n_layers;
|
int n_layers;
|
||||||
toff_t *subifd_offsets;
|
toff_t *subifd_offsets;
|
||||||
Layer *p;
|
Layer *p;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "wtiff_write_image: OME pyr mode\n" );
|
printf( "wtiff_write_page: OME pyr mode\n" );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
/* This magic tag makes the n_layers directories we write
|
/* This magic tag makes the n_layers directories we write
|
||||||
* after this one into subdirectories. We set the offsets to 0
|
* after this one into subdirectories. We set the offsets to 0
|
||||||
* and libtiff will fill them in automatically.
|
* and libtiff will fill them in automatically.
|
||||||
*/
|
*/
|
||||||
for( n_layers = 0, p = wtiff->layer; p; p = p->below )
|
for( n_layers = 0, p = wtiff->layer->below; p; p = p->below )
|
||||||
n_layers += 1;
|
n_layers += 1;
|
||||||
subifd_offsets = VIPS_ARRAY( NULL, n_layers, toff_t );
|
subifd_offsets = VIPS_ARRAY( NULL, n_layers, toff_t );
|
||||||
memset( subifd_offsets, 0, n_layers * sizeof( toff_t ) );
|
memset( subifd_offsets, 0, n_layers * sizeof( toff_t ) );
|
||||||
TIFFSetField( wtiff->layer->tif, TIFFTAG_SUBIFD,
|
TIFFSetField( wtiff->layer->tif, TIFFTAG_SUBIFD,
|
||||||
n_layers, subifd_offsets );
|
n_layers, subifd_offsets );
|
||||||
|
g_free( subifd_offsets );
|
||||||
|
}
|
||||||
|
|
||||||
if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
|
if( vips_sink_disc( page, write_strip, wtiff ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Free lower pyramid resources ... this will
|
/* Append any pyr layers, if necessary.
|
||||||
|
*/
|
||||||
|
if( wtiff->layer->below ) {
|
||||||
|
/* Free any lower pyramid resources ... this will
|
||||||
* TIFFClose() (but not delete) the smaller layers
|
* TIFFClose() (but not delete) the smaller layers
|
||||||
* ready for us to read from them again.
|
* ready for us to read from them again.
|
||||||
*/
|
*/
|
||||||
if( wtiff->layer->below )
|
|
||||||
layer_free_all( wtiff->layer->below );
|
layer_free_all( wtiff->layer->below );
|
||||||
|
|
||||||
/* Append smaller layers to the main file.
|
/* Append smaller layers to the main file.
|
||||||
@ -1989,38 +1979,44 @@ wtiff_write_image( Wtiff *wtiff )
|
|||||||
if( wtiff_gather( wtiff ) )
|
if( wtiff_gather( wtiff ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
|
/* We can delete any temps now ready for the next page.
|
||||||
|
*/
|
||||||
|
wtiff_delete_temps( wtiff );
|
||||||
|
|
||||||
|
/* And free all lower pyr layers ready to be rebuilt for the
|
||||||
|
* next page.
|
||||||
|
*/
|
||||||
|
VIPS_FREEF( layer_free_all, wtiff->layer->below );
|
||||||
}
|
}
|
||||||
else if( wtiff->pyramid ) {
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write all pages.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
wtiff_write_image( Wtiff *wtiff )
|
||||||
|
{
|
||||||
|
int y;
|
||||||
|
|
||||||
|
for( y = 0; y < wtiff->ready->Ysize; y += wtiff->page_height ) {
|
||||||
|
VipsImage *page;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
printf( "wtiff_write_image: pyramid mode\n" );
|
printf( "writing page %d ...\n", wtiff->page_number );
|
||||||
#endif /*DEBUG*/
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
|
if( vips_crop( wtiff->ready, &page,
|
||||||
|
0, y, wtiff->ready->Xsize, wtiff->page_height,
|
||||||
|
NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
if( wtiff_write_page( wtiff, page ) ) {
|
||||||
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
|
g_object_unref( page );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Free lower pyramid resources ... this will
|
|
||||||
* TIFFClose() (but not delete) the smaller layers
|
|
||||||
* ready for us to read from them again.
|
|
||||||
*/
|
|
||||||
if( wtiff->layer->below )
|
|
||||||
layer_free_all( wtiff->layer->below );
|
|
||||||
|
|
||||||
/* Append smaller layers to the main file.
|
|
||||||
*/
|
|
||||||
if( wtiff_gather( wtiff ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
g_object_unref( page );
|
||||||
#ifdef DEBUG
|
|
||||||
printf( "wtiff_write_image: single-image mode\n" );
|
|
||||||
#endif /*DEBUG*/
|
|
||||||
|
|
||||||
if( vips_sink_disc( wtiff->ready, write_strip, wtiff ) )
|
wtiff->page_number += 1;
|
||||||
return( -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
Loading…
Reference in New Issue
Block a user