# HG changeset patch # User magedrifaat # Date 1659634176 -7200 # Node ID 1e633a093faa7773bf44049ee135f5f1204e7faf # Parent a30b144bc10bd3e0f9f773d845270e13d85553ea Tiff write: added support for logical tile images and corresponding unit tests * __tiff__.cc(write_tiled_image): added logic for logical images. * Tiff.m: added unit tests for write method for tiled images. diff -r a30b144bc10b -r 1e633a093faa libinterp/dldfcn/__tiff__.cc --- a/libinterp/dldfcn/__tiff__.cc Thu Aug 04 03:12:42 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Thu Aug 04 19:29:36 2022 +0200 @@ -1282,6 +1282,9 @@ } else if (image_data->bits_per_sample == 1) { + if (image_data->samples_per_pixel != 1) + error ("Bi-Level images must have one channel only"); + // Create a buffer to hold the packed strip data // Unique pointers are faster than vectors for constant size buffers std::unique_ptr strip_ptr @@ -1316,8 +1319,6 @@ { // TODO(maged): remove this? ASSUMES pixel data dimensions are already validated - typedef typename T::element_type P; - uint32_t tile_width, tile_height; if (! TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width)) error ("Failed to get the tile width"); @@ -1385,14 +1386,47 @@ uint8_t *pixel_fvec = reinterpret_cast (pixel_data.fortran_vec ()); uint32_t tile_count = TIFFNumberOfTiles (tif); - uint64_t tile_size = tile_width * tile_height * sizeof (P); - if (image_data->planar_configuration == PLANARCONFIG_CONTIG) - tile_size *= image_data->samples_per_pixel; + tsize_t tile_size = TIFFTileSize (tif); + for (uint32_t tile = 0; tile bits_per_sample == 8 + || image_data->bits_per_sample == 16 + || image_data->bits_per_sample == 32 + || image_data->bits_per_sample == 64) + { + if (! TIFFWriteEncodedTile (tif, tile, pixel_fvec, tile_size)) + error ("Failed to write tile data"); + pixel_fvec += tile_size; + } + else if (image_data->bits_per_sample == 1) + { + if (image_data->samples_per_pixel != 1) + error ("Bi-Level images must have one channel only"); + + // Create a buffer to hold the packed tile data + // Unique pointers are faster than vectors for + // constant size buffers + std::unique_ptr tile_ptr + = std::make_unique (tile_size); + uint8_t *tile_buf = tile_ptr.get (); + // Packing the pixel data into bits + for (uint32_t row = 0; row < tile_height; row++) + { + for (uint32_t col = 0; col < tile_width; col++) + { + uint8_t shift = 7 - col % 8; + tile_buf[row * tile_width / 8 + col / 8] + |= pixel_fvec[col] << shift; + } + pixel_fvec += tile_width; + } + if (TIFFWriteEncodedTile (tif, tile, tile_buf, + TIFFTileSize (tif)) == -1) + error ("Failed to write tile data to image"); + } + else + error ("Unsupported bit depth"); } } diff -r a30b144bc10b -r 1e633a093faa scripts/io/Tiff.m --- a/scripts/io/Tiff.m Thu Aug 04 03:12:42 2022 +0200 +++ b/scripts/io/Tiff.m Thu Aug 04 19:29:36 2022 +0200 @@ -1061,3 +1061,110 @@ %! verify_data (filename, data, [10, 10, 3]); %! endfunction %! file_wrapper (@test_fn); + +## test write method tiled BiLevel image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16)); +%! data = logical (repmat ([1,0,0,0,1,0,1,1,1,0], [40, 4])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method tiled grayscale image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 16)); +%! data = uint16 (reshape (1:1600, [40, 40])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method tiled RGB image chunky +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 16, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, +%! "PlanarConfiguration", 1)); +%! data = uint16 (reshape (1:4800, [40, 40, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method tiled RGB image separate +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 16, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, +%! "PlanarConfiguration", 2)); +%! data = uint16 (reshape (1:4800, [40, 40, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method 32-bit tiled image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 32, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, +%! "PlanarConfiguration", 1)); +%! data = uint32 (reshape (1:4800, [40, 40, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method single-precision tiled image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 32, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, +%! "PlanarConfiguration", 1, "SampleFormat", 3)); +%! data = single (reshape (1:4800, [40, 40, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40, 3]); +%! endfunction +%! file_wrapper (@test_fn); + +## test write method double-precision tiled image +%!testif HAVE_TIFF +%! function test_fn (filename) +%! img = Tiff (filename, "w"); +%! setTag(img, struct ("ImageLength", 40, "ImageWidth", 40, +%! "TileWidth", 16, "TileLength", 16, +%! "BitsPerSample", 64, "SamplesPerPixel", 3, +%! "PhotometricInterpretation", 2, +%! "PlanarConfiguration", 1, "SampleFormat", 3)); +%! data = double (reshape (1:4800, [40, 40, 3])); +%! write (img, data); +%! img.close(); +%! verify_data (filename, data, [40, 40, 3]); +%! endfunction +%! file_wrapper (@test_fn);