Skip to content

Commit be0b0d1

Browse files
committed
better tiff write looping
We were looping over pages, cropping each one out, and saving. Now there's a single loop for thw whole of the image, so things like percent reporting work in the obvious way. See libvips#2450
1 parent 2501a62 commit be0b0d1

File tree

1 file changed

+89
-36
lines changed

1 file changed

+89
-36
lines changed

libvips/foreign/vips2tiff.c

Lines changed: 89 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,8 +1659,8 @@ wtiff_layer_write_strip( Wtiff *wtiff, Layer *layer, VipsRegion *strip )
16591659
int y;
16601660

16611661
#ifdef DEBUG_VERBOSE
1662-
printf( "Writing %d pixel strip at height %d to image %s\n",
1663-
height, area->top, TIFFFileName( layer->tif ) );
1662+
printf( "wtiff_layer_write_strip: top %d, height %d, file %s\n",
1663+
area->top, height, TIFFFileName( layer->tif ) );
16641664
#endif /*DEBUG_VERBOSE*/
16651665

16661666
for( y = 0; y < height; y++ ) {
@@ -1842,23 +1842,29 @@ layer_strip_arrived( Layer *layer )
18421842
return( 0 );
18431843
}
18441844

1845-
/* Another strip of image pixels from vips_sink_disc(). Write into the top
1846-
* pyramid layer.
1845+
/* Another few scanlines of pixels. We know the scanlines are all within the
1846+
* current page.
18471847
*/
18481848
static int
1849-
write_strip( VipsRegion *region, VipsRect *area, void *a )
1849+
wtiff_write_lines( Wtiff *wtiff, VipsRegion *region, VipsRect *lines )
18501850
{
1851-
Wtiff *wtiff = (Wtiff *) a;
18521851
Layer *layer = wtiff->layer;
1852+
int page_top = wtiff->page_number * wtiff->page_height;
18531853

18541854
#ifdef DEBUG_VERBOSE
1855-
printf( "write_strip: strip at %d, height %d\n",
1856-
area->top, area->height );
1855+
printf( "wtiff_write_lines: top %d, height %d\n",
1856+
lines->top, lines->height );
18571857
#endif/*DEBUG_VERBOSE*/
18581858

1859+
/* Keep filling the current strip of the top layer. Each time it
1860+
* fills, write a chunk of pyramid.
1861+
*
1862+
* lines is in
1863+
*/
18591864
for(;;) {
18601865
VipsRect *to = &layer->strip->valid;
18611866
VipsRect target;
1867+
VipsRect page_lines;
18621868

18631869
/* The bit of strip that needs filling.
18641870
*/
@@ -1868,9 +1874,15 @@ write_strip( VipsRegion *region, VipsRect *area, void *a )
18681874
target.height = to->height;
18691875
vips_rect_intersectrect( &target, to, &target );
18701876

1871-
/* Clip against what we have available.
1877+
/* region and lines are in world coordinates, we must subtract
1878+
* the top of the current page to get layer coordinates.
18721879
*/
1873-
vips_rect_intersectrect( &target, area, &target );
1880+
page_lines = *lines;
1881+
page_lines.top -= page_top;
1882+
1883+
/* Clip against the lines we've been given.
1884+
*/
1885+
vips_rect_intersectrect( &target, &page_lines, &target );
18741886

18751887
/* Are we empty? All done.
18761888
*/
@@ -1883,8 +1895,9 @@ write_strip( VipsRegion *region, VipsRect *area, void *a )
18831895
* received, we could skip the copy. Will this happen very
18841896
* often? Unclear.
18851897
*/
1898+
target.top += page_top;
18861899
vips_region_copy( region, layer->strip,
1887-
&target, target.left, target.top );
1900+
&target, target.left, target.top - page_top );
18881901

18891902
layer->write_y += target.height;
18901903

@@ -2113,20 +2126,18 @@ wtiff_gather( Wtiff *wtiff )
21132126
return( 0 );
21142127
}
21152128

2116-
/* Write one page from our input image, optionally pyramiding it.
2117-
*/
21182129
static int
2119-
wtiff_write_page( Wtiff *wtiff, VipsImage *page )
2130+
wtiff_page_start( Wtiff *wtiff )
21202131
{
21212132
#ifdef DEBUG
2122-
printf( "wtiff_write_page:\n" );
2133+
printf( "wtiff_page_start: page %d\n", wtiff->page_number );
21232134
#endif /*DEBUG*/
21242135

21252136
/* Init the pyramid framework for this page. This will just make a
21262137
* single layer if we're not pyramiding.
21272138
*/
21282139
wtiff_layer_init( wtiff, &wtiff->layer, NULL,
2129-
page->Xsize, page->Ysize );
2140+
wtiff->ready->Xsize, wtiff->page_height );
21302141

21312142
/* Fill all the layers and write the TIFF headers.
21322143
*/
@@ -2158,8 +2169,15 @@ wtiff_write_page( Wtiff *wtiff, VipsImage *page )
21582169
g_free( subifd_offsets );
21592170
}
21602171

