Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libheif for openSUSE:Factory checked in at 2023-11-06 21:13:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libheif (Old) and /work/SRC/openSUSE:Factory/.libheif.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libheif" Mon Nov 6 21:13:32 2023 rev:25 rq:1123517 version:1.17.3 Changes: -------- --- /work/SRC/openSUSE:Factory/libheif/libheif.changes 2023-10-20 23:17:18.915719989 +0200 +++ /work/SRC/openSUSE:Factory/.libheif.new.17445/libheif.changes 2023-11-06 21:13:33.849687329 +0100 @@ -1,0 +2,14 @@ +Fri Nov 3 14:49:07 UTC 2023 - Arjen de Korte <suse+bu...@de-korte.org> + +- update to 1.17.3 + * Bug fix #1026: corrected transform box generation for + heif_orientation_flip_vertically and + heif_orientation_rotate_90_cw_then_flip_vertically + +- update to 1.17.2: + * #1010 loading of HEIF files with extra zero bytes at the end + * #1015 / #1017 default nclx values now match sRGB + * support JPEG2000 images with alpha channel + * various smaller fixes + +------------------------------------------------------------------- Old: ---- libheif-1.17.1.tar.gz New: ---- libheif-1.17.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libheif.spec ++++++ --- /var/tmp/diff_new_pack.vOvpe8/_old 2023-11-06 21:13:34.861724582 +0100 +++ /var/tmp/diff_new_pack.vOvpe8/_new 2023-11-06 21:13:34.865724729 +0100 @@ -31,7 +31,7 @@ %endif Name: libheif -Version: 1.17.1 +Version: 1.17.3 Release: 0 Summary: HEIF/AVIF file format decoder and encoder License: GPL-2.0-or-later ++++++ libheif-1.17.1.tar.gz -> libheif-1.17.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/CMakeLists.txt new/libheif-1.17.3/CMakeLists.txt --- old/libheif-1.17.1/CMakeLists.txt 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/CMakeLists.txt 2023-11-03 15:08:35.000000000 +0100 @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.16.3) # Oldest Ubuntu LTS (20.04 currently) -project(libheif LANGUAGES C CXX VERSION 1.17.1) +project(libheif LANGUAGES C CXX VERSION 1.17.3) # compatibility_version is never allowed to be decreased for any specific SONAME. # Libtool in the libheif-1.15.1 release had set it to 17.0.0, so we have to use this for the v1.x.y versions. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/README.md new/libheif-1.17.3/README.md --- old/libheif-1.17.1/README.md 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/README.md 2023-11-03 15:08:35.000000000 +0100 @@ -122,7 +122,7 @@ Also install x265 and its development files if you want to use HEIF encoding, but note that x265 is GPL. An alternative to x265 is kvazaar (BSD). -The basic build steps are as follows: +The basic build steps are as follows (--preset argument needs CMake >= 3.21): ````sh mkdir build @@ -180,7 +180,7 @@ brew install cmake make pkg-config x265 libde265 libjpeg libtool ``` -2. Configure and build project +2. Configure and build project (--preset argument needs CMake >= 3.21): ```sh mkdir build diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/examples/decoder_png.cc new/libheif-1.17.3/examples/decoder_png.cc --- old/libheif-1.17.1/examples/decoder_png.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/examples/decoder_png.cc 2023-11-03 15:08:35.000000000 +0100 @@ -213,6 +213,7 @@ // --- read XMP data +#ifdef PNG_iTXt_SUPPORTED png_textp textPtr = nullptr; const png_uint_32 nTextChunks = png_get_text(png_ptr, info_ptr, &textPtr, nullptr); for (png_uint_32 i = 0; i < nTextChunks; i++, textPtr++) { @@ -231,6 +232,7 @@ } } } +#endif int band = png_get_channels(png_ptr, info_ptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/examples/encoder_png.cc new/libheif-1.17.3/examples/encoder_png.cc --- old/libheif-1.17.1/examples/encoder_png.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/examples/encoder_png.cc 2023-11-03 15:08:35.000000000 +0100 @@ -134,6 +134,7 @@ // --- write XMP metadata +#ifdef PNG_iTXt_SUPPORTED // spec: https://raw.githubusercontent.com/adobe/xmp-docs/master/XMPSpecifications/XMPSpecificationPart3.pdf std::vector<uint8_t> xmp = get_xmp_metadata(handle); if (!xmp.empty()) { @@ -156,6 +157,7 @@ xmp_text.itxt_length = text_length; png_set_text(png_ptr, info_ptr, &xmp_text, 1); } +#endif png_write_info(png_ptr, info_ptr); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/examples/heif_convert.cc new/libheif-1.17.3/examples/heif_convert.cc --- old/libheif-1.17.1/examples/heif_convert.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/examples/heif_convert.cc 2023-11-03 15:08:35.000000000 +0100 @@ -171,7 +171,7 @@ std::cout << "JPEG decoders:\n"; list_decoders(heif_compression_JPEG); - std::cout << "JPEG-2000 decoders:\n"; + std::cout << "JPEG 2000 decoders:\n"; list_decoders(heif_compression_JPEG2000); #if WITH_UNCOMPRESSED_CODEC diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/examples/heif_enc.cc new/libheif-1.17.3/examples/heif_enc.cc --- old/libheif-1.17.1/examples/heif_enc.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/examples/heif_enc.cc 2023-11-03 15:08:35.000000000 +0100 @@ -64,9 +64,9 @@ const char* encoderId = nullptr; std::string chroma_downsampling; +uint16_t nclx_colour_primaries = 1; +uint16_t nclx_transfer_characteristic = 13; uint16_t nclx_matrix_coefficients = 6; -uint16_t nclx_colour_primaries = 2; -uint16_t nclx_transfer_characteristic = 2; int nclx_full_range = true; std::string property_pitm_description; @@ -114,7 +114,7 @@ {(char* const) "avif", no_argument, 0, 'A'}, {(char* const) "jpeg", no_argument, 0, OPTION_USE_JPEG_COMPRESSION}, {(char* const) "jpeg2000", no_argument, 0, OPTION_USE_JPEG2000_COMPRESSION}, -#if ENABLE_UNCOMPRESSED_ENCODER +#if WITH_UNCOMPRESSED_CODEC {(char* const) "uncompressed", no_argument, 0, 'U'}, #endif {(char* const) "matrix_coefficients", required_argument, 0, OPTION_NCLX_MATRIX_COEFFICIENTS}, @@ -160,8 +160,8 @@ << " -p set encoder parameter (NAME=VALUE)\n" << " -A, --avif encode as AVIF (not needed if output filename with .avif suffix is provided)\n" << " --jpeg encode as JPEG\n" - << " --jpeg2000 encode as JPEG-2000 (experimental)\n" -#if ENABLE_UNCOMPRESSED_ENCODER + << " --jpeg2000 encode as JPEG 2000 (experimental)\n" +#if WITH_UNCOMPRESSED_CODEC << " -U, --uncompressed encode as uncompressed image (according to ISO 23001-17) (EXPERIMENTAL)\n" #endif << " --list-encoders list all available encoders for all compression formats\n" @@ -349,6 +349,30 @@ } +static const char* get_compression_format_name(heif_compression_format format) +{ + switch (format) { + case heif_compression_AV1: + return "AV1"; + break; + case heif_compression_HEVC: + return "HEVC"; + break; + case heif_compression_JPEG: + return "JPEG"; + break; + case heif_compression_JPEG2000: + return "JPEG 2000"; + break; + case heif_compression_uncompressed: + return "Uncompressed"; + break; + default: + assert(false); + return "unknown"; + } +} + static void show_list_of_all_encoders() { for (auto compression_format : {heif_compression_HEVC, heif_compression_AV1, heif_compression_JPEG, heif_compression_JPEG2000 @@ -368,7 +392,7 @@ std::cout << "JPEG"; break; case heif_compression_JPEG2000: - std::cout << "JPEG-2000"; + std::cout << "JPEG 2000"; break; case heif_compression_uncompressed: std::cout << "Uncompressed"; @@ -687,7 +711,7 @@ active_encoder_descriptor = encoder_descriptors[idx]; } else { - std::cerr << "No " << (compressionFormat == heif_compression_AV1 ? "AV1" : "HEVC") << " encoder available.\n"; + std::cerr << "No " << get_compression_format_name(compressionFormat) << " encoder available.\n"; return 5; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/Doxyfile.in new/libheif-1.17.3/libheif/Doxyfile.in --- old/libheif-1.17.1/libheif/Doxyfile.in 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/Doxyfile.in 2023-11-03 15:08:35.000000000 +0100 @@ -170,7 +170,7 @@ # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = @CMAKE_CURRENT_SOURCE_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -864,7 +864,8 @@ # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@/libheif/heif.h +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/libheif/heif.h \ +@CMAKE_CURRENT_SOURCE_DIR@/libheif/heif_regions.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/avif.cc new/libheif-1.17.3/libheif/avif.cc --- old/libheif-1.17.1/libheif/avif.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/avif.cc 2023-11-03 15:08:35.000000000 +0100 @@ -33,6 +33,13 @@ { //parse_full_box_header(range); + if (!has_fixed_box_size()) { + // Note: in theory, it is allowed to have an av1C box with unspecified size (until the end of the file), + // but that would be very uncommon and give us problems in the calculation of `configOBUs_bytes` below. + // It's better to error on this case than to open a DoS vulnerability. + return Error{heif_error_Invalid_input, heif_suberror_Unspecified, "av1C with unspecified box size"}; + } + uint8_t byte; auto& c = m_configuration; // abbreviation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/box.cc new/libheif-1.17.3/libheif/box.cc --- old/libheif-1.17.1/libheif/box.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/box.cc 2023-11-03 15:08:35.000000000 +0100 @@ -85,7 +85,7 @@ Fraction Fraction::operator+(const Fraction& b) const { if (denominator == b.denominator) { - int64_t n = numerator + b.numerator; + int64_t n = int64_t{numerator} + b.numerator; int64_t d = denominator; return Fraction{n,d}; } @@ -99,7 +99,7 @@ Fraction Fraction::operator-(const Fraction& b) const { if (denominator == b.denominator) { - int64_t n = numerator - b.numerator; + int64_t n = int64_t{numerator} - b.numerator; int64_t d = denominator; return Fraction{n,d}; } @@ -617,7 +617,7 @@ box->set_short_header(hdr); - if (hdr.get_box_size() < hdr.get_header_size()) { + if (hdr.has_fixed_box_size() && hdr.get_box_size() < hdr.get_header_size()) { std::stringstream sstr; sstr << "Box size (" << hdr.get_box_size() << " bytes) smaller than header size (" << hdr.get_header_size() << " bytes)"; @@ -636,14 +636,15 @@ } - auto status = range.wait_for_available_bytes(hdr.get_box_size() - hdr.get_header_size()); - if (status != StreamReader::size_reached) { - // TODO: return recoverable error at timeout - return Error(heif_error_Invalid_input, - heif_suberror_End_of_data); + if (hdr.has_fixed_box_size()) { + auto status = range.wait_for_available_bytes(hdr.get_box_size() - hdr.get_header_size()); + if (status != StreamReader::size_reached) { + // TODO: return recoverable error at timeout + return Error(heif_error_Invalid_input, + heif_suberror_End_of_data); + } } - // Security check: make sure that box size does not exceed int64 size. if (hdr.get_box_size() > (uint64_t) std::numeric_limits<int64_t>::max()) { @@ -652,7 +653,7 @@ } int64_t box_size = static_cast<int64_t>(hdr.get_box_size()); - int64_t box_size_without_header = box_size - hdr.get_header_size(); + int64_t box_size_without_header = hdr.has_fixed_box_size() ? (box_size - hdr.get_header_size()) : (int64_t)range.get_remaining_bytes(); // Box size may not be larger than remaining bytes in parent box. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/box.h new/libheif-1.17.3/libheif/box.h --- old/libheif-1.17.1/libheif/box.h 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/box.h 2023-11-03 15:08:35.000000000 +0100 @@ -115,6 +115,8 @@ uint64_t get_box_size() const { return m_size; } + bool has_fixed_box_size() const { return m_size != 0; } + uint32_t get_header_size() const { return m_header_size; } uint32_t get_short_type() const { return m_type; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/color-conversion/colorconversion.cc new/libheif-1.17.3/libheif/color-conversion/colorconversion.cc --- old/libheif-1.17.1/libheif/color-conversion/colorconversion.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/color-conversion/colorconversion.cc 2023-11-03 15:08:35.000000000 +0100 @@ -446,8 +446,7 @@ // --- pass the color profiles to the new image - auto output_nclx = std::make_shared<color_profile_nclx>(); - *output_nclx = step.output_state.nclx_profile; + auto output_nclx = std::make_shared<color_profile_nclx>(step.output_state.nclx_profile); out->set_color_profile_nclx(output_nclx); out->set_color_profile_icc(in->get_color_profile_icc()); @@ -521,19 +520,7 @@ input_state.nclx_profile = *input->get_color_profile_nclx(); } - // If some input nclx values are unspecified, use CCIR-601 values as default. - - if (input_state.nclx_profile.get_matrix_coefficients() == heif_matrix_coefficients_unspecified) { - input_state.nclx_profile.set_matrix_coefficients(heif_matrix_coefficients_ITU_R_BT_601_6); - } - - if (input_state.nclx_profile.get_colour_primaries() == heif_color_primaries_unspecified) { - input_state.nclx_profile.set_colour_primaries(heif_color_primaries_ITU_R_BT_601_6); - } - - if (input_state.nclx_profile.get_transfer_characteristics() == heif_color_primaries_unspecified) { - input_state.nclx_profile.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_601_6); - } + input_state.nclx_profile.replace_undefined_values_with_sRGB_defaults(); std::set<enum heif_channel> channels = input->get_channel_set(); assert(!channels.empty()); @@ -546,7 +533,7 @@ output_state.nclx_profile = *target_profile; } - // If some output nclx values are unspecified, set the to the same as the input. + // If some output nclx values are unspecified, set them to the same as the input. if (output_state.nclx_profile.get_matrix_coefficients() == heif_matrix_coefficients_unspecified) { output_state.nclx_profile.set_matrix_coefficients(input_state.nclx_profile.get_matrix_coefficients()); @@ -556,7 +543,7 @@ output_state.nclx_profile.set_colour_primaries(input_state.nclx_profile.get_colour_primaries()); } - if (output_state.nclx_profile.get_transfer_characteristics() == heif_color_primaries_unspecified) { + if (output_state.nclx_profile.get_transfer_characteristics() == heif_transfer_characteristic_unspecified) { output_state.nclx_profile.set_transfer_characteristics(input_state.nclx_profile.get_transfer_characteristics()); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/context.cc new/libheif-1.17.3/libheif/context.cc --- old/libheif-1.17.1/libheif/context.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/context.cc 2023-11-03 15:08:35.000000000 +0100 @@ -1193,7 +1193,7 @@ return err; } - // TODO: this should be codec specific. JPEG-2000, for example, can use RGB internally. + // TODO: this should be codec specific. JPEG 2000, for example, can use RGB internally. *out_colorspace = heif_colorspace_YCbCr; *out_chroma = heif_chroma_undefined; @@ -2429,6 +2429,29 @@ } +static std::shared_ptr<color_profile_nclx> compute_target_nclx_profile(const std::shared_ptr<HeifPixelImage>& image, const heif_color_profile_nclx* output_nclx_profile) +{ + auto target_nclx_profile = std::make_shared<color_profile_nclx>(); + + // If there is an output NCLX specified, use that. + if (output_nclx_profile) { + target_nclx_profile->set_from_heif_color_profile_nclx(output_nclx_profile); + } + // Otherwise, if there is an input NCLX, keep that. + else if (auto input_nclx = image->get_color_profile_nclx()) { + *target_nclx_profile = *input_nclx; + } + // Otherwise, just use the defaults (set below) + else { + target_nclx_profile->set_undefined(); + } + + target_nclx_profile->replace_undefined_values_with_sRGB_defaults(); + + return target_nclx_profile; +} + + Error HeifContext::encode_image_as_hevc(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, @@ -2444,8 +2467,7 @@ heif_colorspace colorspace = image->get_colorspace(); heif_chroma chroma = image->get_chroma_format(); - auto target_nclx_profile = std::make_shared<color_profile_nclx>(); - target_nclx_profile->set_from_heif_color_profile_nclx(options.output_nclx_profile); + auto target_nclx_profile = compute_target_nclx_profile(image, options.output_nclx_profile); if (encoder->plugin->plugin_api_version >= 2) { encoder->plugin->query_input_colorspace2(encoder->encoder, &colorspace, &chroma); @@ -2652,8 +2674,7 @@ heif_colorspace colorspace = image->get_colorspace(); heif_chroma chroma = image->get_chroma_format(); - auto target_nclx_profile = std::make_shared<color_profile_nclx>(); - target_nclx_profile->set_from_heif_color_profile_nclx(options.output_nclx_profile); + auto target_nclx_profile = compute_target_nclx_profile(image, options.output_nclx_profile); if (encoder->plugin->plugin_api_version >= 2) { encoder->plugin->query_input_colorspace2(encoder->encoder, &colorspace, &chroma); @@ -2828,8 +2849,7 @@ auto nclx_profile = std::dynamic_pointer_cast<const color_profile_nclx>(color_profile); */ - auto target_nclx_profile = std::make_shared<color_profile_nclx>(); - target_nclx_profile->set_from_heif_color_profile_nclx(options.output_nclx_profile); + auto target_nclx_profile = compute_target_nclx_profile(image, options.output_nclx_profile); if (encoder->plugin->plugin_api_version >= 2) { encoder->plugin->query_input_colorspace2(encoder->encoder, &colorspace, &chroma); @@ -2855,6 +2875,38 @@ // ---end--- + // --- if there is an alpha channel, add it as an additional image + + if (options.save_alpha_channel && src_image->has_channel(heif_channel_Alpha)) { + + // --- generate alpha image + // TODO: can we directly code a monochrome image instead of the dummy color channels? + + std::shared_ptr<HeifPixelImage> alpha_image; + alpha_image = create_alpha_image_from_image_alpha_channel(src_image); + + + // --- encode the alpha image + + std::shared_ptr<HeifContext::Image> heif_alpha_image; + + + Error error = encode_image_as_jpeg2000(alpha_image, encoder, options, + heif_image_input_class_alpha, + heif_alpha_image); + if (error) { + return error; + } + + m_heif_file->add_iref_reference(heif_alpha_image->get_id(), fourcc("auxl"), {image_id}); + m_heif_file->set_auxC_property(heif_alpha_image->get_id(), "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"); + + if (src_image->is_premultiplied_alpha()) { + m_heif_file->add_iref_reference(image_id, fourcc("prem"), {heif_alpha_image->get_id()}); + } + } + + //Encode Image heif_image c_api_image; c_api_image.image = src_image; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/file.cc new/libheif-1.17.3/libheif/file.cc --- old/libheif-1.17.1/libheif/file.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/file.cc 2023-11-03 15:08:35.000000000 +0100 @@ -1013,7 +1013,7 @@ rotation_ccw = 180; break; case heif_orientation_flip_vertically: - mirror = heif_transform_mirror_direction_horizontal; + mirror = heif_transform_mirror_direction_vertical; has_mirror = true; break; case heif_orientation_rotate_90_cw_then_flip_horizontally: @@ -1026,7 +1026,7 @@ break; case heif_orientation_rotate_90_cw_then_flip_vertically: rotation_ccw = 270; - mirror = heif_transform_mirror_direction_horizontal; + mirror = heif_transform_mirror_direction_vertical; has_mirror = true; break; case heif_orientation_rotate_270_cw: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/heif.cc new/libheif-1.17.3/libheif/heif.cc --- old/libheif-1.17.1/libheif/heif.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/heif.cc 2023-11-03 15:08:35.000000000 +0100 @@ -83,24 +83,19 @@ return (LIBHEIF_NUMERIC_VERSION); } -static uint8_t bcd2dec(uint8_t v) -{ - return uint8_t((v >> 4) * 10 + (v & 0x0F)); -} - int heif_get_version_number_major(void) { - return bcd2dec(((LIBHEIF_NUMERIC_VERSION) >> 24) & 0xFF); + return ((LIBHEIF_NUMERIC_VERSION) >> 24) & 0xFF; } int heif_get_version_number_minor(void) { - return bcd2dec(((LIBHEIF_NUMERIC_VERSION) >> 16) & 0xFF); + return ((LIBHEIF_NUMERIC_VERSION) >> 16) & 0xFF; } int heif_get_version_number_maintenance(void) { - return bcd2dec(((LIBHEIF_NUMERIC_VERSION) >> 8) & 0xFF); + return ((LIBHEIF_NUMERIC_VERSION) >> 8) & 0xFF; } @@ -2606,7 +2601,7 @@ options.macOS_compatibility_workaround = false; options.save_two_colr_boxes_when_ICC_and_nclx_available = false; options.output_nclx_profile = nullptr; - options.macOS_compatibility_workaround_no_nclx_profile = true; + options.macOS_compatibility_workaround_no_nclx_profile = false; options.image_orientation = heif_orientation_normal; options.color_conversion_options.version = 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/heif.h new/libheif-1.17.3/libheif/heif.h --- old/libheif-1.17.1/libheif/heif.h 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/heif.h 2023-11-03 15:08:35.000000000 +0100 @@ -77,19 +77,18 @@ // Version string of linked libheif library. LIBHEIF_API const char* heif_get_version(void); -// Numeric version of linked libheif library, encoded as BCD 0xHHMMLL00 = HH.MM.LL. -// For example: 0x02143000 is version 2.14.30 +// Numeric version of linked libheif library, encoded as 0xHHMMLL00 = hh.mm.ll, where hh, mm, ll is the decimal representation of HH, MM, LL. +// For example: 0x02150300 is version 2.21.3 LIBHEIF_API uint32_t heif_get_version_number(void); -// Numeric part "HH" from above. Returned as a decimal number (not BCD). +// Numeric part "HH" from above. Returned as a decimal number. LIBHEIF_API int heif_get_version_number_major(void); -// Numeric part "MM" from above. Returned as a decimal number (not BCD). +// Numeric part "MM" from above. Returned as a decimal number. LIBHEIF_API int heif_get_version_number_minor(void); -// Numeric part "LL" from above. Returned as a decimal number (not BCD). +// Numeric part "LL" from above. Returned as a decimal number. LIBHEIF_API int heif_get_version_number_maintenance(void); // Helper macros to check for given versions of libheif at compile time. -// Note: h, m, l should be 2-digit BCD numbers. I.e., decimal 17 = 0x17 (BCD) #define LIBHEIF_MAKE_VERSION(h, m, l) ((h) << 24 | (m) << 16 | (l) << 8) #define LIBHEIF_HAVE_VERSION(h, m, l) (LIBHEIF_NUMERIC_VERSION >= LIBHEIF_MAKE_VERSION(h, m, l)) @@ -392,7 +391,7 @@ */ heif_compression_EVC = 6, /** - * JPEG 2000 compression. (Currently unused in libheif.) + * JPEG 2000 compression. * * The encapsulation of JPEG 2000 is specified in ISO/IEC 15444-16:2021. * The core encoding is defined in ISO/IEC 15444-1, or ITU-T T.800. @@ -401,7 +400,7 @@ /** * Uncompressed encoding. * - * This is defined in ISO/IEC 23001-17:2023 (Draft International Standard). + * This is defined in ISO/IEC 23001-17:2023 (Final Draft International Standard). */ heif_compression_uncompressed = 8, /** @@ -479,24 +478,36 @@ }; -// You should call heif_init() when you start using libheif and heif_deinit() when you are finished. -// These calls are reference counted. Each call to heif_init() should be matched by one call to heif_deinit(). -// -// For backwards compatibility, it is not really necessary to call heif_init(), but some library memory objects -// will never be freed if you do not call heif_init()/heif_deinit(). -// -// heif_init() will load the external modules installed in the default plugin path. Thus, you need it when you -// want to load external plugins from the default path. -// Codec plugins that are compiled into the library directly (selected by the compile-time parameters of libheif) -// will be available even without heif_init(). -// -// Make sure that you don't have one part of your program use heif_init()/heif_deinit() and another part that doesn't -// use it as the latter may try to use an uninitialized library. If in doubt, enclose everything with init/deinit. - -// You may pass nullptr to get default parameters. Currently, no parameters are supported. +/** + * Initialise library. + * + * You should call heif_init() when you start using libheif and heif_deinit() when you are finished. + * These calls are reference counted. Each call to heif_init() should be matched by one call to heif_deinit(). + * + * For backwards compatibility, it is not really necessary to call heif_init(), but some library memory objects + * will never be freed if you do not call heif_init()/heif_deinit(). + * + * heif_init() will load the external modules installed in the default plugin path. Thus, you need it when you + * want to load external plugins from the default path. + * Codec plugins that are compiled into the library directly (selected by the compile-time parameters of libheif) + * will be available even without heif_init(). + * + * Make sure that you do not have one part of your program use heif_init()/heif_deinit() and another part that does + * not use it as the latter may try to use an uninitialized library. If in doubt, enclose everything with init/deinit. + * + * You may pass nullptr to get default parameters. Currently, no parameters are supported. + */ LIBHEIF_API struct heif_error heif_init(struct heif_init_params*); +/** + * Deinitialise and clean up library. + * + * You should call heif_init() when you start using libheif and heif_deinit() when you are finished. + * These calls are reference counted. Each call to heif_init() should be matched by one call to heif_deinit(). + * + * \sa heif_init() + */ LIBHEIF_API void heif_deinit(void); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/heif_regions.h new/libheif-1.17.3/libheif/heif_regions.h --- old/libheif-1.17.1/libheif/heif_regions.h 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/heif_regions.h 2023-11-03 15:08:35.000000000 +0100 @@ -506,7 +506,7 @@ * The points are provided as pairs of X,Y coordinates, in the order X<sub>1</sub>, * Y<sub>1</sub>, X<sub>2</sub>, Y<sub>2</sub>, ..., X<sub>n</sub>, Y<sub>n</sub>. * - * @param region the region to equery, which must be of type #heif_region_type_polyline + * @param region the region to query, which must be of type #heif_region_type_polyline * @param image_id the identifier for the image to transform / scale the region to * @param out_pts_array the array to return the points in, which must have twice as many entries as there are points * in the polyline. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/hevc.cc new/libheif-1.17.3/libheif/hevc.cc --- old/libheif-1.17.1/libheif/hevc.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/hevc.cc 2023-11-03 15:08:35.000000000 +0100 @@ -90,8 +90,9 @@ if (range.prepare_read(size)) { nal_unit.resize(size); bool success = range.get_istream()->read((char*) nal_unit.data(), size); - assert(success); - (void) success; + if (!success) { + return Error{heif_error_Invalid_input, heif_suberror_End_of_data, "error while reading hvcC box"}; + } } array.m_nal_units.push_back(std::move(nal_unit)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/jpeg.cc new/libheif-1.17.3/libheif/jpeg.cc --- old/libheif-1.17.1/libheif/jpeg.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/jpeg.cc 2023-11-03 15:08:35.000000000 +0100 @@ -20,6 +20,7 @@ #include "jpeg.h" #include <string> +#include "security_limits.h" std::string Box_jpgC::dump(Indent& indent) const { @@ -46,7 +47,15 @@ Error Box_jpgC::parse(BitstreamRange& range) { + if (!has_fixed_box_size()) { + return Error{heif_error_Unsupported_feature, heif_suberror_Unspecified, "jpgC with unspecified size are not supported"}; + } + size_t nBytes = range.get_remaining_bytes(); + if (nBytes > MAX_MEMORY_BLOCK_SIZE) { + return Error{heif_error_Invalid_input, heif_suberror_Unspecified, "jpgC block exceeds maximum size"}; + } + m_data.resize(nBytes); range.read(m_data.data(), nBytes); return range.get_error(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/nclx.cc new/libheif-1.17.3/libheif/nclx.cc --- old/libheif-1.17.1/libheif/nclx.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/nclx.cc 2023-11-03 15:08:35.000000000 +0100 @@ -20,6 +20,7 @@ #include "nclx.h" +#include "security_limits.h" #include <cassert> #include <limits> @@ -294,9 +295,11 @@ if (profile) { profile->version = 1; - profile->color_primaries = heif_color_primaries_unspecified; - profile->transfer_characteristics = heif_transfer_characteristic_unspecified; - profile->matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_601_6; + + // sRGB defaults + profile->color_primaries = heif_color_primaries_ITU_R_BT_709_5; // 1 + profile->transfer_characteristics = heif_transfer_characteristic_IEC_61966_2_1; // 13 + profile->matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_601_6; // 6 profile->full_range_flag = true; } @@ -310,10 +313,11 @@ } -void color_profile_nclx::set_default() +void color_profile_nclx::set_sRGB_defaults() { - m_colour_primaries = 2; - m_transfer_characteristics = 2; + // sRGB defaults + m_colour_primaries = 1; + m_transfer_characteristics = 13; m_matrix_coefficients = 6; m_full_range_flag = true; } @@ -339,6 +343,22 @@ } +void color_profile_nclx::replace_undefined_values_with_sRGB_defaults() +{ + if (m_matrix_coefficients == heif_matrix_coefficients_unspecified) { + m_matrix_coefficients = heif_matrix_coefficients_ITU_R_BT_601_6; + } + + if (m_colour_primaries == heif_color_primaries_unspecified) { + m_colour_primaries = heif_color_primaries_ITU_R_BT_709_5; + } + + if (m_transfer_characteristics == heif_transfer_characteristic_unspecified) { + m_transfer_characteristics = heif_transfer_characteristic_IEC_61966_2_1; + } +} + + Error Box_colr::parse(BitstreamRange& range) { StreamReader::grow_status status; @@ -354,8 +374,12 @@ } else if (colour_type == fourcc("prof") || colour_type == fourcc("rICC")) { + if (!has_fixed_box_size()) { + return Error(heif_error_Unsupported_feature, heif_suberror_Unspecified, "colr boxes with undefined box size are not supported"); + } + uint64_t profile_size_64 = get_box_size() - get_header_size() - 4; - if (profile_size_64 > std::numeric_limits<size_t>::max()) { + if (profile_size_64 > MAX_COLOR_PROFILE_SIZE) { return Error(heif_error_Invalid_input, heif_suberror_Security_limit_exceeded, "Color profile exceeds maximum supported size"); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/nclx.h new/libheif-1.17.3/libheif/nclx.h --- old/libheif-1.17.1/libheif/nclx.h 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/nclx.h 2023-11-03 15:08:35.000000000 +0100 @@ -121,7 +121,7 @@ class color_profile_nclx : public color_profile { public: - color_profile_nclx() { set_default(); } + color_profile_nclx() { set_sRGB_defaults(); } uint32_t get_type() const override { return fourcc("nclx"); } @@ -147,7 +147,7 @@ void set_full_range_flag(bool full_range) { m_full_range_flag = full_range; } - void set_default(); + void set_sRGB_defaults(); void set_undefined(); @@ -159,6 +159,8 @@ void set_from_heif_color_profile_nclx(const struct heif_color_profile_nclx* nclx); + void replace_undefined_values_with_sRGB_defaults(); + private: uint16_t m_colour_primaries = heif_color_primaries_unspecified; uint16_t m_transfer_characteristics = heif_transfer_characteristic_unspecified; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/plugins/decoder_libde265.cc new/libheif-1.17.3/libheif/plugins/decoder_libde265.cc --- old/libheif-1.17.1/libheif/plugins/decoder_libde265.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/plugins/decoder_libde265.cc 2023-11-03 15:08:35.000000000 +0100 @@ -338,10 +338,25 @@ struct heif_color_profile_nclx* nclx = heif_nclx_color_profile_alloc(); #if LIBDE265_NUMERIC_VERSION >= 0x01000700 - HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_color_primaries(nclx, static_cast<uint16_t>(de265_get_image_colour_primaries(image))), { heif_nclx_color_profile_free(nclx);}); - HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_transfer_characteristics(nclx, static_cast<uint16_t>(de265_get_image_transfer_characteristics(image))), { heif_nclx_color_profile_free(nclx);}); - HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_matrix_coefficients(nclx, static_cast<uint16_t>(de265_get_image_matrix_coefficients(image))), { heif_nclx_color_profile_free(nclx);}); - nclx->full_range_flag = (bool)de265_get_image_full_range_flag(image); + HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_color_primaries(nclx, static_cast<uint16_t>(de265_get_image_colour_primaries(image))), + { + heif_nclx_color_profile_free(nclx); + heif_image_release(*out_img); + *out_img = nullptr; + }); + HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_transfer_characteristics(nclx, static_cast<uint16_t>(de265_get_image_transfer_characteristics(image))), + { + heif_nclx_color_profile_free(nclx); + heif_image_release(*out_img); + *out_img = nullptr; + }); + HEIF_WARN_OR_FAIL(decoder->strict_decoding, *out_img, heif_nclx_color_profile_set_matrix_coefficients(nclx, static_cast<uint16_t>(de265_get_image_matrix_coefficients(image))), + { + heif_nclx_color_profile_free(nclx); + heif_image_release(*out_img); + *out_img = nullptr; + }); + nclx->full_range_flag = (bool) de265_get_image_full_range_flag(image); #endif heif_image_set_nclx_color_profile(*out_img, nclx); heif_nclx_color_profile_free(nclx); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/plugins/encoder_jpeg.cc new/libheif-1.17.3/libheif/plugins/encoder_jpeg.cc --- old/libheif-1.17.1/libheif/plugins/encoder_jpeg.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/plugins/encoder_jpeg.cc 2023-11-03 15:08:35.000000000 +0100 @@ -411,6 +411,7 @@ jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); + encoder->data_read = false; encoder->compressed_data.resize(outlength); memcpy(encoder->compressed_data.data(), outbuffer, outlength); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/plugins/encoder_openjpeg.cc new/libheif-1.17.3/libheif/plugins/encoder_openjpeg.cc --- old/libheif-1.17.1/libheif/plugins/encoder_openjpeg.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/plugins/encoder_openjpeg.cc 2023-11-03 15:08:35.000000000 +0100 @@ -321,6 +321,9 @@ if (encoder->chroma != heif_chroma_undefined) { *inout_chroma = encoder->chroma; } + else { + *inout_chroma = heif_chroma_444; + } } } @@ -518,6 +521,7 @@ } } + encoder->data_read = false; encoder->codestream.clear(); //Fixes issue when encoding multiple images and old data persists. //Encodes the image into a 'codestream' which is stored in the 'encoder' variable diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/security_limits.h new/libheif-1.17.3/libheif/security_limits.h --- old/libheif-1.17.1/libheif/security_limits.h 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/security_limits.h 2023-11-03 15:08:35.000000000 +0100 @@ -27,6 +27,7 @@ static const int MAX_ILOC_ITEMS = 20000; static const int MAX_ILOC_EXTENTS_PER_ITEM = 32; static const int MAX_MEMORY_BLOCK_SIZE = 512 * 1024 * 1024; // 512 MB +static const int MAX_COLOR_PROFILE_SIZE = 100 * 1024 * 1024; // 100 MB // Artificial limit to avoid allocating too much memory. // 32768^2 = 1.5 GB as YUV-4:2:0 or 4 GB as RGB32 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libheif-1.17.1/libheif/uncompressed_image.cc new/libheif-1.17.3/libheif/uncompressed_image.cc --- old/libheif-1.17.1/libheif/uncompressed_image.cc 2023-10-19 12:05:29.000000000 +0200 +++ new/libheif-1.17.3/libheif/uncompressed_image.cc 2023-11-03 15:08:35.000000000 +0100 @@ -679,7 +679,8 @@ 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) { + 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); @@ -751,7 +752,7 @@ 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, tile_width); + memcpy(dst + dst_offset, uncompressed_data.data() + src_offset /** + row * tile_width **/, tile_width); // TODO: ** is a hack } } } @@ -946,7 +947,7 @@ { int bpp_alpha = image->get_bits_per_pixel(heif_channel_Alpha); Box_uncC::Component component3 = {3, (uint8_t)(bpp_alpha), component_format_unsigned, 0}; - uncC->add_component(component3); + uncC->add_component(component3); } } uncC->set_sampling_type(sampling_type_no_subsampling); @@ -1008,7 +1009,7 @@ } return Error::Ok; } - + Error UncompressedImageCodec::encode_uncompressed_image(const std::shared_ptr<HeifFile>& heif_file, const std::shared_ptr<HeifPixelImage>& src_image,