diff --git a/ChangeLog b/ChangeLog index 68fbbcb3..dd81b5e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,7 +10,8 @@ - all loaders have a @fail option, meaning fail on first warning, though it only does anything for jpg and csv - add vips_image_get_fields() to help bindings -- add multi-page read to tiffload +- add tiff multi-page read/write +- add VIPS_META_PAGE_HEIGHT metadata 11/11/16 started 8.4.4 - fix crash in vips.exe arg parsing on Windows, thanks Yury diff --git a/TODO b/TODO index 7715e425..f99c9889 100644 --- a/TODO +++ b/TODO @@ -1,16 +1,12 @@ -- add VIPS_META_PAGE_HEIGHT and probably some others too .. "orientation"? - -- in wtiff_layer_rewind() we size strip height by tileh, but is this correct - for strip images? - -- test data - - http://downloads.openmicroscopy.org/images/OME-TIFF/2016-06/bioformats-artificial/multi-channel-z-series.ome.tif - - all toilet roll loaders need to set "page-height" magick, pdf and tiff need to use the same page/n interface + + + + + - not sure about utf8 error messages on win - strange: diff --git a/libvips/foreign/tiff2vips.c b/libvips/foreign/tiff2vips.c index b6534836..0ec28d7f 100644 --- a/libvips/foreign/tiff2vips.c +++ b/libvips/foreign/tiff2vips.c @@ -1209,7 +1209,8 @@ rtiff_set_header( Rtiff *rtiff, VipsImage *out ) out->Ysize = rtiff->header.height * rtiff->n; if( rtiff->n > 1 ) - vips_image_set_int( out, "page-height", rtiff->header.height ); + vips_image_set_int( out, + VIPS_META_PAGE_HEIGHT, rtiff->header.height ); /* Even though we could end up serving tiled data, always hint * THINSTRIP, since we're quite happy doing that too, and it could need diff --git a/libvips/foreign/tiffload.c b/libvips/foreign/tiffload.c index ccbd9501..29fd58c4 100644 --- a/libvips/foreign/tiffload.c +++ b/libvips/foreign/tiffload.c @@ -328,8 +328,8 @@ vips_foreign_load_tiff_buffer_init( VipsForeignLoadTiffBuffer *buffer ) * * @n means load this many pages. By default a single page is read. All the * pages must have the same dimensions, and they are loaded as a tall, thin - * "toilet roll" image. The "page-height" metadata tag gives the height in - * pixels of each page. Use -1 to load all pages. + * "toilet roll" image. The #VIPS_META_PAGE_HEIGHT metadata + * tag gives the height in pixels of each page. Use -1 to load all pages. * * Setting @autorotate to %TRUE will make the loader interpret the * orientation tag and automatically rotate the image appropriately during diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index bfbc9f26..7e2db098 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -475,6 +475,10 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) * * Write a VIPS image to a file as TIFF. * + * If @in has the #VIPS_META_PAGE_HEIGHT metadata item, this is assumed to be a + * "toilet roll" image. It will be + * written as series of pages, each #VIPS_META_PAGE_HEIGHT pixels high. + * * Use @compression to set the tiff compression. Currently jpeg, packbits, * fax4, lzw, none and deflate are supported. The default is no compression. * JPEG compression is a good lossy compressor for photographs, packbits is diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 2e7396c4..8cd9f744 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -198,9 +198,9 @@ */ /* - */ #define DEBUG_VERBOSE #define DEBUG + */ #ifdef HAVE_CONFIG_H #include @@ -921,8 +921,9 @@ wtiff_new( VipsImage *im, const char *filename, /* Check for a toilet roll image. */ - if( vips_image_get_typeof( im, "page-height" ) && - vips_image_get_int( im, "page-height", &wtiff->page_height ) ) { + if( vips_image_get_typeof( im, VIPS_META_PAGE_HEIGHT ) && + vips_image_get_int( im, + VIPS_META_PAGE_HEIGHT, &wtiff->page_height ) ) { wtiff_free( wtiff ); return( NULL ); } diff --git a/libvips/include/vips/header.h b/libvips/include/vips/header.h index 5affb207..1ae81011 100644 --- a/libvips/include/vips/header.h +++ b/libvips/include/vips/header.h @@ -133,6 +133,15 @@ extern "C" { */ #define VIPS_META_ORIENTATION "orientation" +/** + * VIPS_META_PAGE_HEIGHT: + * + * If set, the height of each page when this image was loaded. If you save an + * image with "page-height" set to a format that supports multiple pages, such + * as tiff, the image will be saved as a series of pages. + */ +#define VIPS_META_PAGE_HEIGHT "page-height" + guint64 vips_format_sizeof( VipsBandFormat format ); guint64 vips_format_sizeof_unsafe( VipsBandFormat format ); diff --git a/test/images/multi-channel-z-series.ome.tif b/test/images/multi-channel-z-series.ome.tif new file mode 100644 index 00000000..1aa66b0f Binary files /dev/null and b/test/images/multi-channel-z-series.ome.tif differ diff --git a/test/test_foreign.py b/test/test_foreign.py index c6d0eba0..98b5ab7e 100755 --- a/test/test_foreign.py +++ b/test/test_foreign.py @@ -41,6 +41,7 @@ class TestForeign(unittest.TestCase): self.jpeg_file = "images/йцук.jpg" self.png_file = "images/sample.png" self.tiff_file = "images/sample.tif" + self.ome_file = "images/multi-channel-z-series.ome.tif" self.profile_file = "images/sRGB.icm" self.analyze_file = "images/t00740_tr1_segm.hdr" self.gif_file = "images/cramps.gif" @@ -315,6 +316,39 @@ class TestForeign(unittest.TestCase): self.assertEqual(x1.height, x2.width) os.unlink("test-14.tif") + x = Vips.Image.new_from_file(self.ome_file) + self.assertEqual(x.width, 439) + self.assertEqual(x.height, 167) + page_height = x.height + + x = Vips.Image.new_from_file(self.ome_file, n = -1) + self.assertEqual(x.width, 439) + self.assertEqual(x.height, page_height * 15) + + x = Vips.Image.new_from_file(self.ome_file, page = 1, n = -1) + self.assertEqual(x.width, 439) + self.assertEqual(x.height, page_height * 14) + + x = Vips.Image.new_from_file(self.ome_file, page = 1, n = 2) + self.assertEqual(x.width, 439) + self.assertEqual(x.height, page_height * 2) + + x = Vips.Image.new_from_file(self.ome_file, n = -1) + self.assertEqual(x(0,166)[0], 96) + self.assertEqual(x(0,167)[0], 0) + self.assertEqual(x(0,168)[0], 1) + + x.write_to_file("test-15.tif") + + x = Vips.Image.new_from_file("test-15.tif", n = -1) + self.assertEqual(x.width, 439) + self.assertEqual(x.height, page_height * 15) + self.assertEqual(x(0,166)[0], 96) + self.assertEqual(x(0,167)[0], 0) + self.assertEqual(x(0,168)[0], 1) + + os.unlink("test-15.tif") + def test_magickload(self): x = Vips.type_find("VipsForeign", "magickload") if not x.is_instantiatable():