2161-
if( vips_sink_disc( page, write_strip, wtiff ) )
2162-
return( -1 );
2172+
return( 0 );
2173+
}
2174+
2175+
static int
2176+
wtiff_page_end( Wtiff *wtiff )
2177+
{
2178+
#ifdef DEBUG
2179+
printf( "wtiff_page_end: page %d\n", wtiff->page_number );
2180+
#endif /*DEBUG*/
21632181

21642182
if( !TIFFWriteDirectory( wtiff->layer->tif ) )
21652183
return( -1 );
@@ -2188,35 +2206,70 @@ wtiff_write_page( Wtiff *wtiff, VipsImage *page )
21882206
VIPS_FREEF( layer_free_all, wtiff->layer->below );
21892207
}
21902208

2209+
wtiff->page_number += 1;
2210+
21912211
return( 0 );
21922212
}
21932213

2194-
/* Write all pages.
2214+
/* A strip of pixels has come in from libvips. Split these strips into pages,
2215+
* and run the page start / end code.
21952216
*/
21962217
static int
2197-
wtiff_write_image( Wtiff *wtiff )
2218+
wtiff_sink_disc_strip( VipsRegion *region, VipsRect *area, void *a )
21982219
{
2199-
int y;
2220+
Wtiff *wtiff = ( Wtiff *) a;
22002221

2201-
for( y = 0; y < wtiff->ready->Ysize; y += wtiff->page_height ) {
2202-
VipsImage *page;
2222+
VipsRect pixels;
22032223

22042224
#ifdef DEBUG
2205-
printf( "writing page %d ...\n", wtiff->page_number );
2225+
printf( "wtiff_sink_disc_strip: top %d, height %d\n",
2226+
area->top, area->height );
22062227
#endif /*DEBUG*/
22072228

2208-
if( vips_crop( wtiff->ready, &page,
2209-
0, y, wtiff->ready->Xsize, wtiff->page_height,
2210-
NULL ) )
2211-
return( -1 );
2212-
if( wtiff_write_page( wtiff, page ) ) {
2213-
g_object_unref( page );
2229+
g_assert( area->width == wtiff->ready->Xsize );
2230+
2231+
/* Loop down this as we write scanlines into pages.
2232+
*/
2233+
pixels = *area;
2234+
2235+
do {
2236+
VipsRect page;
2237+
VipsRect lines;
2238+
2239+
/* The rect for the current page.
2240+
*/
2241+
page.left = 0;
2242+
page.top = wtiff->page_height * wtiff->page_number;
2243+
page.width = wtiff->ready->Xsize;
2244+
page.height = wtiff->page_height;
2245+
2246+
/* The scanlines we have for this page.
2247+
*/
2248+
vips_rect_intersectrect( &page, &pixels, &lines );
2249+
2250+
/* At the top of the page? Run the page start code.
2251+
*/
2252+
if( lines.top == page.top &&
2253+
wtiff_page_start( wtiff ) )
22142254
return( -1 );
2215-
}
2216-
g_object_unref( page );
22172255

2218-
wtiff->page_number += 1;
2219-
}
2256+
/* Write the scanlines into the page.
2257+
*/
2258+
if( wtiff_write_lines( wtiff, region, &lines ) )
2259+
return( -1 );
2260+
2261+
/* Hit the end of the page? Run the page end code.
2262+
*/
2263+
if( VIPS_RECT_BOTTOM( &page ) == VIPS_RECT_BOTTOM( &lines ) &&
2264+
wtiff_page_end( wtiff ) )
2265+
return( -1 );
2266+
2267+
/* Remove the pixels we've written and loop if we have some
2268+
* still to write.
2269+
*/
2270+
pixels.top += lines.height;
2271+
pixels.height -= lines.height;
2272+
} while( !vips_rect_isempty( &pixels ) );
22202273

22212274
return( 0 );
22222275
}
@@ -2257,7 +2310,7 @@ vips__tiff_write( VipsImage *input, const char *filename,
22572310
subifd, premultiply )) )
22582311
return( -1 );
22592312

2260-
if( wtiff_write_image( wtiff ) ) {
2313+
if( vips_sink_disc( wtiff->ready, wtiff_sink_disc_strip, wtiff ) ) {
22612314
wtiff_free( wtiff );
22622315
return( -1 );
22632316
}
@@ -2303,7 +2356,7 @@ vips__tiff_write_buf( VipsImage *input,
23032356
wtiff->obuf = obuf;
23042357
wtiff->olen = olen;
23052358

2306-
if( wtiff_write_image( wtiff ) ) {
2359+
if( vips_sink_disc( wtiff->ready, wtiff_sink_disc_strip, wtiff ) ) {
23072360
wtiff_free( wtiff );
23082361
return( -1 );
23092362
}

0 commit comments

Comments
 (0)