# HG changeset patch # User magedrifaat # Date 1657282015 -7200 # Node ID 5d79d99c96b96523cbafe1f558c29d85babda8e2 # Parent 2daeeff339802c374841d4b738aa1d3dbc78a8ab Tiff read: Added support for bi-level and 4-bit-grayscale images * __tiff__.cc (F__tiff_read__): added the necessary logic for handling bit depths that are less than one byte in width (1 or 4 bits). diff -r 2daeeff33980 -r 5d79d99c96b9 libinterp/dldfcn/__tiff__.cc --- a/libinterp/dldfcn/__tiff__.cc Thu Jul 07 01:54:20 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Fri Jul 08 14:06:55 2022 +0200 @@ -596,12 +596,12 @@ // TODO(maged): replace malloc with a suitable C++ structure void ***image = (void ***)malloc (sizeof(void ***) * height); uint32_t pixel_size = samples_per_pixel * (bits_per_sample / 8); - uint32_t row_size = width * pixel_size; for (uint32_t row = 0; row < height; row++) { image[row] = (void **)malloc (sizeof(void **) * width); for (uint32_t column = 0; column < width; column++) - image[row][column] = malloc (pixel_size); + // Allocate at least one byte per pixel (For BitsPerSample < 8) + image[row][column] = malloc (pixel_size > 0? pixel_size: 1); } if (is_tiled) @@ -616,23 +616,61 @@ error ("Failed to allocate buffer for strip data"); uint32_t row_index = 0; + uint32_t row_size_in_bits = width * samples_per_pixel + * bits_per_sample; + // According to the Tiff format specification, the row size is + // padded at least up to the next byte, so we add padding to + // complete the byte + row_size_in_bits += (8 - row_size_in_bits % 8) % 8; for (uint32_t strip = 0; strip < strip_count; strip++) { - uint32_t strip_bytes; - if ((strip_bytes = TIFFReadEncodedStrip (tif, strip, buf, -1)) == -1) + uint32_t strip_bytes = TIFFReadEncodedStrip (tif, strip, buf, -1); + if (strip_bytes == -1) error ("Failed to read strip data"); if (planar_configuration == PLANARCONFIG_CONTIG) { - uint32_t rows_in_strip = strip_bytes / row_size; + uint32_t rows_in_strip = strip_bytes * 8 / row_size_in_bits; for (uint32_t row_subindex = 0; row_subindex < rows_in_strip; row_subindex++) { for (uint32_t column = 0; column < width; column++) - memcpy (image[row_index + row_subindex][column], - buf + row_size * row_subindex - + column * pixel_size, pixel_size); + { + uint32_t row_offset = row_size_in_bits / 8 + * row_subindex; + // TODO(maged): support arbitrary BitsPerSample + // for palette images + if (bits_per_sample >= 8 && bits_per_sample % 8 == 0) + { + memcpy (image[row_index + row_subindex][column], + buf + row_offset + column * pixel_size, + pixel_size); + } + else if (bits_per_sample == 4 + && samples_per_pixel == 1) + { + // TODO(maged): Check FillOrder for completeness + uint8_t byte + = ((uint8_t *)buf)[row_offset + column / 2]; + // Extract the needed nibble from the byte + byte = (column % 2 == 0? byte >> 4: byte) & 0x0F; + uint8_t ***u8_img = (uint8_t ***)image; + u8_img[row_index + row_subindex][column][0] = byte; + } + else if (bits_per_sample == 1 + && samples_per_pixel == 1) + { + uint8_t byte + = ((uint8_t *)buf)[row_offset + column / 8]; + // Extract the needed bit from the byte + uint8_t bit = (byte >> (7 - column % 8)) & 0x01; + uint8_t ***u8_img = (uint8_t ***)image; + u8_img[row_index + row_subindex][column][0] = bit; + } + else + error ("Unsupported bit depth"); + } } row_index += rows_in_strip; } @@ -647,7 +685,6 @@ // TODO(maged): what about palette images? are they handled internally? switch (bits_per_sample) { - // TODO(maged): this is probably incorrect as bilevel has no BitsPerSample case 1: { boolNDArray arr(arr_dims); @@ -659,7 +696,6 @@ retval(0) = arr; break; } - // TODO(maged): bits_per_sample of 4 will probably require more logic case 4: case 8: {