From a37785ae56bd145630cbfbbdcbb4bc465381d9b4 Mon Sep 17 00:00:00 2001 From: Brad Hards Date: Tue, 12 Dec 2023 16:03:56 +1100 Subject: [PATCH 1/2] uncompressed: split up uncompressed implementation This moves the enumerations into a shared header file. The sampling type enumeration and interleave type enumeration are renamed to be sampling mode and enumeration mode to match the changes in the FDIS. Documentation is added (although its not public API). The cmpd and uncC box definitions are split off from the codec, to keep file sizes reasonable. --- libheif/CMakeLists.txt | 2 + libheif/box.cc | 2 +- libheif/uncompressed.h | 285 ++++++++++++++++++++++++++ libheif/uncompressed_box.cc | 316 +++++++++++++++++++++++++++++ libheif/uncompressed_box.h | 221 +++++++++++++++++++++ libheif/uncompressed_image.cc | 364 ++-------------------------------- libheif/uncompressed_image.h | 187 ----------------- tests/CMakeLists.txt | 1 + tests/uncompressed_box.cc | 130 ++++++++++++ 9 files changed, 974 insertions(+), 534 deletions(-) create mode 100644 libheif/uncompressed.h create mode 100644 libheif/uncompressed_box.cc create mode 100644 libheif/uncompressed_box.h create mode 100644 tests/uncompressed_box.cc diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt index fee6b5b83c..818a37b5ff 100644 --- a/libheif/CMakeLists.txt +++ b/libheif/CMakeLists.txt @@ -151,6 +151,8 @@ endif () if (WITH_UNCOMPRESSED_CODEC) target_compile_definitions(heif PUBLIC WITH_UNCOMPRESSED_CODEC=1) target_sources(heif PRIVATE + uncompressed_box.h + uncompressed_box.cc uncompressed_image.h uncompressed_image.cc) endif () diff --git a/libheif/box.cc b/libheif/box.cc index d0dda4a7ee..db15dd9b82 100644 --- a/libheif/box.cc +++ b/libheif/box.cc @@ -39,7 +39,7 @@ #include #if WITH_UNCOMPRESSED_CODEC -#include "uncompressed_image.h" +#include "uncompressed_box.h" #endif diff --git a/libheif/uncompressed.h b/libheif/uncompressed.h new file mode 100644 index 0000000000..c8e60f5a93 --- /dev/null +++ b/libheif/uncompressed.h @@ -0,0 +1,285 @@ +/* + * HEIF codec. + * Copyright (c) 2023 Dirk Farin + * + * This file is part of libheif. + * + * libheif is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libheif is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libheif. If not, see . + */ + + +#ifndef LIBHEIF_UNCOMPRESSED_H +#define LIBHEIF_UNCOMPRESSED_H + +#include + +/** + * Component type. + * + * See ISO/IEC 23001-17 Table. +*/ +enum heif_uncompressed_component_type +{ + /** + * Monochrome component. + */ + component_type_monochrome = 0, + + /** + * Luma component (Y). + */ + component_type_Y = 1, + + /** + * Chroma component (Cb / U). + */ + component_type_Cb = 2, + + /** + * Chroma component (Cr / V). + */ + component_type_Cr = 3, + + /** + * Red component (R). + */ + component_type_red = 4, + + /** + * Green component (G). + */ + component_type_green = 5, + + /** + * Blue component (B). + */ + component_type_blue = 6, + + /** + * Alpha / transparency component (A). + */ + component_type_alpha = 7, + + /** + * Depth component (D). + */ + component_type_depth = 8, + + /** + * Disparity component (Disp). + */ + component_type_disparity = 9, + + /** + * Palette component (P). + * + * The {@code component_format} value for this component shall be 0. + */ + component_type_palette = 10, + + /** + * Filter Array (FA) component such as Bayer, RGBW, etc. + */ + component_type_filter_array = 11, + + /** + * Padded component (unused bits/bytes). + */ + component_type_padded = 12, + + /** + * Cyan component (C). + */ + component_type_cyan = 13, + + /** + * Magenta component (M). + */ + component_type_magenta = 14, + + /** + * Yellow component (Y). + */ + component_type_yellow = 15, + + /** + * Key (black) component (K). + */ + component_type_key_black = 16, + + /** + * Maximum valid component type value. + */ + component_type_max_valid = component_type_key_black +}; + +/** + * HEIF uncompressed component format. + * + * The binary representation of a component is determined by the + * {@code component_bit_depth} and the component format. + * + * See ISO/IEC 23001-17 Table 2. + */ +enum heif_uncompressed_component_format +{ + /** + * Unsigned integer. + * + * The component value is an unsigned integer. + */ + component_format_unsigned = 0, + + /** + * Floating point value. + * + * The component value is an IEEE 754 binary float. + * Valid bit depths for this format are: + *
    + *
  • 16 (half precision) + *
  • 32 (single precision) + *
  • 64 (double precision) + *
  • 128 (quadruple precision) + *
  • 256 (octuple precision) + *
