# HG changeset patch # User magedrifaat # Date 1657991109 -7200 # Node ID 5b3465a9c34085c50bd9f69c3bf68cf982ee40f7 # Parent 9dead1249449e5ca420e42066a555040490ee9a1 Tiff read: support for reading image arranged in planes (RRRGGGBBB) * __tiff__.cc (read_stripped_image): Added support for reading stripped images with PlanarConfiguration=Separate (RRRGGGBBB) as opposed to (RGBRGBRGB). diff -r 9dead1249449 -r 5b3465a9c340 libinterp/dldfcn/__tiff__.cc --- a/libinterp/dldfcn/__tiff__.cc Sat Jul 16 17:29:14 2022 +0200 +++ b/libinterp/dldfcn/__tiff__.cc Sat Jul 16 19:05:09 2022 +0200 @@ -16,7 +16,7 @@ # include #endif -// TODO(maged): Tidy up the formatting to be consistant with octave +// TODO(maged): Fix warnings namespace octve { @@ -51,77 +51,93 @@ uint32_t row_index = 0; uint32_t row_size_in_bits = image_data->width - * image_data->samples_per_pixel * image_data->bits_per_sample; + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + row_size_in_bits *= image_data->samples_per_pixel; // 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++) { + // Can't rely on StripByteCounts because in compressed images + // the byte count reflect the actual number of bytes stored + // in the file not the size of the uncompressed strip uint32_t strip_bytes = TIFFReadEncodedStrip (tif, strip, buf, -1); if (strip_bytes == -1) error ("Failed to read strip data"); - if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + uint32_t rows_in_strip = strip_bytes * 8 / row_size_in_bits; + uint32_t plane_size = image_data->width * image_data->height; + for (uint32_t row_subindex = 0; + row_subindex < rows_in_strip; + row_subindex++) { - 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 < image_data->width; + column++) { - for (uint32_t column = 0; - column < image_data->width; - column++) + uint32_t row_offset = row_size_in_bits / 8 + * row_subindex; + // TODO(maged): support arbitrary BitsPerSample? + if (image_data->bits_per_sample >= 8 + && image_data->bits_per_sample % 8 == 0) { - uint32_t row_offset = row_size_in_bits / 8 - * row_subindex; - // TODO(maged): support arbitrary BitsPerSample? - if (image_data->bits_per_sample >= 8 - && image_data->bits_per_sample % 8 == 0) + // TODO(maged): clean up the math for both cases + if (image_data->planar_configuration == PLANARCONFIG_CONTIG) + for (uint16_t sample = 0; + sample < image_data->samples_per_pixel; sample++) + // The memory organization of fvec is inverted from + // what would be expected for a normal C-like array. + // It is treated as samples * columns * rows as + // opposed to rows * columns * samples. + img_fvec[sample * plane_size + + column * image_data->height + + row_index + row_subindex] + = ((P *)buf)[row_subindex * image_data->width + * image_data->samples_per_pixel + + column * image_data->samples_per_pixel + + sample]; + else { - // TODO(maged): copy entire strip at once? - for (uint16_t sample = 0; - sample < image_data->samples_per_pixel; sample++) - // The memory organization of fvec is inverted from - // what would be expected for a normal C-like array. - // It is treated as samples * columns * rows as - // opposed to rows * columns * samples. - img_fvec[sample * image_data->width * image_data->height - + column * image_data->height - + row_index + row_subindex] - = ((P *)buf)[row_subindex * image_data->width * image_data->samples_per_pixel - + column * image_data->samples_per_pixel + sample]; + uint16_t channel_no = strip + * image_data->samples_per_pixel + / strip_count; + uint16_t corrected_row = (row_index + row_subindex) + % image_data->height; + img_fvec[channel_no * plane_size + + column * image_data->height + + corrected_row] + = ((P *)buf)[row_subindex * image_data->width + + column]; } - else if (image_data->bits_per_sample == 4 - && image_data->samples_per_pixel == 1) - { - // TODO(maged): Check FillOrder for completeness - uint8_t nibble - = ((uint8_t *)buf)[row_offset + column / 2]; - // Extract the needed nibble from the byte - nibble = (column % 2 == 0? nibble >> 4: nibble) & 0x0F; - img_fvec[(row_index + row_subindex) - + column * image_data->height] = nibble; - } - else if (image_data->bits_per_sample == 1 - && image_data->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; - img_fvec[(row_index + row_subindex) - + column * image_data->height] = bit; - } - else - error ("Unsupported bit depth"); + } + else if (image_data->bits_per_sample == 4 + && image_data->samples_per_pixel == 1) + { + // TODO(maged): Check FillOrder for completeness + uint8_t nibble + = ((uint8_t *)buf)[row_offset + column / 2]; + // Extract the needed nibble from the byte + nibble = (column % 2 == 0? nibble >> 4: nibble) & 0x0F; + img_fvec[(row_index + row_subindex) + + column * image_data->height] = nibble; } + else if (image_data->bits_per_sample == 1 + && image_data->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; + img_fvec[(row_index + row_subindex) + + column * image_data->height] = bit; + } + else + error ("Unsupported bit depth"); } - row_index += rows_in_strip; } - else - error ("Images with multiple planes are not implemented yet"); + row_index += rows_in_strip; } _TIFFfree (buf); @@ -550,6 +566,7 @@ case TIFFTAG_DOTRANGE: case TIFFTAG_YCBCRSUBSAMPLING: { + // TODO(maged): fix bug where only first one is returned uint16_t tag_part1, tag_part2; validate_tiff_get_field (TIFFGetField (tif, tag_id, &tag_part1, &tag_part2));