+ */ + component_format_float = 1, + + /** + * Complex value. + * + * The component value is two IEEE 754 binary float numbers + * where the first part is the real part of the value and + * the second part is the imaginary part of the value. + * + * Each part has the same number of bits, which is half + * the component bit depth value. Valid bit depths for this + * format are: + *
    + *
  • 32 - each part is 16 bits (half precision) + *
  • 64 - each part is 32 bits (single precision) + *
  • 128 - each part is 64 bits (double precision) + *
  • 256 - each part is 128 bits (quadruple precision) + *
+ */ + component_format_complex = 2, + + /** + * Maximum valid component format identifier. + */ + component_format_max_valid = component_format_complex +}; + + +/** + * HEIF uncompressed sampling mode. + * + * All components in a frame use the same dimensions, or use pre-defined + * sampling modes. This is only valid for YCbCr formats. + * + * See ISO/IEC 23001-17 Table 3. + */ +enum heif_uncompressed_sampling_mode +{ + /** + * No subsampling. + */ + sampling_mode_no_subsampling = 0, + + /** + * YCbCr 4:2:2 subsampling. + * + * Y dimensions are the same as the dimensions of the frame. + * Cb (U) and Cr (V) have the same height as the frame, but only have + * half the width. + */ + sampling_mode_422 = 1, + + /** + * YCbCr 4:2:0 subsampling. + * + * Y dimensions are the same as the dimensions of the frame. + * Cb (U) and Cr (V) have the half the height and half the width of + * the frame. + */ + sampling_mode_420 = 2, + + /** + * YCbCr 4:1:1 subsampling. + * + * Y dimensions are the same as the dimensions of the frame. + * Cb (U) and Cr (V) have the same height as the frame, but only have + * one quarter the width. + */ + sampling_mode_411 = 3, + + /** + * Maximum valid sampling mode identifier. + */ + sampling_type_max_valid = sampling_mode_411 +}; + + +/** + * HEIF uncompressed interleaving mode. + * + * See ISO/IEC 23001-17 Table 4. + */ +enum heif_uncompressed_interleave_mode +{ + /** + * Component interleaving. + */ + interleave_mode_component = 0, + + /** + * Pixel interleaving. + */ + interleave_mode_pixel = 1, + + /** + * Mixed interleaving. + * + * This is associated with YCbCr images, with subsampling + * and "semi-planar" interleave. + */ + interleave_mode_mixed = 2, + + /** + * Row interleaving. + */ + interleave_mode_row = 3, + + /** + * Tile-component interleaving. + */ + interleave_mode_tile_component = 4, + + /** + * Multi-Y pixel interleaving. + * + * This is only valid with 4:2:2 and 4:1:1 subsampling. + */ + interleave_mode_multi_y = 5, + + /** + * Maximum valid interleave mode identifier. + */ + interleave_mode_max_valid = interleave_mode_multi_y +}; + + + + +#endif //LIBHEIF_UNCOMPRESSED_H diff --git a/libheif/uncompressed_box.cc b/libheif/uncompressed_box.cc new file mode 100644 index 0000000000..afd25e027a --- /dev/null +++ b/libheif/uncompressed_box.cc @@ -0,0 +1,316 @@ +/* + * HEIF codec. + * Copyright (c) 2023 Dirk Farin + * + * This file is part of libheif. + * + * libheif is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libheif is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libheif. If not, see . + */ + + +#include +#include +#include +#include +#include +#include + +#include "libheif/heif.h" +#include "uncompressed.h" +#include "uncompressed_box.h" + + +bool is_valid_component_format(uint8_t format) +{ + return format <= component_format_max_valid; +} + +static std::map sNames_uncompressed_component_format{ + {component_format_unsigned, "unsigned"}, + {component_format_float, "float"}, + {component_format_complex, "complex"} +}; + + +bool is_valid_interleave_mode(uint8_t sampling) +{ + return sampling <= interleave_mode_max_valid; +} + +static std::map sNames_uncompressed_interleave_mode{ + {interleave_mode_component, "component"}, + {interleave_mode_pixel, "pixel"}, + {interleave_mode_mixed, "mixed"}, + {interleave_mode_row, "row"}, + {interleave_mode_tile_component, "tile-component"}, + {interleave_mode_multi_y, "multi-y"} +}; + + +bool is_valid_sampling_mode(uint8_t sampling) +{ + return sampling <= sampling_type_max_valid; +} + +static std::map sNames_uncompressed_sampling_mode{ + {sampling_mode_no_subsampling, "no subsampling"}, + {sampling_mode_422, "4:2:2"}, + {sampling_mode_420, "4:2:0"}, + {sampling_mode_411, "4:1:1"} +}; + + +bool is_predefined_component_type(uint16_t type) +{ + // check whether the component type can be mapped to heif_uncompressed_component_type and we have a name defined for + // it in sNames_uncompressed_component_type. + return (type >= 0 && type <= component_type_max_valid); +} + +static std::map sNames_uncompressed_component_type{ + {component_type_monochrome, "monochrome"}, + {component_type_Y, "Y"}, + {component_type_Cb, "Cb"}, + {component_type_Cr, "Cr"}, + {component_type_red, "red"}, + {component_type_green, "green"}, + {component_type_blue, "blue"}, + {component_type_alpha, "alpha"}, + {component_type_depth, "depth"}, + {component_type_disparity, "disparity"}, + {component_type_palette, "palette"}, + {component_type_filter_array, "filter-array"}, + {component_type_padded, "padded"}, + {component_type_cyan, "cyan"}, + {component_type_magenta, "magenta"}, + {component_type_yellow, "yellow"}, + {component_type_key_black, "key (black)"} +}; + +template const char* get_name(T val, const std::map& table) +{ + auto iter = table.find(val); + if (iter == table.end()) { + return "unknown"; + } + else { + return iter->second; + } +} + +Error Box_cmpd::parse(BitstreamRange& range) +{ + unsigned int component_count = range.read32(); + + for (unsigned int i = 0; i < component_count && !range.error() && !range.eof(); i++) { + Component component; + component.component_type = range.read16(); + if (component.component_type >= 0x8000) { + component.component_type_uri = range.read_string(); + } + else { + component.component_type_uri = std::string(); + } + m_components.push_back(component); + } + + return range.get_error(); +} + +std::string Box_cmpd::Component::get_component_type_name(uint16_t component_type) +{ + std::stringstream sstr; + + if (is_predefined_component_type(component_type)) { + sstr << get_name(heif_uncompressed_component_type(component_type), sNames_uncompressed_component_type) << "\n"; + } + else { + sstr << "0x" << std::hex << component_type << std::dec << "\n"; + } + + return sstr.str(); +} + + +std::string Box_cmpd::dump(Indent& indent) const +{ + std::ostringstream sstr; + sstr << Box::dump(indent); + + for (const auto& component : m_components) { + sstr << indent << "component_type: " << component.get_component_type_name(); + + if (component.component_type >= 0x8000) { + sstr << indent << "| component_type_uri: " << component.component_type_uri << "\n"; + } + } + + return sstr.str(); +} + +Error Box_cmpd::write(StreamWriter& writer) const +{ + size_t box_start = reserve_box_header_space(writer); + + writer.write32((uint32_t) m_components.size()); + for (const auto& component : m_components) { + writer.write16(component.component_type); + if (component.component_type >= 0x8000) { + writer.write(component.component_type_uri); + } + } + + prepend_header(writer, box_start); + + return Error::Ok; +} + +Error Box_uncC::parse(BitstreamRange& range) +{ + parse_full_box_header(range); + m_profile = range.read32(); + + unsigned int component_count = range.read32(); + + for (unsigned int i = 0; i < component_count && !range.error() && !range.eof(); i++) { + Component component; + component.component_index = range.read16(); + component.component_bit_depth = uint16_t(range.read8() + 1); + component.component_format = range.read8(); + component.component_align_size = range.read8(); + m_components.push_back(component); + + if (!is_valid_component_format(component.component_format)) { + return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid component format"}; + } + } + + m_sampling_type = range.read8(); + if (!is_valid_sampling_mode(m_sampling_type)) { + return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid sampling mode"}; + } + + m_interleave_type = range.read8(); + if (!is_valid_interleave_mode(m_interleave_type)) { + return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid interleave mode"}; + } + + m_block_size = range.read8(); + + uint8_t flags = range.read8(); + m_components_little_endian = !!(flags & 0x80); + m_block_pad_lsb = !!(flags & 0x40); + m_block_little_endian = !!(flags & 0x20); + m_block_reversed = !!(flags & 0x10); + m_pad_unknown = !!(flags & 0x08); + + m_pixel_size = range.read32(); + + m_row_align_size = range.read32(); + + m_tile_align_size = range.read32(); + + m_num_tile_cols = range.read32() + 1; + + m_num_tile_rows = range.read32() + 1; + + return range.get_error(); +} + + +std::string Box_uncC::dump(Indent& indent) const +{ + std::ostringstream sstr; + sstr << Box::dump(indent); + + sstr << indent << "profile: " << m_profile; + if (m_profile != 0) { + sstr << " (" << to_fourcc(m_profile) << ")"; + } + sstr << "\n"; + + for (const auto& component : m_components) { + sstr << indent << "component_index: " << component.component_index << "\n"; + sstr << indent << "component_bit_depth: " << (int) component.component_bit_depth << "\n"; + sstr << indent << "component_format: " << get_name(heif_uncompressed_component_format(component.component_format), sNames_uncompressed_component_format) << "\n"; + sstr << indent << "component_align_size: " << (int) component.component_align_size << "\n"; + } + + sstr << indent << "sampling_type: " << get_name(heif_uncompressed_sampling_mode(m_sampling_type), sNames_uncompressed_sampling_mode) << "\n"; + + sstr << indent << "interleave_type: " << get_name(heif_uncompressed_interleave_mode(m_interleave_type), sNames_uncompressed_interleave_mode) << "\n"; + + sstr << indent << "block_size: " << (int) m_block_size << "\n"; + + sstr << indent << "components_little_endian: " << m_components_little_endian << "\n"; + sstr << indent << "block_pad_lsb: " << m_block_pad_lsb << "\n"; + sstr << indent << "block_little_endian: " << m_block_little_endian << "\n"; + sstr << indent << "block_reversed: " << m_block_reversed << "\n"; + sstr << indent << "pad_unknown: " << m_pad_unknown << "\n"; + + sstr << indent << "pixel_size: " << m_pixel_size << "\n"; + + sstr << indent << "row_align_size: " << m_row_align_size << "\n"; + + sstr << indent << "tile_align_size: " << m_tile_align_size << "\n"; + + sstr << indent << "num_tile_cols: " << m_num_tile_cols << "\n"; + + sstr << indent << "num_tile_rows: " << m_num_tile_rows << "\n"; + + return sstr.str(); +} + +bool Box_uncC::get_headers(std::vector* dest) const +{ + // TODO: component_bit_depth? + return true; +} + +Error Box_uncC::write(StreamWriter& writer) const +{ + size_t box_start = reserve_box_header_space(writer); + + writer.write32(m_profile); + writer.write32((uint32_t) m_components.size()); + for (const auto& component : m_components) { + if (component.component_bit_depth < 1 || component.component_bit_depth > 256) { + return {heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "component bit-depth out of range [1..256]"}; + } + + writer.write16(component.component_index); + writer.write8(uint8_t(component.component_bit_depth - 1)); + writer.write8(component.component_format); + writer.write8(component.component_align_size); + } + writer.write8(m_sampling_type); + writer.write8(m_interleave_type); + writer.write8(m_block_size); + uint8_t flags = 0; + flags |= (m_components_little_endian ? 0x80 : 0); + flags |= (m_block_pad_lsb ? 0x40 : 0); + flags |= (m_block_little_endian ? 0x20 : 0); + flags |= (m_block_reversed ? 0x10 : 0); + flags |= (m_pad_unknown ? 0x08 : 0); + writer.write8(flags); + writer.write32(m_pixel_size); + writer.write32(m_row_align_size); + writer.write32(m_tile_align_size); + writer.write32(m_num_tile_cols - 1); + writer.write32(m_num_tile_rows - 1); + prepend_header(writer, box_start); + + return Error::Ok; +} + diff --git a/libheif/uncompressed_box.h b/libheif/uncompressed_box.h new file mode 100644 index 0000000000..cebf9f5602 --- /dev/null +++ b/libheif/uncompressed_box.h @@ -0,0 +1,221 @@ +/* + * HEIF codec. + * Copyright (c) 2023 Dirk Farin + * + * This file is part of libheif. + * + * libheif is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libheif is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libheif. If not, see . + */ + + +#ifndef LIBHEIF_UNCOMPRESSED_BOX_H +#define LIBHEIF_UNCOMPRESSED_BOX_H + +#include "box.h" +#include "bitstream.h" + +#include +#include +#include +#include + + +/** + * Component definition (cmpd) box. + */ +class Box_cmpd : public Box +{ +public: + Box_cmpd() + { + set_short_type(fourcc("cmpd")); + } + + std::string dump(Indent&) const override; + + Error write(StreamWriter& writer) const override; + + struct Component + { + uint16_t component_type; + std::string component_type_uri; + + std::string get_component_type_name() const { return get_component_type_name(component_type); } + + static std::string get_component_type_name(uint16_t type); + }; + + const std::vector& get_components() const { return m_components; } + + void add_component(const Component& component) + { + m_components.push_back(component); + } + +protected: + Error parse(BitstreamRange& range) override; + + std::vector m_components; +}; + +class Box_uncC : public FullBox +{ +public: + Box_uncC() + { + m_profile = 0; + set_short_type(fourcc("uncC")); + } + + std::string dump(Indent&) const override; + + bool get_headers(std::vector* dest) const; + + Error write(StreamWriter& writer) const override; + + struct Component + { + uint16_t component_index; + uint16_t component_bit_depth; // range [1..256] + uint8_t component_format; + uint8_t component_align_size; + }; + + const std::vector& get_components() const { return m_components; } + + void add_component(Component component) + { + m_components.push_back(component); + } + + uint32_t get_profile() const { return m_profile; } + + void set_profile(const uint32_t profile) + { + m_profile = profile; + } + + uint8_t get_sampling_type() const { return m_sampling_type; } + + void set_sampling_type(const uint8_t sampling_type) + { + m_sampling_type = sampling_type; + } + + uint8_t get_interleave_type() const { return m_interleave_type; } + + void set_interleave_type(const uint8_t interleave_type) + { + m_interleave_type = interleave_type; + } + + uint8_t get_block_size() const { return m_block_size; } + + void set_block_size(const uint8_t block_size) + { + m_block_size = block_size; + } + + bool is_components_little_endian() const { return m_components_little_endian; } + + void set_components_little_endian (const bool components_little_endian) + { + m_components_little_endian = components_little_endian; + } + + bool is_block_pad_lsb() const { return m_block_pad_lsb; } + + void set_block_pad_lsb(const bool block_pad_lsb) + { + m_block_pad_lsb = block_pad_lsb; + } + + bool is_block_little_endian() const { return m_block_little_endian; } + + void set_block_little_endian(const bool block_little_endian) + { + m_block_little_endian = block_little_endian; + } + + bool is_block_reversed() const { return m_block_reversed; } + + void set_block_reversed(const bool block_reversed) + { + m_block_reversed = block_reversed; + } + + bool is_pad_unknown() const { return m_pad_unknown; } + + void set_pad_unknown(const bool pad_unknown) + { + m_pad_unknown = pad_unknown; + } + + uint32_t get_pixel_size() const { return m_pixel_size; } + + void set_pixel_size(const uint32_t pixel_size) + { + m_pixel_size = pixel_size; + } + + uint32_t get_row_align_size() const { return m_row_align_size; } + + void set_row_align_size(const uint32_t row_align_size) + { + m_row_align_size = row_align_size; + } + + uint32_t get_tile_align_size() const { return m_tile_align_size; } + + void set_tile_align_size(const uint32_t tile_align_size) + { + m_tile_align_size = tile_align_size; + } + + uint32_t get_number_of_tile_columns() const { return m_num_tile_cols; } + + void set_number_of_tile_columns(const uint32_t num_tile_cols) + { + m_num_tile_cols = num_tile_cols; + } + + uint32_t get_number_of_tile_rows() const { return m_num_tile_rows; } + + void set_number_of_tile_rows(const uint32_t num_tile_rows) + { + m_num_tile_rows = num_tile_rows; + } + +protected: + Error parse(BitstreamRange& range) override; + + uint32_t m_profile; + + std::vector m_components; + uint8_t m_sampling_type; + uint8_t m_interleave_type; + uint8_t m_block_size; + bool m_components_little_endian; + bool m_block_pad_lsb; + bool m_block_little_endian; + bool m_block_reversed; + bool m_pad_unknown; + uint32_t m_pixel_size; + uint32_t m_row_align_size; + uint32_t m_tile_align_size; + uint32_t m_num_tile_cols; + uint32_t m_num_tile_rows; +}; + +#endif //LIBHEIF_UNCOMPRESSED_BOX_H diff --git a/libheif/uncompressed_image.cc b/libheif/uncompressed_image.cc index c91e5dba4f..f660cfa9db 100644 --- a/libheif/uncompressed_image.cc +++ b/libheif/uncompressed_image.cc @@ -27,339 +27,11 @@ #include #include "libheif/heif.h" +#include "uncompressed.h" +#include "uncompressed_box.h" #include "uncompressed_image.h" -enum heif_uncompressed_component_type -{ - component_type_monochrome = 0, - component_type_Y = 1, - component_type_Cb = 2, - component_type_Cr = 3, - component_type_red = 4, - component_type_green = 5, - component_type_blue = 6, - component_type_alpha = 7, - component_type_depth = 8, - component_type_disparity = 9, - component_type_palette = 10, - component_type_filter_array = 11, - component_type_padded = 12, - component_type_cyan = 13, - component_type_magenta = 14, - component_type_yellow = 15, - component_type_key_black = 16, - component_type_max_valid = component_type_key_black -}; - -bool is_predefined_component_type(uint16_t type) -{ - // check whether the component type can be mapped to heif_uncompressed_component_type and we have a name defined for - // it in sNames_uncompressed_component_type. - return (type >= 0 && type <= 16); -} - -static std::map sNames_uncompressed_component_type{ - {component_type_monochrome, "monochrome"}, - {component_type_Y, "Y"}, - {component_type_Cb, "Cb"}, - {component_type_Cr, "Cr"}, - {component_type_red, "red"}, - {component_type_green, "green"}, - {component_type_blue, "blue"}, - {component_type_alpha, "alpha"}, - {component_type_depth, "depth"}, - {component_type_disparity, "disparity"}, - {component_type_palette, "palette"}, - {component_type_filter_array, "filter-array"}, - {component_type_padded, "padded"}, - {component_type_cyan, "cyan"}, - {component_type_magenta, "magenta"}, - {component_type_yellow, "yellow"}, - {component_type_key_black, "key (black)"} -}; - -enum heif_uncompressed_component_format -{ - component_format_unsigned = 0, - component_format_float = 1, - component_format_complex = 2, -}; - -bool is_valid_component_format(uint8_t format) -{ - return format <= 2; -} - -static std::map sNames_uncompressed_component_format{ - {component_format_unsigned, "unsigned"}, - {component_format_float, "float"}, - {component_format_complex, "complex"} -}; - - -enum heif_uncompressed_sampling_type -{ - sampling_type_no_subsampling = 0, - sampling_type_422 = 1, - sampling_type_420 = 2, - sampling_type_411 = 3 -}; - -bool is_valid_sampling_type(uint8_t sampling) -{ - return sampling <= 3; -} - -static std::map sNames_uncompressed_sampling_type{ - {sampling_type_no_subsampling, "no subsampling"}, - {sampling_type_422, "4:2:2"}, - {sampling_type_420, "4:2:0"}, - {sampling_type_411, "4:1:1"} -}; - -enum heif_uncompressed_interleave_type -{ - interleave_type_component = 0, - interleave_type_pixel = 1, - interleave_type_mixed = 2, - interleave_type_row = 3, - interleave_type_tile_component = 4, - interleave_type_multi_y = 5 -}; - -bool is_valid_interleave_type(uint8_t sampling) -{ - return sampling <= 5; -} - -static std::map sNames_uncompressed_interleave_type{ - {interleave_type_component, "component"}, - {interleave_type_pixel, "pixel"}, - {interleave_type_mixed, "mixed"}, - {interleave_type_row, "row"}, - {interleave_type_tile_component, "tile-component"}, - {interleave_type_multi_y, "multi-y"} -}; - -template const char* get_name(T val, const std::map& table) -{ - auto iter = table.find(val); - if (iter == table.end()) { - return "unknown"; - } - else { - return iter->second; - } -} - - -Error Box_cmpd::parse(BitstreamRange& range) -{ - unsigned int component_count = range.read32(); - - for (unsigned int i = 0; i < component_count && !range.error() && !range.eof(); i++) { - Component component; - component.component_type = range.read16(); - if (component.component_type >= 0x8000) { - component.component_type_uri = range.read_string(); - } - else { - component.component_type_uri = std::string(); - } - m_components.push_back(component); - } - - return range.get_error(); -} - -std::string Box_cmpd::Component::get_component_type_name(uint16_t component_type) -{ - std::stringstream sstr; - - if (is_predefined_component_type(component_type)) { - sstr << get_name(heif_uncompressed_component_type(component_type), sNames_uncompressed_component_type) << "\n"; - } - else { - sstr << "0x" << std::hex << component_type << std::dec << "\n"; - } - - return sstr.str(); -} - - -std::string Box_cmpd::dump(Indent& indent) const -{ - std::ostringstream sstr; - sstr << Box::dump(indent); - - for (const auto& component : m_components) { - sstr << indent << "component_type: " << component.get_component_type_name() << "\n"; - - if (component.component_type >= 0x8000) { - sstr << indent << "| component_type_uri: " << component.component_type_uri << "\n"; - } - } - - return sstr.str(); -} - -Error Box_cmpd::write(StreamWriter& writer) const -{ - size_t box_start = reserve_box_header_space(writer); - - writer.write32((uint32_t) m_components.size()); - for (const auto& component : m_components) { - writer.write16(component.component_type); - if (component.component_type >= 0x8000) { - writer.write(component.component_type_uri); - } - } - - prepend_header(writer, box_start); - - return Error::Ok; -} - -Error Box_uncC::parse(BitstreamRange& range) -{ - parse_full_box_header(range); - m_profile = range.read32(); - - unsigned int component_count = range.read32(); - - for (unsigned int i = 0; i < component_count && !range.error() && !range.eof(); i++) { - Component component; - component.component_index = range.read16(); - component.component_bit_depth = uint16_t(range.read8() + 1); - component.component_format = range.read8(); - component.component_align_size = range.read8(); - m_components.push_back(component); - - if (!is_valid_component_format(component.component_format)) { - return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid component format"}; - } - } - - m_sampling_type = range.read8(); - if (!is_valid_sampling_type(m_sampling_type)) { - return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid sampling type"}; - } - - m_interleave_type = range.read8(); - if (!is_valid_interleave_type(m_interleave_type)) { - return Error{heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "Invalid interleave type"}; - } - - m_block_size = range.read8(); - - uint8_t flags = range.read8(); - m_components_little_endian = !!(flags & 0x80); - m_block_pad_lsb = !!(flags & 0x40); - m_block_little_endian = !!(flags & 0x20); - m_block_reversed = !!(flags & 0x10); - m_pad_unknown = !!(flags & 0x08); - - m_pixel_size = range.read32(); - - m_row_align_size = range.read32(); - - m_tile_align_size = range.read32(); - - m_num_tile_cols = range.read32() + 1; - - m_num_tile_rows = range.read32() + 1; - - return range.get_error(); -} - - -std::string Box_uncC::dump(Indent& indent) const -{ - std::ostringstream sstr; - sstr << Box::dump(indent); - - sstr << indent << "profile: " << m_profile; - if (m_profile != 0) { - sstr << " (" << to_fourcc(m_profile) << ")"; - } - sstr << "\n"; - - for (const auto& component : m_components) { - sstr << indent << "component_index: " << component.component_index << "\n"; - sstr << indent << "component_bit_depth: " << (int) component.component_bit_depth << "\n"; - sstr << indent << "component_format: " << get_name(heif_uncompressed_component_format(component.component_format), sNames_uncompressed_component_format) << "\n"; - sstr << indent << "component_align_size: " << (int) component.component_align_size << "\n"; - } - - sstr << indent << "sampling_type: " << get_name(heif_uncompressed_sampling_type(m_sampling_type), sNames_uncompressed_sampling_type) << "\n"; - - sstr << indent << "interleave_type: " << get_name(heif_uncompressed_interleave_type(m_interleave_type), sNames_uncompressed_interleave_type) << "\n"; - - sstr << indent << "block_size: " << (int) m_block_size << "\n"; - - sstr << indent << "components_little_endian: " << m_components_little_endian << "\n"; - sstr << indent << "block_pad_lsb: " << m_block_pad_lsb << "\n"; - sstr << indent << "block_little_endian: " << m_block_little_endian << "\n"; - sstr << indent << "block_reversed: " << m_block_reversed << "\n"; - sstr << indent << "pad_unknown: " << m_pad_unknown << "\n"; - - sstr << indent << "pixel_size: " << m_pixel_size << "\n"; - - sstr << indent << "row_align_size: " << m_row_align_size << "\n"; - - sstr << indent << "tile_align_size: " << m_tile_align_size << "\n"; - - sstr << indent << "num_tile_cols: " << m_num_tile_cols << "\n"; - - sstr << indent << "num_tile_rows: " << m_num_tile_rows << "\n"; - - return sstr.str(); -} - -bool Box_uncC::get_headers(std::vector* dest) const -{ - // TODO: component_bit_depth? - return true; -} - -Error Box_uncC::write(StreamWriter& writer) const -{ - size_t box_start = reserve_box_header_space(writer); - - writer.write32(m_profile); - writer.write32((uint32_t) m_components.size()); - for (const auto& component : m_components) { - if (component.component_bit_depth < 1 || component.component_bit_depth > 256) { - return {heif_error_Invalid_input, heif_suberror_Invalid_parameter_value, "component bit-depth out of range [1..256]"}; - } - - writer.write16(component.component_index); - writer.write8(uint8_t(component.component_bit_depth - 1)); - writer.write8(component.component_format); - writer.write8(component.component_align_size); - } - writer.write8(m_sampling_type); - writer.write8(m_interleave_type); - writer.write8(m_block_size); - uint8_t flags = 0; - flags |= (m_components_little_endian ? 0x80 : 0); - flags |= (m_block_pad_lsb ? 0x40 : 0); - flags |= (m_block_little_endian ? 0x20 : 0); - flags |= (m_block_reversed ? 0x10 : 0); - flags |= (m_pad_unknown ? 0x08 : 0); - writer.write8(flags); - writer.write32(m_pixel_size); - writer.write32(m_row_align_size); - writer.write32(m_tile_align_size); - writer.write32(m_num_tile_cols - 1); - writer.write32(m_num_tile_rows - 1); - prepend_header(writer, box_start); - - return Error::Ok; -} - - static Error uncompressed_image_type_is_supported(std::shared_ptr& uncC, std::shared_ptr& cmpd) { for (Box_uncC::Component component : uncC->get_components()) { @@ -394,16 +66,16 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc sstr.str()); } } - if (uncC->get_sampling_type() != sampling_type_no_subsampling) { + if (uncC->get_sampling_type() != sampling_mode_no_subsampling) { std::stringstream sstr; sstr << "Uncompressed sampling_type of " << ((int) uncC->get_sampling_type()) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, sstr.str()); } - if ((uncC->get_interleave_type() != interleave_type_component) - && (uncC->get_interleave_type() != interleave_type_pixel) - && (uncC->get_interleave_type() != interleave_type_row) + if ((uncC->get_interleave_type() != interleave_mode_component) + && (uncC->get_interleave_type() != interleave_mode_pixel) + && (uncC->get_interleave_type() != interleave_mode_row) ) { std::stringstream sstr; sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet"; @@ -732,7 +404,7 @@ Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptrget_number_of_tile_rows(); uint32_t tile_width = width / numTileColumns; uint32_t tile_height = height / numTileRows; - if (uncC->get_interleave_type() == interleave_type_component) { + if (uncC->get_interleave_type() == interleave_mode_component) { // Source is planar // TODO: assumes 8 bits long unsigned int content_bytes_per_tile = tile_width * tile_height * get_bytes_per_pixel(uncC); @@ -764,7 +436,7 @@ Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptrget_interleave_type() == interleave_type_pixel) { + else if (uncC->get_interleave_type() == interleave_mode_pixel) { // TODO: we need to be smarter about block size, etc // TODO: we can only do this if we are 8 bits @@ -793,7 +465,7 @@ Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptrget_interleave_type() == interleave_type_row) { + else if (uncC->get_interleave_type() == interleave_mode_row) { // TODO: we need to be smarter about block size, etc // TODO: we can only do this if we are 8 bits @@ -850,15 +522,15 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptradd_component(component2); if (image->get_chroma_format() == heif_chroma_444) { - uncC->set_sampling_type(sampling_type_no_subsampling); + uncC->set_sampling_type(sampling_mode_no_subsampling); } else if (image->get_chroma_format() == heif_chroma_422) { - uncC->set_sampling_type(sampling_type_422); + uncC->set_sampling_type(sampling_mode_422); } else if (image->get_chroma_format() == heif_chroma_420) { - uncC->set_sampling_type(sampling_type_420); + uncC->set_sampling_type(sampling_mode_420); } else { @@ -866,7 +538,7 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptrset_interleave_type(interleave_type_component); + uncC->set_interleave_type(interleave_mode_component); uncC->set_block_size(0); uncC->set_components_little_endian(false); uncC->set_block_pad_lsb(false); @@ -913,7 +585,7 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptrget_chroma_format() == heif_chroma_interleaved_RRGGBBAA_BE) || (image->get_chroma_format() == heif_chroma_interleaved_RRGGBBAA_LE)) { - uncC->set_interleave_type(interleave_type_pixel); + uncC->set_interleave_type(interleave_mode_pixel); int bpp = image->get_bits_per_pixel(heif_channel_interleaved); uint8_t component_align = 1; if (bpp == 8) @@ -939,7 +611,7 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptradd_component(component3); } } else { - uncC->set_interleave_type(interleave_type_component); + uncC->set_interleave_type(interleave_mode_component); int bpp_red = image->get_bits_per_pixel(heif_channel_R); Box_uncC::Component component0 = {0, (uint8_t)(bpp_red), component_format_unsigned, 0}; uncC->add_component(component0); @@ -956,7 +628,7 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptradd_component(component3); } } - uncC->set_sampling_type(sampling_type_no_subsampling); + uncC->set_sampling_type(sampling_mode_no_subsampling); uncC->set_block_size(0); if ((image->get_chroma_format() == heif_chroma_interleaved_RRGGBB_LE) || (image->get_chroma_format() == heif_chroma_interleaved_RRGGBBAA_LE)) @@ -993,8 +665,8 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptradd_component(component1); } - uncC->set_sampling_type(sampling_type_no_subsampling); - uncC->set_interleave_type(interleave_type_component); + uncC->set_sampling_type(sampling_mode_no_subsampling); + uncC->set_interleave_type(interleave_mode_component); uncC->set_block_size(0); uncC->set_components_little_endian(false); uncC->set_block_pad_lsb(false); diff --git a/libheif/uncompressed_image.h b/libheif/uncompressed_image.h index c5df2e9d60..742f9a76f8 100644 --- a/libheif/uncompressed_image.h +++ b/libheif/uncompressed_image.h @@ -22,8 +22,6 @@ #ifndef LIBHEIF_UNCOMPRESSED_IMAGE_H #define LIBHEIF_UNCOMPRESSED_IMAGE_H -#include "box.h" -#include "bitstream.h" #include "pixelimage.h" #include "file.h" #include "context.h" @@ -34,191 +32,6 @@ #include -class Box_cmpd : public Box -{ -public: - Box_cmpd() - { - set_short_type(fourcc("cmpd")); - } - - std::string dump(Indent&) const override; - - Error write(StreamWriter& writer) const override; - - struct Component - { - uint16_t component_type; - std::string component_type_uri; - - std::string get_component_type_name() const { return get_component_type_name(component_type); } - - static std::string get_component_type_name(uint16_t type); - }; - - const std::vector& get_components() const { return m_components; } - - void add_component(Component component) - { - m_components.push_back(component); - } - -protected: - Error parse(BitstreamRange& range) override; - - std::vector m_components; -}; - -class Box_uncC : public FullBox -{ -public: - Box_uncC() - { - m_profile = 0; - set_short_type(fourcc("uncC")); - } - - std::string dump(Indent&) const override; - - bool get_headers(std::vector* dest) const; - - Error write(StreamWriter& writer) const override; - - struct Component - { - uint16_t component_index; - uint16_t component_bit_depth; // range [1..256] - uint8_t component_format; - uint8_t component_align_size; - }; - - const std::vector& get_components() const { return m_components; } - - void add_component(Component component) - { - m_components.push_back(component); - } - - uint32_t get_profile() const { return m_profile; } - - void set_profile(const uint32_t profile) - { - m_profile = profile; - } - - uint8_t get_sampling_type() const { return m_sampling_type; } - - void set_sampling_type(const uint8_t sampling_type) - { - m_sampling_type = sampling_type; - } - - uint8_t get_interleave_type() const { return m_interleave_type; } - - void set_interleave_type(const uint8_t interleave_type) - { - m_interleave_type = interleave_type; - } - - uint8_t get_block_size() const { return m_block_size; } - - void set_block_size(const uint8_t block_size) - { - m_block_size = block_size; - } - - bool is_components_little_endian() const { return m_components_little_endian; } - - void set_components_little_endian (const bool components_little_endian) - { - m_components_little_endian = components_little_endian; - } - - bool is_block_pad_lsb() const { return m_block_pad_lsb; } - - void set_block_pad_lsb(const bool block_pad_lsb) - { - m_block_pad_lsb = block_pad_lsb; - } - - bool is_block_little_endian() const { return m_block_little_endian; } - - void set_block_little_endian(const bool block_little_endian) - { - m_block_little_endian = block_little_endian; - } - - bool is_block_reversed() const { return m_block_reversed; } - - void set_block_reversed(const bool block_reversed) - { - m_block_reversed = block_reversed; - } - - bool is_pad_unknown() const { return m_pad_unknown; } - - void set_pad_unknown(const bool pad_unknown) - { - m_pad_unknown = pad_unknown; - } - - uint32_t get_pixel_size() const { return m_pixel_size; } - - void set_pixel_size(const uint32_t pixel_size) - { - m_pixel_size = pixel_size; - } - - uint32_t get_row_align_size() const { return m_row_align_size; } - - void set_row_align_size(const uint32_t row_align_size) - { - m_row_align_size = row_align_size; - } - - uint32_t get_tile_align_size() const { return m_tile_align_size; } - - void set_tile_align_size(const uint32_t tile_align_size) - { - m_tile_align_size = tile_align_size; - } - - uint32_t get_number_of_tile_columns() const { return m_num_tile_cols; } - - void set_number_of_tile_columns(const uint32_t num_tile_cols) - { - m_num_tile_cols = num_tile_cols; - } - - uint32_t get_number_of_tile_rows() const { return m_num_tile_rows; } - - void set_number_of_tile_rows(const uint32_t num_tile_rows) - { - m_num_tile_rows = num_tile_rows; - } - -protected: - Error parse(BitstreamRange& range) override; - - uint32_t m_profile; - - std::vector m_components; - uint8_t m_sampling_type; - uint8_t m_interleave_type; - uint8_t m_block_size; - bool m_components_little_endian; - bool m_block_pad_lsb; - bool m_block_little_endian; - bool m_block_reversed; - bool m_pad_unknown; - uint32_t m_pixel_size; - uint32_t m_row_align_size; - uint32_t m_tile_align_size; - uint32_t m_num_tile_cols; - uint32_t m_num_tile_rows; -}; - - class UncompressedImageCodec { public: diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index dfd9de207d..848776a3d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,6 +21,7 @@ else() add_libheif_test(conversion) add_libheif_test(jpeg2000) add_libheif_test(avc_box) + add_libheif_test(uncompressed_box) endif() # --- tests that only access the public API diff --git a/tests/uncompressed_box.cc b/tests/uncompressed_box.cc new file mode 100644 index 0000000000..530c2c62f0 --- /dev/null +++ b/tests/uncompressed_box.cc @@ -0,0 +1,130 @@ +/* + libheif uncompressed box unit tests + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/uncompressed_box.h" +#include +#include + + +TEST_CASE( "cmpd" ) +{ + std::shared_ptr cmpd = std::make_shared(); + REQUIRE(cmpd->get_components().size() == 0); + Box_cmpd::Component component; + component.component_type = 1; + cmpd->add_component(component); + REQUIRE(cmpd->get_components().size() == 1); + REQUIRE(cmpd->get_components()[0].component_type == 1); + REQUIRE(cmpd->get_components()[0].component_type_uri == ""); + REQUIRE(cmpd->get_components()[0].get_component_type_name() == "Y\n"); + + StreamWriter writer; + Error err = cmpd->write(writer); + REQUIRE(err.error_code == heif_error_Ok); + const std::vector bytes = writer.get_data(); + std::vector expected = {0x00, 0x00, 0x00, 0x0e, 'c', 'm', 'p', 'd', 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}; + REQUIRE(bytes == expected); + + Indent indent; + std::string dump_output = cmpd->dump(indent); + REQUIRE(dump_output == "Box: cmpd -----\nsize: 0 (header size: 0)\ncomponent_type: Y\n"); +} + +TEST_CASE( "cmpd_multi" ) +{ + std::shared_ptr cmpd = std::make_shared(); + REQUIRE(cmpd->get_components().size() == 0); + + Box_cmpd::Component red_component; + red_component.component_type = 4; + cmpd->add_component(red_component); + + Box_cmpd::Component green_component; + green_component.component_type = 5; + cmpd->add_component(green_component); + + Box_cmpd::Component blue_component; + blue_component.component_type = 6; + cmpd->add_component(blue_component); + REQUIRE(cmpd->get_components().size() == 3); + REQUIRE(cmpd->get_components()[0].component_type == 4); + REQUIRE(cmpd->get_components()[0].component_type_uri == ""); + REQUIRE(cmpd->get_components()[0].get_component_type_name() == "red\n"); + REQUIRE(cmpd->get_components()[1].component_type == 5); + REQUIRE(cmpd->get_components()[1].component_type_uri == ""); + REQUIRE(cmpd->get_components()[1].get_component_type_name() == "green\n"); + REQUIRE(cmpd->get_components()[2].component_type == 6); + REQUIRE(cmpd->get_components()[2].component_type_uri == ""); + REQUIRE(cmpd->get_components()[2].get_component_type_name() == "blue\n"); + + StreamWriter writer; + Error err = cmpd->write(writer); + REQUIRE(err.error_code == heif_error_Ok); + const std::vector bytes = writer.get_data(); + std::vector expected = {0x00, 0x00, 0x00, 0x12, 'c', 'm', 'p', 'd', 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06}; + REQUIRE(bytes == expected); + + Indent indent; + std::string dump_output = cmpd->dump(indent); + REQUIRE(dump_output == "Box: cmpd -----\nsize: 0 (header size: 0)\ncomponent_type: red\ncomponent_type: green\ncomponent_type: blue\n"); +} + +TEST_CASE( "cmpd_custom" ) +{ + std::shared_ptr cmpd = std::make_shared(); + REQUIRE(cmpd->get_components().size() == 0); + + Box_cmpd::Component component0; + component0.component_type = 0x8000; + component0.component_type_uri = "http://example.com/custom_component_uri"; + cmpd->add_component(component0); + + Box_cmpd::Component component1; + component1.component_type = 0x8002; + component1.component_type_uri = "http://example.com/another_custom_component_uri"; + cmpd->add_component(component1); + + REQUIRE(cmpd->get_components().size() == 2); + REQUIRE(cmpd->get_components()[0].component_type == 0x8000); + REQUIRE(cmpd->get_components()[0].component_type_uri == "http://example.com/custom_component_uri"); + REQUIRE(cmpd->get_components()[0].get_component_type_name() == "0x8000\n"); + REQUIRE(cmpd->get_components()[1].component_type == 0x8002); + REQUIRE(cmpd->get_components()[1].component_type_uri == "http://example.com/another_custom_component_uri"); + REQUIRE(cmpd->get_components()[1].get_component_type_name() == "0x8002\n"); + StreamWriter writer; + Error err = cmpd->write(writer); + REQUIRE(err.error_code == heif_error_Ok); + const std::vector bytes = writer.get_data(); + std::vector expected = {0x00, 0x00, 0x00, 0x68, 'c', 'm', 'p', 'd', 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 'h', 't', 't', 'p', ':', '/', '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', '/', 'c', 'u', 's', 't', 'o', 'm', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', '_', 'u', 'r', 'i', 0x00, 0x80, 0x02, 'h', 't', 't', 'p', ':', '/', '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', '/', 'a', 'n', 'o', 't', 'h', 'e', 'r', '_', 'c', 'u', 's', 't', 'o', 'm', '_', 'c', 'o', 'm', 'p', 'o', 'n', 'e', 'n', 't', '_', 'u', 'r', 'i', 0x00}; + REQUIRE(bytes == expected); + + Indent indent; + std::string dump_output = cmpd->dump(indent); + REQUIRE(dump_output == "Box: cmpd -----\nsize: 0 (header size: 0)\ncomponent_type: 0x8000\n| component_type_uri: http://example.com/custom_component_uri\ncomponent_type: 0x8002\n| component_type_uri: http://example.com/another_custom_component_uri\n"); +} + From 52119a3e0f0f314faf79eb573866a03c049dfdd7 Mon Sep 17 00:00:00 2001 From: Brad Hards Date: Fri, 15 Dec 2023 12:21:26 +1100 Subject: [PATCH 2/2] uncompressed: refactor and extend uncompressed decode --- libheif/uncompressed.h | 2 +- libheif/uncompressed_box.cc | 32 +- libheif/uncompressed_box.h | 23 +- libheif/uncompressed_image.cc | 793 +++++++++++----- tests/CMakeLists.txt | 10 +- tests/data/uncompressed_comp_ABGR.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_comp_ABGR_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_comp_B16R16G16.heif | Bin 0 -> 4004 bytes .../uncompressed_comp_B16R16G16_tiled.heif | Bin 0 -> 4004 bytes tests/data/uncompressed_comp_M.heif | Bin 0 -> 990 bytes tests/data/uncompressed_comp_M_tiled.heif | Bin 0 -> 990 bytes .../data/uncompressed_comp_R5G6B5_tiled.heif | Bin 0 -> 1684 bytes .../uncompressed_comp_R7+1G7+1B7+1_tiled.heif | Bin 0 -> 2204 bytes .../uncompressed_comp_R7G7+1B7_tiled.heif | Bin 0 -> 2124 bytes .../data/uncompressed_comp_R7G7B7_tiled.heif | Bin 0 -> 2084 bytes tests/data/uncompressed_comp_RGB.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_comp_RGB_tiled.heif | Bin 0 -> 2204 bytes ...pressed_comp_RGB_tiled_row_tile_align.heif | Bin 0 -> 4252 bytes tests/data/uncompressed_comp_RGxB.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_comp_RGxB_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_comp_VUY_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_comp_VUY_422.heif | Bin 0 -> 1684 bytes .../data/uncompressed_comp_Y16U16V16_420.heif | Bin 0 -> 2324 bytes .../data/uncompressed_comp_Y16U16V16_422.heif | Bin 0 -> 2964 bytes tests/data/uncompressed_comp_YUV_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_comp_YUV_422.heif | Bin 0 -> 1684 bytes tests/data/uncompressed_comp_YUV_tiled.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_comp_YVU_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_comp_YVU_422.heif | Bin 0 -> 1684 bytes tests/data/uncompressed_comp_tile_align.heif | Bin 1064 -> 0 bytes tests/data/uncompressed_mix_VUY_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_mix_VUY_422.heif | Bin 0 -> 1684 bytes .../data/uncompressed_mix_Y16U16V16_420.heif | Bin 0 -> 2324 bytes .../data/uncompressed_mix_Y16U16V16_422.heif | Bin 0 -> 2964 bytes tests/data/uncompressed_mix_YUV_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_mix_YUV_422.heif | Bin 0 -> 1684 bytes tests/data/uncompressed_mix_YVU_420.heif | Bin 0 -> 1364 bytes tests/data/uncompressed_mix_YVU_422.heif | Bin 0 -> 1684 bytes tests/data/uncompressed_pix_ABGR.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_pix_ABGR_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_pix_B16R16G16.heif | Bin 0 -> 4004 bytes .../uncompressed_pix_B16R16G16_tiled.heif | Bin 0 -> 4004 bytes tests/data/uncompressed_pix_M.heif | Bin 0 -> 990 bytes tests/data/uncompressed_pix_M_tiled.heif | Bin 0 -> 990 bytes tests/data/uncompressed_pix_R5G6B5_tiled.heif | Bin 0 -> 1604 bytes .../uncompressed_pix_R7+1G7+1B7+1_tiled.heif | Bin 0 -> 2204 bytes .../data/uncompressed_pix_R7G7+1B7_tiled.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_pix_R7G7B7_tiled.heif | Bin 0 -> 2004 bytes ...pressed_pix_R8G8B8A8_bsz0_psz10_tiled.heif | Bin 0 -> 6411 bytes ...mpressed_pix_R8G8B8A8_bsz0_psz5_tiled.heif | Bin 0 -> 3411 bytes ...ompressed_pix_R8G8B8_bsz0_psz10_tiled.heif | Bin 0 -> 6404 bytes ...compressed_pix_R8G8B8_bsz0_psz5_tiled.heif | Bin 0 -> 3404 bytes tests/data/uncompressed_pix_RGB.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_pix_RGB_tiled.heif | Bin 0 -> 2204 bytes ...mpressed_pix_RGB_tiled_row_tile_align.heif | Bin 0 -> 3068 bytes tests/data/uncompressed_pix_RGxB.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_pix_RGxB_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_pix_YUV_tiled.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_pix_tile_align.heif | Bin 1064 -> 0 bytes tests/data/uncompressed_planar_tiled.heif | Bin 1004 -> 0 bytes tests/data/uncompressed_rgb3.heif | Bin 1004 -> 0 bytes tests/data/uncompressed_row.heif | Bin 1004 -> 0 bytes tests/data/uncompressed_row_ABGR.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_row_ABGR_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_row_B16R16G16.heif | Bin 0 -> 4004 bytes .../uncompressed_row_B16R16G16_tiled.heif | Bin 0 -> 4004 bytes tests/data/uncompressed_row_M.heif | Bin 0 -> 990 bytes tests/data/uncompressed_row_M_tiled.heif | Bin 0 -> 990 bytes tests/data/uncompressed_row_R5G6B5_tiled.heif | Bin 0 -> 1684 bytes .../uncompressed_row_R7+1G7+1B7+1_tiled.heif | Bin 0 -> 2204 bytes .../data/uncompressed_row_R7G7+1B7_tiled.heif | Bin 0 -> 2124 bytes tests/data/uncompressed_row_R7G7B7_tiled.heif | Bin 0 -> 2084 bytes tests/data/uncompressed_row_RGB.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_row_RGB_tiled.heif | Bin 0 -> 2204 bytes ...mpressed_row_RGB_tiled_row_tile_align.heif | Bin 0 -> 4252 bytes tests/data/uncompressed_row_RGxB.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_row_RGxB_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_row_YUV_tiled.heif | Bin 0 -> 2204 bytes tests/data/uncompressed_row_tile_align.heif | Bin 1064 -> 0 bytes tests/data/uncompressed_row_tiled.heif | Bin 1004 -> 0 bytes tests/data/uncompressed_tile_ABGR_tiled.heif | Bin 0 -> 2811 bytes .../uncompressed_tile_B16R16G16_tiled.heif | Bin 0 -> 4004 bytes tests/data/uncompressed_tile_M_tiled.heif | Bin 0 -> 990 bytes .../data/uncompressed_tile_R5G6B5_tiled.heif | Bin 0 -> 1684 bytes .../uncompressed_tile_R7+1G7+1B7+1_tiled.heif | Bin 0 -> 2204 bytes .../uncompressed_tile_R7G7+1B7_tiled.heif | Bin 0 -> 2124 bytes .../data/uncompressed_tile_R7G7B7_tiled.heif | Bin 0 -> 2084 bytes tests/data/uncompressed_tile_RGB_tiled.heif | Bin 0 -> 2204 bytes ...pressed_tile_RGB_tiled_row_tile_align.heif | Bin 0 -> 4844 bytes tests/data/uncompressed_tile_RGxB_tiled.heif | Bin 0 -> 2811 bytes tests/data/uncompressed_tile_YUV_tiled.heif | Bin 0 -> 2204 bytes tests/region.cc | 2 +- tests/test_utils.cc | 19 + tests/test_utils.h | 2 + tests/uncompressed_box.cc | 88 ++ tests/uncompressed_decode.cc | 176 +--- tests/uncompressed_decode.h | 113 +++ tests/uncompressed_decode_mono.cc | 195 ++++ tests/uncompressed_decode_rgb.cc | 407 +++++++++ tests/uncompressed_decode_rgb16.cc | 453 ++++++++++ tests/uncompressed_decode_rgb565.cc | 407 +++++++++ tests/uncompressed_decode_rgb7.cc | 407 +++++++++ tests/uncompressed_decode_ycbcr.cc | 401 +++++++++ tests/uncompressed_decode_ycbcr420.cc | 846 ++++++++++++++++++ tests/uncompressed_decode_ycbcr422.cc | 845 +++++++++++++++++ tests/uncompressed_encode.cc | 1 + 106 files changed, 4869 insertions(+), 353 deletions(-) create mode 100644 tests/data/uncompressed_comp_ABGR.heif create mode 100644 tests/data/uncompressed_comp_ABGR_tiled.heif create mode 100644 tests/data/uncompressed_comp_B16R16G16.heif create mode 100644 tests/data/uncompressed_comp_B16R16G16_tiled.heif create mode 100644 tests/data/uncompressed_comp_M.heif create mode 100644 tests/data/uncompressed_comp_M_tiled.heif create mode 100644 tests/data/uncompressed_comp_R5G6B5_tiled.heif create mode 100644 tests/data/uncompressed_comp_R7+1G7+1B7+1_tiled.heif create mode 100644 tests/data/uncompressed_comp_R7G7+1B7_tiled.heif create mode 100644 tests/data/uncompressed_comp_R7G7B7_tiled.heif create mode 100644 tests/data/uncompressed_comp_RGB.heif create mode 100644 tests/data/uncompressed_comp_RGB_tiled.heif create mode 100644 tests/data/uncompressed_comp_RGB_tiled_row_tile_align.heif create mode 100644 tests/data/uncompressed_comp_RGxB.heif create mode 100644 tests/data/uncompressed_comp_RGxB_tiled.heif create mode 100644 tests/data/uncompressed_comp_VUY_420.heif create mode 100644 tests/data/uncompressed_comp_VUY_422.heif create mode 100644 tests/data/uncompressed_comp_Y16U16V16_420.heif create mode 100644 tests/data/uncompressed_comp_Y16U16V16_422.heif create mode 100644 tests/data/uncompressed_comp_YUV_420.heif create mode 100644 tests/data/uncompressed_comp_YUV_422.heif create mode 100644 tests/data/uncompressed_comp_YUV_tiled.heif create mode 100644 tests/data/uncompressed_comp_YVU_420.heif create mode 100644 tests/data/uncompressed_comp_YVU_422.heif delete mode 100644 tests/data/uncompressed_comp_tile_align.heif create mode 100644 tests/data/uncompressed_mix_VUY_420.heif create mode 100644 tests/data/uncompressed_mix_VUY_422.heif create mode 100644 tests/data/uncompressed_mix_Y16U16V16_420.heif create mode 100644 tests/data/uncompressed_mix_Y16U16V16_422.heif create mode 100644 tests/data/uncompressed_mix_YUV_420.heif create mode 100644 tests/data/uncompressed_mix_YUV_422.heif create mode 100644 tests/data/uncompressed_mix_YVU_420.heif create mode 100644 tests/data/uncompressed_mix_YVU_422.heif create mode 100644 tests/data/uncompressed_pix_ABGR.heif create mode 100644 tests/data/uncompressed_pix_ABGR_tiled.heif create mode 100644 tests/data/uncompressed_pix_B16R16G16.heif create mode 100644 tests/data/uncompressed_pix_B16R16G16_tiled.heif create mode 100644 tests/data/uncompressed_pix_M.heif create mode 100644 tests/data/uncompressed_pix_M_tiled.heif create mode 100644 tests/data/uncompressed_pix_R5G6B5_tiled.heif create mode 100644 tests/data/uncompressed_pix_R7+1G7+1B7+1_tiled.heif create mode 100644 tests/data/uncompressed_pix_R7G7+1B7_tiled.heif create mode 100644 tests/data/uncompressed_pix_R7G7B7_tiled.heif create mode 100644 tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz10_tiled.heif create mode 100644 tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz5_tiled.heif create mode 100644 tests/data/uncompressed_pix_R8G8B8_bsz0_psz10_tiled.heif create mode 100644 tests/data/uncompressed_pix_R8G8B8_bsz0_psz5_tiled.heif create mode 100644 tests/data/uncompressed_pix_RGB.heif create mode 100644 tests/data/uncompressed_pix_RGB_tiled.heif create mode 100644 tests/data/uncompressed_pix_RGB_tiled_row_tile_align.heif create mode 100644 tests/data/uncompressed_pix_RGxB.heif create mode 100644 tests/data/uncompressed_pix_RGxB_tiled.heif create mode 100644 tests/data/uncompressed_pix_YUV_tiled.heif delete mode 100644 tests/data/uncompressed_pix_tile_align.heif delete mode 100644 tests/data/uncompressed_planar_tiled.heif delete mode 100644 tests/data/uncompressed_rgb3.heif delete mode 100644 tests/data/uncompressed_row.heif create mode 100644 tests/data/uncompressed_row_ABGR.heif create mode 100644 tests/data/uncompressed_row_ABGR_tiled.heif create mode 100644 tests/data/uncompressed_row_B16R16G16.heif create mode 100644 tests/data/uncompressed_row_B16R16G16_tiled.heif create mode 100644 tests/data/uncompressed_row_M.heif create mode 100644 tests/data/uncompressed_row_M_tiled.heif create mode 100644 tests/data/uncompressed_row_R5G6B5_tiled.heif create mode 100644 tests/data/uncompressed_row_R7+1G7+1B7+1_tiled.heif create mode 100644 tests/data/uncompressed_row_R7G7+1B7_tiled.heif create mode 100644 tests/data/uncompressed_row_R7G7B7_tiled.heif create mode 100644 tests/data/uncompressed_row_RGB.heif create mode 100644 tests/data/uncompressed_row_RGB_tiled.heif create mode 100644 tests/data/uncompressed_row_RGB_tiled_row_tile_align.heif create mode 100644 tests/data/uncompressed_row_RGxB.heif create mode 100644 tests/data/uncompressed_row_RGxB_tiled.heif create mode 100644 tests/data/uncompressed_row_YUV_tiled.heif delete mode 100644 tests/data/uncompressed_row_tile_align.heif delete mode 100644 tests/data/uncompressed_row_tiled.heif create mode 100644 tests/data/uncompressed_tile_ABGR_tiled.heif create mode 100644 tests/data/uncompressed_tile_B16R16G16_tiled.heif create mode 100644 tests/data/uncompressed_tile_M_tiled.heif create mode 100644 tests/data/uncompressed_tile_R5G6B5_tiled.heif create mode 100644 tests/data/uncompressed_tile_R7+1G7+1B7+1_tiled.heif create mode 100644 tests/data/uncompressed_tile_R7G7+1B7_tiled.heif create mode 100644 tests/data/uncompressed_tile_R7G7B7_tiled.heif create mode 100644 tests/data/uncompressed_tile_RGB_tiled.heif create mode 100644 tests/data/uncompressed_tile_RGB_tiled_row_tile_align.heif create mode 100644 tests/data/uncompressed_tile_RGxB_tiled.heif create mode 100644 tests/data/uncompressed_tile_YUV_tiled.heif create mode 100644 tests/uncompressed_decode.h create mode 100644 tests/uncompressed_decode_mono.cc create mode 100644 tests/uncompressed_decode_rgb.cc create mode 100644 tests/uncompressed_decode_rgb16.cc create mode 100644 tests/uncompressed_decode_rgb565.cc create mode 100644 tests/uncompressed_decode_rgb7.cc create mode 100644 tests/uncompressed_decode_ycbcr.cc create mode 100644 tests/uncompressed_decode_ycbcr420.cc create mode 100644 tests/uncompressed_decode_ycbcr422.cc diff --git a/libheif/uncompressed.h b/libheif/uncompressed.h index c8e60f5a93..a94587691e 100644 --- a/libheif/uncompressed.h +++ b/libheif/uncompressed.h @@ -227,7 +227,7 @@ enum heif_uncompressed_sampling_mode /** * Maximum valid sampling mode identifier. */ - sampling_type_max_valid = sampling_mode_411 + sampling_mode_max_valid = sampling_mode_411 }; diff --git a/libheif/uncompressed_box.cc b/libheif/uncompressed_box.cc index afd25e027a..0020225b54 100644 --- a/libheif/uncompressed_box.cc +++ b/libheif/uncompressed_box.cc @@ -31,6 +31,12 @@ #include "uncompressed_box.h" +/** + * Check for valid component format. + * + * @param format the format value to check + * @return true if the format is a valid value, or false otherwise + */ bool is_valid_component_format(uint8_t format) { return format <= component_format_max_valid; @@ -43,9 +49,15 @@ static std::map sNames_uncompre }; -bool is_valid_interleave_mode(uint8_t sampling) +/** + * Check for valid interleave mode. + * + * @param interleave the interleave value to check + * @return true if the interleave mode is valid, or false otherwise + */ +bool is_valid_interleave_mode(uint8_t interleave) { - return sampling <= interleave_mode_max_valid; + return interleave <= interleave_mode_max_valid; } static std::map sNames_uncompressed_interleave_mode{ @@ -58,9 +70,15 @@ static std::map sNames_uncompres }; +/** + * Check for valid sampling mode. + * + * @param sampling the sampling value to check + * @return true if the sampling mode is valid, or false otherwise + */ bool is_valid_sampling_mode(uint8_t sampling) { - return sampling <= sampling_type_max_valid; + return sampling <= sampling_mode_max_valid; } static std::map sNames_uncompressed_sampling_mode{ @@ -180,6 +198,9 @@ Error Box_uncC::parse(BitstreamRange& range) { parse_full_box_header(range); m_profile = range.read32(); + if (get_version() != 0) { + return Error{heif_error_Invalid_input, heif_suberror_Unsupported_data_version, "Unsupported version (only 0 is currently supported)"}; + } unsigned int component_count = range.read32(); @@ -272,11 +293,6 @@ std::string Box_uncC::dump(Indent& indent) const return sstr.str(); } -bool Box_uncC::get_headers(std::vector* dest) const -{ - // TODO: component_bit_depth? - return true; -} Error Box_uncC::write(StreamWriter& writer) const { diff --git a/libheif/uncompressed_box.h b/libheif/uncompressed_box.h index cebf9f5602..e48000c9a0 100644 --- a/libheif/uncompressed_box.h +++ b/libheif/uncompressed_box.h @@ -24,6 +24,7 @@ #include "box.h" #include "bitstream.h" +#include "libheif/uncompressed.h" #include #include @@ -69,19 +70,33 @@ class Box_cmpd : public Box std::vector m_components; }; +/** + * Uncompressed Frame Configuration Box +*/ class Box_uncC : public FullBox { public: - Box_uncC() + Box_uncC() : + m_profile(0), + m_sampling_type(sampling_mode_no_subsampling), + m_interleave_type(interleave_mode_component), + m_block_size(0), + m_components_little_endian(false), + m_block_pad_lsb(false), + m_block_little_endian(false), + m_block_reversed(false), + m_pad_unknown(false), + m_pixel_size(0), + m_row_align_size(0), + m_tile_align_size(0), + m_num_tile_cols(1), + m_num_tile_rows(1) { - m_profile = 0; set_short_type(fourcc("uncC")); } std::string dump(Indent&) const override; - bool get_headers(std::vector* dest) const; - Error write(StreamWriter& writer) const override; struct Component diff --git a/libheif/uncompressed_image.cc b/libheif/uncompressed_image.cc index f660cfa9db..bab45ae41e 100644 --- a/libheif/uncompressed_image.cc +++ b/libheif/uncompressed_image.cc @@ -25,26 +25,30 @@ #include #include #include +#include +#include "libheif/common_utils.h" +#include "libheif/error.h" #include "libheif/heif.h" #include "uncompressed.h" #include "uncompressed_box.h" #include "uncompressed_image.h" - static Error uncompressed_image_type_is_supported(std::shared_ptr& uncC, std::shared_ptr& cmpd) { for (Box_uncC::Component component : uncC->get_components()) { uint16_t component_index = component.component_index; uint16_t component_type = cmpd->get_components()[component_index].component_type; - if (component_type > 7) { + if ((component_type > 7) && (component_type != component_type_padded)) { + printf("unsupported component type: %d\n", component_type); std::stringstream sstr; sstr << "Uncompressed image with component_type " << ((int) component_type) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, sstr.str()); } - if (component.component_bit_depth > 16) { + if ((component.component_bit_depth > 8) && (component.component_bit_depth != 16)) { + printf("unsupported component bit depth for index: %d, value: %d\n", component_index, component.component_bit_depth); std::stringstream sstr; sstr << "Uncompressed image with component_bit_depth " << ((int) component.component_bit_depth) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, @@ -52,6 +56,7 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc sstr.str()); } if (component.component_format != component_format_unsigned) { + printf("unsupported component format\n"); std::stringstream sstr; sstr << "Uncompressed image with component_format " << ((int) component.component_format) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, @@ -59,6 +64,7 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc sstr.str()); } if (component.component_align_size > 2) { + printf("unsupported component_align_size\n"); std::stringstream sstr; sstr << "Uncompressed image with component_align_size " << ((int) component.component_align_size) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, @@ -66,7 +72,11 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc sstr.str()); } } - if (uncC->get_sampling_type() != sampling_mode_no_subsampling) { + if ((uncC->get_sampling_type() != sampling_mode_no_subsampling) + && (uncC->get_sampling_type() != sampling_mode_422) + && (uncC->get_sampling_type() != sampling_mode_420) + ) { + printf("bad sampling: %d\n", uncC->get_sampling_type()); std::stringstream sstr; sstr << "Uncompressed sampling_type of " << ((int) uncC->get_sampling_type()) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, @@ -75,15 +85,103 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc } if ((uncC->get_interleave_type() != interleave_mode_component) && (uncC->get_interleave_type() != interleave_mode_pixel) + && (uncC->get_interleave_type() != interleave_mode_mixed) && (uncC->get_interleave_type() != interleave_mode_row) - ) { + && (uncC->get_interleave_type() != interleave_mode_tile_component) + ) { + printf("bad interleave: %d\n", uncC->get_interleave_type()); std::stringstream sstr; sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, sstr.str()); } + // Validity checks per ISO/IEC 23001-17 Section 5.2.1.5.3 + if (uncC->get_sampling_type() == sampling_mode_422) { + // We check Y Cb and Cr appear in the chroma test + // TODO: error for tile width not multiple of 2 + if ((uncC->get_interleave_type() != interleave_mode_component) + && (uncC->get_interleave_type() != interleave_mode_mixed) + && (uncC->get_interleave_type() != interleave_mode_multi_y)) + { + std::stringstream sstr; + sstr << "YCbCr 4:2:2 subsampling is only valid with component, mixed or multi-Y interleave mode (ISO/IEC 23001-17 5.2.1.5.3)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + if ((uncC->get_row_align_size() != 0) && (uncC->get_interleave_type() == interleave_mode_component)) { + if (uncC->get_row_align_size() % 2 != 0) { + std::stringstream sstr; + sstr << "YCbCr 4:2:2 subsampling with component interleave requires row_align_size to be a multiple of 2 (ISO/IEC 23001-17 5.2.1.5.3)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + } + if (uncC->get_tile_align_size() != 0) { + if (uncC->get_tile_align_size() % 2 != 0) { + std::stringstream sstr; + sstr << "YCbCr 4:2:2 subsampling requires tile_align_size to be a multiple of 2 (ISO/IEC 23001-17 5.2.1.5.3)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + } + } + // Validity checks per ISO/IEC 23001-17 Section 5.2.1.5.4 + if (uncC->get_sampling_type() == sampling_mode_422) { + // We check Y Cb and Cr appear in the chroma test + // TODO: error for tile width not multiple of 2 + if ((uncC->get_interleave_type() != interleave_mode_component) + && (uncC->get_interleave_type() != interleave_mode_mixed)) + { + std::stringstream sstr; + sstr << "YCbCr 4:2:0 subsampling is only valid with component or mixed interleave mode (ISO/IEC 23001-17 5.2.1.5.4)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + if ((uncC->get_row_align_size() != 0) && (uncC->get_interleave_type() == interleave_mode_component)) { + if (uncC->get_row_align_size() % 2 != 0) { + std::stringstream sstr; + sstr << "YCbCr 4:2:2 subsampling with component interleave requires row_align_size to be a multiple of 2 (ISO/IEC 23001-17 5.2.1.5.4)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + } + if (uncC->get_tile_align_size() != 0) { + if (uncC->get_tile_align_size() % 4 != 0) { + std::stringstream sstr; + sstr << "YCbCr 4:2:2 subsampling requires tile_align_size to be a multiple of 4 (ISO/IEC 23001-17 5.2.1.5.3)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + } + } + if ((uncC->get_interleave_type() == interleave_mode_mixed) && (uncC->get_sampling_type() == sampling_mode_no_subsampling)) + { + std::stringstream sstr; + sstr << "Interleave interleave mode is not valid with subsampling mode (ISO/IEC 23001-17 5.2.1.6.4)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + if ((uncC->get_interleave_type() == interleave_mode_multi_y) + && ((uncC->get_sampling_type() != sampling_mode_422) && (uncC->get_sampling_type() != sampling_mode_411))) + { + std::stringstream sstr; + sstr << "Multi-Y interleave mode is only valid with 4:2:2 and 4:1:1 subsampling modes (ISO/IEC 23001-17 5.2.1.6.7)."; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, + sstr.str()); + } + // TODO: throw error if mixed and Cb and Cr are not adjacent. + if (uncC->get_block_size() != 0) { + printf("unsupported block size\n"); std::stringstream sstr; sstr << "Uncompressed block_size of " << ((int) uncC->get_block_size()) << " is not implemented yet"; return Error(heif_error_Unsupported_feature, @@ -91,37 +189,34 @@ static Error uncompressed_image_type_is_supported(std::shared_ptr& unc sstr.str()); } if (uncC->is_components_little_endian()) { + printf("unsupported components LE\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Uncompressed components_little_endian == 1 is not implemented yet"); } if (uncC->is_block_pad_lsb()) { + printf("unsupported block pad LSB\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Uncompressed block_pad_lsb == 1 is not implemented yet"); } if (uncC->is_block_little_endian()) { + printf("unsupported block LE\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Uncompressed block_little_endian == 1 is not implemented yet"); } if (uncC->is_block_reversed()) { + printf("unsupported block reversed\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Uncompressed block_reversed == 1 is not implemented yet"); } - if (uncC->get_pixel_size() != 0) { - std::stringstream sstr; - sstr << "Uncompressed pixel_size of " << ((int) uncC->get_pixel_size()) << " is not implemented yet"; - return Error(heif_error_Unsupported_feature, - heif_suberror_Unsupported_data_version, - sstr.str()); - } - if (uncC->get_row_align_size() != 0) { + if ((uncC->get_pixel_size() != 0) && ((uncC->get_interleave_type() != interleave_mode_pixel) && (uncC->get_interleave_type() != interleave_mode_multi_y))) { std::stringstream sstr; - sstr << "Uncompressed row_align_size of " << ((int) uncC->get_row_align_size()) << " is not implemented yet"; - return Error(heif_error_Unsupported_feature, - heif_suberror_Unsupported_data_version, + sstr << "Uncompressed pixel_size of " << ((int) uncC->get_pixel_size()) << " is only valid with interleave_type 1 or 5 (ISO/IEC 23001-17 5.2.1.7)"; + return Error(heif_error_Invalid_input, + heif_suberror_Invalid_parameter_value, sstr.str()); } return Error::Ok; @@ -145,7 +240,10 @@ static Error get_heif_chroma_uncompressed(std::shared_ptr& uncC, std:: sstr << "a component_type > " << component_type_max_valid << " is not supported"; return { heif_error_Unsupported_feature, heif_suberror_Invalid_parameter_value, sstr.str()}; } - + if (component_type == component_type_padded) { + // not relevant for determining chroma + continue; + } componentSet |= (1 << component_type); } @@ -156,29 +254,36 @@ static Error get_heif_chroma_uncompressed(std::shared_ptr& uncC, std:: } if (componentSet == ((1 << component_type_Y) | (1 << component_type_Cb) | (1 << component_type_Cr))) { - if (uncC->get_interleave_type() == 0) { - // Planar YCbCr - *out_chroma = heif_chroma_444; - *out_colourspace = heif_colorspace_YCbCr; + switch (uncC->get_sampling_type()) { + case sampling_mode_no_subsampling: + *out_chroma = heif_chroma_444; + break; + case sampling_mode_422: + *out_chroma = heif_chroma_422; + break; + case sampling_mode_420: + *out_chroma = heif_chroma_420; + break; } + *out_colourspace = heif_colorspace_YCbCr; } if (componentSet == ((1 << component_type_monochrome)) || componentSet == ((1 << component_type_monochrome) | (1 << component_type_alpha))) { - if (uncC->get_interleave_type() == 0) { - // Planar mono or planar mono + alpha - *out_chroma = heif_chroma_monochrome; - *out_colourspace = heif_colorspace_monochrome; - } + // mono or mono + alpha input, mono output. + *out_chroma = heif_chroma_monochrome; + *out_colourspace = heif_colorspace_monochrome; } // TODO: more combinations if (*out_chroma == heif_chroma_undefined) { + printf("unknown chroma\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Could not determine chroma"); } else if (*out_colourspace == heif_colorspace_undefined) { + printf("unknown colourspace\n"); return Error(heif_error_Unsupported_feature, heif_suberror_Unsupported_data_version, "Could not determine colourspace"); @@ -234,45 +339,448 @@ int UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci(cons } } -static unsigned int get_bytes_per_pixel(const std::shared_ptr& uncC) +static bool map_uncompressed_component_to_channel(const std::shared_ptr &cmpd, const Box_uncC::Component component, heif_channel *channel) { + uint16_t component_index = component.component_index; + uint16_t component_type = cmpd->get_components()[component_index].component_type; + switch (component_type) { + case component_type_monochrome: + *channel = heif_channel_Y; + return true; + case component_type_Y: + *channel = heif_channel_Y; + return true; + case component_type_Cb: + *channel = heif_channel_Cb; + return true; + case component_type_Cr: + *channel = heif_channel_Cr; + return true; + case component_type_red: + *channel = heif_channel_R; + return true; + case component_type_green: + *channel = heif_channel_G; + return true; + case component_type_blue: + *channel = heif_channel_B; + return true; + case component_type_alpha: + *channel = heif_channel_Alpha; + return true; + case component_type_padded: + return false; + default: + printf("unmapped component_type: %d\n", component_type); + return false; + } +} + +class UncompressedBitReader : public BitReader +{ + public: + UncompressedBitReader(const std::vector& data) : BitReader(data.data(), (int)data.size()) + {} + + void markPixelStart() { + m_pixelStartOffset = get_current_byte_index(); + } + + void markRowStart() { + m_rowStartOffset = get_current_byte_index(); + } + + void markTileStart() { + m_tileStartOffset = get_current_byte_index(); + } + + inline void handlePixelAlignment(uint32_t pixel_size) { + if (pixel_size != 0) { + uint32_t bytes_in_pixel = get_current_byte_index() - m_pixelStartOffset; + uint32_t padding = pixel_size - bytes_in_pixel; + skip_bytes(padding); + } + } + + void handleRowAlignment(uint32_t alignment) { + skip_to_byte_boundary(); + if (alignment != 0) { + uint32_t bytes_in_row = get_current_byte_index() - m_rowStartOffset; + uint32_t residual = bytes_in_row % alignment; + if (residual != 0) { + uint32_t padding = alignment - residual; + skip_bytes(padding); + } + } + } + + void handleTileAlignment(uint32_t alignment) { + if (alignment != 0) { + uint32_t bytes_in_tile = get_current_byte_index() - m_tileStartOffset; + uint32_t residual = bytes_in_tile % alignment; + if (residual != 0) { + uint32_t tile_padding = alignment - residual; + skip_bytes(tile_padding); + } + } + } + + private: + int m_pixelStartOffset; + int m_rowStartOffset; + int m_tileStartOffset; +}; + + +class AbstractDecoder { - unsigned int bytes = 0; - for (Box_uncC::Component component: uncC->get_components()) +public: + virtual Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) = 0; + virtual ~AbstractDecoder() = default; +protected: + AbstractDecoder(uint32_t width, uint32_t height, const std::shared_ptr cmpd, const std::shared_ptr uncC): + m_width(width), + m_height(height), + m_cmpd(std::move(cmpd)), + m_uncC(std::move(uncC)) { - if (component.component_align_size == 0) + m_tile_height = m_height / m_uncC->get_number_of_tile_rows(); + m_tile_width = m_width / m_uncC->get_number_of_tile_columns(); + } + + const uint32_t m_width; + const uint32_t m_height; + const std::shared_ptr m_cmpd; + const std::shared_ptr m_uncC; + // TODO: see if we can make this const + uint32_t m_tile_height; + uint32_t m_tile_width; + + class ChannelListEntry + { + public: + uint32_t get_bytes_per_tile() const { - // TODO: needs more work when we have components with padding - unsigned int component_bytes = (component.component_bit_depth + 7) / 8; - bytes += component_bytes; + return bytes_per_tile_row_src * tile_height; } - else + + inline uint64_t getDestinationRowOffset(uint32_t tile_row, uint32_t tile_y) const { + uint64_t dst_row_number = tile_row * tile_height + tile_y; + return dst_row_number * dst_plane_stride; + } + + heif_channel channel; + uint8_t* dst_plane; + uint8_t* other_chroma_dst_plane; + int dst_plane_stride; + int other_chroma_dst_plane_stride; + uint32_t tile_width; + uint32_t tile_height; + uint32_t bytes_per_component_sample; + uint16_t bits_per_component_sample; + uint8_t component_alignment; + uint32_t bytes_per_tile_row_src; + bool use_channel; + }; + + std::vector channelList; + + void buildChannelList(std::shared_ptr& img) { + for (Box_uncC::Component component : m_uncC->get_components()) { + ChannelListEntry entry = buildChannelListEntry(component, img); + channelList.push_back(entry); + } + } + + protected: + void processComponentSample(UncompressedBitReader &srcBits, ChannelListEntry &entry, uint64_t dst_row_offset, uint32_t tile_column, uint32_t tile_x) { + uint64_t dst_col_number = tile_column * entry.tile_width + tile_x; + uint64_t dst_column_offset = dst_col_number * entry.bytes_per_component_sample; + int val = srcBits.get_bits(entry.bits_per_component_sample); + memcpy(entry.dst_plane + dst_row_offset + dst_column_offset, &val, entry.bytes_per_component_sample); + } + + // Handles the case where a row consists of a single component type + // Not valid for Pixel interleave + // Not valid for the Cb/Cr channels in Mixed Interleave + // Not valid for multi-Y pixel interleave + void processComponentRow(ChannelListEntry &entry, UncompressedBitReader &srcBits, uint64_t dst_row_offset, uint32_t tile_column) { - bytes += component.component_align_size; + for (uint32_t tile_x = 0; tile_x < entry.tile_width; tile_x++) { + if (entry.component_alignment != 0) { + srcBits.skip_to_byte_boundary(); + int numPadBits = (entry.component_alignment * 8) - entry.bits_per_component_sample; + srcBits.skip_bits(numPadBits); + } + processComponentSample(srcBits, entry, dst_row_offset, tile_column, tile_x); + } + srcBits.skip_to_byte_boundary(); } + + private: + ChannelListEntry buildChannelListEntry(Box_uncC::Component component, std::shared_ptr &img) { + ChannelListEntry entry; + entry.use_channel = map_uncompressed_component_to_channel(m_cmpd, component, &(entry.channel)); + entry.dst_plane = img->get_plane(entry.channel, &(entry.dst_plane_stride)); + entry.tile_width = m_tile_width; + entry.tile_height = m_tile_height; + if ((entry.channel == heif_channel_Cb) || (entry.channel == heif_channel_Cr)) { + if (m_uncC->get_sampling_type() == sampling_mode_422) { + entry.tile_width /= 2; + } else if (m_uncC->get_sampling_type() == sampling_mode_420) { + entry.tile_width /= 2; + entry.tile_height /= 2; + } + if (entry.channel == heif_channel_Cb) { + entry.other_chroma_dst_plane = img->get_plane(heif_channel_Cr, &(entry.other_chroma_dst_plane_stride)); + } else if (entry.channel == heif_channel_Cr) { + entry.other_chroma_dst_plane = img->get_plane(heif_channel_Cb, &(entry.other_chroma_dst_plane_stride)); + } + } + entry.bits_per_component_sample = component.component_bit_depth; + entry.component_alignment = component.component_align_size; + entry.bytes_per_component_sample = (component.component_bit_depth + 7) / 8; + entry.bytes_per_tile_row_src = entry.tile_width * entry.bytes_per_component_sample; + return entry; + } +}; + + +class ComponentInterleaveDecoder : public AbstractDecoder +{ +public: + ComponentInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr cmpd, std::shared_ptr uncC): + AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) + {} + + Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) override { + UncompressedBitReader srcBits(uncompressed_data); + + buildChannelList(img); + + for (uint32_t tile_row = 0; tile_row < m_uncC->get_number_of_tile_rows(); tile_row++) { + for (uint32_t tile_column = 0; tile_column < m_uncC->get_number_of_tile_columns(); tile_column++) { + srcBits.markTileStart(); + processTile(srcBits, tile_row, tile_column); + srcBits.handleTileAlignment(m_uncC->get_tile_align_size()); + } + } + + return Error::Ok; } - return bytes; -} -static long unsigned int get_tile_base_offset(uint32_t col, uint32_t row, const std::shared_ptr& uncC, const std::vector& channels, uint32_t width, uint32_t height) + void processTile(UncompressedBitReader &srcBits, uint32_t tile_row, uint32_t tile_column) { + for (ChannelListEntry &entry : channelList) { + for (uint32_t tile_y = 0; tile_y < entry.tile_height; tile_y++) { + srcBits.markRowStart(); + if (entry.use_channel) { + uint64_t dst_row_offset = entry.getDestinationRowOffset(tile_row, tile_y); + processComponentRow(entry, srcBits, dst_row_offset, tile_column); + } else { + srcBits.skip_bytes(entry.bytes_per_tile_row_src); + } + srcBits.handleRowAlignment(m_uncC->get_row_align_size()); + } + } + } +}; + +class PixelInterleaveDecoder : public AbstractDecoder { - uint32_t numTileColumns = uncC->get_number_of_tile_columns(); - uint32_t numTileRows = uncC->get_number_of_tile_rows(); - uint32_t tile_width = width / numTileColumns; - uint32_t tile_height = height / numTileRows; - long unsigned int content_bytes_per_tile = tile_width * tile_height * get_bytes_per_pixel(uncC); - uint32_t tile_align_size = uncC->get_tile_align_size(); - long unsigned int tile_padding = 0; - if (tile_align_size > 0) { - tile_padding = tile_align_size - (content_bytes_per_tile % tile_align_size); - } - long unsigned int bytes_per_tile = content_bytes_per_tile + tile_padding; - uint32_t tile_idx_y = row / tile_height; - uint32_t tile_idx_x = col / tile_width; - uint32_t tile_idx = tile_idx_y * numTileColumns + tile_idx_x; - long unsigned int tile_base_offset = tile_idx * bytes_per_tile; - return tile_base_offset; -} +public: + PixelInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr cmpd, std::shared_ptr uncC): + AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) + {} + + Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) override { + UncompressedBitReader srcBits(uncompressed_data); + + buildChannelList(img); + + for (uint32_t tile_row = 0; tile_row < m_uncC->get_number_of_tile_rows(); tile_row++) { + for (uint32_t tile_column = 0; tile_column < m_uncC->get_number_of_tile_columns(); tile_column++) { + srcBits.markTileStart(); + processTile(srcBits, tile_row, tile_column); + srcBits.handleTileAlignment(m_uncC->get_tile_align_size()); + } + } + + return Error::Ok; + } + + void processTile(UncompressedBitReader &srcBits, uint32_t tile_row, uint32_t tile_column) { + for (uint32_t tile_y = 0; tile_y < m_tile_height; tile_y++) { + srcBits.markRowStart(); + for (uint32_t tile_x = 0; tile_x < m_tile_width; tile_x++) { + srcBits.markPixelStart(); + for (ChannelListEntry &entry : channelList) { + if (entry.use_channel) { + uint64_t dst_row_offset = entry.getDestinationRowOffset(tile_row, tile_y); + if (entry.component_alignment != 0) { + srcBits.skip_to_byte_boundary(); + int numPadBits = (entry.component_alignment * 8) - entry.bits_per_component_sample; + srcBits.skip_bits(numPadBits); + } + processComponentSample(srcBits, entry, dst_row_offset, tile_column, tile_x); + } else { + srcBits.skip_bytes(entry.bytes_per_component_sample); + } + } + srcBits.handlePixelAlignment(m_uncC->get_pixel_size()); + } + srcBits.handleRowAlignment(m_uncC->get_row_align_size()); + } + } +}; +class MixedInterleaveDecoder : public AbstractDecoder +{ +public: + MixedInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr cmpd, std::shared_ptr uncC): + AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) + {} + + Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) override { + UncompressedBitReader srcBits(uncompressed_data); + + buildChannelList(img); + + for (uint32_t tile_row = 0; tile_row < m_uncC->get_number_of_tile_rows(); tile_row++) { + for (uint32_t tile_column = 0; tile_column < m_uncC->get_number_of_tile_columns(); tile_column++) { + srcBits.markTileStart(); + processTile(srcBits, tile_row, tile_column); + srcBits.handleTileAlignment(m_uncC->get_tile_align_size()); + } + } + + return Error::Ok; + } + + void processTile(UncompressedBitReader &srcBits, uint32_t tile_row, uint32_t tile_column) { + bool haveProcessedChromaForThisTile = false; + for (ChannelListEntry &entry : channelList) { + if (entry.use_channel) { + if ((entry.channel == heif_channel_Cb) || (entry.channel == heif_channel_Cr)) { + if (!haveProcessedChromaForThisTile) { + for (uint32_t tile_y = 0; tile_y < entry.tile_height; tile_y++) { + // TODO: row padding + uint64_t dst_row_number = tile_row * entry.tile_width + tile_y; + uint64_t dst_row_offset = dst_row_number * entry.dst_plane_stride; + for (uint32_t tile_x = 0; tile_x < entry.tile_width; tile_x++) { + uint64_t dst_column_number = tile_column * entry.tile_width + tile_x; + uint64_t dst_column_offset = dst_column_number * entry.bytes_per_component_sample; + int val = srcBits.get_bits(entry.bytes_per_component_sample * 8); + memcpy(entry.dst_plane + dst_row_offset + dst_column_offset, &val, entry.bytes_per_component_sample); + val = srcBits.get_bits(entry.bytes_per_component_sample * 8); + memcpy(entry.other_chroma_dst_plane + dst_row_offset + dst_column_offset, &val, entry.bytes_per_component_sample); + } + haveProcessedChromaForThisTile = true; + } + } + } else { + for (uint32_t tile_y = 0; tile_y < entry.tile_height; tile_y++) { + uint64_t dst_row_offset = entry.getDestinationRowOffset(tile_row, tile_y); + processComponentRow(entry, srcBits, dst_row_offset, tile_column); + } + } + } else { + // skip over the data we are not using + srcBits.skip_bytes(entry.get_bytes_per_tile()); + continue; + } + } + } +}; + +class RowInterleaveDecoder : public AbstractDecoder +{ +public: + RowInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr cmpd, std::shared_ptr uncC): + AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) + {} + + Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) override { + UncompressedBitReader srcBits(uncompressed_data); + buildChannelList(img); + for (uint32_t tile_row = 0; tile_row < m_uncC->get_number_of_tile_rows(); tile_row++) { + for (uint32_t tile_column = 0; tile_column < m_uncC->get_number_of_tile_columns(); tile_column++) { + srcBits.markTileStart(); + processTile(srcBits, tile_row, tile_column); + srcBits.handleTileAlignment(m_uncC->get_tile_align_size()); + } + } + return Error::Ok; + } + +private: + void processTile(UncompressedBitReader &srcBits, uint32_t tile_row, uint32_t tile_column) { + for (uint32_t tile_y = 0; tile_y < m_tile_height; tile_y++) { + for (ChannelListEntry &entry : channelList) { + srcBits.markRowStart(); + if (entry.use_channel) { + uint64_t dst_row_offset = entry.getDestinationRowOffset(tile_row, tile_y); + processComponentRow(entry, srcBits, dst_row_offset, tile_column); + } else { + srcBits.skip_bytes(entry.bytes_per_tile_row_src); + } + srcBits.handleRowAlignment(m_uncC->get_row_align_size()); + } + } + } +}; + + +class TileComponentInterleaveDecoder : public AbstractDecoder +{ +public: + TileComponentInterleaveDecoder(uint32_t width, uint32_t height, std::shared_ptr cmpd, std::shared_ptr uncC): + AbstractDecoder(width, height, std::move(cmpd), std::move(uncC)) + {} + + Error decode(const std::vector& uncompressed_data, std::shared_ptr& img) override { + UncompressedBitReader srcBits(uncompressed_data); + + buildChannelList(img); + + for (ChannelListEntry &entry : channelList) { + if (!entry.use_channel) { + uint64_t bytes_per_component = entry.get_bytes_per_tile() * m_uncC->get_number_of_tile_columns() * m_uncC->get_number_of_tile_rows(); + srcBits.skip_bytes((int)bytes_per_component); + continue; + } + for (uint32_t tile_row = 0; tile_row < m_uncC->get_number_of_tile_rows(); tile_row++) { + for (uint32_t tile_column = 0; tile_column < m_uncC->get_number_of_tile_columns(); tile_column++) { + srcBits.markTileStart(); + for (uint32_t tile_y = 0; tile_y < entry.tile_height; tile_y++) { + srcBits.markRowStart(); + uint64_t dst_row_offset = entry.getDestinationRowOffset(tile_row, tile_y); + processComponentRow(entry, srcBits, dst_row_offset, tile_column); + srcBits.handleRowAlignment(m_uncC->get_row_align_size()); + } + srcBits.handleTileAlignment(m_uncC->get_tile_align_size()); + } + } + } + + return Error::Ok; + } +}; + +static AbstractDecoder* makeDecoder(uint32_t width, uint32_t height, const std::shared_ptr& cmpd, const std::shared_ptr& uncC) +{ + if (uncC->get_interleave_type() == interleave_mode_component) { + return new ComponentInterleaveDecoder(width, height, cmpd, uncC); + } else if (uncC->get_interleave_type() == interleave_mode_pixel) { + return new PixelInterleaveDecoder(width, height, cmpd, uncC); + } else if (uncC->get_interleave_type() == interleave_mode_mixed) { + return new MixedInterleaveDecoder(width, height, cmpd, uncC); + } else if (uncC->get_interleave_type() == interleave_mode_row) { + return new RowInterleaveDecoder(width, height, cmpd, uncC); + } else if (uncC->get_interleave_type() == interleave_mode_tile_component) { + return new TileComponentInterleaveDecoder(width, height, cmpd, uncC); + } else { + return nullptr; + } +} Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptr& heif_file, heif_item_id ID, @@ -286,6 +794,7 @@ Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptr> item_properties; Error error = heif_file->get_properties(ID, item_properties); if (error) { + printf("failed to get properties\n"); return error; } uint32_t width = 0; @@ -303,7 +812,7 @@ Error UncompressedImageCodec::decode_uncompressed_image(const std::shared_ptrcreate(width, height, colourspace, chroma); - std::vector channels; - std::map channel_to_pixelOffset; - - uint32_t componentOffset = 0; for (Box_uncC::Component component : uncC->get_components()) { - uint16_t component_index = component.component_index; - uint16_t component_type = cmpd->get_components()[component_index].component_type; - if (component_type == component_type_Y || - component_type == component_type_monochrome) { - img->add_plane(heif_channel_Y, width, height, component.component_bit_depth); - channels.push_back(heif_channel_Y); - channel_to_pixelOffset.emplace(heif_channel_Y, componentOffset); - } - else if (component_type == component_type_Cb) { - img->add_plane(heif_channel_Cb, width, height, component.component_bit_depth); - channels.push_back(heif_channel_Cb); - channel_to_pixelOffset.emplace(heif_channel_Cb, componentOffset); - } - else if (component_type == component_type_Cr) { - img->add_plane(heif_channel_Cr, width, height, component.component_bit_depth); - channels.push_back(heif_channel_Cr); - channel_to_pixelOffset.emplace(heif_channel_Cr, componentOffset); - } - else if (component_type == component_type_red) { - img->add_plane(heif_channel_R, width, height, component.component_bit_depth); - channels.push_back(heif_channel_R); - channel_to_pixelOffset.emplace(heif_channel_R, componentOffset); - } - else if (component_type == component_type_green) { - img->add_plane(heif_channel_G, width, height, component.component_bit_depth); - channels.push_back(heif_channel_G); - channel_to_pixelOffset.emplace(heif_channel_G, componentOffset); - } - else if (component_type == component_type_blue) { - img->add_plane(heif_channel_B, width, height, component.component_bit_depth); - channels.push_back(heif_channel_B); - channel_to_pixelOffset.emplace(heif_channel_B, componentOffset); - } - else if (component_type == component_type_alpha) { - img->add_plane(heif_channel_Alpha, width, height, component.component_bit_depth); - channels.push_back(heif_channel_Alpha); - channel_to_pixelOffset.emplace(heif_channel_Alpha, componentOffset); - } - - // TODO: other component types - componentOffset++; - } - - // TODO: properly interpret uncompressed_data per uncC config, subsampling etc. - uint32_t bytes_per_channel = width * height; - uint32_t numTileColumns = uncC->get_number_of_tile_columns(); - uint32_t numTileRows = uncC->get_number_of_tile_rows(); - uint32_t tile_width = width / numTileColumns; - uint32_t tile_height = height / numTileRows; - if (uncC->get_interleave_type() == interleave_mode_component) { - // Source is planar - // TODO: assumes 8 bits - long unsigned int content_bytes_per_tile = tile_width * tile_height * get_bytes_per_pixel(uncC); - uint32_t tile_align_size = uncC->get_tile_align_size(); - long unsigned int tile_padding = 0; - if (tile_align_size > 0) { - tile_padding = tile_align_size - (content_bytes_per_tile % tile_align_size); - }; - long unsigned int bytes_per_tile = content_bytes_per_tile + tile_padding; - for (uint32_t c = 0; c < channels.size(); c++) { - int stride; - uint8_t* dst = img->get_plane(channels[c], &stride); - if ((numTileRows == 1) && (numTileColumns == 1) && (((uint32_t) stride) == width)) { - memcpy(dst, uncompressed_data.data() + c * bytes_per_channel, bytes_per_channel); - } - else { - int pixel_offset = channel_to_pixelOffset[channels[c]]; - for (uint32_t row = 0; row < height; row++) { - for (uint32_t col = 0; col < width; col += tile_width) { - uint32_t tile_idx_y = row / tile_height; - uint32_t tile_idx_x = col / tile_width; - uint32_t tile_idx = tile_idx_y * numTileColumns + tile_idx_x; - long unsigned int tile_base_offset = tile_idx * bytes_per_tile; - long unsigned int src_offset = tile_base_offset + pixel_offset * tile_width * tile_height; - long unsigned int dst_offset = row * stride + col; - memcpy(dst + dst_offset, uncompressed_data.data() + src_offset /** + row * tile_width **/, tile_width); // TODO: ** is a hack - } - } + heif_channel channel; + if (map_uncompressed_component_to_channel(cmpd, component, &channel)) { + if ((channel == heif_channel_Cb) || (channel == heif_channel_Cr)) { + img->add_plane(channel, (width / chroma_h_subsampling(chroma)), (height / chroma_v_subsampling(chroma)), component.component_bit_depth); + } else { + img->add_plane(channel, width, height, component.component_bit_depth); } } } - else if (uncC->get_interleave_type() == interleave_mode_pixel) { - // TODO: we need to be smarter about block size, etc - - // TODO: we can only do this if we are 8 bits - long unsigned int pixel_stride = get_bytes_per_pixel(uncC); - const uint8_t* src = uncompressed_data.data(); - for (uint32_t c = 0; c < channels.size(); c++) { - int pixel_offset = channel_to_pixelOffset[channels[c]]; - int stride; - uint8_t* dst = img->get_plane(channels[c], &stride); - for (uint32_t row = 0; row < height; row++) { - long unsigned int tile_row_idx = row % tile_height; - size_t tile_row_offset = tile_width * tile_row_idx * channels.size(); - uint32_t col = 0; - for (col = 0; col < width; col++) { - long unsigned int tile_base_offset = get_tile_base_offset(col, row, uncC, channels, width, height); - long unsigned int tile_col = col % tile_width; - size_t tile_offset = tile_row_offset + tile_col * pixel_stride + pixel_offset; - size_t src_offset = tile_base_offset + tile_offset; - uint32_t dstPixelIndex = row * stride + col; - dst[dstPixelIndex] = src[src_offset]; - } - for (; col < (uint32_t) stride; col++) { - uint32_t dstPixelIndex = row * stride + col; - dst[dstPixelIndex] = 0; - } - } - } - } - else if (uncC->get_interleave_type() == interleave_mode_row) { - // TODO: we need to be smarter about block size, etc - - // TODO: we can only do this if we are 8 bits - for (uint32_t c = 0; c < channels.size(); c++) { - int pixel_offset = channel_to_pixelOffset[channels[c]]; - int stride; - uint8_t* dst = img->get_plane(channels[c], &stride); - for (uint32_t row = 0; row < height; row++) { - long unsigned int tile_row_idx = row % tile_height; - size_t tile_row_offset = tile_width * (tile_row_idx * channels.size() + pixel_offset); - uint32_t col = 0; - for (col = 0; col < width; col += tile_width) { - long unsigned int tile_base_offset = get_tile_base_offset(col, row, uncC, channels, width, height); - long unsigned int tile_col = col % tile_width; - size_t tile_offset = tile_row_offset + tile_col; - size_t src_offset = tile_base_offset + tile_offset; - uint32_t dst_offset = row * stride + col; - memcpy(dst + dst_offset, uncompressed_data.data() + src_offset, tile_width); - } - for (; col < (uint32_t) stride; col++) { - uint32_t dstPixelIndex = row * stride + col; - dst[dstPixelIndex] = 0; - } - } - } + + AbstractDecoder *decoder = makeDecoder(width, height, cmpd, uncC); + if (decoder != nullptr) { + Error result = decoder->decode(uncompressed_data, img); + delete decoder; + return result; + } else { + printf("bad interleave mode - we should have detected this earlier: %d\n", uncC->get_interleave_type()); + std::stringstream sstr; + sstr << "Uncompressed interleave_type of " << ((int) uncC->get_interleave_type()) << " is not implemented yet"; + return Error(heif_error_Unsupported_feature, + heif_suberror_Unsupported_data_version, + sstr.str()); } - return Error::Ok; } Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptr& uncC, const std::shared_ptr& image) @@ -511,14 +904,14 @@ Error fill_cmpd_and_uncC(std::shared_ptr& cmpd, std::shared_ptradd_component(cbComponent); Box_cmpd::Component crComponent = {component_type_Cr}; cmpd->add_component(crComponent); - int bpp_y = image->get_bits_per_pixel(heif_channel_Y); - Box_uncC::Component component0 = {0, (uint8_t)(bpp_y - 1), component_format_unsigned, 0}; + u_int8_t bpp_y = image->get_bits_per_pixel(heif_channel_Y); + Box_uncC::Component component0 = {0, bpp_y, component_format_unsigned, 0}; uncC->add_component(component0); - int bpp_cb = image->get_bits_per_pixel(heif_channel_Cb); - Box_uncC::Component component1 = {1, (uint8_t)(bpp_cb - 1), component_format_unsigned, 0}; + u_int8_t bpp_cb = image->get_bits_per_pixel(heif_channel_Cb); + Box_uncC::Component component1 = {1, bpp_cb, component_format_unsigned, 0}; uncC->add_component(component1); - int bpp_cr = image->get_bits_per_pixel(heif_channel_Cr); - Box_uncC::Component component2 = {2, (uint8_t)(bpp_cr - 1), component_format_unsigned, 0}; + u_int8_t bpp_cr = image->get_bits_per_pixel(heif_channel_Cr); + Box_uncC::Component component2 = {2, bpp_cr, component_format_unsigned, 0}; uncC->add_component(component2); if (image->get_chroma_format() == heif_chroma_444) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 848776a3d8..e1af4ca541 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,7 +16,7 @@ endmacro() # --- tests that require access to internal symbols if (WITH_REDUCED_VISIBILITY) - message(WARNING "Conversion, JPEG 2000 and AVC box unit tests can only be compiled with full symbol visibility (WITH_REDUCED_VISIBILITY=OFF)") + message(WARNING "Conversion and box unit tests can only be compiled with full symbol visibility (WITH_REDUCED_VISIBILITY=OFF)") else() add_libheif_test(conversion) add_libheif_test(jpeg2000) @@ -31,6 +31,14 @@ add_libheif_test(region) if (WITH_UNCOMPRESSED_CODEC) add_libheif_test(uncompressed_decode) + add_libheif_test(uncompressed_decode_mono) + add_libheif_test(uncompressed_decode_rgb) + add_libheif_test(uncompressed_decode_rgb16) + add_libheif_test(uncompressed_decode_rgb565) + add_libheif_test(uncompressed_decode_rgb7) + add_libheif_test(uncompressed_decode_ycbcr) + add_libheif_test(uncompressed_decode_ycbcr420) + add_libheif_test(uncompressed_decode_ycbcr422) add_libheif_test(uncompressed_encode) else() message(WARNING "Tests of the 'uncompressed codec' are not compiled because the uncompressed codec is not enabled (WITH_UNCOMPRESSED_CODEC==OFF)") diff --git a/tests/data/uncompressed_comp_ABGR.heif b/tests/data/uncompressed_comp_ABGR.heif new file mode 100644 index 0000000000000000000000000000000000000000..d0a01266ebca3f149cc1dbf3e631cfb6d90a3cc8 GIT binary patch literal 2811 zcmcJR&2G~`6otoWpsG|=EGqG{sJuemq*4N^U`0{+D*~x(kk~QU<7T8d896Sfs}6-F zFTjeGU!X707vKSS0k&E20^y#xS9MW+7bO0o_{^O%xyKVZj+IiklKjY}Ht8w?+BY^) zD(I#r*O()E{dka-L#3RJavnpU??2uRF&Vzl!+2n33)h^@)7h$kjvIC`icqz8R6s8x zcmrK|Ps2@Xhm=UbxkH6%omYp$$nK^3z@YwNUFJx=br#Dg({9?ITVKA?R{CkI^Qp)m zk>4V}M1G2#iJXcQBHu;6i5!b$B8kX5kyj#*M0z53MQ)3%ityFQmshp+zFJ{LwVvO- zI+Oc0<4Rp8lV;t^-(I=T3855nn{n&AvI9lFConG02qWfyUG9j_qZbsEInB8BUA-@g z=3L$%Yq?Kk7RAX4&$2GgMW?H~BDFcUK9l}OeRD4Fh!d*neRD2y04K2Gin{#Ut*%;( z%UP^t*Xa~@j=D3N*X1nMi%h;tRTymFseb`LE)LEB literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_ABGR_tiled.heif b/tests/data/uncompressed_comp_ABGR_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..5e9ed55bcb8ceec8fea8add43ad80a57d752b088 GIT binary patch literal 2811 zcmb7G&2G~`5Z<(b3aLUIDnU6^K2=92dl?A#m&q z^u)<8&==?n^a1(;z2?vtF!QZ<6OZ%%MfS|MvokyUc@7amJPDFtQK*8tAiy@I3WTWC zLz%c(BQ%z^@)V zHoP$M$yUXhxG(OJ6=IL7?vu5kwKei9c&*^Iiq|+$ZGS0aI~lYCAEBJpx=>hFO>vHX;#Kkq?*?aAbXW>U6iO{ZheD&PEW6^k} zrO6a6*~nm^doNMDBTaR5Dn-ByQJVJqB|20E)k#T&(dk55h-BGdP@-oXF-O30%yGz} zn>3vmnQUW*qDR2&%*iBbHyK-^wyG&Jo0f7*w3thw*_2Cl#-)n6Q~{Ujm`io2Pr~Oy zKVzd(7$S;^ITTH!6b5^2R0@%P-;~NXPNL`rrBHHgR0;H z;Vnf=lVipUQ=?~OG(_`hX;jR3VTkYzmZEg{ry!Q{pxgN@edRjuRZBWYamPRPr0@Jx oNz>7PNE^>z)ZV`PT8rh6o!2|Hli-#6vi`l{%3A1l6Z(_-ANIx$(f|Me literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_B16R16G16.heif b/tests/data/uncompressed_comp_B16R16G16.heif new file mode 100644 index 0000000000000000000000000000000000000000..730106cc10fe983a99bbf5fa8f73b796fc4ec569 GIT binary patch literal 4004 zcmdT{!A{#i6kLb2M~YCTq8^Zss8WzfE7YnNsS~Fx`;#I=CDw!A>xPE8$p8@{kHHnU|(*UdZaR zT(c+0S~BL9tRtLSIL)s&KIHapTVk|-wJv{4hP6DkfBhpExlyIB%I%+0^Y%D1Z@&&& zdL%yPRr{reSZ6Ig693ohwG=hPCTXAI6AI&uaj1L)BGW? z$jUk3yysg-ZB?(-0hyh>f92%dBDM5LFFFG`5%ZjFlD3LhXs)E1sO2-_bJLuCW&6X3g`Nh@pqSc8}Is|iw}!&dYZU2{^83(JpFR+ hZocn){dUwT+}ZZ0?aoQ|(SF!E?poK$?WB~i>07(AWvT!G literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_B16R16G16_tiled.heif b/tests/data/uncompressed_comp_B16R16G16_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..34c55deb404881c7fcc3ab1ea9b89c9997fe3bb9 GIT binary patch literal 4004 zcmcInO>fgc5M8H%W2q1l6^F`4gcPI(RDrmF%2z8P^~BxSn`WgrSvfAKw*vhU{R8|x z{z90^_;s^p6P(~oWY6xrd2eRdUL{dV?GMUJo14L*B4a<)W}sB`B-draF|z(J8x=BC z%9^yqnEi*dH^(st^%{c9gnDpXCF z8?FYMpgw0-X(HN21!zE1JfiTcqUZ{_SCwJzbK6J5is%X+-MDASyzQakdR&tcR~P$^ ze7~!2;jY?3T~~{WT=N&%vYrqZ4<>vQ6uIzCIDU?sg*AY0g4Q`Q zU#2K1?-^S-OR&w*up*vZGZfjgS-lhCW5w&B%Q(Nume=!9bdS2M>A35o?i?*DvMSeI zjk>y=&jt-S3lekp=4hD1sz1n@qLPO_@t+$s!l)muuX7U=oO)fq$1u7qDw_X;Zlf#o zBfegt3F`J6ZwyrYvk*evJGjUZ9_xlUO;IR918ZUazfMYsBRpnqj-m&*GCn12O->5x z3PU)|Ei?3(-b=yblikOQ>Z+^7CSM8&y z;J$(RZDr$*!cp|PJ#_U+;orz&(kY)xG3gnzwo$iNp>rg^3~?fHexxIQw?dpYP|`RZ z6k4B5C!cg?lK8zD>G-UeWEZK<;%}xL#`Ay9{in}*Z{L0H75eMZ%cI`;;6?KM@Jm0@ Ly*!zg^l$nPPxoc6 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_M.heif b/tests/data/uncompressed_comp_M.heif new file mode 100644 index 0000000000000000000000000000000000000000..e6d0c5424e04d3f38d9b9952dd2b737e72363afb GIT binary patch literal 990 zcmcIjO-sW-5Z#1=x8gxiL`sfcBD6|T@SxPM3PMlf(KWki2D8nQY!z=Qdh*BSFX&9t zL6P>`X1B}?PVuSfY+y-mpT)~64X8!vJ zp8C-!>AukTBj$`{$&4zPGp?pCpGkfHSLF>DOEltDwRq2Us631DXJ%DVuGyJ!ed_Ox z{&sEt^0JvLtG98k^{~k9v;rAiL8^mMo~dc1RqzTf3F45DNXg)ro27IVDnpLJb6 zbg$(oh*VzKFqG-M%E7xyQS39Tp9%*L%sJs$y9eAO8bOf{;X5FzRFhC86?G7_%C!>f*Zi7Fd(Nb|nhkn=nzT zm&Ug$An9IGq}+ZI2V-9a?h9o@H~;6_`v>0n#hsU^=gx7*8-z#lu=UuM%F{B<@E?8w Dnkao5 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_R5G6B5_tiled.heif b/tests/data/uncompressed_comp_R5G6B5_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..07a67a2c5e99cd3afddcb9372e3ac0e5ee033c39 GIT binary patch literal 1684 zcma)-&ubGw6vy8t(ez|R1dE5V$09^97HtusQh&7|^yGcroiqd4WJ$Kw9%@$f-B~y5(Ux?bLRMJ@7cD^llE(;@AZUEyb;LI*I5?)s_YG19yPYe!UtyU za=ga4CS@NLVZ3q|15wLH2YpxW_|CrI@i!R^1H>a4xC6x7aunzV@G6h-y%{(o&f%T- zd&~6$53x=S6uS<3f<3npbF1T2V2h7ZW12PI2x)Xj2ELOmqm9O=+UGCmVafNLP^q81 zvaI52(vN2;bevpZtkeYlznmv1y@h^GsaOvbYz{5+8jkjxXsqC##?{nRDx&&%qT;`3 znjcnI$z&1ElP^AgXfTh5Z1=(&v_DY7Av7eEF<)x)n%7bQIC17cVfX(jnPcb zxh{IY=}(3PoPe9=#3C78%7}%%94qxJGE~%K9;41x0>Re4FLBi=qqNawhFI9k4@9HL zkkQ3Z){O3G)}`%fKPhtBJ3KV2;2DLcBF1H8bTP!&OsUPYaa=}Nn(9&HeA14H=CRSm zkiKTk%`>7hGFoN&HBaMeDr%GJhneGKvIrZ6kj>XD;c8W66dL22o&4axX*CtK(Kn0* zvy#aoY!u>ab`tZ^stF0ZouLprqrn^DNymOEd&1ru4!i?bc=mf4c5VHpXy1R>dj8^V bYbXvMx7S^Dz0Nz=ZTZe9#M|Q^84=v~ literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_R7+1G7+1B7+1_tiled.heif b/tests/data/uncompressed_comp_R7+1G7+1B7+1_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..d1f4771d720e7563cf079edebfe50d5fc2a5841f GIT binary patch literal 2204 zcmb7GO>5gg6kI#*$Ek!;Xz3y7SPCxG4Q-$Ysia>C6oL-DtI{f7uxueKDmjVL{)qnE z&a8H&MXnY31?$c1n>X*tn}dZA&(iWX&s6$aAefg@r9w}IaPINY`x>p2mDIvVxhgZQn&5e&R-2e?7KjP{5R*&h2M+;XD7D5!9^&&HL{1I6 zS;y)ki>@X4UzHa*@~z6_4e}GU&2<6zgdCsaJlax2Cw?BsS)L#tiJ7=3?gPDt=Q*;C zBY|Tq#mAJ7-QXEy;;G8B$du7B`!)Uj2k&s4B~e);Y$q{dGD@zl z%=e{o_fonFYPBQ$57o2S5F&OirS2+0fW-!B{}yP?1}=-q9pnw&LD9-KS}-FlG=`(8 z6*42N6|rMAic+L^Y1VO|wX*KUd4NLU)2~8clMZskL6o!2?eUHrsQ*Wrdu8Qrs;wyG zR*-j)=pYLHWm-sivE6)=iHf|>Y9+m^Vw2p&GVy+@a_Q+`42xH9<{v+OpBJ)vw>X_& UpS?XhP0}B6JkO$SiC+=_08WSs0{{R3 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_R7G7+1B7_tiled.heif b/tests/data/uncompressed_comp_R7G7+1B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..d3f4e26f95876ebd80392377b05ac2269c9948f7 GIT binary patch literal 2124 zcmb7_&u-H|5XRSO2seTd5(ufSj|eG9gbFHgNUHL$m5{0&xEp)ZtQ03!;s*6Xg5V)| z6OeLf--AQ)03f*afP(qH^;)%4;<^(#Gr!%L^~}z0B80fx4vzz0wI2xxbw{eU5Y_`< zh7QLd^^Vsa#HJ8|a>K-?es!?3YjeR)O1xzO9CVo`AhU#&a`phVX~b2;?Z7nq8moksc03;u zs!K8YBBpj7lPd|yP#6!1A))N9=TY3ylQH5KQ{Cn2ETN?x&&O12TCHYt37O(%X4h9y z+|ZK`2w0z*_9ld}l|4WKY+(Tfubc)j@x((Hk%xF2h5nEjQe@5)4-Dp3Qf?3Q#fhTt zUwbngyBu2D@nz(pY(bh3)SruaJunx?LPDqbS%|OEf60`bshpd09rqQ=bn-G{9q>*L zU&>?+SHest6NW-CcorvAlrlXSBYrU*{e+q$$>Nl4K&mzRm;Ss{mt(dE@x>YaU^PM% zCpho72U6}0`){PD9Q&o}O8a2Y_l{iY+3!`@vGqTE{o&)<^A~Sx137wH->MyMKiS^$ P+V5Pq<~zd>|N8#`liLw~ literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_R7G7B7_tiled.heif b/tests/data/uncompressed_comp_R7G7B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..34e37e899ed50bfdf2a00832b40b8cab34cc6ef9 GIT binary patch literal 2084 zcma)-&u-H|5XRSOXgLvtkU&VZKB7uNB2-X`OHujPNJtR}?#5m>E5(VGxT$(+T)_iy zLFx-|;0ZY7P~L-s{Q#hHKlJWN457KkbN9@ zPLyTYFWJ?|ve=xIT$!+Pnw+4KRNxHhaCT0!mnr}vSWF?zj4&-3iCy4Y%QA9}BsM1t z`6-fS=VzE*<&o&=Ulju)71#w-et*f=0!eCADrSUH`7=Nzr8qZ;sI4MgL{tfMt9_Uw zz1CGE(=S(1edX+PmDl?)gba;j5(?65T}5&mPbSEpP4jv-l7jSFR}syQ_jA(zwBE7v zwUk7wTa!DMQoNXG2IL)L$la;h)Pm49S8JV+HusiSk)EehnTII;523rLHH9#Uks(qq z5xpT*R8@I-NV4qv*M5SNnje|ViKZ@Vt&=BBv!4vNF$*3U%G7ufjAPBSBwZ&>O zwq@VvLxJlrsX_%fmC6nP_hh8z0`L~DVKfzw@C;_cv1|Lv0j#qI+hCi(E+JKs-rSkbghB6xOwU1ADy6HPS{)V6@i4!IXF+4$>a6Pry6Z2N9QU!zw1oAA) zud@u5ya<<`S%!PMX2SB+)rx*+)m<*~Twg`MReyBC(7V;B#aWXiO{-J$>qO5qoz1FK zv7eM(_m(`-wK}!fld@sH@({F|?EBdPTLDr(#BoRTuh26?y7j{9o0M`JVL8 zQI(okX9l6GsYWf%N(v%&g*vZqRDwEiLm~Q6@F*O~%{%D{^C=9Ri7g!SO~xa0{>IQb fIkj$XpRG{5b}zct&^_m8?UxQ0md~RY-XeYg|JBt1 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_RGB_tiled.heif b/tests/data/uncompressed_comp_RGB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..ab30d7f2113cb567d837931c858b1ea62936a126 GIT binary patch literal 2204 zcmb7G%Wl&^6dkAGu|gF>05g@B{w6 z{6aWq9?r;4Q|DIpJ;(RlGuOUdL5g2=IppE|?!Y1bm^?3@7p-uIC_f zVA=I7R_9rCCCUG(yvUJnR36WfpQuHy3&2O@xDNAZK@FXFJ&vWiruu;dkb}kp-jl25@Cp@9&A+_B?0Gw-g#`L+TB#v>(#17n?tFn>)ljO zWrTITT()R485NpzmckBO^`Ka-^trAN6hVQ_E$UUM*iBo#E$a6YBb>spHgyVnZi}*) z;q~4^`IzrZWp^o?3TkUlxP|Jo*ia)nOVOX(RF+E&wh?ZjdTuH>U1uq7bEt4bcTkK) z7f#2FaM1eqrcTI=a8|^gRWC}Bp2dvgL1*RMt@92Fh20*P;z1s<7u8>Kvm?7m?nnQR zY$|ut)>0~3m~|0Vy!EA!UZjPT=ZpC_nW!lItfn%&Eau5|ER*n;Dkq`-#V~&Ldi3$r c_fa8#p1eC5U8QfMH^)E5ksM{wqQtL={|qwK1ONa4 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_RGB_tiled_row_tile_align.heif b/tests/data/uncompressed_comp_RGB_tiled_row_tile_align.heif new file mode 100644 index 0000000000000000000000000000000000000000..602cc850ffe0cdc4ca8b337f4ae8b081294a357e GIT binary patch literal 4252 zcmcgw&2G~`5ZijxjlF4BiW4hwi+T%fAA%Ri z>*W=~e6!wW?X`^@*Gy#3?0oah%#OWP6CuRYVR8{iYPc^*phr>-h3LGDWa7g|G8l#9 znKp%pRgf4P`s>NZLk~{xn?DK1k^>*aDv3C%L-##3o(5R;K8Ox|NIJ*R5AT!tLa7N= zgp;mkw2<9&bv6mqQRJUWtpBKZ7L&eEaWEzQSj}Sw$lk-6uHD$5BL6_qUDF4e5zm z0qvo9Zk!!6b;fa17g6P1-8#x$>8y*za%oKhCU?a~X;-bFNXng=_m3SlZ`f5iWn0wn zij$Y4W+x^h+gTG7nM~HYT^X+7XS-^GA|u4j`0uR6oQ>Dy#njvi4N&e@XI-yXt4&3= zs?q9`)C9$b=x+kf=W=;@neVC+)s3h895Y=SeqGe&IkV#ZqGx1v(c)UR7um5+l?`cc z32N~;B1>$7B9q0>CgxQ+Y9Yq7_{IfIVj(b%i?Kq~MC6Dmw;DAZiZW)ZZC+h8mny&H zQg}O1!+ATZQL*8zR!-ARP&BjcIkR}q38hDfp7rUijq>vcA47CzRgH38&2yQ$t1VH` zDg=`RY_uC{kaT0YfOb%m6`CYh6H5*7TkzjdyOrXuOlQTjY8NdS1H14>qVpArGfE3_ zF#4*p;oUM?ea!sZruj#(oeak#%QkF8t4!!VQE9uo40NEGPW6Y{65prAuG<>%oBq3v3Iw8f# zx82LOjf?gjAGm!n+qkD?sAjt?7^|{BbZ}N~F$*q$^@zOl4B@eq18@YOas(4mn$N}q zM|KqN37mgR9cbW4YG(*skt015Ag2q0Qw}w#8E^M?x2`BpPKE7dCjU+0dWMt zIF8fnEJ7tO;)Q1%<62TPadGN$MXOnpE@ye>SJ7|TADs}%su?vqYZOhV=G62$(Q`VT zOw6g+Ps*P3mORnboSN+k=Urr0#q4XWJ7A&%_=`bMZj6)X8CP(IC{|5!u4W}yGwOd? z=^rWm8|7F3b}y+j1}x4i>NTC$`PFPsQqnyOQ187!h|XyEAY94q8`&3jHyFBON4WNz m41Ig{LfSYvtzBI|)dKO_ylB>X-Z?+3zcje0DLx9}CG{6J>ecT6 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_RGxB_tiled.heif b/tests/data/uncompressed_comp_RGxB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..3899c91c2f5d58e03d29bd807631e68334d73c4a GIT binary patch literal 2811 zcmb_eO>fgc5Z$B!goF@>N+1rEk6eP3fGW5Zm9HWpl?!K#y=hj86Dx5+y_vNCgH!%q z{z7pgSS`r_oCQBr%h4+yeO(L?+iE7~ow7$^Z{|5J&F=OlqF!B^c zw=KIIN9HUEFEsgYlTK6E+@#S2_R!2y3BW%h$MYx+XUw4zpTj6gW7rOUchm!Q7yb!U zPhlN8O5KCs;;YTq0bkpo-T|J+CQU*c#%Vgg+SfNY$}ow;Yz4SV`ao^!Ct5!T=vtZD z)Jt6NZzUTta^h(ls6&;JgIfLM0iqls7MuwdA?XQbU&1l2F2NQ zRhKePI&+^=7S_iu*bd4ASqW<#b%HiyH!amxP%bqDc0^dYf>hCeN2Jtg@MtLCNoBJl zakW}5OH^uE&kW24U80hDk;P&@FVTkXXf5N~@Ggs8ZBsvSxs)TgL{NYU)|RLjVa9G+ zsx48!mOkJz3g%Nr8iExUbx2lFw~^NdmntZid36kJkIE*3*vd<+pd!wK1+X$khP41w`urtL`@my}P7nP4v%oIn(ju%~-+)dCXU`V)Ha-dm|2 zy!GbMzu_MV&Lj=Csd}q#$S5deBULV_U8r`6FY%_sMc zM#Ev6e`iKD3}<;b(T-6 zra8UZG%o=c01XfVu+5)pmvIgi~I_lvojvqyLHHwDUa Kg0_8l{k{MvE-uIb literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_VUY_422.heif b/tests/data/uncompressed_comp_VUY_422.heif new file mode 100644 index 0000000000000000000000000000000000000000..53de4201ead40665ba1d863e9b1dbef0b33a950e GIT binary patch literal 1684 zcmcgt%}T>S5Z<&EJ&A~*2$38`h|nrU@uJkfRD~WA?`yJYw>0gNrbk>E_yU@KP5A%4s5%r~>Mvoi@SA!N<=y29aho&ZqR7`F+LwjAbBv;hh=tKmi} zA%dG;tfM@u9F-I_D(AFmHCVWDQE<-*cS*2r@J7o-mOCU841iQdIfv>d=S|26K+if5 zmKn27)8v{%s|@)w7p?%=<-%-%T;XjIIzU&D!(0-yjeGDUoXe&oERb0knb2|oXO_Sc zBTL9U=n^g&STJe^R=IHK*av0g9x{(lP{V>_Q7;HItzP#5y&fUHpOjBWk48!PWbV;u zI84evZ;sJHkeo+#N70%V_u;Qx*9{}eO2}Z~`$_q9v@9p(leuNN-%rZ1U(wAmTGx~F z$!NovKJ9mY3Ag~rfB=BM={w*Ja1Th^|5NT4K-&IUbz|;VK-&KAdLHM--ly&V`n@M} zWAFdLU$$Mww07%?S)3}Tyup-;+p;<)vy?mT)s*n1C~WVj$0ygS%WjMNMYU@0(cSz_ Mfil&hZ4X|L5B$5r=Kufz literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_Y16U16V16_420.heif b/tests/data/uncompressed_comp_Y16U16V16_420.heif new file mode 100644 index 0000000000000000000000000000000000000000..412ab1d039e345acdef035c15a1ea3197c928dbb GIT binary patch literal 2324 zcmdT`zfaph6h4PY-CBeywW^fLBSJDLX@y#KfQlbY0!R#@`_(>^6S?H%m>?#nf&q2T zz#e6aq7L04tjzoc3`|JOtaab>;{jD7#Dy z0GLrm|Evw&SL>PovQ{U(t!F6z*#6P9Y-R5qS_(}Vsw%hCWlK62s zYc1xU$j9n^sKwml=Mm>IzjCo$+*{aN2<`x|Ugx}XPAp;t_rZM<|CIKueb!FmC+&;c z!O~zUi657<)<$PPrlv=Htlozl<{m$fI1g8??0SrqnvE^yaB8me8Z)=OhO=)o$2{PE l)r|gB3iI!*)wQpd$6AXY7p-0Q1AU+WR-nuhwCTg&%O7->GO_>w literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_Y16U16V16_422.heif b/tests/data/uncompressed_comp_Y16U16V16_422.heif new file mode 100644 index 0000000000000000000000000000000000000000..16d71dacb4f8b0239a6d14fadd35ff7b246a4ce1 GIT binary patch literal 2964 zcmdT`y-O=W5Z}wQ5DOI%6d`h@JUGQDqFDGIekD=CLhaYPJ+qiimdhEjx`RDQ{iY(aJEx9X#T^fwTyjV8T>i9!60Em`H z-G$Q;&Pxyx1eqZ)SgK*|l}w%!bcdmR#-$@cA8=`wLHF~D3<#L(Xv5PhX$AM-N%-`c zLRz4Ift7-hkXbl$9&{+M)&p}5hZGFx)j|fi6tuxX8XbqJqhrXSQ&`kpJyBQ@3h7Y= z|6L(G^7&EW+Eu7EB;>d1LJJi}Q=P`DQf_V`J@O z=Og$1IX2cl+7IpKvA+3iKD#@%JLbIt;P;%~p579J7~Y%r7B~M@?3>z6EpEP5-Wa<+ zSD%ZUZ&vd#cF_Ax?xd}J|S)-tTAmcV$wm z)t@}>8>_WivW|p@p=n-U)2v>Pu^`CuadkAx^7P!%XgJLB@5-dctB*S+Jk3lqSx2mz zChn)=ctV)%)|s#+Hx6Y(80TKg?pVS$Zlzy0qL;3`vR2wZxF~tzW@BrkbmeUF_0`KV L7bTaseY}33WI8U$ literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_YUV_422.heif b/tests/data/uncompressed_comp_YUV_422.heif new file mode 100644 index 0000000000000000000000000000000000000000..bf4d870095e1d503f875b0869df75b8b5bc49a83 GIT binary patch literal 1684 zcmcIlO-sW-5Z%;@o(fmHi+Y$RlGwnv=hB^maA;&39t+#W82uX1RVow zQ?NA>83@Yy0Si*O{N0B(vNxIAJM=K^+T1?@jsYDA0SbEsUVv*LZU1kzpMbReKlM$u zpMkXf-_1O(O|wti|Mh#1*QVL0?XOmAwJ;0-#`^srNXkEF>v~c?UR&26ACvNrlT&uJ znw&>{N7=PnJcs}CFf`4J3#xj5&sY#7<)5>M!=!w?_HZ~DB;_9`r|f9@Q78Z9#h(+M_JjY_RaB&!;l8Uw{jQ{ls$3B=q$Bo1=#QD!6+iydM*Nd5Wx|(+c(j@ zuk{e$NQ2n!0aU}$=`hlrRGui}pW2KK+B0pU5!%~&V(bC*_lU9W8abhJs1j|rqSVA_ zZ-5%u3-Js!57Cx^v2FAN+BInRZ%`phy`xPk-C;~)>s#aeJF<7vSY}ry}MyJ_cJSM@AS*S**xm*;6%tAFf&7^Cw zSS}fE*n1 zFf4Q3DpVu0zz|PmscX6HcB_$DU}&eb)-{{;dez7*FtktQTGxCI12n_`B9r3jqS@5K zawRFrIda|7S1qJ+o+JOJy*zUDFA$UBo-Wcwua8>Dq~w>n==D(xnH0|ty*_Fo7WF6@ zE7h5d-m6&4@UdV2?gVss%L_XgC)RwB1 K%1MTQ5q|+`FtQr} literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_YVU_420.heif b/tests/data/uncompressed_comp_YVU_420.heif new file mode 100644 index 0000000000000000000000000000000000000000..38afbeaab55b94c9c0be851639c25276131b0c98 GIT binary patch literal 1364 zcmcIk%SyvQ6rHq!I}s5SA(EvC6@?z6S{EkPSl0F z?p*pC{z&lL#9$jAyPS|Y_sqF-@5}_k7@K#4zVf77W&m+RNS85f*%JY$IiS*TT7D8T zrlcLDG4Ww_XV;)f+tT!SU68()%2(jNRCWhEE4wN-5F4cNPAlG}9I8a`jO{50T!bnzD!YZ6yWkW> z#wHPKG!!tzty6QH=cMxZ*A$L1aZ|XxL+N+V;lU|z0_Z>lP}&FZ3S0wu`~UTR2J-g* zIyd!x0rK{LyYsX+-F@DE_Ir=^rn}GEk0R4-HbY=AU@Q!?dfXijvwC#xaQO6;)!&uL zjiR4A>6^HwneHRiwVGums~CHH48yD*cXd6hN7w55!$Vfnev-=M)@ncXsB2l{*_MUx zbL{#;nBC5qa3nVlWJ?%TzvJ|5;TTskXc+OIuClUP+S@-b`QmbYbG=k|H~3olqQXVV JS5Z<&EJ&A~*2$38`sL(1!@uJkfRD~WI?`yJYSCVE)Ql+OT`UpLE@2yl1 z-ugJcNN}cUFcqujkS}CszMa3FNni;fYo^~7HaANIfU?E7Nr<#%GoRufpxiPnH&O`^ zT=!!gp)m; z!a8l8t2S*iJv~DY3${W1OTYy{27~}~`vANH9spU}f2;ip$l5-u zZ>;?W$lCtX%;VZP`>gHXzjv}W&OU2<7^>>+Z2;)?2nm9;d^&nGO3RbAN2B2|E&n<> zMu%Z~9`zkXt7<%l|MEsd)1s<`3N!`;;8Z!~7E|i3V{~+8DEHiNDdU@>yuDLAKDjQs?5?t3DK^bLx?8#_ MQ&zO8=fmys37(O{=Kufz literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_comp_tile_align.heif b/tests/data/uncompressed_comp_tile_align.heif deleted file mode 100644 index d1557c1d00c1fc675d673d3da9b9a3157d916146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1064 zcmbtTO-sW-5S^q^!GnkhiU)}|5hA2TLA)sSs|BGa@5^S>4rH4p*($xY=uhzA!T(xk z(o_((AmoMFH(&cQyRZOonA)k)n8rY09w|%#yfdw=;2fbnO0r_<0vMEbm{ew1r>qOXv19fWynmN!wuHNbxb+IhDD*w$jpKJXL&9xmDIcu)! zx|{WqRGy ShL>>~%d~T)A}vZwFZu^UOd!wz diff --git a/tests/data/uncompressed_mix_VUY_420.heif b/tests/data/uncompressed_mix_VUY_420.heif new file mode 100644 index 0000000000000000000000000000000000000000..d13e101dac5d67c93cded49eee50dd3ac6c4cbae GIT binary patch literal 1364 zcmcgsO-sW-5Z$B&Zz3WnLS>I4L}-s&a5Xd9A;3}b*o-FE$N zlMp4WFtL$O%Lj)PgY=9wZI{Oj=amR$yh?+4O}L(gUUr{oFaTN!Ir9$Yx)4pM2tZ{O z9Ig+&R?`xuWHpZdvrxVQZVP33z)K=fu>dwjAHD^}0$hVT;kRf>Wdmnm=y7BZ_B@10 zf(#*ZU~4$(FzIpaME$|bLP<7^z%{ZD`r{L9{UL1@MwO^yR?TW7YD9NKbV!Gg9_gVw zOP`iI$PIF{^htFwx8Ln|XX)e4oaEx!|DuoHcQhBzj``E{3&1%b2Z#XJ=1;&I;2w~+ zKCSi(AZ>lpy|MNyAZ>kI&y(8N`?U4n|9iAH_WmFAlH+r32HqvN1*0dz<+SX3cFW>6 my%k}d#xGrAbIUk7zA}7%Q`{{YHD`xy=dTNl8a<<6x_`d0NN(wE+N{UU=hU}pwM)@;MXNY zayv?Ww3pRV*}$Z6Mca?} zqfXoAmY@xW@jI7+1l#4(_Q7uOP$mTU2F5VgBn@#7o`iGV7SaKmfuSdv6F9RBnG_j9 zmciF>(P7aN?UemvH@OsaoPjd3FZ$~n)UYBP8pXA^X4S2FD{jS4WAsRmkO3KBsG6Ur zJ<5%8s`*)UqxP^r?5pOd^*q(a-Y^>rqC=XYkn9*W0Bv*8}m!~A`LGE>kng5To@w<^Nv literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_mix_Y16U16V16_420.heif b/tests/data/uncompressed_mix_Y16U16V16_420.heif new file mode 100644 index 0000000000000000000000000000000000000000..9b24e1da12f4094336c8f7f43f97ec8caba19466 GIT binary patch literal 2324 zcmdT`zb^zq6rNoY9U>AUAzO-Mi6cT3h+lVyM1g+n&bo=4yUE@jxoS@+M6J+^N<^W< zwQ7HXLM2gat@n0r3X;p=s(mlty!U42o0m89Hd#VQzZX=b;NCa^L7QXTBg7aHETA|C zlFGSxU%7-x?gZLLySllsXyK%lrUf_8;*Fh>2O{2Oz&OP7MF*qyd18Qq7+JI(Rd9zn zFF-~RTp56Xnf0h#aCk=0J%;fGm%apB;nFFB?d2sIFMw}h4Ct1$gnRHLM2{n+3$_g+ z6GlR2;mk#_T41gVd;C)`CY}G=KL1&_?)#+kn|ehXqbpF<3 zR6}eZWYdVKwm*glYvFs0D2$bm^9RJWL2N|$5`G|B<^MPD;M;u_(JKG1_3FHrS2uHr zR{6iZ=bw4?y|>J7^1hAo>U&q+5k`&rqZuE*pRDIImMIlCn9HfP!t>19^owrUVXk$^ mgPaxrsia0H?4{)$+h+$;GgJ1SH%%wUcT<$vf|dgKd-(#v_cF8q literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_mix_Y16U16V16_422.heif b/tests/data/uncompressed_mix_Y16U16V16_422.heif new file mode 100644 index 0000000000000000000000000000000000000000..d58817fc01ef772ece5e20c60a5ee0ce301bff03 GIT binary patch literal 2964 zcmdT`zb^zq6rMc_Q6M5A60)U8_QVk(3dGMlBv+sxyR&ZM=5DgLh-wLyTA>$}h(d>J z)&2s7N}|?U@9o?aBo}uo^S*rZ-kX^>n=kuzvV@R6KRlFz`=bO5eSvYG5NlYlkm4Lz zrr;F=6%r!38|oPSa(-^!#z}jHmb@ZMHg-rJie#4s;~+1VUCdf%i3I?&a_HMJ9OAqL zPXxo2en?oVmhF{Xo)vV5VSd47Ai*DU>6XFw@QO?pAht0Fc1c>nJ$Mqb+ZECS-vU_* zMnb0H%z5zIV6GEl3x^a8R`P7U`px%pDQIm5WV9ZqPEJ8XoA7A3cBZf@6b8}?@uz}5 z==E9QE>t+Gnd$X^)qV4%V0wMC?_2A>%_^8)-)Nuz)UEs8^!nev?|Qm*-%P3YnL(Of z-)Nuz)UEs8`1)VI?|Qm*->cgpitF7E|GggW@0=enmaUZ6na8QU#EZ<%2W4;1WuAS& m!-AdsDQD7S&cfoB6R`b>sR?JtpQPiX+ZoCnK`SBrJ%0g$eTSd` literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_mix_YUV_420.heif b/tests/data/uncompressed_mix_YUV_420.heif new file mode 100644 index 0000000000000000000000000000000000000000..98c9425e884b5ef3c3c94055f802cc6ef295f90f GIT binary patch literal 1364 zcmcIkO-sW-5Z$B&Zz3WnLM2BLDzr*byeRc6RiTI0`-oZ(;*g`r#!nWZulYot^!FWsI#ken+{|$uNMpDx|}hw&e<+Qx3>h?Yj5l zGNz>EM?Udc@hERl(m3Z0yDq|ki%R-#I7)-vkoBfTQSy*!_yDayocMsdDP;p40aDfx z2z?Z_8UfqA@fR{mYiCY;XdR4$Ig9=FEd5 zAh!TtBcsFUVed%&#j8@ee3Zd9l8^e+Gp7D@ZSG$J7eERK02=lMyaNwF-1@BEuRz@T zw0%?WHz00((wRrS>Fndy|K9g_Z#w(9^-@p@%4XRNYC-LO1lDEUKI=0I=jpR*Q^VA7 zo<6NF)%FIx!90D^nxk4;`+xND{f^ht+Npk)j{7M%o)BiMc_nPgjZ;|{M$v29ZA;k3 no%E|l_|j#!chbiv*J)4O=Js>xinGUeGdEc-(k^fLc>TTsCB-hv literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_mix_YUV_422.heif b/tests/data/uncompressed_mix_YUV_422.heif new file mode 100644 index 0000000000000000000000000000000000000000..1f5688c313d4f7bcb3028d10770bbc0dc734446e GIT binary patch literal 1684 zcmcgt%SyvQ6rEH>S0W-PLM2NPBD6|T+$i%qzBsb5cC(KgNblSFX%m*3P j%=o3q?(SKqXSY@$?sJDZtLh%`{mfmK3(M!N5US=snV5-enJ=SyDQa& zyY5{28~#Y}-q=8uKHTJl%(-{Year&}0M?waBR%2d06|>m!U0gWJRUNdL*(nW8~m66 zQdnVP6Q7ljiaJf|=d5YFJPurxBJ|=Y1;-8H`WAVaLs0NTC?#U;1IkGSYX5X-noeeAiY&cO@dcr9Hg1E_r1EB4AJYuwlC^l_3_z3}| zu%a|3zNns*bz0OfS=)AbQn)Nd$ELldaS`Ie-kp0$Xy{VA9+oLG7&J=DaWxQSx7as6OC2NlQwb|vn)ho1fl#ea>v`%;y;rUOz3)kH>b+_`uEjO8Zq{3ID}EfK2R(oR3@BBt&+{JTM|suy ztaFq1us`gp)~EG6^`_qchdz1Vlit*O@>i+j|6Oqc&dt!j;kID<2!=v;D zTv5#iya8_@3&;l2rpN{k|8f%d`IY>e`>*>^y(b^bebFlY_y2x?H@SXXDXwtH$SpZ2z$D?^d^5 zjei`q5B_}X6PFLO?0_PNpWNprUAesba?sDVN6BvL@Bd_Zk#jDyyno1fEj!AW1Fj$V zd)&#BBfsO{ztk2;;k<@UmZNV$#u%iF8*f9JbdK1wd1 z^3$yTSo!svA7yVeNXFuvSfvxE*dfdR9K4qmg}L9l60a_vlw~P6=POp}&gllc^xP0R z=d}S%zOOK&5YS~e@=cu5wMutNH=ucHh@8?5X!3o98Qp*;yOD3=gsxS(6S@J-6GP;L zZa|aoE6nHyG}(=O6UQ_R8pnpnF`aU&ACQ*j*6~9vob^~x&h6~U`98f$!N#O?2oQG&=@!x&cl0BbptJW=Esh(R>qa8kX=(q0!c8v^5%SjYeC$X!y>h zl3wXrbS;q<-GF9GquJ7Ewltb8jUMk;e6w^7x|T?TZa}l4(QIfm8yd}qMw9m|zFE3D zT}z}+H=tS9Xx25Fb&Y0SqsjXf-z=%Rcf%r0w~r3rr-LkMzRvd3=1y@q_|i`Y&2QOw puetn#wEgJu`pZ`z*NgP)=CjT9-Qm;Z$;Rh)lCF=EqcMM^{srWL4$lAp literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_ABGR_tiled.heif b/tests/data/uncompressed_pix_ABGR_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..031b90810593a0cb6541b03282afb3740d1d105f GIT binary patch literal 2811 zcmY+GPi_-Q6o<rr0ERa_gn;@k@Xl7*)!weuJ!3N2@>9O0Sr8sGI3}{wv z{w#9=uUPd3d;wn|2gn7oWswUM-z&GP-|Ogebyxj9$M3gD?40|3w)nr8=d(k{CF@a^ z&z$QV&a*`-dtAxU^tjyKI#=YA#qM6#e_lU%+Lz7#^YmnToQ2>oMZTDaREO8Q`SIyQ zp7tNR4nJI-H?rRPm)m=Je!_3$l9M|;WP8oi`;$rjVxGRs%Y@oD_ z!TSxhMfiN1hBdAMZ*A~?jT^yRH`KTWyxQP>jT^zM8&>2j-ml0;$gK>V(T#A9Ymq$# z-noG@@nFOLCaiMbK*t*m9d9(DDl7_lAa@UxioObd_sw9kv#=oY2Zve zn2|G(lm7uNoJ(#8vyl&saSeE51Lt@VJo14Nt^sdk;2bxCM?Mhd=68jd(Dm zX9FD%4V=?+gwIJnkdU)@pOB4^OEi4Gq+x(-@qU0C!5e7s1`R!2i}yX;2wqQv*K6qF zTDH5G~^PEGz{3r5 z=?>EX literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_B16R16G16.heif b/tests/data/uncompressed_pix_B16R16G16.heif new file mode 100644 index 0000000000000000000000000000000000000000..3b07cc4d7817e6d9ed9958c3940c888bb5a6f24c GIT binary patch literal 4004 zcmeHK%}T>S5Z<)aV=W?BJd_+oh|nrU@uJkf7KEO>ugRueXxb%BmEL0YA$)7xJ!s}Uvz;g3w z)VF!lqaB9v2N%8oJLbY3fZgLm5lw(!!5BtK&>_~~N;r0HPdH%nWSbPo7I+u1W&>;@ zc|vx;H&EpwFPTZ%eJ(sY&%$LCUUP5na1CY8q0o`p45!kXkTApbZBD~%V=@uFpTGP8h1~N9xrCGHm!9ztdbyy8Rm8M`TufYnGe$`vI2F6 z8GE40>i60v^;!4S!ak+%rZ}VaP>z11pD}w;e}YUVvCc5Z=OgQ%yd%En?I!hE&s>?Q zs=q$o${fbCLmbJu=}@aUic@P*DU0c<#JW}mR3K6U!Y&l zuMlT$I^Esd4JheJEl#-kzrWp?nj{l>vFCO*RGjP|r*g0DT*6cs7lkVGbhU^B^lt4suQ07kzOL zwAX;S2a;(`hz-yaWW7e?$hAZuNE45=Ddm+H%IKf>zI}%pw#r;WM-~eVg+(Oms+A+KJw?Z8i< ziwoj6QFR>oUz|GXa>#iaLm8WuWxf!XdK9Am*?h)uZvwfy+2{_L?zDSDUERN}@wsi^ z4tf{35+4`M)o&|uce4?nTI>UL%ICgiv)mq%z6{r{@v(f%X59^BsxGXBdu3-BE9dVx zcZOXZb9kOtM{v;)m4ChbM|Qgb`aw}CwLhC4s$9$TgC48&sG8=dnab0zx*ny?Kj-1I g=Yx0ej|Y|dvioXxa8kUKFLpi;r5coSR>QyPU;VXZuK)l5 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_M.heif b/tests/data/uncompressed_pix_M.heif new file mode 100644 index 0000000000000000000000000000000000000000..2b4c44531f6c1366106239fc97daf0cf8562a0c2 GIT binary patch literal 990 zcmcIjO-sW-5Z#1=x8gxiL`sfcBD6|T@SxPM3PMlf(KWki2D8nQY!z=Qdh*BSFX&9t zL6P>`X1B}?PVgor9F1Bs3M$RQXcx&dr zf8ePfjgsyQjlW{fSeDGFf;r=A>hhV?_kUI1fU!g)UR8_tT!+fD7=LC~73G?p8P})& z-so@F<}WXsxw3j2=UNYo>`p6?!4;%B80DFoMp^~0;F6%ebG?JZ@Z$15%=JtEq#uss QV|mnl>Pa0MSvb6h-@MX&7XSbN literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_M_tiled.heif b/tests/data/uncompressed_pix_M_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..bae5b75c0b12fc71a03935aa8e3ea08aaa4cec38 GIT binary patch literal 990 zcmb7DO-sW-5Z%;*x8gxiL`sfcBD6|T@SxPM3PMlf(KXq$gV|N?5%9 zR(t=z)(<+6*$iR37$g2o%R=D1(GHkQR-$6jhtA3h)`cBP+f}Kp6oN9fc!I#>UukYU z7tUtW=@R8lY&-H2EmgSm2j%9UjTRLwF)Inbp-V>PtuSUaTJ^>2;S5T3NDy@`mRNU1rB5W!ls;6 zkoaV8Iu}iilG?4&w;UEtTo*iWqge_*tK9KSiqvyZP*IdNS@i?mea`#1BPDU{V!#S< z^w>9f%Qd=;;&(25fp*A+>7m`?0}%n}S1HD^A&dddp_OQCny#?W7D0s)tf6;?Yc|m) zQp76IS4#LOL|%gYSXv0D!8RAJ5ofUt^`-FohHrnmmJxh`)Z$nw>`4tH$q!w=Ul__V z6AKWIrItgfqv>dxAG&-$+H(doNUu2yI?wuIe=E?X93?fUca)BX4$*GDaV7J-F)l$}!F`S97Rohbzbc33-K#Q=Bkn=g}69@g#$x5q&XqcJ|D(^Lx`5vx838931W+b{+S@woT8P2Kb8j0Efv6 A1ONa4 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_R7G7+1B7_tiled.heif b/tests/data/uncompressed_pix_R7G7+1B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..a2390e43867bdfce4c127c83b3cd6f4f92426a7f GIT binary patch literal 2204 zcmd5;%}T>S5T3NPdXgf7;-TayLIrElf`?Y>UkgI%!Fx-Kp=rbhWj>1zh_ft!NcrjL^FUgX9=rCP2I5?&}$i|qOay8E2>aYkyyvWFFx z32P61l{ZbL%c%awg(c9AxKIaZxA{=`9q1RSj-?=!Az^4FDqE^4G_+aB!5ZYzJHs&> zXs40|zgfy7K0^R{EH2c7FxcV3RKhM?M(#QD@``IHn3`gHAi1Fe)FKKVg!<_^fqE+f zPKpzw#o$BnB0iGjIx_{puBp1UG3ttd6XW!wb=;2Rb|NXm^exC*jEz*(r2{8UJtzMc zamK*2l%caAYcV$F5B@XQOPCsSK{}~_OzQ8cz{y#gFDe~%Uijw5_rQF#7)8qj|D3fy zQ0I8Tn;Y2!(a|s$r2Y{{F)Rt3in{P%B9pwaR|TAgx^XQyn!Za!@Wlxat`z|z&n?|z ztT`OqGL0+p6*rjNwg%dR$~5_j+dbL;V<;aUmo6^vN)~%OEmun2>PfYt>G!HyGL@l? Ge-U4j_eN0w literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_R7G7B7_tiled.heif b/tests/data/uncompressed_pix_R7G7B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..8bfbe08b6e220aad9aa097d1a072c8fc332df2cf GIT binary patch literal 2004 zcmc&#&ubGw6#ga~n_D9yD1yx%MTlT5TIeB>`Xem}J$YYuXPbd+GHkYyUXqmd5Af*G zgMWhH!Grk|#G@kJtB2AYga(^re6!hANE8+fRKKxGF{9MJPu1HBoQcI?GnT z=tstOv|p)EcuR-|{Ue#4xj_lf#Myqs7Tcb+$94W%NMDja5YldvzbaZXnxJ@1=X70` zR!d{_O8UBDd(t6qAd5>_p=guV+#;WtK~+%9^eq!b$;@xB7a|z03F%q!D7BG2%p4ul z(^b#0f(dd1lzVIhrMa8(0k+$E32HFa1tE-f$f(j{i6yHB47$+ioZ zg-gpzXFMz2Z*SVC#{2ltrqghGXfF##{O!0t=i9C3Gwuk>d?M=H-1VEzzRex;r3h+f l^rbD`xmSGj_<7Oi?FXgx;@-ynjdjO;VcSK|Y6bN5{RL{=nkE1M literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz10_tiled.heif b/tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz10_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..3153cd3c6fdc78aa4e50deac0637dd80c605dd53 GIT binary patch literal 6411 zcma)>!H!d96vt18Q4>Rq3lh`?>B_Jf6Go!!#2_k065N=$EbT3Glj+P&rzotf;*u9& z<*F~>3-|&&059N{1ut;@eeF5tlJw@^-l6TU_dDM?KRW-9WEeC1Xu5dX%^v+D!a|z zUq5f2%AHF*uGY@V&`^fCSv=W4iukIjgqfQc5F|CixUZs^FTzqv0SsQhdu!?Ct#Eh34 zs~u!*)JbBR*J)yA_S+`*W+pSwc>>tGwMu>FR1sm1y^@y8rPp=DhD>MXIdhNI)+)0y zr;4zOy^?V8x{k2QbY`CO1YotbidE)R5mvER5-wiX5muSb%yXUqthQFM%A6{~D)vgk z#p^m^Zl-fTVp`->5;MF`Q@hH!Nu0cYF)NoQYoksQpS{;E?%dJZeh?-rjBWmQ%TJ5I!#QAJWG20=WDO)s7oDIkyA;yc%3G!BF~a=@w$#U zgTM1#TwjVfd0wZ9M%hmhpGNlECamTzB?%X=(?qZArwFU;*GKK<$2GozikRkgnwXaT z6frLP^$;$XY6SrRV3LlaifSrRT@*AZ5c;#KBZ5-z?&6IRh#5-wiX5mu4n zRpwa|F1|w(R?%4!E?)N*nf)-GSJl0X^ZV7L9u2>(PpjdB`T6AWxS9-qs~0E3^)D!n mKl}XXo4Y?B&8uI(JidAK=++mvZce5T$K#{f=wiVyE&d0%t`8po literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz5_tiled.heif b/tests/data/uncompressed_pix_R8G8B8A8_bsz0_psz5_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..5269301d781345f01e3bab9e2909c190dab8e1af GIT binary patch literal 3411 zcmZXXy>1g}6o!vOU<)EdfdttCxr(+45(WWXKSn?o#Fk zQc?K^QqhGA$OYsE(o*CGzJ1Sg8J1R&~XFTvok3?zhVQDnH=; zUDdp9R^5GNWYX(aZ&>xYFY|NNuGufVe~R@v_t~{<`M9NLOTraF-A2#i(#aKGx65kS zogVXTmj7P*_bXrJ$FScWC9}j&fQ@x>36?mENL-xEVRoTL4=fi_1z4htKtkIBX6I6Q zU^$m6z!GHy7TOjtJCn)-%b8RGmM9~z&^8Ahr)mqZL>WQHsoFfqC^rL7HBNo72o00o z0J%s7jK||-8JugJ8gT@9%`||TTm+U2sqz9ePK`JMi)I=?O)dhh$Jmag3a~^Of#p~# z4>HQlF}8_R0s6qGJg`ip@*tzg0_jL?9&{Y3&4Y|00Zdns8L%8m<$>i;Di1P>1Yl8Q z2A*o1O>oFeBUs*vHt4}uMj&u$l1*^POe3%yOXYzDfxx9nHo+k?jleRI%7YYw3{8!W z2Ix3an+F}tIpXI(KaVUUPYo3_jlgm!l?N8)9D(Ifs=T)YzGU)Xc?XCC$S4xP$53tt zEVWb~SZb*}$S4wkMUe&4Ky4m$)})#O%c@i! zSXQO-pe7Q5WmT#vu&hYsfn`N14{9P2SXQK(f~OlQ8(?|NIfCVFXoDUskDP#o=}t7_ z2s%1y^Pq!V1iwSshk%OdPBh{OENfDEU?CTQg?$L9nC?U)j=-`il?N7b5m?xVfQso( zG~x&>D^hu2As2y#ePo!u8PrAbdVlY2(J#C07v)aTepm1HKlO@!`%5|6Zs$LAI`F+N6< zd|Lg1M5WDYkKOq8*F8I(XYOk7f_nVNNAK8;yCuU1 z*3MYb1^K+s7pC7{oy{_PRHUcIUH`OY<>sH;GMn>w*DlJ2V7%w9`Mh1G3pdAQa_60_ zD03cnXh7HKI-}>D^N>e>>=4~x+;cDe1~tr0&pVD!o<_U2EYdd4Z)5Pa|NRF?zZ7{| zui7|~j%XPs>L`-OtE^Tk3Sxei?5}er*F~z@W^1)sHSDIaaYS&{dAK=jQ_@j{4mU5C z%QiVs=ZZ@bDg=ZI0c~fkHoIR?4WQL8?*V8#d$4omHanise%<5|^E8BfI+8UmM`2Gw zSN+Vu85?np+akDZHot}E}@iJimhn~&q=Ts z-!9q(1A+m4mw=TVNHOT@2ws4;wFkqxsow+8`#M7R=m={hBkyW6YQd{)rloZ+U_-VD zP{pu0#s9QGLsv%;GlBkBuKqTm)NfKu?>w;RJRrO`)K5o}11Sbw9l;9_97vg^n63d9 z8andbw*HLjToFlClWL`R9@x+m5rBQFBdn2#A}XHNHNc7*paYV2EMi_YHimQ&*$5rd zz=4EfZag2-MPws%NF#Yc%&W%6kS-z{p+g!tkPxy+tQ5l&Nk>w@NinGhp{r|vl`=~) zNll7L-;+C6>z^s8+W%84?!Du2Wz5lH{@&y^P2Sk4NlvPHewLX$`E2V+()=h*_VWj;L{?GH~6o*wMyS5T5i$4}ypYiU-M2ga}sAf)}O!RS-ORkIBX^H0_c`rMLR?5Wax#;L#`Y z73$2kb(&2P2`NaY?CdwQyOZ5-zorxb)`GaJLK*A;8ubk!0|09)6tPP=v`WKoMgs_- zq!*7c_2<{eHJg(5h1>F*LQh;&G7j}D3;l*{wmphUM_}Ox&AOz1;RE5Olr4NBC9$nz zAPU3izU9e!=-vs6-=vBZ_FbvGHufvBqx1mc4T`ZXDYrv&s1mhhFH}DEMJPcT<`5lX z%^LP2D+0_Tw#XGU(j(>3IE`V$X|O6)=nnIEjM7u#T;}V4 zuydN0wA5{-g_K+{h*HZaolIul!IVp-%j=Ev8;KE1fYEfsK-BSb8S!%&@eUZV05TqC z%B6A?1Kpo#N#zZMXvlFAFJ>8vXRB0xy3(3t5i(-sFk(3};@{+%FNHF?3?d=wo%WUR zrE8zbrm(N0wtw#l-+q*F!`A-zR+lldC&o>gC B)_4E_ literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_RGB.heif b/tests/data/uncompressed_pix_RGB.heif new file mode 100644 index 0000000000000000000000000000000000000000..dac85fca2e6bab67c8156da0ba8512435b7fb3ae GIT binary patch literal 2204 zcmd^B&1%9x5T2<0ITa~|mL4R>Qb<8tq@|aN{ZlA->V2Et=s?yiNo?_Ee;%SQ;OqGc z>1>QiKnha5XeYCoZzh{>laFOs0622Op_1rSflSAqKnK7$l_F%iMpo-_*PlWFg?2c@ zIzDt7O;Z=mN7m=Ah$rqT3}rmapnC;f&(>M#1`N8$jJA$Dy97@V`?R7i(m19>6q0Pv zx3MKzSLpm3m9HocQQ02F0}NFBfN(|UG|GwvdX8q&W8apFQ!GLWwqTpkHE}j6&a6mZ zLDe;&dY@b!F! z_)UIxH>i{rg-&NPGrQmJ&U_O}i0E&W-s@OJ8w6q7kt!nc)?%3oo`bYIVK*sUBCUe7 z^4T6=?CtwJ>7R&R*p)eOL8~;*Q68Qvs@o4ZYVMMUAH+LjJ2ww^RjD3s^ zH@!fe#^PFX{GxQCVegd=`mn#%K<5kaS2)I4)MCIGK8eRt5bF?jhMF`>zu@iQ%zfBO zW{?GZj~|WPt5%HVg8-vHO2?v{MH$V9#?v!)FUFxrGa{ojB&&8hvoalEni*?nP-{pD`l@v%Z9wqsO_4|05C?s7d-MbhkTPH&pCnujMz3g z8@Uv-P<5@wMs2+o6tIcGBdky#U?`dv@Ho^V`J$n2Tir$!uY2)F zG$mm0d=@2Ao(}rwGE~ApQeEj^B>nIvkfDF4(vF{hF|^k=TL*`itwi2#{oiU`N894x P##LL$RxAc7z9QZMT5#0` literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_RGB_tiled_row_tile_align.heif b/tests/data/uncompressed_pix_RGB_tiled_row_tile_align.heif new file mode 100644 index 0000000000000000000000000000000000000000..c2829edff81f3ba5d35a30765204b6c194192c13 GIT binary patch literal 3068 zcmdT`&2G~`5FV$YNE{GCNK`#kz91o_AT^*0#06CTTB%Y`+_(0+St(9djtj~y6dr;X z;Pv_n<{LZSU2jd3HbSA3UC+$!e6uqMs$`cy%m-2>M8UIE=7QHi{Xsm; zDv?O5D6eJapN`+{hrAem7NdA5OT+tGZQKSx1aVlB=rF5pjr%Fd-@JDK*%MHjotYbdVV!}4;iRZ&8)iL-6b?FXm zLV5$A``|Tg5Z#3w@S{^o^-k&Z3GZRTj2fR;I=^dk4+~FbSg9yxC3)U&BbF}b7PHwS+UOF(d=YOjuK!3DSE?)+=4dseHwN~Ko8;zllazS~h%UscueBVQNRkHgn( zjrnRUEmLJ{-S~NEDCWjoV^3~B%egVn-c{Fybz`uy6EhO8dSl5BS!h4+t6BLUXOCp* zHe#C@v}=b+Cgs6od?aHf!jEbw!{clmpG7hbzo~o>mT%yA_rkynppDtHaj=!D(m-6YZ~NUhEK zsJ++ndC@->y|61y;F4BpY@$5ORn_eW?3J73VL-fd)(e*~*Olsl5yCrbaAaxZ4SRt) ziN&>K|5@ooLuX0{edvlBXtM#k%095H#eie@Bt|8ObqHO?n59LUgWbfbEoducqIuXJ zPbHpajBB^Q=oO`7FKvcE(rD!Fa{1Uj4Y#! z;c~KF;LOaCg^($)smaIW)|l;Ll_|G%o>W~eU;ctm0j9j@2zOg;eZ*I)72 zzP>)tE5qhx^^_NtaD?Bai|^j&=YD>!^Q7u(`#Qd`#k=IBW=uCXwtt%6f9IW8T}_KH zWg|ej@@M@7315$Y%zGLoQl1R@XEId6KU7`mx08N23}oovs; X?cMF#b+jY4>Q@aRYq1!l_(^>O82Q!k literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_RGxB_tiled.heif b/tests/data/uncompressed_pix_RGxB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..d964a29154ac191130b8930876ab58a3d6ba5fdd GIT binary patch literal 2811 zcmdT`%}(1u5FRI?6%s-{AhqHU`N+jc2?&)N70@=7km#jn7JHqn6elakwBlx<@6l6V zFR$Q!<7R?42OuO;lwHk!GqXFhJ3p38L?7bp)+Q!y5e8#Vo0!OJB|1~A!)W)Se)^v! zvL?)gXZ&*c>C|VX|5Xj5zAg`LTazW_DGzJY^oJo!jT7=PF}&}Ln^$1>j2YlY4Bpv= zplcK9W)PZAqPm*pKgOmOm>U}ofjeeo%MI{NmO<~V8u1zS#IzG8HUc&;brh633Q9c%DMyw->u8IYe~VMCJEP%+j*Rj@o4)oh(_wTI>d60P mvYuc5khb>^g0u4(UAL7E5;e;3lll+g4At}i literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_YUV_tiled.heif b/tests/data/uncompressed_pix_YUV_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..b84f32b091256a0a46dd223b50af6b9cce7f7c25 GIT binary patch literal 2204 zcmd5;&r1S96rMG~P9YH#fwIR4478AkLzS+@X4~lGLIDRwldvCv)9p4+*C4{Uvepk5M$rChb>x?^u80#+csf?i&>UP6Z zln}u!f5@dhuI`si88lC5({8X(xFERihAIPNmN#0K^pbnTzz5B!NSm4mUE{ooJIWyX zDjb#=c%7!j%Py@k=|6Mf3D_1=mh~VBjSnsRJ(o8d;zhtF+K6fGcYcnvBa^m zF+DMkjXo_PsszzOsB(O~yaBPqv9b|MjQndLGaC9Q5Z$L%j;q?Q#nFj>o4SdssdA_X z*Yw1(Qm3l`GO`fSea?tDx}{zasG}Y|@X5Sfc$M?mZE>fVt2x_rD}P;}Ea%d;kGF^)w}!GD literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_pix_tile_align.heif b/tests/data/uncompressed_pix_tile_align.heif deleted file mode 100644 index c80a7ad4da94494f46bbd6a65c8cc2ff22e7fc24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1064 zcmbtTO-lnY5S`tw3LZp6P&~+b6JdpIQ4lXm{c1tz$$Ln$?ZBoRc2lLdiv9!-9{jI$ zCf)vlW;QeL%_Mo74*~$kg_~Q0MGj<)6O9ExbYZj;TqEmFR9UYmfJN!nobh>d-%q)i zzKE$RwI8@=(HTD~qIimBB{@s(Afk^f8ZyQ|M9&eY^hYj|pHQOXHk(Z)4vZLU&VSL? zmT-<%R)mMxSl_{%e3yLRiiXFq68nKPRuOg}fi2i3c1xOl!nJh(c8EtDV$aq+9?vKy zwGtaIfhMvo18k)b9z*v)D_8`yb_1cS z2sp_0F2YZe6oy5u^`NO%QOM$>V)tCVU=SDlh8lgK?dHJ6LSd?y^Ge3^+`Z0^~ zlbESo*Ty}I&eX1e)>F(2$yIa<0X>9Z#2mg-dWJZoi7Zl_P@%(BHJ?cw8Zpsa|DY`` z@dB+Zh!3%{^#p`l|gJ*2AiJ)(S=ZfVqyxWufL$tM~)mG_G%8_o9~!?q8BpzhCy!WO9{esmyxU LIx(VhbSwV=v@;+# diff --git a/tests/data/uncompressed_rgb3.heif b/tests/data/uncompressed_rgb3.heif deleted file mode 100644 index 036ec37983e34bae3ab6873e712b8fa628464d1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1004 zcmeHGO-sZu5S@0bf(H>16c5s)2o<_TLA)sI*DeTq5|4%?-3~NuXtT=R6#WtY+jXXH zw+sFReaYm#naoT`AONtRx|ubY#z0`sG^POFvC&R&jL^?iUj0Y_i_*24`EGnQ2ss$u zi$dkPN!+sNOq1o&dWd-`*$Xbgqe1XS%>EO}BgBGE2$Z3vFeI zXJ}16c5s)2o<_TLA)sI*DeTq5|4%?-3~NuXtT=RR`f^sZ*``- zfkp5Sh_B4NH!m|O2?PN4b2qaF^Arfog~l8pI5ye|_6Yq#mCZr|Sd`9d=DYFLAZ9bZ z7nLe?*SKZTnXW6Ke28T&xr#0!ppOuYn8PQMM~D^ukxhyNDs;H4rj^8@5fjbzC)&mm z&(O-6co$pSEwHB8q}aBiRa7Mclo>{z;Zx-#jLbemTw3WOA0~sm!x;ofy$NdX?V>Y#=oN diff --git a/tests/data/uncompressed_row_ABGR.heif b/tests/data/uncompressed_row_ABGR.heif new file mode 100644 index 0000000000000000000000000000000000000000..5a60fd6ec9e9d310bca8b35ac011d795c4f26871 GIT binary patch literal 2811 zcmcJRyKWOf6ozMwA&P_|ib!0FXe&fxBpVb#MNqgT2&ANmM8~i@8;|6*N9#=x6+@uR z3#6j*3-AJYfjj^&K)VGmu$+GsttPtW}R(>_P&iaCY4wcS? zi2AuIC2GWAn2rh;3So3o`WX6l@8x!kV!R{A=}0vT*NiUnW>rMvh8|54WZf+h(T|As zp{t)Le5Cc590|-kphR^pv!ijMcXN5DkpI%AFr-$SWJ0>Gr>2>pcmp~8?-)778k~gx zdXk%zv@2G`Epd}nh%GvGo76+K6^bJa9Sk>`!B5ZWU2SrCS*5q>e((JFNv|@@Q(4w5 z{wTkwom-2{5>Tx0ir89T@zu6k`;P@{0nPv}bNO<Xap%?>Clkz6DD--;4#m=np`Q{vfUhS3!mufLYgDbQcvr3&kvI*jv{hS^QqV zAA1om@B5x5obL;kaJ~Z;+$n(n)jM|eMZHBg{XQu6;tbbY^!*_V_JHg6z0cxYL-^ii z3Fk{Ezsm}xcBhjMD%CQ6qem*5af?{h1eX1Q zu2}g8`UCxeen5Yq+bsG6;hyo_;%fwSPGsLXckY>)d+bC}NLpR`BS+{D!eLeol}dGx^BD2X?u#uCN$;&c3Wt#?yqoGgF;y+Puj=7A0PAe37JUe< z4~Ta@(eRPhBifOGnTJH8wq*ySKyN4hegytgr&&s|&}lHHxU46snV|71I9>Nre}WpU zgljoS(vV_DEvnn<7Dc5tY1J)?49YFixP@CAw*_FbE~7U;UK)5Nz~>ZbFp{rv~E zGDt!{pG&aTW*wWVDWW4AY;z`X z1xQh#f_tx1q>DmYb!CcK@IS4z>e5Lot-5g1N~_LsT+^U+iLC%FOE!smrGDmT5-f#= z#;D;GqJ^D3mB1wLMZYQb@SdgEb(B2BYv637CL;s!+pX;&nW1scT-iVD&$ zNgxX}iW?Laq?J}}IQcBC>K9nDdM_}lzZcjE`&aJ;zEIMtwE~KpYNb^xPFiWzl9QH> z_%6<(XnQh#ABEcYUh84x?PlZfAc#Wmi_Qn0`9s=&{G|Kx)yHlY9j-rL@9xLX{HMLo OeLw0Z{v@YAslNbly$;m? literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_B16R16G16.heif b/tests/data/uncompressed_row_B16R16G16.heif new file mode 100644 index 0000000000000000000000000000000000000000..754d6b8af06aa6d0ab68eeeaf8fb21ab31bb83d0 GIT binary patch literal 4004 zcmeH~&59F26oo69=yDuHaBwm7QiKQ-Wl-EG|*^NIB;S2bB zc?G>EnGeb$AzApd$qngq@44sH?Nrq!&bj@5b6HoRf9NcP10VX%wH{Qy$;Dap2IX+F zNS&)g(U1$@oV_^CL}qXEQ91N;;cgw8YOZS8^B@ezg{sbT*RqdA>r}YAXX*VAMmABT zeeYS}+t<~_s0b%je(qI&5A~!rybN_QHoOz2^}J#Efol8i)%jE!t)%bmqN+>79e2}p z+zrc~*_y|O#Ex^fEN|)2*29PuaW~Xee%-U5(fQo|`ptgBepTkb?T92llSr4OePuzu zN&}zjOHL0=`LvGbDp#!Yvc@tkJ=Or>=L4b{^o3~P(i*RL@>N>AAo?E` zsRs=_2#*&&Ml^6~jaNMRDlJ|R{q~*z-Q8gCLCy+<=WO6-7UXDF)p*fu;zf&BcS7;S zf*#0R5FRi5CUeo^WvxxTXz?!Ic>B)U7xtAsqGqq)|I|LSKFIpagV#KTYBcoH8ZZ39 zIh#=nQ!hQd@tx3JUN$#f11~&tmwB0o7B4(rY9ZQ~Q;v80&j0Uja5f-k#M!`euGBH& zfx`=rml~ZA4#d0cPDro5FpktqkGa$_;(=o>JYH&aLO2lb_MPKhTIB2z9rg0PT<2a@Ho3;c`lDhz zv!!#jA2h5LUmZT%%QTq1&L_pVTnaa8-&9LgM~>TmJRPXled;>$C)PPo+}M=mUGFDy zMh(j6jyUDo$~&G6{C<@mmFj=<^{f^=@%3OTc+1c0B_Zo=_2si!=X2F)CH>qSRCOV^ z?ykG8yC$nAQgcrbTX*h;tUG#G(}M&e(?S}(?dvLEak7o>r?oF%We;0bkp~k|$s%d1 zPS+>a~657{spmxl$z+^bjlPy4qypfWE#g~b9bvjfT2JXGzKMU`gLx#Xl-qNuKB zWp>w2QunE5Olk_sYP`)srHtBlF)G7>#6t{Ot3nU$dD1yyZm5ZKFRL;=f^nDT$E^8i z(=1UCb%-%*KAN-Hc81~f;w)H=w>hX_Pv0A@3f4LzhyGwMw=!MP4c+|^YyTs`qBa%} zR;Qr$S?qUHaPGX7IV(uVA;zrvXwocE5Os(#Yd)GZ8%JaHSvBHZ{1B-Krdgt<3cdD< z5jUhFm}ZIoP387X+&R=f@4azxl^2UtuiCHm4$B;rQ8ORbo)3FM>?zTXVNXv%bN}Va zwl6vc*?q_oHC5=fS1inlE82|WD1MsdOd(57nk9-V%!LI*mYg(86jhiD3x+H?X_hFe zFc%gy_Tuik_6wIKEWSf{LM%`F)|DE$=GpOot1P=d7|zOa ze?EOv7Cz5j`f-^Z&Zfojpe(Wvz8Pi9U(Wse4|>mEyzR}(_q&gGdq=}Z`NN%e{k-f| K`Mi-|(?0& z{Y#muL|26!3(izk9=^MfWD%+MvGDLg^Nt8xw@7yYQk+OZ^eq&+)u?G2!O+ODCjAaJ zw}=m5qYQB!3R@+RcS)nKSy@mGbt3OX#;S%35n{gqDmJWGMZUuN7jA$xvWeos+b^xx zH$3&7QPO>&@dwNqXESD0!JKii?EIP3_kXjz0pkpfcv=3v=Q6T9i}7n_SyHUtnQ?j9 z?;HK>TL0yFGZ)TY#ktnQBD>ZKq<;>H_D6Z9rjb_u6S#?A-MQZGUT}JL6Xg1_f7lPk R@qyeA?|V`QMivh5;U~g^eHj1% literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_M_tiled.heif b/tests/data/uncompressed_row_M_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..05aa7f71ace3d5ed7cf0301c786fdcd402eec541 GIT binary patch literal 990 zcmb7DO-sW-5Z%;*H}N1SA|*#J5n81vcu?wB1)(SL=$dTW!ECc6sp74oCx2}JLVS~E zZCd>5gw4D+UvIJyA;eagy%|H3!jPX?%>J@>+HpDP zUddq)siJVrP^OD22k!<&vCpi2A{;z0=a_x%4se%f2t^L!Y=fv;$wot;x?1)X^A9qK zfqx|9$M74Jnj!(*V2-nHWXd%>iO-s^O;BPXnwZxCvxbUQ;1$ciJhyUmlZ=*S6pPni zYj5w^`d$Yz%VD;GG3?*8S_oV;+5zM7QdG?P&^fn)Rbhq7cJtI`%7QAjcnrhjUuhvc zEzI-DWP$P~wjF+fRx+IWgL3oFLbD8($SZ~4&;_CDRv5D!o!7;6@hz|>f9+Bfy4PW% zR5y)pR6x?bph&sBBo0Qt3fyPP25#}swf6SCv-4XoQBUoow$~32ZckQ3P&||zi?D)g(H0Su`mY6{C+{(N=|0%(K9aQBLrp|aegY3Y z`8^8x1pNqYZXPRmh@fTs&D-Q6Xb#Ix$jrR?J>G9--h>d*%`iPMkq++?MC?fEkjS|m zsnnAgWH<`O@ysPM+D{u_?2DZzo2~@im);~8E4%TE(P?CNInXP5JoRPOdrS@^}kdx$ePVH@cpEBKD2(h(1VzeEm_=nZWmuf|YD??dO~C)BVM1zyVhU65ri zp%1GwXyyW1EOWVNyk8)e|TH|^Wt(f=Na>l+};eDv-)+( zUd{PCq9kv_+wyP2ZR=|_YYy^2f10VD7jMhI4VTej-Z;t1i)z*!Hz%^A)89D3NY9D4 z)mQhge_YzhK`wk)74T(hD~a0qSs30{Uxv{+`X(Qlog8V7Qx!5gN61Y+v&G_|*bZZ* zwvy>96==_WuE)yViKoGyuLAe2PDif&Qw;Ci8$5mXdJwDq2g9|&?)v@pwIF=s`-8|! IQv5ys05dY&`Tzg` literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_R7+1G7+1B7+1_tiled.heif b/tests/data/uncompressed_row_R7+1G7+1B7+1_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..7b299c0a56404f30135ce1256ed319a08f8e42a2 GIT binary patch literal 2204 zcmd5;!D<^Z5S1M_?J0y3Na!K#u@qdW8`3}yc1hDVfkN;h_wBAW7Izz^2Aq<{Ge;ag)yn8+l)HvqaR z=ysHti#)#3#1F<67Jg=IGKSwX6YC0y4~g;Z+IT_^JMnv+a1lo#IZ&LL9**)M>bCp$G%#iQXAR74}}_gN6V^+UOY-$RZk)P?zWfkAc6WNMV| z!I1fUsfvu%$(~8I&)&vABfFE;5~^xC<(!JJ59{?79t2e$a#ixuT`fU32n*9@IciCgBMGde0#d!UN*`4Duj66uSAY8ze)?Wmaf? zF&Y2RsfnYnW~ig9Vw~P4I*sm3If&dphR*ws?Jwuo?LtpKb&lFMC&wp8Y4$To+Ic)F H@h{>L5w;2j literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_R7G7+1B7_tiled.heif b/tests/data/uncompressed_row_R7G7+1B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..081b9b1c8cf7a93e26c4bbbb5f50ca2d41fdbe47 GIT binary patch literal 2124 zcmc&#&x_MQ6rOZzy;%`K5nOW=p@MbMg*_y){@Mj$>A`zUCfk9g9nx%NFD9aYg#U>` z54-<|hwdMs=xq;D$M4IeZ1G|XmVRaW-n{o^^3BVeLuRXW1pH0TF|O)hNDf!xxE3Zl zg53~xaY;1b?O@Ga*cmpU0>0A#zeW#%zrckUy`gjxR5@&;{=W9%Bd$J8q98NI{Isd2 zF$Fyjpw07~1^@>rFxE@8YAA;~=5$s*q1-xzm{p=nNvGLQX~@H|EV2izZ%V(nDw zID?+)uX8?v3!R?V=};&)f+RT>xZs}^SQ(X7#^SSfplQ5P>( z4$af?=sV0A-mkX%S$@83ZTpYDafbb_n+gs4aVq8BaPUe-DsZ2xo^%h=L39+#$bGA_ nu3LWL+xH)~o<4isO6BNrd#iQ0{b+kDir<7`D+z`fzWRRvp=l9; literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_R7G7B7_tiled.heif b/tests/data/uncompressed_row_R7G7B7_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..943b60655b07071cb2ff5024bcf5b12bddf96a05 GIT binary patch literal 2084 zcmc&#PfHs?6rYXJda5D?rBK~t5mGQp6?##uS_6g9gZJ(3tQp8A!)8tKVpi-2=tb}g zc<>W=$RYh69+D5xVh;rm635@$nGpY=EU4ryGw=Q0`_0UI!`ofP*pwgb%0T#Y3_`lZ zh0mBZ8}P^>A0%J$%AqzHlfsR9HtCJx%BoFH`-@ZY$~+;ymLdugmW6p*l&dbG>@u_P zK&%4kkzX+13sJ#|qPK`LU z6O9QskRJ39%d%lM0_zj@T!rq*5VC-6(UhSHjypmdk#|zaz%enDk=@T6{KV>`z;hy{ z)IS{>Q!0k_>b%{8GKfN;Kw^vmGAR*=Nn)>iNx9rg2_Q-E3V|7=NR72)gD7~e5&Tvk z4US1kbdXH<@&dO@2yzAV{{&uL15hUcG$BkyKUTZpJ~tE1ps=;+i5m!h5_7Dkq+zD7 z{Uw;XHChd1-fhygqBUBL!r^SuHm%XxLoM%`EIl)Q?dh3F>_(UO5v7IW_T?CL;2Wu%z5WLXGFT=ODEJ}go3-j!?g__U7iDf2 v!>YIAa?k!DqLQ8bx$__9bD!6?av`rT<`;6?OCOgOJpa4v<^rb{;ctEoJ?Ekr literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_RGB.heif b/tests/data/uncompressed_row_RGB.heif new file mode 100644 index 0000000000000000000000000000000000000000..30c440000e97cdfc1b8116e91e416ba8384f2306 GIT binary patch literal 2204 zcmeHJ%SyvQ6rHs7v63Q!;-X|JLWEW+iW{ZAS`fN&KPHoQAZdm)Rl1ASkMIZjd-(;u zC+Q{7(jTy%lAL?bnS0xuMTrpN$WNvw)P7SCz(b{dA*|C-B@!B;HS~hGD1|WEO}GX> z_HR2jMEgmOyg=m#_l!=${FFuah7KYZUF}9#^dVS1@XjukCt8o_8zItlOpU56y2;4Z z-B1n``fqJwLp;^SjffBQ*yIM)4fJ%?jU3|)HsRWLL*o%wMNMppZK|$mXNQ!Bx;9|DhY&77uiQUaJ&Fi@!MKtT-@?y|xTc=I;n zsR2%f8R;U+bs4AWe9m(`!#z)-|KD7u!8tL*L7ipGIYEUxC(LH(fIQAcqHxi#&O(KY ziB%UW+`qaR&xZt<%OtW4TIr%LlbFrQ8J>rWIwO=W@7V0koDq0A31~%Ls~PiuET6zE z>LO!Qz`Be}cY`+f{8*{(IC@r|miB`Vl--XbZ{jM?e%Hy+&fgeXXXnn{{fiT;xAs-r T8Tgm-qWRjA$_eE-p|^-%49C?2 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_RGB_tiled.heif b/tests/data/uncompressed_row_RGB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..a5d6ebcc5a1cee68fea3a704ba40e3bfbcc1ac86 GIT binary patch literal 2204 zcmd5;%We}f6!oOxu|gF>0|3DmBpq9bUoJb!l2EP}(cO!^8@l4ra0)siNSlTY@!LL>FN8VN1VP*ArVEX_*DR(- zSv}gM+h4k3qrW&P>GrR;@z2EmWUYnGX1(S<@*qvKTKPkU>qM7_>?_{7t1ap`!oaeC zC8obZpzIKT3RwyrFKGu6`j*TSm4wgkM6iT zgFFZi#nZ`y>`)9RXGLYq>0|3n<2>(F- zUj9P8XOg>_W+u=I1y}bh$(=dp-m^1zk`^k2co=6FX`e<;OR7Xj0Dlz}1(pgIJLZ#u9;(awwwLs%N%<0-qgE?~GgzH|Iq!Gm( z(HA$wO&Yx>&qIog9U*Sf*u$-d8xb{N`j{>lfqkITB%lb;Hu~RtKYr34c9ST`mV`LIG^Ybr`Nh$88U7OgE^TK3P}LS@*E&#By1dt^Vm|RGlb_#iFIwpJUbM zoL!6TtvI)r;h6JDP~1q>8+I4fKHG6NTpbHGReN!)Vu9VNnbov}Swuo3=#fcvt7cYX zz$_x65!P^SCAX*AY%5RJ_MDA3p)BooU^fL}L1=GR=+7dsCBag!q_e#Xli>%3qp4Nj zuwbAPRz=M+Wvg6=NG(TbL3`58ts)s2ZWRhLy4CL5f6o~^>H>8rM=$V1+eZlX58npE z)$*l-FNAu}t8L7bkpvKZanN6d!P)7bYm5qG;i^1^O h^TE6KUj{RIe(>sGa2mf1UhIDz26B)D^NfB)_ze?j)mi`m literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_RGxB.heif b/tests/data/uncompressed_row_RGxB.heif new file mode 100644 index 0000000000000000000000000000000000000000..de274d5c8b3ad05d2f50e63d76aa86d76c5cbfa3 GIT binary patch literal 2811 zcmeHJ%SyvQ6rI$n2qG>7#YM@|O@&qw-Bo;65Om|(F`3wbrXA8$aTlxq;VQqEU#RzF zyre~|NVmBmbME_2&ZIO#h^-)gF`*6`f&|!6IuOEXgesQsku*DgH?pb_Mtd>qz>AyX z6BkbRQuh3=$`jX&j>A05p|z&FeGgW(B^uukokC?%`whk_Sq&$nsV)Iv^$(WN$zQ@kO7Sm(Q+>H1~%sBnYm@O9FNCY zHp%?-%rqU1>|R4I_|jn2WfM6uYP)V bSC7=w!O=neF*ua_jfbXG^-vCC`bhl*C9u`< literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_RGxB_tiled.heif b/tests/data/uncompressed_row_RGxB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..e438fc2268c6ccf1ce6b6f86f9ee506698b51ad7 GIT binary patch literal 2811 zcmdT`O>fgc5M8GMgoF@>N+1rEk6eP3fGW5Zm9HWpl?!JUd(*5GCo9JV^=1nHgH!%q z{z79w~(%8WD&Jpu8FqEJH+J;2)&})rH4&7bv>U) zy|$)ATZb&M(VT@Hw%;l@?8&-W#u}8$LPVm$EpTJ55ZURbbN)x%=w2+Biv_E|Z-Dn= zKEJ$-=HyL@5+Iq1$#ieXC6%5I>L-||7LKl#gdbi4zBMUl)uvuRu5~V9d#f4UbmmW4p zc#T9+n#|Z4E()z#G>;65@NdsI=Ar2o-j!L^oJzPCoKLjpu5eNIhhb^V$!z-3v*8QW2B1Ev4s$9|r zwEOWOyB-Q*bd*yfmsw8e3ou?%$K)asuOB>S#Mgj>+LlYvd4)7U(x+dhBzXi5c^A|qan!i-Z5Wj(6z+^&`rRgV7D%So0Xj&U`&ELsnKELH} zvsv@k+U3$K8ml9_0;pAD84Ume*i8eU|a=qe$LMYmg?=<9?`r@bCdbd`|VtSDAT z_6l7sA@qno()7<4QaN+;_WEyRuh6*@!i4a0u{R0f<>F2V6T-`7O~^>VNs=km8IRtp zSj+H84^()XjpFl2#o-s7_rvmwq5b$t>-C$DtxR1UJU?iiCC}v3{ZDPFTB#i8_=@-g DFw?Rg literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_row_tile_align.heif b/tests/data/uncompressed_row_tile_align.heif deleted file mode 100644 index 9f06aacdee7d344401d23f27c30baf4bbffce30e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1064 zcmeHGO-sW-5S^q^!GnkhiU)}|5hA2TLA)sSs|BGa@5}C{9mqCIvQ>Jk=uhzA!T+i= zF-yHhufApGy_wyaNfs6Wb~87(2D20h%oB|nKyYNV6PzP-Cn_($C4fcgyk@=~UG`&6 z#&=?>a$O(Xu;@&EDj>g)c_BH9E+C*q2!_nz8_7e&DNW=g*&YQtY@*pz;=qWp=J*|L zX^H1(WkI}+m8~~eldY3&T2b*C?!>kwja9@Qh+qX)Nu5*AKCwp!V2yOZE@VfEA2=W# zk#Vyfv_>?0^c&H0`0`3cA4UoHNocm9t@d>Q3xbc@YF`Jf=P$pP)o-z!|2M_+eTTN% z*ZtpQa}&d?)Ot`A_gbNdZ!p*Ks4Ub>Y85}Bo5c0&?H>1%tLulP)Q=~16c5s)2o<_TLA)sI*DeTq5|4%?-3~NuXtT=RR`f^sZ*`__ zLA=$zGI?(%^D=EA0I;9Bg*BMQKw!=^rU2ft(N1uUFw9h5{YU_d(zTlTZhAEexftGy zLgl(?+_LCQ)8)~6h@|m>pGMB`=EW-|1i&OeO)#Cy8fTv{p{~L zll%LCXZFA(t+XE3<%3oz!duLBIIT)Gms*9d=(4c6fy0v|y1sdgD*bYr#L?_5PGgxS M=Q=W?c62Mh0ld2)IsgCw diff --git a/tests/data/uncompressed_tile_ABGR_tiled.heif b/tests/data/uncompressed_tile_ABGR_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..157944f4bbf4ae6514052562de5dfad4193e9ace GIT binary patch literal 2811 zcmb7`PfpuF6vihZEvkg7E|6NfKwhD4QYmSL+7(pv9~G78rV_il@tBMhCzfNVx*|=x zT@5d*$z5M(G((9t<I!v)COt|wSq#@7LuAs+Cb78l2*(~)Q6(9HHV2Nj_t{V zK`EP0W!8XHa4a%+%(k;f3Xq;WA?K{=mRV+GG=jv@Xnr9cH3fC%Z0nF6Yb}8mAr@Gy zYuCKp%VPT$TBp!}StC-xEM<9$*+{*>J6kJ}cQoHsy`!|kQa0aMp3BTEbI9{8KLStH z(X~9pD#%VD$6AS5HXJ(EC1YJqHW~TEMOLq9N+D}xIMnBgzpO*j{}$`oOQ1(CWu3b8 zB23Nvkd(1zH>~>HWLcXt-R4<3k%P(NXq~IO*xQ4_Zy*2fdAgRpSn9H@X;S1|+nTl} z&$apFB5^#X4-~T|)+J*h1J-eYMY3CHQj@=u))J;zr;xo!!j!XEmtF+#Lh+%djVNQO z?x!%3a<||6ECc0x?^Q>7`$;c2YRSO+q0+XO{~&EXe^Gz??rS}f$D6M=>xbbh|7GKQ N)0g$g@2B)5^&faC4%Pqw literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_B16R16G16_tiled.heif b/tests/data/uncompressed_tile_B16R16G16_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..3937184d173b01c57c59d2921cbbe1be9b64cef2 GIT binary patch literal 4004 zcmcInO>fgc5Z$zaW2q1l6^F`4gcPI(RDrmF%2z8P^~BxSn`Wgru@V>5Tlx4A`~m(R ze<94v=4G?i+KC)IRXn@<=FPkr+o__IIvNx=d1eMDN(_Fe%|NNnlS~&e&cyn|bTqX~ zrE-%LT*H63d~+7zF!~se(~({T9^|IT7Ev9!9-Gl5!LIvSb>vU1a{+&FD9gvjjHMzD zUu!Qqz`MUM}3Z~XIV{9m%~oT&1jpBLLAFO-d)hTj;i{!_1Z)0JMt&TDNs#& zX!wb7_qA@4yKvbVy`Rf{2l(eo;V!j@y1uE)J{73xsuC+}$Qp2b!6WNXu-yS5*)O$mZ>w|n|Iu(pz612``-9T}uRSze4>kXY!NWKeYO;HaHABN0sb&*O9rRQJ z&CEf}{ny-#hB@H<5UWQwX|_0Xl%wr=__Ut09qLbEyN<#fOaeN0L+kpjnu5K{?VH-1-0;A4dQOR>Lm}-4Kn|#u#iKF*sq@&B}B)v{_8htaxFk1X_?mvCj gd;9KlZ>qnZzC7(+4PM00PrmeH-OJ)xA-|^o0npWDvH$=8 literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_M_tiled.heif b/tests/data/uncompressed_tile_M_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..07cce7eecd1b310fb994295d9cf8a194cd277ca2 GIT binary patch literal 990 zcmb7@O-sW-5QaCk;7vRTib%=PON3S_3LcdDRYB-UJh~>Eb}-v4Nve3O=*b`3zYyO^ zvowv7GVij@S@|Wk<6`V~nT9&t1 zy#88yd&k!II*?fovke@>{*Bc_#6_bWFdi?3V%CSwxfQGmD^#|dN1G`Ns%Yae43mGw zLU>x3=ab0-@+P(&egP{PPW^%0{Ik$3gC+7x;WxM-RNV?=mcw~nye@tVtjYg&DTMBI zm?+gv;~N!_bT24UZZC<0k*@;xnX-Xfd~>b6eedl2)=Sh=`>5^p!$Wz{d}vAKX_;pD G4nF~(3AI=%ytJhyJ0u2_E0yXC;tKu zJ^6nW@)z_^Xmj&e!9xTs_T}}eM0AArSo~wZ~VINlF z=bGyW9&D3ZNOl?Y5Sp8?d26C7u*Ib`nE3g-u@Kzoh75dXwuEi8J~Tdl!XB1<&k2?K z&MV6*sV5z-U49Zx6}m@BJ++mJsCk;I#Ke}hv^x5rQ$_6cgDHVZ@g}luhc~v zFT%O=+56A)q^wiaEHaiLuKT#iMV%_vRUy&p*CiIYNM~HsDRQ0&Hm>2hPEj+Tv?HP_ zE^20ZF>{#4i*Qj>?}!swX}kzSU!S5%{zv#<<@b#U*Wj4%TMc1ts(ziO5g?B(BbMct zn3a(c2J_f|iIbndBbr2p%2af@oH8jR6KhD9+uk@KDkGyZD>vo)hNe^n85J(~NPE{4 z)V6zLA+{!?SHhEy{ag-&y)zzpd#>>8w=(S8`b*KhbFcIC+3U_&>_6zPb#~Y9udjK% NH?G_9ok@tV#~-}F-1`6k literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_R7+1G7+1B7+1_tiled.heif b/tests/data/uncompressed_tile_R7+1G7+1B7+1_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..0c404607887b972f5eefe827d7977a57c9626361 GIT binary patch literal 2204 zcmb7GO>5gg6kI#*$Ek!;Xz3y7SPCxG4Q-$Ysia>C6oL-DtI{f7uxueK3OSk5{D}PA z&aAZ7YOC7OGtzsrZ{EC7VjBw~UZmwso~iV$KrqjxN`)A`&SV+!3^AK0i=r-t$W>gL zn)%zsr&EuI-uGykETkqr$yJ$Y)(H0_wOGYOlR%8{LX6ItA3a9-N~t9_@(|Zc06A{Z z)iPFRS#&9h?^Iso$TupFSIE!QI@b-LkN@1_84j}~DmMr-z#4IHXcJNEK_lS%gP>^V zFxjzSwr~TYADT`>u%W4a1jctltzHv1o2qgkSDSHU2U;Dr_COB*e^J|kiH$|_78$|Vfo(vp=rZ!;A7=}UMKvx-<40GHqolXyI9Q7=+IzfOXa1QGv_QCF6%MIrSK@M1ptWtjnS_}Ij z_cHk0h#Cxl^_U*)3^(s9BfSsmz0~59)g~-uqr#)QY5WrICTcz@t+Jlzhc>aQI>h>8 zOTxbvcw%*orH0r89c2e@z4FTf%EoIyY#mX?-if(E&{?F1>z$Mt1i?Q~3n|ams~<8^ zk@rcIxbPU$?)yBn zX${itx&2XMG8PCY%xuyxkDngsw5Y$b2X3EB$LoOzed(p)e@FC(4pGx&8h#M%h;-{K z%zHu%P>~jK-39PQN~Z%y9QyVNC;lvgQ2>1=0%r()ON;}#0egoS*Nwm)lMiL0>!#xe zF7yU#vTLjbYaclepflM(7qGP!{2OF7vz>pM62Xn#7J+Z4t2jpUL*wHoL|^!>9ma9| zE7{tL<7s_L)1?7_fbBRYwKbpCCk^on1TBAGqB;zcyoptWc4O>Q*NMtV&AEz_cF!YZ zTF#hCYEG5X25Trar%K782fyt0kvSPKA|2n zAf%%xS_=zt6exp{LyBRng;YC@GYrcrWnPVG>sh@rs+miLN?2&YvP`pt<;-+uNVcq+ zrJV|l=vWryN}e2ZiSiDT;P)$-RB!`}Sm$_Jdg8z{>;{0$te9c{9 z>n}u~>&K&^d+Kmke<#A8F2C^I2ah_>p1sGt&;qVm^BND&9_#@;k5#fg=;sd{OQ-~qTG z^#wTa1RQb*@4+E?01zCIdZ<$K&F&g!rNmk$vS+^CnfYec6Pq!1tCbwbk!am#5YlZf zT8uec5l?(tgVft$r>{)LVi6>{P5MRi$(~1x-b=q5cDQuB8jB>7UJmY?qSFfqxx384 z58^aPuYZJjSBNecX%W|L0AA7Pup5Z|$UoqOPet61p^rrz^q_BuK`b|5ZxY6JE%pcG zLz(Eh9z<~ny~bR2iLJwWjGTMWxvZfI*bdz)baV5af0`1(jolP+qoB!_}eHU0W?#l1o&D34${Lf8VIt_+K3#k^P`lR-7T zn^LxEYLDPg0zOD8ZCgZ743f_aV(D?{d9g#pS5@;eBU?^^&RK@wLLx)*a&ttB)y14E zkt%m`f`B_?U3`vY{uK<^qoyJBb}K_=4D|eFI5WIozNvXxg-iy}l3-EKizPDoRMW#B zG8eN)@NcyGobL~MuXreY@44u3ui5W~hXD`0BayT{`Q@(Pdr*7&>`krDhmY#pwS%39 RJKJIFZ4lHVe~{p7{ueW`q8R`H literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_RGB_tiled.heif b/tests/data/uncompressed_tile_RGB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..d4adc501da00e8c5a68f65e31cbbb0c11e7d49b8 GIT binary patch literal 2204 zcmb7GO>fgc5M8I?(KRfGQ9dQ2A;lq@K7h_PSXqPF9W!>dgdx1b@JP zFMq+zTkkrPB~9ar?3uUoX5M(ci6Vq}l9ksc*V(ZkgP$m!2@yTdRVlGXHlC!@q78*G zIw^e&|M}wmX^h4Ai=3rXWr+`rE_2I@=zgT9^8{%4PDJz}i_YQi-KX%G)-zJXB3(}j zsDVRQvqYce@=^i+)uu4yueC|$Xp>I%C zy`WgvQRT)6UIhwlx=rXaj=-UhD>CZ56I$Vx*fgtE05OR#Cm%qTLFyKW;+uum85*Kt z#4Ruo;!{zZesEKlwhOxeO+0Nc2wik@`n@2lvpeZ}V2XyFt9_t-4K1;%>N@DW8+uvx z2 zYuZE72SOLdcA^(_b=|r0#qM0~3&FE9U<)nq6WMp=k`QZ?Jj+HvGJuwkwRPt}h(k_X zt$0SXUt19VAHnOojGy6V7<3L`H!FTD+_^%p?QlI2+HlQoFT1_noegv=uv<+;6>j@N zqMm1kQfG_#SCwiRf6`MGUljB7Dp6_tQTH4jCQDVa5lHb)M!~8N)}XKTJo{ zT4k)@NvU+mk7sX>BRHc^@i-l2BJg&>%Unct=zhRQlLS`x4eQV!oz5xb-LIrR;e1RT z;iT&k8QGq+F2)Hz$>Z}3_FrC13zC<-NG2rj^I0JP(hp$Mb*G4Dh(RS>_maFwN$#^Q zyTNXf_L^!QlT>G)v0J2faNEPJs}NE2F)+F)j6L8*9!r$Q=>FRK{fB1wmZx#Kq$44w zsnQh=)q1Y_E8kX9WGQ}CW#oiIu_aNxqI11FqyHABs^bpb6;*kXq*2_D8o`#SvfY!n zK(&1?my3nb*pC{)O{QW;(h<^(YKSAT4eFp_y8M&-QC7c7*ymzl58VbeY1+1bFNjwW z#KTSxh&r0Bxx9O!=Uwg7-Y5%)t}$#jz#S-&bOeP#wW_YB4jzU}WMQv3)|(+5D&Avt z&#Icw4OUy2{>j^*XbxslI=J{zN5Yy5**M^6PhMj?p<31X{OW40X+4tc=|GL(CKD}y zNnwOFqZ*=AEmyf9>1YU4tAVdTOL zhdP?+F8^NWU60qH-ls)89I7+ipv%oQM1?`stJTod?_NDLsABCj94c7VJ*}>O#v1CM zd{=bWJdM~!)j#>JsGeti9~VzGK6gOQMmJJkeJZ#kH*ZblQKV9(M6Pma>Q<=A^GVci zp4^LSd5)d6L4Ab(YjVlIp$PG*zOS<2(+ z10QA4*>sX#Bv~5$YWc>#xD-P_v5UW$Fq`tmHG!f CP}Tnc literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_RGxB_tiled.heif b/tests/data/uncompressed_tile_RGxB_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..68a29d18774114d0527bdb3dc3001fc935739343 GIT binary patch literal 2811 zcmeHJO^?$s5Oul*goF@>l|UR;IdUmd3tGW#(ekxONXvyYCULfwn$}9QAa0@XKRD&@ z^)Hlpj@?d8x0@We?L@KXdEU&MxcR6M;!#%qFuBf#f(-Lm=}d@dn5$A^jchbdCq?55 zVRTY@AM?BOSEn%+9{5CiQD9# zP}NhKz4e8-LwUxQ_%IZy>p&=gj9Ax;MF95;f$SMJ@jB=_+9AXuiv``HP3s`;g4?>h1%Cm> z?fz(>TY=qZ!mBW}g+%?36-u4WXCGCnW&Bo8RD52{(#u4p@poO0WBZ46^z_-_^_$Ow aLVY`ac|5qtUdZReuOq1jxty2uC-pDw%+>b* literal 0 HcmV?d00001 diff --git a/tests/data/uncompressed_tile_YUV_tiled.heif b/tests/data/uncompressed_tile_YUV_tiled.heif new file mode 100644 index 0000000000000000000000000000000000000000..3b965e6c32880a3a266c60460676202857b7c813 GIT binary patch literal 2204 zcmb7`Pm9w)7{({Hu%4Dh1V!kQqX-qY%A$Bt)_+|q?4f!elj(M(X@@kc>?x7;BY5!M zo3uT6%g6DH6rVSp)bwQ?nx{-=ev^5h_nqlbDulQ@NG?sJ2S);;eyH?72=76p5=nDV zXBdv+^-u_-gQOf&|K{w)iBFUMTR9F#s#v&hbP^S-JUkEeXc7=Lp9>Ek$UCKe?=LYBy$0+m3Qq!#v}4-i$CrfDs##36Jo+Q%=bE>`1OE#~Y-TY8ZZ zHVo5kXE$z2r#my7F=WmR?T*U?Ze-33i_=?|Fq`%JZoDQ@b<23YGqObKzY^$@)IvI( zF7z2f3AL~iS8gu-0nt9}#LieT?O1&|etO(KA3Twdk3MyzYDaRK;9taFbttkQ literal 0 HcmV?d00001 diff --git a/tests/region.cc b/tests/region.cc index 5ce6e25562..2aef44ff74 100644 --- a/tests/region.cc +++ b/tests/region.cc @@ -35,7 +35,7 @@ TEST_CASE("no regions") { - auto context = get_context_for_test_file("uncompressed_rgb3.heif"); + auto context = get_context_for_test_file("uncompressed_comp_RGB.heif"); heif_image_handle *handle = get_primary_image_handle(context); int num_region_items = heif_image_handle_get_number_of_region_items(handle); REQUIRE(num_region_items == 0); diff --git a/tests/test_utils.cc b/tests/test_utils.cc index 0e4f45c5fa..04f045a9ac 100644 --- a/tests/test_utils.cc +++ b/tests/test_utils.cc @@ -25,6 +25,7 @@ */ #include "test_utils.h" +#include "libheif/heif.h" #include "test-config.h" #include #include "catch.hpp" @@ -65,6 +66,24 @@ struct heif_image * get_primary_image(heif_image_handle * handle) return img; } +struct heif_image * get_primary_image_mono(heif_image_handle * handle) +{ + struct heif_error err; + struct heif_image* img; + err = heif_decode_image(handle, &img, heif_colorspace_monochrome, heif_chroma_monochrome, NULL); + REQUIRE(err.code == heif_error_Ok); + return img; +} + +struct heif_image * get_primary_image_ycbcr(heif_image_handle * handle, heif_chroma chroma) +{ + struct heif_error err; + struct heif_image* img; + err = heif_decode_image(handle, &img, heif_colorspace_YCbCr, chroma, NULL); + REQUIRE(err.code == heif_error_Ok); + return img; +} + void fill_new_plane(heif_image* img, heif_channel channel, int w, int h) { struct heif_error err; diff --git a/tests/test_utils.h b/tests/test_utils.h index edacf9c8f5..a99c1c6133 100644 --- a/tests/test_utils.h +++ b/tests/test_utils.h @@ -33,5 +33,7 @@ struct heif_context * get_context_for_local_file(std::string filename); struct heif_image_handle * get_primary_image_handle(heif_context *context); struct heif_image * get_primary_image(heif_image_handle * handle); +struct heif_image * get_primary_image_mono(heif_image_handle * handle); +struct heif_image * get_primary_image_ycbcr(heif_image_handle * handle, heif_chroma chroma); void fill_new_plane(heif_image* img, heif_channel channel, int w, int h); \ No newline at end of file diff --git a/tests/uncompressed_box.cc b/tests/uncompressed_box.cc index 530c2c62f0..0b6a2b464d 100644 --- a/tests/uncompressed_box.cc +++ b/tests/uncompressed_box.cc @@ -25,7 +25,9 @@ */ #include "catch.hpp" +#include "libheif/box.h" #include "libheif/heif.h" +#include "libheif/uncompressed.h" #include "libheif/uncompressed_box.h" #include #include @@ -128,3 +130,89 @@ TEST_CASE( "cmpd_custom" ) REQUIRE(dump_output == "Box: cmpd -----\nsize: 0 (header size: 0)\ncomponent_type: 0x8000\n| component_type_uri: http://example.com/custom_component_uri\ncomponent_type: 0x8002\n| component_type_uri: http://example.com/another_custom_component_uri\n"); } +TEST_CASE( "uncC" ) +{ + std::shared_ptr uncC = std::make_shared(); + uncC->set_profile(fourcc("rgba")); + REQUIRE(uncC->get_components().size() == 0); + Box_uncC::Component r; + r.component_index = 0; + r.component_bit_depth = 8; + r.component_format = component_format_unsigned; + r.component_align_size = 0; + uncC->add_component(r); + Box_uncC::Component g; + g.component_index = 1; + g.component_bit_depth = 8; + g.component_format = component_format_unsigned; + g.component_align_size = 0; + uncC->add_component(g); + Box_uncC::Component b; + b.component_index = 2; + b.component_bit_depth = 8; + b.component_format = component_format_unsigned; + b.component_align_size = 0; + uncC->add_component(b); + Box_uncC::Component a; + a.component_index = 3; + a.component_bit_depth = 8; + a.component_format = component_format_unsigned; + a.component_align_size = 0; + uncC->add_component(a); + uncC->set_sampling_type(sampling_mode_no_subsampling); + uncC->set_interleave_type(interleave_mode_pixel); + + REQUIRE(uncC->get_components().size() == 4); + Box_uncC::Component component0 = uncC->get_components()[0]; + REQUIRE(component0.component_index == 0); + REQUIRE(component0.component_bit_depth == 8); + REQUIRE(component0.component_format == 0); + REQUIRE(component0.component_align_size == 0); + Box_uncC::Component component1 = uncC->get_components()[1]; + REQUIRE(component1.component_index == 1); + REQUIRE(component1.component_bit_depth == 8); + REQUIRE(component1.component_format == 0); + REQUIRE(component1.component_align_size == 0); + Box_uncC::Component component2 = uncC->get_components()[2]; + REQUIRE(component2.component_index == 2); + REQUIRE(component2.component_bit_depth == 8); + REQUIRE(component2.component_format == 0); + REQUIRE(component2.component_align_size == 0); + Box_uncC::Component component3 = uncC->get_components()[3]; + REQUIRE(component3.component_index == 3); + REQUIRE(component3.component_bit_depth == 8); + REQUIRE(component3.component_format == 0); + REQUIRE(component3.component_align_size == 0); + REQUIRE(uncC->get_sampling_type() == 0); + REQUIRE(uncC->get_interleave_type() == 1); + REQUIRE(uncC->get_block_size() == 0); + REQUIRE(uncC->is_components_little_endian() == false); + REQUIRE(uncC->is_block_pad_lsb() == false); + REQUIRE(uncC->is_block_little_endian() == false); + REQUIRE(uncC->is_pad_unknown() == false); + REQUIRE(uncC->get_pixel_size() == 0); + REQUIRE(uncC->get_row_align_size() == 0); + REQUIRE(uncC->get_tile_align_size() == 0); + REQUIRE(uncC->get_number_of_tile_columns() == 1); + REQUIRE(uncC->get_number_of_tile_rows() == 1); + + StreamWriter writer; + Error err = uncC->write(writer); + REQUIRE(err.error_code == heif_error_Ok); + const std::vector bytes = writer.get_data(); + std::vector expected = { + 0x00, 0x00, 0x00, 0x40, 'u', 'n', 'c', 'C', + 0x00, 0x00, 0x00, 0x00, 'r', 'g', 'b', 'a', + 0x00, 0x00, 0x00, 0x04, 0, 0, 7, 0x00, + 0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, 0x02, + 0x07, 0x00, 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + REQUIRE(bytes == expected); + + Indent indent; + std::string dump_output = uncC->dump(indent); + REQUIRE(dump_output == "Box: uncC -----\nsize: 0 (header size: 0)\nprofile: 1919378017 (rgba)\ncomponent_index: 0\ncomponent_bit_depth: 8\ncomponent_format: unsigned\ncomponent_align_size: 0\ncomponent_index: 1\ncomponent_bit_depth: 8\ncomponent_format: unsigned\ncomponent_align_size: 0\ncomponent_index: 2\ncomponent_bit_depth: 8\ncomponent_format: unsigned\ncomponent_align_size: 0\ncomponent_index: 3\ncomponent_bit_depth: 8\ncomponent_format: unsigned\ncomponent_align_size: 0\nsampling_type: no subsampling\ninterleave_type: pixel\nblock_size: 0\ncomponents_little_endian: 0\nblock_pad_lsb: 0\nblock_little_endian: 0\nblock_reversed: 0\npad_unknown: 0\npixel_size: 0\nrow_align_size: 0\ntile_align_size: 0\nnum_tile_cols: 1\nnum_tile_rows: 1\n"); +} diff --git a/tests/uncompressed_decode.cc b/tests/uncompressed_decode.cc index 1cc7465d12..837619f0ba 100644 --- a/tests/uncompressed_decode.cc +++ b/tests/uncompressed_decode.cc @@ -23,55 +23,72 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #include "catch.hpp" #include "libheif/heif.h" #include "libheif/api_structs.h" #include #include -#include "test-config.h" #include "test_utils.h" +#include -#define FILES "uncompressed_rgb3.heif", "uncompressed_planar_tiled.heif", "uncompressed_row.heif", \ - "uncompressed_row_tiled.heif", "uncompressed_pix_tile_align.heif", \ - "uncompressed_comp_tile_align.heif", "uncompressed_row_tile_align.heif" +#include "uncompressed_decode.h" void check_image_handle_size(struct heif_context *&context) { heif_image_handle *handle = get_primary_image_handle(context); int ispe_width = heif_image_handle_get_ispe_width(handle); - REQUIRE(ispe_width == 20); + REQUIRE(ispe_width == 30); int ispe_height = heif_image_handle_get_ispe_height(handle); - REQUIRE(ispe_height == 10); + REQUIRE(ispe_height == 20); int width = heif_image_handle_get_width(handle); - REQUIRE(width == 20); + REQUIRE(width == 30); int height = heif_image_handle_get_height(handle); - REQUIRE(height == 10); + REQUIRE(height == 20); heif_image_handle_release(handle); } TEST_CASE("check image handle size") { - auto file = GENERATE(FILES); + auto file = GENERATE(FILES, MONO_FILES, YUV_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); check_image_handle_size(context); heif_context_free(context); } -void check_image_handle_no_alpha(struct heif_context *&context) { +void check_image_handle_size_subsampled(struct heif_context *&context) { heif_image_handle *handle = get_primary_image_handle(context); - - int has_alpha = heif_image_handle_has_alpha_channel(handle); - REQUIRE(has_alpha == 0); + int ispe_width = heif_image_handle_get_ispe_width(handle); + REQUIRE(ispe_width == 32); + int ispe_height = heif_image_handle_get_ispe_height(handle); + REQUIRE(ispe_height == 20); + int width = heif_image_handle_get_width(handle); + REQUIRE(width == 32); + int height = heif_image_handle_get_height(handle); + REQUIRE(height == 20); heif_image_handle_release(handle); } -TEST_CASE("check image handle no alpha channel") { - auto file = GENERATE(FILES); + +TEST_CASE("check image handle size subsampled") { + auto file = GENERATE(YUV_422_FILES, YUV_420_FILES, YUV_16BIT_422_FILES, YUV_16BIT_420_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); - check_image_handle_no_alpha(context); + check_image_handle_size_subsampled(context); + heif_context_free(context); +} + +TEST_CASE("check image handle alpha channel") { + auto file = GENERATE(FILES, MONO_FILES, ALL_YUV_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + // int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + int expect_alpha = 0; // TODO: fix this + heif_image_handle *handle = get_primary_image_handle(context); + int has_alpha = heif_image_handle_has_alpha_channel(handle); + REQUIRE(has_alpha == expect_alpha); + + heif_image_handle_release(handle); heif_context_free(context); } @@ -88,7 +105,7 @@ void check_image_handle_no_depth_images(struct heif_context *&context) { } TEST_CASE("check image handle no depth images") { - auto file = GENERATE(FILES); + auto file = GENERATE(FILES, MONO_FILES, ALL_YUV_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); check_image_handle_no_depth_images(context); @@ -105,7 +122,7 @@ void check_image_handle_no_thumbnails(struct heif_context *&context) { } TEST_CASE("check image handle no thumbnails") { - auto file = GENERATE(FILES); + auto file = GENERATE(FILES, MONO_FILES, ALL_YUV_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); check_image_handle_no_thumbnails(context); @@ -122,7 +139,7 @@ void check_image_handle_no_aux_images(struct heif_context *&context) { } TEST_CASE("check image handle no auxiliary images") { - auto file = GENERATE(FILES); + auto file = GENERATE(FILES, MONO_FILES, ALL_YUV_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); check_image_handle_no_aux_images(context); @@ -140,130 +157,13 @@ void check_image_handle_no_metadata(struct heif_context *&context) { } TEST_CASE("check image handle no metadata blocks") { - auto file = GENERATE(FILES); + auto file = GENERATE(FILES, MONO_FILES, ALL_YUV_FILES); auto context = get_context_for_test_file(file); INFO("file name: " << file); check_image_handle_no_metadata(context); heif_context_free(context); } -void check_image_size(struct heif_context *&context) { - heif_image_handle *handle = get_primary_image_handle(context); - heif_image *img = get_primary_image(handle); - - REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 0); - REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); - REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); - REQUIRE(heif_image_has_channel(img, heif_channel_R) == 1); - REQUIRE(heif_image_has_channel(img, heif_channel_G) == 1); - REQUIRE(heif_image_has_channel(img, heif_channel_B) == 1); - REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); - REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); - int width = heif_image_get_primary_width(img); - REQUIRE(width == 20); - int height = heif_image_get_primary_height(img); - REQUIRE(height == 10); - width = heif_image_get_width(img, heif_channel_R); - REQUIRE(width == 20); - height = heif_image_get_height(img, heif_channel_R); - REQUIRE(height == 10); - width = heif_image_get_width(img, heif_channel_G); - REQUIRE(width == 20); - height = heif_image_get_height(img, heif_channel_G); - REQUIRE(height == 10); - width = heif_image_get_width(img, heif_channel_B); - REQUIRE(width == 20); - height = heif_image_get_height(img, heif_channel_B); - REQUIRE(height == 10); - - int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_R); - REQUIRE(pixel_depth == 8); - pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_G); - REQUIRE(pixel_depth == 8); - pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_B); - REQUIRE(pixel_depth == 8); - - int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_R); - REQUIRE(pixel_range == 8); - pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_G); - REQUIRE(pixel_range == 8); - pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_B); - REQUIRE(pixel_range == 8); - - heif_image_release(img); - heif_image_handle_release(handle); -} -TEST_CASE("check image size") { - auto file = GENERATE(FILES); - auto context = get_context_for_test_file(file); - INFO("file name: " << file); - check_image_size(context); - heif_context_free(context); -} -void check_image_content(struct heif_context *&context) { - heif_image_handle *handle = get_primary_image_handle(context); - heif_image *img = get_primary_image(handle); - - int stride; - const uint8_t *img_plane = - heif_image_get_plane_readonly(img, heif_channel_R, &stride); - REQUIRE(stride == 64); - for (int row = 0; row < 10; row++) { - INFO("row: " << row); - REQUIRE(((int)(img_plane[stride * row + 0])) == 255); - REQUIRE(((int)(img_plane[stride * row + 3])) == 255); - REQUIRE(((int)(img_plane[stride * row + 4])) == 0); - REQUIRE(((int)(img_plane[stride * row + 7])) == 0); - REQUIRE(((int)(img_plane[stride * row + 8])) == 0); - REQUIRE(((int)(img_plane[stride * row + 11])) == 0); - REQUIRE(((int)(img_plane[stride * row + 12])) == 255); - REQUIRE(((int)(img_plane[stride * row + 15])) == 255); - REQUIRE(((int)(img_plane[stride * row + 16])) == 0); - REQUIRE(((int)(img_plane[stride * row + 19])) == 0); - } - - img_plane = heif_image_get_plane_readonly(img, heif_channel_G, &stride); - REQUIRE(stride == 64); - for (int row = 0; row < 10; row++) { - INFO("row: " << row); - REQUIRE(((int)(img_plane[stride * row + 0])) == 0); - REQUIRE(((int)(img_plane[stride * row + 3])) == 0); - REQUIRE(((int)(img_plane[stride * row + 4])) == 128); - REQUIRE(((int)(img_plane[stride * row + 7])) == 128); - REQUIRE(((int)(img_plane[stride * row + 8])) == 0); - REQUIRE(((int)(img_plane[stride * row + 11])) == 0); - REQUIRE(((int)(img_plane[stride * row + 12])) == 255); - REQUIRE(((int)(img_plane[stride * row + 15])) == 255); - REQUIRE(((int)(img_plane[stride * row + 16])) == 0); - REQUIRE(((int)(img_plane[stride * row + 19])) == 0); - } - - img_plane = heif_image_get_plane_readonly(img, heif_channel_B, &stride); - REQUIRE(stride == 64); - for (int row = 0; row < 10; row++) { - INFO("row: " << row); - REQUIRE(((int)(img_plane[stride * row + 0])) == 0); - REQUIRE(((int)(img_plane[stride * row + 3])) == 0); - REQUIRE(((int)(img_plane[stride * row + 4])) == 0); - REQUIRE(((int)(img_plane[stride * row + 7])) == 0); - REQUIRE(((int)(img_plane[stride * row + 8])) == 255); - REQUIRE(((int)(img_plane[stride * row + 11])) == 255); - REQUIRE(((int)(img_plane[stride * row + 12])) == 255); - REQUIRE(((int)(img_plane[stride * row + 15])) == 255); - REQUIRE(((int)(img_plane[stride * row + 16])) == 0); - REQUIRE(((int)(img_plane[stride * row + 19])) == 0); - } - - heif_image_release(img); - heif_image_handle_release(handle); -} -TEST_CASE("check image content") { - auto file = GENERATE(FILES); - auto context = get_context_for_test_file(file); - INFO("file name: " << file); - check_image_content(context); - heif_context_free(context); -} diff --git a/tests/uncompressed_decode.h b/tests/uncompressed_decode.h new file mode 100644 index 0000000000..4b12486676 --- /dev/null +++ b/tests/uncompressed_decode.h @@ -0,0 +1,113 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#define FILES_RGB \ + "uncompressed_comp_ABGR.heif", "uncompressed_comp_ABGR.heif", \ + "uncompressed_comp_RGB.heif", "uncompressed_comp_RGB_tiled.heif", \ + "uncompressed_comp_RGB_tiled_row_tile_align.heif", \ + "uncompressed_comp_RGxB.heif", "uncompressed_comp_RGxB_tiled.heif", \ + "uncompressed_pix_ABGR.heif", "uncompressed_pix_ABGR_tiled.heif", \ + "uncompressed_pix_RGB.heif", "uncompressed_pix_RGB_tiled.heif", \ + "uncompressed_pix_RGB_tiled_row_tile_align.heif", \ + "uncompressed_pix_RGxB.heif", "uncompressed_pix_RGxB_tiled.heif", \ + "uncompressed_row_ABGR.heif", "uncompressed_row_ABGR_tiled.heif", \ + "uncompressed_row_RGB.heif", "uncompressed_row_RGB_tiled.heif", \ + "uncompressed_row_RGB_tiled_row_tile_align.heif", \ + "uncompressed_row_RGxB.heif", "uncompressed_row_RGxB_tiled.heif", \ + "uncompressed_tile_ABGR_tiled.heif", \ + "uncompressed_tile_RGB_tiled.heif", \ + "uncompressed_tile_RGB_tiled_row_tile_align.heif", \ + "uncompressed_tile_RGxB_tiled.heif", \ + "uncompressed_pix_R8G8B8A8_bsz0_psz10_tiled.heif", \ + "uncompressed_pix_R8G8B8A8_bsz0_psz5_tiled.heif", \ + "uncompressed_pix_R8G8B8_bsz0_psz10_tiled.heif", \ + "uncompressed_pix_R8G8B8_bsz0_psz5_tiled.heif" + + +#define FILES_16BIT_RGB \ + "uncompressed_comp_B16R16G16.heif", "uncompressed_comp_B16R16G16_tiled.heif", \ + "uncompressed_pix_B16R16G16.heif", "uncompressed_pix_B16R16G16_tiled.heif", \ + "uncompressed_row_B16R16G16.heif", "uncompressed_row_B16R16G16_tiled.heif", \ + "uncompressed_tile_B16R16G16_tiled.heif" + +#define FILES_7BIT_RGB \ + "uncompressed_comp_R7+1G7+1B7+1_tiled.heif", "uncompressed_comp_R7G7B7_tiled.heif", \ + "uncompressed_comp_R7G7+1B7_tiled.heif", \ + "uncompressed_pix_R7+1G7+1B7+1_tiled.heif", "uncompressed_pix_R7G7B7_tiled.heif", \ + "uncompressed_pix_R7G7+1B7_tiled.heif", \ + "uncompressed_row_R7+1G7+1B7+1_tiled.heif", "uncompressed_row_R7G7B7_tiled.heif", \ + "uncompressed_row_R7G7+1B7_tiled.heif", \ + "uncompressed_tile_R7+1G7+1B7+1_tiled.heif", "uncompressed_tile_R7G7B7_tiled.heif", \ + "uncompressed_tile_R7G7+1B7_tiled.heif" + +#define FILES_565_RGB \ + "uncompressed_comp_R5G6B5_tiled.heif", \ + "uncompressed_pix_R5G6B5_tiled.heif", \ + "uncompressed_row_R5G6B5_tiled.heif", \ + "uncompressed_tile_R5G6B5_tiled.heif" + +#define FILES FILES_RGB, FILES_16BIT_RGB, FILES_7BIT_RGB, FILES_565_RGB + +#define MONO_FILES \ + "uncompressed_comp_M.heif", "uncompressed_comp_M_tiled.heif", \ + "uncompressed_pix_M.heif", "uncompressed_pix_M_tiled.heif", \ + "uncompressed_row_M.heif", "uncompressed_row_M_tiled.heif", \ + "uncompressed_tile_M_tiled.heif" + +#define YUV_422_FILES \ + "uncompressed_comp_VUY_422.heif", "uncompressed_comp_YUV_422.heif", "uncompressed_comp_YVU_422.heif", \ + "uncompressed_mix_VUY_422.heif", "uncompressed_mix_YUV_422.heif", "uncompressed_mix_YVU_422.heif" + +#define YUV_16BIT_422_FILES \ + "uncompressed_comp_Y16U16V16_422.heif", "uncompressed_mix_Y16U16V16_422.heif" + +#define YUV_420_FILES \ + "uncompressed_comp_VUY_420.heif", "uncompressed_comp_YUV_420.heif", "uncompressed_comp_YVU_420.heif", \ + "uncompressed_mix_VUY_420.heif", "uncompressed_mix_YUV_420.heif", "uncompressed_mix_YVU_420.heif" + +#define YUV_16BIT_420_FILES \ + "uncompressed_comp_Y16U16V16_420.heif", "uncompressed_mix_Y16U16V16_420.heif" + +#define YUV_FILES \ + "uncompressed_comp_YUV_tiled.heif", \ + "uncompressed_pix_YUV_tiled.heif", \ + "uncompressed_row_YUV_tiled.heif", \ + "uncompressed_tile_YUV_tiled.heif" + +#define ALL_YUV_FILES \ + YUV_422_FILES, YUV_420_FILES, YUV_16BIT_422_FILES, YUV_16BIT_420_FILES, YUV_FILES + +#if 0 + \ +"uncompressed_comp_p.heif", \ +"uncompressed_comp_p_tiled.heif", \ +"uncompressed_pix_p.heif", \ +"uncompressed_pix_p_tiled.heif", \ +"uncompressed_row_p.heif", \ +"uncompressed_row_p_tiled.heif", \ +"uncompressed_tile_p_tiled.heif" + +#endif diff --git a/tests/uncompressed_decode_mono.cc b/tests/uncompressed_decode_mono.cc new file mode 100644 index 0000000000..a219933c35 --- /dev/null +++ b/tests/uncompressed_decode_mono.cc @@ -0,0 +1,195 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + + +void check_image_size_mono(struct heif_context *&context, int expect_alpha) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_mono(handle); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == expect_alpha); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + if (expect_alpha == 1) { + width = heif_image_get_width(img, heif_channel_Alpha); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Alpha); + REQUIRE(height == 20); + } + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 8); + + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size mono") { + auto file = GENERATE(MONO_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + check_image_size_mono(context, expect_alpha); + heif_context_free(context); +} + +void check_image_content_mono(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_mono(handle); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 29])) == 255); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 238); + REQUIRE(((int)(img_plane[stride * row + 29])) == 238); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 238); + REQUIRE(((int)(img_plane[stride * row + 27])) == 238); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 29])) == 255); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 238); + REQUIRE(((int)(img_plane[stride * row + 23])) == 238); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } +} + +TEST_CASE("check image content mono") { + auto file = GENERATE(MONO_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_mono(context); + heif_context_free(context); +} + diff --git a/tests/uncompressed_decode_rgb.cc b/tests/uncompressed_decode_rgb.cc new file mode 100644 index 0000000000..78289a3322 --- /dev/null +++ b/tests/uncompressed_decode_rgb.cc @@ -0,0 +1,407 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size(struct heif_context *&context, int expect_alpha) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == expect_alpha); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_R); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_R); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_G); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_G); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_B); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_B); + REQUIRE(height == 20); + if (expect_alpha == 1) { + width = heif_image_get_width(img, heif_channel_Alpha); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Alpha); + REQUIRE(height == 20); + } + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_R); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_G); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_B); + REQUIRE(pixel_depth == 8); + + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_R); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_G); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_B); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size") { + auto file = GENERATE(FILES_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + check_image_size(context, expect_alpha); + heif_context_free(context); +} + + +void check_image_content(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_R, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 29])) == 255); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 238); + REQUIRE(((int)(img_plane[stride * row + 29])) == 238); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 238); + REQUIRE(((int)(img_plane[stride * row + 27])) == 238); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 29])) == 255); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 238); + REQUIRE(((int)(img_plane[stride * row + 23])) == 238); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_G, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 128); + REQUIRE(((int)(img_plane[stride * row + 7])) == 128); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 128); + REQUIRE(((int)(img_plane[stride * row + 3])) == 128); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 165); + REQUIRE(((int)(img_plane[stride * row + 29])) == 165); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 165); + REQUIRE(((int)(img_plane[stride * row + 27])) == 165); + REQUIRE(((int)(img_plane[stride * row + 28])) == 130); + REQUIRE(((int)(img_plane[stride * row + 29])) == 130); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 165); + REQUIRE(((int)(img_plane[stride * row + 23])) == 165); + REQUIRE(((int)(img_plane[stride * row + 24])) == 130); + REQUIRE(((int)(img_plane[stride * row + 27])) == 130); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 9])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 165); + REQUIRE(((int)(img_plane[stride * row + 19])) == 165); + REQUIRE(((int)(img_plane[stride * row + 20])) == 130); + REQUIRE(((int)(img_plane[stride * row + 23])) == 130); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_B, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 19])) == 255); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 238); + REQUIRE(((int)(img_plane[stride * row + 29])) == 238); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 238); + REQUIRE(((int)(img_plane[stride * row + 27])) == 238); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 9])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 238); + REQUIRE(((int)(img_plane[stride * row + 23])) == 238); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content") { + auto file = GENERATE(FILES_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content(context); + heif_context_free(context); +} diff --git a/tests/uncompressed_decode_rgb16.cc b/tests/uncompressed_decode_rgb16.cc new file mode 100644 index 0000000000..ab724e6e24 --- /dev/null +++ b/tests/uncompressed_decode_rgb16.cc @@ -0,0 +1,453 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size_rgb16(struct heif_context *&context, int expect_alpha) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == expect_alpha); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_R); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_R); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_G); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_G); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_B); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_B); + REQUIRE(height == 20); + if (expect_alpha == 1) { + width = heif_image_get_width(img, heif_channel_Alpha); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Alpha); + REQUIRE(height == 20); + } + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_R); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_G); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_B); + REQUIRE(pixel_depth == 16); + + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_R); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_G); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_B); + REQUIRE(pixel_range == 16); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size 16 bit RGB") { + auto file = GENERATE(FILES_16BIT_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + check_image_size_rgb16(context, expect_alpha); + heif_context_free(context); +} + +void check_image_content_rgb16(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_R, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 255); + REQUIRE(((int)(img_plane[stride * row + 47])) == 255); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0); + REQUIRE(((int)(img_plane[stride * row + 56])) == 128); + REQUIRE(((int)(img_plane[stride * row + 59])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0); + REQUIRE(((int)(img_plane[stride * row + 32])) == 255); + REQUIRE(((int)(img_plane[stride * row + 39])) == 255); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0); + REQUIRE(((int)(img_plane[stride * row + 48])) == 128); + REQUIRE(((int)(img_plane[stride * row + 55])) == 128); + REQUIRE(((int)(img_plane[stride * row + 56])) == 255); + REQUIRE(((int)(img_plane[stride * row + 59])) == 255); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 35])) == 0); + REQUIRE(((int)(img_plane[stride * row + 36])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 128); + REQUIRE(((int)(img_plane[stride * row + 43])) == 128); + REQUIRE(((int)(img_plane[stride * row + 44])) == 128); + REQUIRE(((int)(img_plane[stride * row + 47])) == 128); + REQUIRE(((int)(img_plane[stride * row + 48])) == 255); + REQUIRE(((int)(img_plane[stride * row + 51])) == 255); + REQUIRE(((int)(img_plane[stride * row + 52])) == 255); + REQUIRE(((int)(img_plane[stride * row + 55])) == 255); + REQUIRE(((int)(img_plane[stride * row + 56])) == 238); + REQUIRE(((int)(img_plane[stride * row + 59])) == 238); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0); + REQUIRE(((int)(img_plane[stride * row + 32])) == 128); + REQUIRE(((int)(img_plane[stride * row + 39])) == 128); + REQUIRE(((int)(img_plane[stride * row + 40])) == 255); + REQUIRE(((int)(img_plane[stride * row + 47])) == 255); + REQUIRE(((int)(img_plane[stride * row + 48])) == 238); + REQUIRE(((int)(img_plane[stride * row + 55])) == 238); + REQUIRE(((int)(img_plane[stride * row + 56])) == 255); + REQUIRE(((int)(img_plane[stride * row + 59])) == 255); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 31])) == 128); + REQUIRE(((int)(img_plane[stride * row + 32])) == 255); + REQUIRE(((int)(img_plane[stride * row + 39])) == 255); + REQUIRE(((int)(img_plane[stride * row + 40])) == 238); + REQUIRE(((int)(img_plane[stride * row + 47])) == 238); + REQUIRE(((int)(img_plane[stride * row + 48])) == 255); + REQUIRE(((int)(img_plane[stride * row + 55])) == 255); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_G, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 255); + REQUIRE(((int)(img_plane[stride * row + 47])) == 255); + REQUIRE(((int)(img_plane[stride * row + 48])) == 255); + REQUIRE(((int)(img_plane[stride * row + 55])) == 255); + REQUIRE(((int)(img_plane[stride * row + 56])) == 128); + REQUIRE(((int)(img_plane[stride * row + 59])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 128); + REQUIRE(((int)(img_plane[stride * row + 7])) == 128); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0); + REQUIRE(((int)(img_plane[stride * row + 32])) == 255); + REQUIRE(((int)(img_plane[stride * row + 39])) == 255); + REQUIRE(((int)(img_plane[stride * row + 40])) == 255); + REQUIRE(((int)(img_plane[stride * row + 47])) == 255); + REQUIRE(((int)(img_plane[stride * row + 48])) == 128); + REQUIRE(((int)(img_plane[stride * row + 55])) == 128); + REQUIRE(((int)(img_plane[stride * row + 56])) == 165); + REQUIRE(((int)(img_plane[stride * row + 59])) == 165); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 27])) == 255); + REQUIRE(((int)(img_plane[stride * row + 28])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 255); + REQUIRE(((int)(img_plane[stride * row + 35])) == 255); + REQUIRE(((int)(img_plane[stride * row + 36])) == 255); + REQUIRE(((int)(img_plane[stride * row + 39])) == 255); + REQUIRE(((int)(img_plane[stride * row + 40])) == 128); + REQUIRE(((int)(img_plane[stride * row + 43])) == 128); + REQUIRE(((int)(img_plane[stride * row + 44])) == 128); + REQUIRE(((int)(img_plane[stride * row + 47])) == 128); + REQUIRE(((int)(img_plane[stride * row + 48])) == 165); + REQUIRE(((int)(img_plane[stride * row + 51])) == 165); + REQUIRE(((int)(img_plane[stride * row + 52])) == 165); + REQUIRE(((int)(img_plane[stride * row + 55])) == 165); + REQUIRE(((int)(img_plane[stride * row + 56])) == 130); + REQUIRE(((int)(img_plane[stride * row + 59])) == 130); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 128); + REQUIRE(((int)(img_plane[stride * row + 39])) == 128); + REQUIRE(((int)(img_plane[stride * row + 40])) == 165); + REQUIRE(((int)(img_plane[stride * row + 47])) == 165); + REQUIRE(((int)(img_plane[stride * row + 48])) == 130); + REQUIRE(((int)(img_plane[stride * row + 55])) == 130); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 31])) == 128); + REQUIRE(((int)(img_plane[stride * row + 32])) == 165); + REQUIRE(((int)(img_plane[stride * row + 39])) == 165); + REQUIRE(((int)(img_plane[stride * row + 40])) == 130); + REQUIRE(((int)(img_plane[stride * row + 47])) == 130); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0); + REQUIRE(((int)(img_plane[stride * row + 56])) == 128); + REQUIRE(((int)(img_plane[stride * row + 59])) == 128); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_B, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0); + REQUIRE(((int)(img_plane[stride * row + 48])) == 255); + REQUIRE(((int)(img_plane[stride * row + 55])) == 255); + REQUIRE(((int)(img_plane[stride * row + 56])) == 128); + REQUIRE(((int)(img_plane[stride * row + 59])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 255); + REQUIRE(((int)(img_plane[stride * row + 47])) == 255); + REQUIRE(((int)(img_plane[stride * row + 48])) == 128); + REQUIRE(((int)(img_plane[stride * row + 55])) == 128); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 3])) == 255); + REQUIRE(((int)(img_plane[stride * row + 4])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 255); + REQUIRE(((int)(img_plane[stride * row + 11])) == 255); + REQUIRE(((int)(img_plane[stride * row + 12])) == 255); + REQUIRE(((int)(img_plane[stride * row + 15])) == 255); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0); + REQUIRE(((int)(img_plane[stride * row + 32])) == 255); + REQUIRE(((int)(img_plane[stride * row + 35])) == 255); + REQUIRE(((int)(img_plane[stride * row + 36])) == 255); + REQUIRE(((int)(img_plane[stride * row + 39])) == 255); + REQUIRE(((int)(img_plane[stride * row + 40])) == 128); + REQUIRE(((int)(img_plane[stride * row + 43])) == 128); + REQUIRE(((int)(img_plane[stride * row + 44])) == 128); + REQUIRE(((int)(img_plane[stride * row + 47])) == 128); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0); + REQUIRE(((int)(img_plane[stride * row + 51])) == 0); + REQUIRE(((int)(img_plane[stride * row + 52])) == 0); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0); + REQUIRE(((int)(img_plane[stride * row + 56])) == 238); + REQUIRE(((int)(img_plane[stride * row + 59])) == 238); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 255); + REQUIRE(((int)(img_plane[stride * row + 7])) == 255); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 255); + REQUIRE(((int)(img_plane[stride * row + 31])) == 255); + REQUIRE(((int)(img_plane[stride * row + 32])) == 128); + REQUIRE(((int)(img_plane[stride * row + 39])) == 128); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0); + REQUIRE(((int)(img_plane[stride * row + 48])) == 238); + REQUIRE(((int)(img_plane[stride * row + 55])) == 238); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 255); + REQUIRE(((int)(img_plane[stride * row + 23])) == 255); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 31])) == 128); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0); + REQUIRE(((int)(img_plane[stride * row + 40])) == 238); + REQUIRE(((int)(img_plane[stride * row + 47])) == 238); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content 16 bit RGB") { + auto file = GENERATE(FILES_16BIT_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_rgb16(context); + heif_context_free(context); +} diff --git a/tests/uncompressed_decode_rgb565.cc b/tests/uncompressed_decode_rgb565.cc new file mode 100644 index 0000000000..c56a60f315 --- /dev/null +++ b/tests/uncompressed_decode_rgb565.cc @@ -0,0 +1,407 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size_rgb565(struct heif_context *&context, int expect_alpha) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == expect_alpha); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_R); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_R); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_G); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_G); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_B); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_B); + REQUIRE(height == 20); + if (expect_alpha == 1) { + width = heif_image_get_width(img, heif_channel_Alpha); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Alpha); + REQUIRE(height == 20); + } + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_R); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_G); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_B); + REQUIRE(pixel_depth == 8); + + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_R); + REQUIRE(pixel_range == 5); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_G); + REQUIRE(pixel_range == 6); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_B); + REQUIRE(pixel_range == 5); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size 5-6-5 bit RGB") { + auto file = GENERATE(FILES_565_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + check_image_size_rgb565(context, expect_alpha); + heif_context_free(context); +} + +void check_image_content_rgb565(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_R, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 31); + REQUIRE(((int)(img_plane[stride * row + 3])) == 31); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 31); + REQUIRE(((int)(img_plane[stride * row + 15])) == 31); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 31); + REQUIRE(((int)(img_plane[stride * row + 23])) == 31); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 15); + REQUIRE(((int)(img_plane[stride * row + 29])) == 15); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 31); + REQUIRE(((int)(img_plane[stride * row + 11])) == 31); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 31); + REQUIRE(((int)(img_plane[stride * row + 19])) == 31); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 15); + REQUIRE(((int)(img_plane[stride * row + 27])) == 15); + REQUIRE(((int)(img_plane[stride * row + 28])) == 31); + REQUIRE(((int)(img_plane[stride * row + 29])) == 31); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 31); + REQUIRE(((int)(img_plane[stride * row + 7])) == 31); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 31); + REQUIRE(((int)(img_plane[stride * row + 15])) == 31); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 15); + REQUIRE(((int)(img_plane[stride * row + 23])) == 15); + REQUIRE(((int)(img_plane[stride * row + 24])) == 31); + REQUIRE(((int)(img_plane[stride * row + 27])) == 31); + REQUIRE(((int)(img_plane[stride * row + 28])) == 28); + REQUIRE(((int)(img_plane[stride * row + 29])) == 28); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 31); + REQUIRE(((int)(img_plane[stride * row + 3])) == 31); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 31); + REQUIRE(((int)(img_plane[stride * row + 11])) == 31); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 15); + REQUIRE(((int)(img_plane[stride * row + 19])) == 15); + REQUIRE(((int)(img_plane[stride * row + 20])) == 31); + REQUIRE(((int)(img_plane[stride * row + 23])) == 31); + REQUIRE(((int)(img_plane[stride * row + 24])) == 28); + REQUIRE(((int)(img_plane[stride * row + 27])) == 28); + REQUIRE(((int)(img_plane[stride * row + 28])) == 31); + REQUIRE(((int)(img_plane[stride * row + 29])) == 31); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 31); + REQUIRE(((int)(img_plane[stride * row + 7])) == 31); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 15); + REQUIRE(((int)(img_plane[stride * row + 15])) == 15); + REQUIRE(((int)(img_plane[stride * row + 16])) == 31); + REQUIRE(((int)(img_plane[stride * row + 19])) == 31); + REQUIRE(((int)(img_plane[stride * row + 20])) == 28); + REQUIRE(((int)(img_plane[stride * row + 23])) == 28); + REQUIRE(((int)(img_plane[stride * row + 24])) == 31); + REQUIRE(((int)(img_plane[stride * row + 27])) == 31); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_G, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 31); + REQUIRE(((int)(img_plane[stride * row + 7])) == 31); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 63); + REQUIRE(((int)(img_plane[stride * row + 23])) == 63); + REQUIRE(((int)(img_plane[stride * row + 24])) == 63); + REQUIRE(((int)(img_plane[stride * row + 27])) == 63); + REQUIRE(((int)(img_plane[stride * row + 28])) == 31); + REQUIRE(((int)(img_plane[stride * row + 29])) == 31); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 31); + REQUIRE(((int)(img_plane[stride * row + 3])) == 31); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 63); + REQUIRE(((int)(img_plane[stride * row + 11])) == 63); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 63); + REQUIRE(((int)(img_plane[stride * row + 19])) == 63); + REQUIRE(((int)(img_plane[stride * row + 20])) == 63); + REQUIRE(((int)(img_plane[stride * row + 23])) == 63); + REQUIRE(((int)(img_plane[stride * row + 24])) == 31); + REQUIRE(((int)(img_plane[stride * row + 27])) == 31); + REQUIRE(((int)(img_plane[stride * row + 28])) == 40); + REQUIRE(((int)(img_plane[stride * row + 29])) == 40); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 63); + REQUIRE(((int)(img_plane[stride * row + 7])) == 63); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 63); + REQUIRE(((int)(img_plane[stride * row + 19])) == 63); + REQUIRE(((int)(img_plane[stride * row + 20])) == 31); + REQUIRE(((int)(img_plane[stride * row + 23])) == 31); + REQUIRE(((int)(img_plane[stride * row + 24])) == 40); + REQUIRE(((int)(img_plane[stride * row + 27])) == 40); + REQUIRE(((int)(img_plane[stride * row + 28])) == 32); + REQUIRE(((int)(img_plane[stride * row + 29])) == 32); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 63); + REQUIRE(((int)(img_plane[stride * row + 3])) == 63); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 63); + REQUIRE(((int)(img_plane[stride * row + 11])) == 63); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 31); + REQUIRE(((int)(img_plane[stride * row + 19])) == 31); + REQUIRE(((int)(img_plane[stride * row + 20])) == 40); + REQUIRE(((int)(img_plane[stride * row + 23])) == 40); + REQUIRE(((int)(img_plane[stride * row + 24])) == 32); + REQUIRE(((int)(img_plane[stride * row + 27])) == 32); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 63); + REQUIRE(((int)(img_plane[stride * row + 7])) == 63); + REQUIRE(((int)(img_plane[stride * row + 8])) == 63); + REQUIRE(((int)(img_plane[stride * row + 9])) == 63); + REQUIRE(((int)(img_plane[stride * row + 12])) == 31); + REQUIRE(((int)(img_plane[stride * row + 15])) == 31); + REQUIRE(((int)(img_plane[stride * row + 16])) == 40); + REQUIRE(((int)(img_plane[stride * row + 19])) == 40); + REQUIRE(((int)(img_plane[stride * row + 20])) == 32); + REQUIRE(((int)(img_plane[stride * row + 23])) == 32); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 31); + REQUIRE(((int)(img_plane[stride * row + 29])) == 31); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_B, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 31); + REQUIRE(((int)(img_plane[stride * row + 11])) == 31); + REQUIRE(((int)(img_plane[stride * row + 12])) == 31); + REQUIRE(((int)(img_plane[stride * row + 15])) == 31); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 31); + REQUIRE(((int)(img_plane[stride * row + 27])) == 31); + REQUIRE(((int)(img_plane[stride * row + 28])) == 15); + REQUIRE(((int)(img_plane[stride * row + 29])) == 15); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 31); + REQUIRE(((int)(img_plane[stride * row + 7])) == 31); + REQUIRE(((int)(img_plane[stride * row + 8])) == 31); + REQUIRE(((int)(img_plane[stride * row + 11])) == 31); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 31); + REQUIRE(((int)(img_plane[stride * row + 23])) == 31); + REQUIRE(((int)(img_plane[stride * row + 24])) == 15); + REQUIRE(((int)(img_plane[stride * row + 27])) == 15); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 31); + REQUIRE(((int)(img_plane[stride * row + 3])) == 31); + REQUIRE(((int)(img_plane[stride * row + 4])) == 31); + REQUIRE(((int)(img_plane[stride * row + 7])) == 31); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 31); + REQUIRE(((int)(img_plane[stride * row + 19])) == 31); + REQUIRE(((int)(img_plane[stride * row + 20])) == 15); + REQUIRE(((int)(img_plane[stride * row + 23])) == 15); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 28); + REQUIRE(((int)(img_plane[stride * row + 29])) == 28); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 31); + REQUIRE(((int)(img_plane[stride * row + 3])) == 31); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 31); + REQUIRE(((int)(img_plane[stride * row + 15])) == 31); + REQUIRE(((int)(img_plane[stride * row + 16])) == 15); + REQUIRE(((int)(img_plane[stride * row + 19])) == 15); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 28); + REQUIRE(((int)(img_plane[stride * row + 27])) == 28); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 31); + REQUIRE(((int)(img_plane[stride * row + 9])) == 31); + REQUIRE(((int)(img_plane[stride * row + 12])) == 15); + REQUIRE(((int)(img_plane[stride * row + 15])) == 15); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 28); + REQUIRE(((int)(img_plane[stride * row + 23])) == 28); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content 5-6-5 bit RGB") { + auto file = GENERATE(FILES_565_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_rgb565(context); + heif_context_free(context); +} diff --git a/tests/uncompressed_decode_rgb7.cc b/tests/uncompressed_decode_rgb7.cc new file mode 100644 index 0000000000..0d79059af2 --- /dev/null +++ b/tests/uncompressed_decode_rgb7.cc @@ -0,0 +1,407 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size_rgb7(struct heif_context *&context, int expect_alpha) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == expect_alpha); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_R); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_R); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_G); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_G); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_B); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_B); + REQUIRE(height == 20); + if (expect_alpha == 1) { + width = heif_image_get_width(img, heif_channel_Alpha); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Alpha); + REQUIRE(height == 20); + } + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_R); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_G); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_B); + REQUIRE(pixel_depth == 8); + + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_R); + REQUIRE(pixel_range == 7); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_G); + REQUIRE(pixel_range == 7); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_B); + REQUIRE(pixel_range == 7); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size 7 bit RGB") { + auto file = GENERATE(FILES_7BIT_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + int expect_alpha = (strchr(file, 'A') == NULL) ? 0 : 1; + check_image_size_rgb7(context, expect_alpha); + heif_context_free(context); +} + +void check_image_content_rgb7(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image(handle); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_R, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 63); + REQUIRE(((int)(img_plane[stride * row + 29])) == 63); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 63); + REQUIRE(((int)(img_plane[stride * row + 27])) == 63); + REQUIRE(((int)(img_plane[stride * row + 28])) == 127); + REQUIRE(((int)(img_plane[stride * row + 29])) == 127); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 63); + REQUIRE(((int)(img_plane[stride * row + 23])) == 63); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 118); + REQUIRE(((int)(img_plane[stride * row + 29])) == 118); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 63); + REQUIRE(((int)(img_plane[stride * row + 19])) == 63); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 118); + REQUIRE(((int)(img_plane[stride * row + 27])) == 118); + REQUIRE(((int)(img_plane[stride * row + 28])) == 127); + REQUIRE(((int)(img_plane[stride * row + 29])) == 127); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 118); + REQUIRE(((int)(img_plane[stride * row + 23])) == 118); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_G, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 63); + REQUIRE(((int)(img_plane[stride * row + 7])) == 63); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 63); + REQUIRE(((int)(img_plane[stride * row + 29])) == 63); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 63); + REQUIRE(((int)(img_plane[stride * row + 3])) == 63); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 63); + REQUIRE(((int)(img_plane[stride * row + 27])) == 63); + REQUIRE(((int)(img_plane[stride * row + 28])) == 82); + REQUIRE(((int)(img_plane[stride * row + 29])) == 82); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 63); + REQUIRE(((int)(img_plane[stride * row + 23])) == 63); + REQUIRE(((int)(img_plane[stride * row + 24])) == 82); + REQUIRE(((int)(img_plane[stride * row + 27])) == 82); + REQUIRE(((int)(img_plane[stride * row + 28])) == 64); + REQUIRE(((int)(img_plane[stride * row + 29])) == 64); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 63); + REQUIRE(((int)(img_plane[stride * row + 19])) == 63); + REQUIRE(((int)(img_plane[stride * row + 20])) == 82); + REQUIRE(((int)(img_plane[stride * row + 23])) == 82); + REQUIRE(((int)(img_plane[stride * row + 24])) == 64); + REQUIRE(((int)(img_plane[stride * row + 27])) == 64); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 82); + REQUIRE(((int)(img_plane[stride * row + 19])) == 82); + REQUIRE(((int)(img_plane[stride * row + 20])) == 64); + REQUIRE(((int)(img_plane[stride * row + 23])) == 64); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 63); + REQUIRE(((int)(img_plane[stride * row + 29])) == 63); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_B, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 63); + REQUIRE(((int)(img_plane[stride * row + 29])) == 63); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 63); + REQUIRE(((int)(img_plane[stride * row + 27])) == 63); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 63); + REQUIRE(((int)(img_plane[stride * row + 23])) == 63); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 118); + REQUIRE(((int)(img_plane[stride * row + 29])) == 118); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 63); + REQUIRE(((int)(img_plane[stride * row + 19])) == 63); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 118); + REQUIRE(((int)(img_plane[stride * row + 27])) == 118); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 63); + REQUIRE(((int)(img_plane[stride * row + 15])) == 63); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 118); + REQUIRE(((int)(img_plane[stride * row + 23])) == 118); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content 7 bit RGB") { + auto file = GENERATE(FILES_7BIT_RGB); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_rgb7(context); + heif_context_free(context); +} diff --git a/tests/uncompressed_decode_ycbcr.cc b/tests/uncompressed_decode_ycbcr.cc new file mode 100644 index 0000000000..b9ea6dc2b3 --- /dev/null +++ b/tests/uncompressed_decode_ycbcr.cc @@ -0,0 +1,401 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size_ycbcr(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_444); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 30); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 30); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 8); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size YCbCr") { + auto file = GENERATE(YUV_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_size_ycbcr(context); + heif_context_free(context); +} + + +void check_image_content_ycbcr(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_444); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 76); + REQUIRE(((int)(img_plane[stride * row + 3])) == 76); + REQUIRE(((int)(img_plane[stride * row + 4])) == 75); + REQUIRE(((int)(img_plane[stride * row + 7])) == 75); + REQUIRE(((int)(img_plane[stride * row + 8])) == 29); + REQUIRE(((int)(img_plane[stride * row + 11])) == 29); + REQUIRE(((int)(img_plane[stride * row + 12])) == 254); + REQUIRE(((int)(img_plane[stride * row + 15])) == 254); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 225); + REQUIRE(((int)(img_plane[stride * row + 23])) == 225); + REQUIRE(((int)(img_plane[stride * row + 24])) == 178); + REQUIRE(((int)(img_plane[stride * row + 27])) == 178); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 75); + REQUIRE(((int)(img_plane[stride * row + 3])) == 75); + REQUIRE(((int)(img_plane[stride * row + 4])) == 29); + REQUIRE(((int)(img_plane[stride * row + 7])) == 29); + REQUIRE(((int)(img_plane[stride * row + 8])) == 254); + REQUIRE(((int)(img_plane[stride * row + 11])) == 254); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 225); + REQUIRE(((int)(img_plane[stride * row + 19])) == 225); + REQUIRE(((int)(img_plane[stride * row + 20])) == 178); + REQUIRE(((int)(img_plane[stride * row + 23])) == 178); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 173); + REQUIRE(((int)(img_plane[stride * row + 29])) == 173); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 29); + REQUIRE(((int)(img_plane[stride * row + 3])) == 29); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 7])) == 254); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 225); + REQUIRE(((int)(img_plane[stride * row + 15])) == 225); + REQUIRE(((int)(img_plane[stride * row + 16])) == 178); + REQUIRE(((int)(img_plane[stride * row + 19])) == 178); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 173); + REQUIRE(((int)(img_plane[stride * row + 27])) == 173); + REQUIRE(((int)(img_plane[stride * row + 28])) == 174); + REQUIRE(((int)(img_plane[stride * row + 29])) == 174); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 225); + REQUIRE(((int)(img_plane[stride * row + 11])) == 225); + REQUIRE(((int)(img_plane[stride * row + 12])) == 178); + REQUIRE(((int)(img_plane[stride * row + 15])) == 178); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 173); + REQUIRE(((int)(img_plane[stride * row + 23])) == 173); + REQUIRE(((int)(img_plane[stride * row + 24])) == 174); + REQUIRE(((int)(img_plane[stride * row + 27])) == 174); + REQUIRE(((int)(img_plane[stride * row + 28])) == 76); + REQUIRE(((int)(img_plane[stride * row + 29])) == 76); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 225); + REQUIRE(((int)(img_plane[stride * row + 7])) == 225); + REQUIRE(((int)(img_plane[stride * row + 8])) == 178); + REQUIRE(((int)(img_plane[stride * row + 9])) == 178); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 173); + REQUIRE(((int)(img_plane[stride * row + 19])) == 173); + REQUIRE(((int)(img_plane[stride * row + 20])) == 174); + REQUIRE(((int)(img_plane[stride * row + 23])) == 174); + REQUIRE(((int)(img_plane[stride * row + 24])) == 76); + REQUIRE(((int)(img_plane[stride * row + 27])) == 76); + REQUIRE(((int)(img_plane[stride * row + 28])) == 75); + REQUIRE(((int)(img_plane[stride * row + 29])) == 75); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cb, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 84); + REQUIRE(((int)(img_plane[stride * row + 3])) == 84); + REQUIRE(((int)(img_plane[stride * row + 4])) == 85); + REQUIRE(((int)(img_plane[stride * row + 7])) == 85); + REQUIRE(((int)(img_plane[stride * row + 8])) == 254); + REQUIRE(((int)(img_plane[stride * row + 11])) == 254); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 170); + REQUIRE(((int)(img_plane[stride * row + 27])) == 170); + REQUIRE(((int)(img_plane[stride * row + 28])) == 127); + REQUIRE(((int)(img_plane[stride * row + 29])) == 127); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 85); + REQUIRE(((int)(img_plane[stride * row + 3])) == 85); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 7])) == 254); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 170); + REQUIRE(((int)(img_plane[stride * row + 23])) == 170); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 29); + REQUIRE(((int)(img_plane[stride * row + 29])) == 29); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 170); + REQUIRE(((int)(img_plane[stride * row + 19])) == 170); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 29); + REQUIRE(((int)(img_plane[stride * row + 27])) == 29); + REQUIRE(((int)(img_plane[stride * row + 28])) == 163); + REQUIRE(((int)(img_plane[stride * row + 29])) == 163); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 170); + REQUIRE(((int)(img_plane[stride * row + 15])) == 170); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 29); + REQUIRE(((int)(img_plane[stride * row + 23])) == 29); + REQUIRE(((int)(img_plane[stride * row + 24])) == 163); + REQUIRE(((int)(img_plane[stride * row + 27])) == 163); + REQUIRE(((int)(img_plane[stride * row + 28])) == 84); + REQUIRE(((int)(img_plane[stride * row + 29])) == 84); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 170); + REQUIRE(((int)(img_plane[stride * row + 9])) == 170); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 29); + REQUIRE(((int)(img_plane[stride * row + 19])) == 29); + REQUIRE(((int)(img_plane[stride * row + 20])) == 163); + REQUIRE(((int)(img_plane[stride * row + 23])) == 163); + REQUIRE(((int)(img_plane[stride * row + 24])) == 84); + REQUIRE(((int)(img_plane[stride * row + 27])) == 84); + REQUIRE(((int)(img_plane[stride * row + 28])) == 85); + REQUIRE(((int)(img_plane[stride * row + 29])) == 85); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cr, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 73); + REQUIRE(((int)(img_plane[stride * row + 7])) == 73); + REQUIRE(((int)(img_plane[stride * row + 8])) == 106); + REQUIRE(((int)(img_plane[stride * row + 11])) == 106); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 148); + REQUIRE(((int)(img_plane[stride * row + 23])) == 148); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0); + REQUIRE(((int)(img_plane[stride * row + 28])) == 127); + REQUIRE(((int)(img_plane[stride * row + 29])) == 127); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 73); + REQUIRE(((int)(img_plane[stride * row + 3])) == 73); + REQUIRE(((int)(img_plane[stride * row + 4])) == 106); + REQUIRE(((int)(img_plane[stride * row + 7])) == 106); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 148); + REQUIRE(((int)(img_plane[stride * row + 19])) == 148); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0); + REQUIRE(((int)(img_plane[stride * row + 24])) == 127); + REQUIRE(((int)(img_plane[stride * row + 27])) == 127); + REQUIRE(((int)(img_plane[stride * row + 28])) == 185); + REQUIRE(((int)(img_plane[stride * row + 29])) == 185); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 106); + REQUIRE(((int)(img_plane[stride * row + 3])) == 106); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 148); + REQUIRE(((int)(img_plane[stride * row + 15])) == 148); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 127); + REQUIRE(((int)(img_plane[stride * row + 23])) == 127); + REQUIRE(((int)(img_plane[stride * row + 24])) == 185); + REQUIRE(((int)(img_plane[stride * row + 27])) == 185); + REQUIRE(((int)(img_plane[stride * row + 28])) == 172); + REQUIRE(((int)(img_plane[stride * row + 29])) == 172); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 148); + REQUIRE(((int)(img_plane[stride * row + 11])) == 148); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 127); + REQUIRE(((int)(img_plane[stride * row + 19])) == 127); + REQUIRE(((int)(img_plane[stride * row + 20])) == 185); + REQUIRE(((int)(img_plane[stride * row + 23])) == 185); + REQUIRE(((int)(img_plane[stride * row + 24])) == 172); + REQUIRE(((int)(img_plane[stride * row + 27])) == 172); + REQUIRE(((int)(img_plane[stride * row + 28])) == 254); + REQUIRE(((int)(img_plane[stride * row + 29])) == 254); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 148); + REQUIRE(((int)(img_plane[stride * row + 7])) == 148); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + REQUIRE(((int)(img_plane[stride * row + 16])) == 185); + REQUIRE(((int)(img_plane[stride * row + 19])) == 185); + REQUIRE(((int)(img_plane[stride * row + 20])) == 172); + REQUIRE(((int)(img_plane[stride * row + 23])) == 172); + REQUIRE(((int)(img_plane[stride * row + 24])) == 254); + REQUIRE(((int)(img_plane[stride * row + 27])) == 254); + REQUIRE(((int)(img_plane[stride * row + 28])) == 73); + REQUIRE(((int)(img_plane[stride * row + 29])) == 73); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content YCbCr") { + auto file = GENERATE(YUV_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_ycbcr(context); + heif_context_free(context); +} + + diff --git a/tests/uncompressed_decode_ycbcr420.cc b/tests/uncompressed_decode_ycbcr420.cc new file mode 100644 index 0000000000..6f30e2693d --- /dev/null +++ b/tests/uncompressed_decode_ycbcr420.cc @@ -0,0 +1,846 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + + +void check_image_size_ycbcr_420(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_420); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 32); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 32); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 10); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 10); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 8); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size YCbCr 4:2:0") { + auto file = GENERATE(YUV_420_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_size_ycbcr_420(context); + heif_context_free(context); +} + + +void check_image_size_ycbcr_420_16bit(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_420); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 32); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 32); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 10); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 10); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 16); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 16); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size YCbCr 4:2:0 16 bit") { + auto file = GENERATE(YUV_16BIT_420_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_size_ycbcr_420_16bit(context); + heif_context_free(context); +} + +void check_image_content_ycbcr420(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_420); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 76); + REQUIRE(((int)(img_plane[stride * row + 3])) == 76); + REQUIRE(((int)(img_plane[stride * row + 4])) == 75); + REQUIRE(((int)(img_plane[stride * row + 7])) == 75); + REQUIRE(((int)(img_plane[stride * row + 8])) == 29); + REQUIRE(((int)(img_plane[stride * row + 11])) == 29); + REQUIRE(((int)(img_plane[stride * row + 12])) == 254); + REQUIRE(((int)(img_plane[stride * row + 15])) == 254); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 225); + REQUIRE(((int)(img_plane[stride * row + 23])) == 225); + REQUIRE(((int)(img_plane[stride * row + 24])) == 178); + REQUIRE(((int)(img_plane[stride * row + 27])) == 178); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 75); + REQUIRE(((int)(img_plane[stride * row + 3])) == 75); + REQUIRE(((int)(img_plane[stride * row + 4])) == 29); + REQUIRE(((int)(img_plane[stride * row + 7])) == 29); + REQUIRE(((int)(img_plane[stride * row + 8])) == 254); + REQUIRE(((int)(img_plane[stride * row + 11])) == 254); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 225); + REQUIRE(((int)(img_plane[stride * row + 19])) == 225); + REQUIRE(((int)(img_plane[stride * row + 20])) == 178); + REQUIRE(((int)(img_plane[stride * row + 23])) == 178); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 173); + REQUIRE(((int)(img_plane[stride * row + 29])) == 173); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 29); + REQUIRE(((int)(img_plane[stride * row + 3])) == 29); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 7])) == 254); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 225); + REQUIRE(((int)(img_plane[stride * row + 15])) == 225); + REQUIRE(((int)(img_plane[stride * row + 16])) == 178); + REQUIRE(((int)(img_plane[stride * row + 19])) == 178); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 173); + REQUIRE(((int)(img_plane[stride * row + 27])) == 173); + REQUIRE(((int)(img_plane[stride * row + 28])) == 174); + REQUIRE(((int)(img_plane[stride * row + 29])) == 174); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 225); + REQUIRE(((int)(img_plane[stride * row + 11])) == 225); + REQUIRE(((int)(img_plane[stride * row + 12])) == 178); + REQUIRE(((int)(img_plane[stride * row + 15])) == 178); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 173); + REQUIRE(((int)(img_plane[stride * row + 23])) == 173); + REQUIRE(((int)(img_plane[stride * row + 24])) == 174); + REQUIRE(((int)(img_plane[stride * row + 27])) == 174); + REQUIRE(((int)(img_plane[stride * row + 28])) == 76); + REQUIRE(((int)(img_plane[stride * row + 29])) == 76); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 225); + REQUIRE(((int)(img_plane[stride * row + 7])) == 225); + REQUIRE(((int)(img_plane[stride * row + 8])) == 178); + REQUIRE(((int)(img_plane[stride * row + 9])) == 178); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 173); + REQUIRE(((int)(img_plane[stride * row + 19])) == 173); + REQUIRE(((int)(img_plane[stride * row + 20])) == 174); + REQUIRE(((int)(img_plane[stride * row + 23])) == 174); + REQUIRE(((int)(img_plane[stride * row + 24])) == 76); + REQUIRE(((int)(img_plane[stride * row + 27])) == 76); + REQUIRE(((int)(img_plane[stride * row + 28])) == 75); + REQUIRE(((int)(img_plane[stride * row + 29])) == 75); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cb, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 2; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 84); + REQUIRE(((int)(img_plane[stride * row + 1])) == 84); + REQUIRE(((int)(img_plane[stride * row + 2])) == 85); + REQUIRE(((int)(img_plane[stride * row + 3])) == 85); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 5])) == 254); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 170); + REQUIRE(((int)(img_plane[stride * row + 13])) == 170); + REQUIRE(((int)(img_plane[stride * row + 14])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + } + for (int row = 2; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 85); + REQUIRE(((int)(img_plane[stride * row + 1])) == 85); + REQUIRE(((int)(img_plane[stride * row + 2])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 10])) == 170); + REQUIRE(((int)(img_plane[stride * row + 11])) == 170); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 13])) == 127); + REQUIRE(((int)(img_plane[stride * row + 14])) == 29); + REQUIRE(((int)(img_plane[stride * row + 15])) == 29); + } + for (int row = 4; row < 6; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 1])) == 254); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 170); + REQUIRE(((int)(img_plane[stride * row + 9])) == 170); + REQUIRE(((int)(img_plane[stride * row + 10])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 29); + REQUIRE(((int)(img_plane[stride * row + 13])) == 29); + REQUIRE(((int)(img_plane[stride * row + 14])) == 163); + REQUIRE(((int)(img_plane[stride * row + 15])) == 163); + } + for (int row = 6; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0); + REQUIRE(((int)(img_plane[stride * row + 6])) == 170); + REQUIRE(((int)(img_plane[stride * row + 7])) == 170); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 29); + REQUIRE(((int)(img_plane[stride * row + 11])) == 29); + REQUIRE(((int)(img_plane[stride * row + 12])) == 163); + REQUIRE(((int)(img_plane[stride * row + 13])) == 163); + REQUIRE(((int)(img_plane[stride * row + 14])) == 84); + REQUIRE(((int)(img_plane[stride * row + 15])) == 84); + } + for (int row = 8; row < 10; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 170); + REQUIRE(((int)(img_plane[stride * row + 5])) == 170); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 29); + REQUIRE(((int)(img_plane[stride * row + 9])) == 29); + REQUIRE(((int)(img_plane[stride * row + 10])) == 163); + REQUIRE(((int)(img_plane[stride * row + 11])) == 163); + REQUIRE(((int)(img_plane[stride * row + 12])) == 84); + REQUIRE(((int)(img_plane[stride * row + 13])) == 84); + REQUIRE(((int)(img_plane[stride * row + 14])) == 85); + REQUIRE(((int)(img_plane[stride * row + 15])) == 85); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cr, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 2; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 1])) == 254); + REQUIRE(((int)(img_plane[stride * row + 2])) == 73); + REQUIRE(((int)(img_plane[stride * row + 3])) == 73); + REQUIRE(((int)(img_plane[stride * row + 4])) == 106); + REQUIRE(((int)(img_plane[stride * row + 5])) == 106); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 148); + REQUIRE(((int)(img_plane[stride * row + 11])) == 148); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0); + REQUIRE(((int)(img_plane[stride * row + 14])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + } + for (int row = 2; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 73); + REQUIRE(((int)(img_plane[stride * row + 1])) == 73); + REQUIRE(((int)(img_plane[stride * row + 2])) == 106); + REQUIRE(((int)(img_plane[stride * row + 3])) == 106); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 148); + REQUIRE(((int)(img_plane[stride * row + 9])) == 148); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 13])) == 127); + REQUIRE(((int)(img_plane[stride * row + 14])) == 185); + REQUIRE(((int)(img_plane[stride * row + 15])) == 185); + } + for (int row = 4; row < 6; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 106); + REQUIRE(((int)(img_plane[stride * row + 1])) == 106); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 148); + REQUIRE(((int)(img_plane[stride * row + 7])) == 148); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 10])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 185); + REQUIRE(((int)(img_plane[stride * row + 13])) == 185); + REQUIRE(((int)(img_plane[stride * row + 14])) == 172); + REQUIRE(((int)(img_plane[stride * row + 15])) == 172); + } + for (int row = 6; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 148); + REQUIRE(((int)(img_plane[stride * row + 5])) == 148); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 185); + REQUIRE(((int)(img_plane[stride * row + 11])) == 185); + REQUIRE(((int)(img_plane[stride * row + 12])) == 172); + REQUIRE(((int)(img_plane[stride * row + 13])) == 172); + REQUIRE(((int)(img_plane[stride * row + 14])) == 254); + REQUIRE(((int)(img_plane[stride * row + 15])) == 254); + } + for (int row = 8; row < 10; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 148); + REQUIRE(((int)(img_plane[stride * row + 3])) == 148); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 185); + REQUIRE(((int)(img_plane[stride * row + 9])) == 185); + REQUIRE(((int)(img_plane[stride * row + 10])) == 172); + REQUIRE(((int)(img_plane[stride * row + 11])) == 172); + REQUIRE(((int)(img_plane[stride * row + 12])) == 254); + REQUIRE(((int)(img_plane[stride * row + 13])) == 254); + REQUIRE(((int)(img_plane[stride * row + 14])) == 73); + REQUIRE(((int)(img_plane[stride * row + 15])) == 73); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content YCbCr 4:2:0") { + auto file = GENERATE(YUV_420_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_ycbcr420(context); + heif_context_free(context); +} + +void check_image_content_ycbcr420_16bit(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_420); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 33])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 34])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 35])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 36])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 37])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 38])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 41])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 42])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 43])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 44])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 45])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 46])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 49])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 50])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 51])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 52])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 53])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 54])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 57])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 60])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 61])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 62])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x80); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0xAD); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0xAF); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xAF); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x4C); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xAF); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x4B); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cb, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 2; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x7F); + } + for (int row = 2; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x1D); + } + for (int row = 4; row < 6; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xA3); + } + for (int row = 6; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xA3); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x54); + } + for (int row = 8; row < 10; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xA3); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x55); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cr, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 2; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x7F); + } + for (int row = 2; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xBA); + } + for (int row = 4; row < 6; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xAD); + } + for (int row = 6; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xFF); + } + for (int row = 8; row < 10; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x4A); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content YCbCr 4:2:0 16 bit") { + auto file = GENERATE(YUV_16BIT_420_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_ycbcr420_16bit(context); + heif_context_free(context); +} \ No newline at end of file diff --git a/tests/uncompressed_decode_ycbcr422.cc b/tests/uncompressed_decode_ycbcr422.cc new file mode 100644 index 0000000000..8baa983130 --- /dev/null +++ b/tests/uncompressed_decode_ycbcr422.cc @@ -0,0 +1,845 @@ +/* + libheif integration tests for uncompressed decoder + + MIT License + + Copyright (c) 2023 Brad Hards + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ +#include "catch.hpp" +#include "libheif/heif.h" +#include "libheif/api_structs.h" +#include +#include +#include "test_utils.h" +#include + +#include "uncompressed_decode.h" + +void check_image_size_ycbcr_422(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_422); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 32); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 32); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 8); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size YCbCr 4:2:2") { + auto file = GENERATE(YUV_422_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_size_ycbcr_422(context); + heif_context_free(context); +} + +void check_image_size_ycbcr_422_16bit(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_422); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 32); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 32); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 16); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 20); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 16); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 16); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 16); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 16); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size YCbCr 4:2:2 16 bit") { + auto file = GENERATE(YUV_16BIT_422_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_size_ycbcr_422_16bit(context); + heif_context_free(context); +} + +void check_image_content_ycbcr422(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_422); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 76); + REQUIRE(((int)(img_plane[stride * row + 3])) == 76); + REQUIRE(((int)(img_plane[stride * row + 4])) == 75); + REQUIRE(((int)(img_plane[stride * row + 7])) == 75); + REQUIRE(((int)(img_plane[stride * row + 8])) == 29); + REQUIRE(((int)(img_plane[stride * row + 11])) == 29); + REQUIRE(((int)(img_plane[stride * row + 12])) == 254); + REQUIRE(((int)(img_plane[stride * row + 15])) == 254); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0); + REQUIRE(((int)(img_plane[stride * row + 20])) == 225); + REQUIRE(((int)(img_plane[stride * row + 23])) == 225); + REQUIRE(((int)(img_plane[stride * row + 24])) == 178); + REQUIRE(((int)(img_plane[stride * row + 27])) == 178); + REQUIRE(((int)(img_plane[stride * row + 28])) == 128); + REQUIRE(((int)(img_plane[stride * row + 29])) == 128); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 75); + REQUIRE(((int)(img_plane[stride * row + 3])) == 75); + REQUIRE(((int)(img_plane[stride * row + 4])) == 29); + REQUIRE(((int)(img_plane[stride * row + 7])) == 29); + REQUIRE(((int)(img_plane[stride * row + 8])) == 254); + REQUIRE(((int)(img_plane[stride * row + 11])) == 254); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0); + REQUIRE(((int)(img_plane[stride * row + 16])) == 225); + REQUIRE(((int)(img_plane[stride * row + 19])) == 225); + REQUIRE(((int)(img_plane[stride * row + 20])) == 178); + REQUIRE(((int)(img_plane[stride * row + 23])) == 178); + REQUIRE(((int)(img_plane[stride * row + 24])) == 128); + REQUIRE(((int)(img_plane[stride * row + 27])) == 128); + REQUIRE(((int)(img_plane[stride * row + 28])) == 173); + REQUIRE(((int)(img_plane[stride * row + 29])) == 173); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 29); + REQUIRE(((int)(img_plane[stride * row + 3])) == 29); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 7])) == 254); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 225); + REQUIRE(((int)(img_plane[stride * row + 15])) == 225); + REQUIRE(((int)(img_plane[stride * row + 16])) == 178); + REQUIRE(((int)(img_plane[stride * row + 19])) == 178); + REQUIRE(((int)(img_plane[stride * row + 20])) == 128); + REQUIRE(((int)(img_plane[stride * row + 23])) == 128); + REQUIRE(((int)(img_plane[stride * row + 24])) == 173); + REQUIRE(((int)(img_plane[stride * row + 27])) == 173); + REQUIRE(((int)(img_plane[stride * row + 28])) == 174); + REQUIRE(((int)(img_plane[stride * row + 29])) == 174); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 225); + REQUIRE(((int)(img_plane[stride * row + 11])) == 225); + REQUIRE(((int)(img_plane[stride * row + 12])) == 178); + REQUIRE(((int)(img_plane[stride * row + 15])) == 178); + REQUIRE(((int)(img_plane[stride * row + 16])) == 128); + REQUIRE(((int)(img_plane[stride * row + 19])) == 128); + REQUIRE(((int)(img_plane[stride * row + 20])) == 173); + REQUIRE(((int)(img_plane[stride * row + 23])) == 173); + REQUIRE(((int)(img_plane[stride * row + 24])) == 174); + REQUIRE(((int)(img_plane[stride * row + 27])) == 174); + REQUIRE(((int)(img_plane[stride * row + 28])) == 76); + REQUIRE(((int)(img_plane[stride * row + 29])) == 76); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 225); + REQUIRE(((int)(img_plane[stride * row + 7])) == 225); + REQUIRE(((int)(img_plane[stride * row + 8])) == 178); + REQUIRE(((int)(img_plane[stride * row + 9])) == 178); + REQUIRE(((int)(img_plane[stride * row + 12])) == 128); + REQUIRE(((int)(img_plane[stride * row + 15])) == 128); + REQUIRE(((int)(img_plane[stride * row + 16])) == 173); + REQUIRE(((int)(img_plane[stride * row + 19])) == 173); + REQUIRE(((int)(img_plane[stride * row + 20])) == 174); + REQUIRE(((int)(img_plane[stride * row + 23])) == 174); + REQUIRE(((int)(img_plane[stride * row + 24])) == 76); + REQUIRE(((int)(img_plane[stride * row + 27])) == 76); + REQUIRE(((int)(img_plane[stride * row + 28])) == 75); + REQUIRE(((int)(img_plane[stride * row + 29])) == 75); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cb, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 84); + REQUIRE(((int)(img_plane[stride * row + 1])) == 84); + REQUIRE(((int)(img_plane[stride * row + 2])) == 85); + REQUIRE(((int)(img_plane[stride * row + 3])) == 85); + REQUIRE(((int)(img_plane[stride * row + 4])) == 254); + REQUIRE(((int)(img_plane[stride * row + 5])) == 254); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 170); + REQUIRE(((int)(img_plane[stride * row + 13])) == 170); + REQUIRE(((int)(img_plane[stride * row + 14])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 85); + REQUIRE(((int)(img_plane[stride * row + 1])) == 85); + REQUIRE(((int)(img_plane[stride * row + 2])) == 254); + REQUIRE(((int)(img_plane[stride * row + 3])) == 254); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 10])) == 170); + REQUIRE(((int)(img_plane[stride * row + 11])) == 170); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 13])) == 127); + REQUIRE(((int)(img_plane[stride * row + 14])) == 29); + REQUIRE(((int)(img_plane[stride * row + 15])) == 29); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 1])) == 254); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 170); + REQUIRE(((int)(img_plane[stride * row + 9])) == 170); + REQUIRE(((int)(img_plane[stride * row + 10])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 29); + REQUIRE(((int)(img_plane[stride * row + 13])) == 29); + REQUIRE(((int)(img_plane[stride * row + 14])) == 163); + REQUIRE(((int)(img_plane[stride * row + 15])) == 163); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0); + REQUIRE(((int)(img_plane[stride * row + 6])) == 170); + REQUIRE(((int)(img_plane[stride * row + 7])) == 170); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 29); + REQUIRE(((int)(img_plane[stride * row + 11])) == 29); + REQUIRE(((int)(img_plane[stride * row + 12])) == 163); + REQUIRE(((int)(img_plane[stride * row + 13])) == 163); + REQUIRE(((int)(img_plane[stride * row + 14])) == 84); + REQUIRE(((int)(img_plane[stride * row + 15])) == 84); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0); + REQUIRE(((int)(img_plane[stride * row + 4])) == 170); + REQUIRE(((int)(img_plane[stride * row + 5])) == 170); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 29); + REQUIRE(((int)(img_plane[stride * row + 9])) == 29); + REQUIRE(((int)(img_plane[stride * row + 10])) == 163); + REQUIRE(((int)(img_plane[stride * row + 11])) == 163); + REQUIRE(((int)(img_plane[stride * row + 12])) == 84); + REQUIRE(((int)(img_plane[stride * row + 13])) == 84); + REQUIRE(((int)(img_plane[stride * row + 14])) == 85); + REQUIRE(((int)(img_plane[stride * row + 15])) == 85); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cr, &stride); + REQUIRE(stride == 64); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 254); + REQUIRE(((int)(img_plane[stride * row + 1])) == 254); + REQUIRE(((int)(img_plane[stride * row + 2])) == 73); + REQUIRE(((int)(img_plane[stride * row + 3])) == 73); + REQUIRE(((int)(img_plane[stride * row + 4])) == 106); + REQUIRE(((int)(img_plane[stride * row + 5])) == 106); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 148); + REQUIRE(((int)(img_plane[stride * row + 11])) == 148); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0); + REQUIRE(((int)(img_plane[stride * row + 14])) == 127); + REQUIRE(((int)(img_plane[stride * row + 15])) == 127); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 73); + REQUIRE(((int)(img_plane[stride * row + 1])) == 73); + REQUIRE(((int)(img_plane[stride * row + 2])) == 106); + REQUIRE(((int)(img_plane[stride * row + 3])) == 106); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 148); + REQUIRE(((int)(img_plane[stride * row + 9])) == 148); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0); + REQUIRE(((int)(img_plane[stride * row + 12])) == 127); + REQUIRE(((int)(img_plane[stride * row + 13])) == 127); + REQUIRE(((int)(img_plane[stride * row + 14])) == 185); + REQUIRE(((int)(img_plane[stride * row + 15])) == 185); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 106); + REQUIRE(((int)(img_plane[stride * row + 1])) == 106); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 127); + REQUIRE(((int)(img_plane[stride * row + 5])) == 127); + REQUIRE(((int)(img_plane[stride * row + 6])) == 148); + REQUIRE(((int)(img_plane[stride * row + 7])) == 148); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0); + REQUIRE(((int)(img_plane[stride * row + 10])) == 127); + REQUIRE(((int)(img_plane[stride * row + 11])) == 127); + REQUIRE(((int)(img_plane[stride * row + 12])) == 185); + REQUIRE(((int)(img_plane[stride * row + 13])) == 185); + REQUIRE(((int)(img_plane[stride * row + 14])) == 172); + REQUIRE(((int)(img_plane[stride * row + 15])) == 172); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 127); + REQUIRE(((int)(img_plane[stride * row + 3])) == 127); + REQUIRE(((int)(img_plane[stride * row + 4])) == 148); + REQUIRE(((int)(img_plane[stride * row + 5])) == 148); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0); + REQUIRE(((int)(img_plane[stride * row + 8])) == 127); + REQUIRE(((int)(img_plane[stride * row + 9])) == 127); + REQUIRE(((int)(img_plane[stride * row + 10])) == 185); + REQUIRE(((int)(img_plane[stride * row + 11])) == 185); + REQUIRE(((int)(img_plane[stride * row + 12])) == 172); + REQUIRE(((int)(img_plane[stride * row + 13])) == 172); + REQUIRE(((int)(img_plane[stride * row + 14])) == 254); + REQUIRE(((int)(img_plane[stride * row + 15])) == 254); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 127); + REQUIRE(((int)(img_plane[stride * row + 1])) == 127); + REQUIRE(((int)(img_plane[stride * row + 2])) == 148); + REQUIRE(((int)(img_plane[stride * row + 3])) == 148); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0); + REQUIRE(((int)(img_plane[stride * row + 6])) == 127); + REQUIRE(((int)(img_plane[stride * row + 7])) == 127); + REQUIRE(((int)(img_plane[stride * row + 8])) == 185); + REQUIRE(((int)(img_plane[stride * row + 9])) == 185); + REQUIRE(((int)(img_plane[stride * row + 10])) == 172); + REQUIRE(((int)(img_plane[stride * row + 11])) == 172); + REQUIRE(((int)(img_plane[stride * row + 12])) == 254); + REQUIRE(((int)(img_plane[stride * row + 13])) == 254); + REQUIRE(((int)(img_plane[stride * row + 14])) == 73); + REQUIRE(((int)(img_plane[stride * row + 15])) == 73); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content YCbCr 4:2:2") { + auto file = GENERATE(YUV_422_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_ycbcr422(context); + heif_context_free(context); +} + + +void check_image_content_ycbcr422_16bit(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_422); + + int stride; + const uint8_t *img_plane = + heif_image_get_plane_readonly(img, heif_channel_Y, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 33])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 34])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 35])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 36])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 37])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 38])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 41])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 42])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 43])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 44])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 45])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 46])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 49])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 50])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 51])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 52])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 53])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 54])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 57])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 59])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 60])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 61])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 62])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x80); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4B); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0xAD); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x2E); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0xAF); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFE); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0xAF); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x4C); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xD0); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xE2); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x74); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xB3); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 32])) == 0xC6); + REQUIRE(((int)(img_plane[stride * row + 39])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 40])) == 0x49); + REQUIRE(((int)(img_plane[stride * row + 47])) == 0xAF); + REQUIRE(((int)(img_plane[stride * row + 48])) == 0x8A); + REQUIRE(((int)(img_plane[stride * row + 55])) == 0x4C); + REQUIRE(((int)(img_plane[stride * row + 56])) == 0x6D); + REQUIRE(((int)(img_plane[stride * row + 63])) == 0x4B); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cb, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x7F); + } + for (int row = 5; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x55); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x1D); + } + for (int row = 9; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xA3); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xA3); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x54); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x01); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0xAB); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xDE); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xE8); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x1D); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xA5); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xA3); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xBC); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x54); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x76); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x55); + } + img_plane = heif_image_get_plane_readonly(img, heif_channel_Cr, &stride); + REQUIRE(stride == 128); + for (int row = 0; row < 4; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 1])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 2])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 5])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 6])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 9])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 10])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 13])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 14])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 17])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 18])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 21])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 22])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 25])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 26])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 29])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 30])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x7F); + } + for (int row = 4; row < 8; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x4A); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xBA); + } + for (int row = 8; row < 12; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0x2F); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x6B); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xAD); + } + for (int row = 12; row < 16; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xEB); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0xFF); + } + for (int row = 16; row < 20; row++) { + INFO("row: " << row); + REQUIRE(((int)(img_plane[stride * row + 0])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 3])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 4])) == 0xBB); + REQUIRE(((int)(img_plane[stride * row + 7])) == 0x94); + REQUIRE(((int)(img_plane[stride * row + 8])) == 0x2D); + REQUIRE(((int)(img_plane[stride * row + 11])) == 0x00); + REQUIRE(((int)(img_plane[stride * row + 12])) == 0xF5); + REQUIRE(((int)(img_plane[stride * row + 15])) == 0x7F); + REQUIRE(((int)(img_plane[stride * row + 16])) == 0x80); + REQUIRE(((int)(img_plane[stride * row + 19])) == 0xBA); + REQUIRE(((int)(img_plane[stride * row + 20])) == 0x3F); + REQUIRE(((int)(img_plane[stride * row + 23])) == 0xAD); + REQUIRE(((int)(img_plane[stride * row + 24])) == 0xBD); + REQUIRE(((int)(img_plane[stride * row + 27])) == 0xFF); + REQUIRE(((int)(img_plane[stride * row + 28])) == 0x48); + REQUIRE(((int)(img_plane[stride * row + 31])) == 0x4A); + } + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image content YCbCr 4:2:2 16 bit") { + auto file = GENERATE(YUV_16BIT_422_FILES); + auto context = get_context_for_test_file(file); + INFO("file name: " << file); + check_image_content_ycbcr422_16bit(context); + heif_context_free(context); +} diff --git a/tests/uncompressed_encode.cc b/tests/uncompressed_encode.cc index f96a457cf7..14933a67d8 100644 --- a/tests/uncompressed_encode.cc +++ b/tests/uncompressed_encode.cc @@ -690,6 +690,7 @@ static void do_encode(heif_image* input_image, const char* filename, bool check_ // TODO: make proper test for interleave to component translation // TODO: compare values + heif_image_release(decode_image); heif_image_handle_release(decode_image_handle); heif_context_free(decode_context); }