From 683fb879c23ccc2c7a9c0c0532636c84b067888d Mon Sep 17 00:00:00 2001 From: kenny-sellers Date: Sun, 20 Apr 2025 21:58:37 -0500 Subject: [PATCH 1/4] Updates to see if this actually works? --- src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp | 75 ++-- src/FileOnQ.Imaging.Heif.Encoders/encoder.h | 36 +- .../encoder_jpeg.cpp | 413 +++++++++++------- .../encoder_jpeg.h | 46 +- .../Build/libheif.targets | 4 +- 5 files changed, 321 insertions(+), 253 deletions(-) diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp b/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp index f8c99d8..ce7b070 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp @@ -1,10 +1,10 @@ /* - libheif example application "convert". - This file is part of convert, an example application using libheif. + libheif example application. MIT License - Copyright (c) 2018 struktur AG, Joachim Bauch + Copyright (c) 2017 struktur AG, Joachim Bauch + Copyright (c) 2023 Dirk Farin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -24,49 +24,40 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif +#ifndef EXAMPLE_ENCODER_H +#define EXAMPLE_ENCODER_H -#include +#include +#include -#include "encoder.h" +#include "libheif/heif.h" +#include -static const char kMetadataTypeExif[] = "Exif"; -// static -bool Encoder::HasExifMetaData(const struct heif_image_handle* handle) +class Encoder { +public: + virtual ~Encoder() = default; - heif_item_id metadata_id; - int count = heif_image_handle_get_list_of_metadata_block_IDs(handle, kMetadataTypeExif, - &metadata_id, 1); - return count > 0; -} + virtual heif_colorspace colorspace(bool has_alpha) const = 0; -// static -uint8_t* Encoder::GetExifMetaData(const struct heif_image_handle* handle, size_t* size) -{ - heif_item_id metadata_id; - int count = heif_image_handle_get_list_of_metadata_block_IDs(handle, kMetadataTypeExif, - &metadata_id, 1); - - for (int i = 0; i < count; i++) { - size_t datasize = heif_image_handle_get_metadata_size(handle, metadata_id); - uint8_t* data = static_cast(malloc(datasize)); - if (!data) { - continue; - } - - heif_error error = heif_image_handle_get_metadata(handle, metadata_id, data); - if (error.code != heif_error_Ok) { - free(data); - continue; - } - - *size = datasize; - return data; - } - - return nullptr; -} + virtual heif_chroma chroma(bool has_alpha, int bit_depth) const = 0; + + virtual void UpdateDecodingOptions(const struct heif_image_handle* handle, + struct heif_decoding_options* options) const + { + // Override if necessary. + } + + virtual bool Encode(const struct heif_image_handle* handle, + const struct heif_image* image, const std::string& filename) = 0; + +protected: + static bool HasExifMetaData(const struct heif_image_handle* handle); + + static uint8_t* GetExifMetaData(const struct heif_image_handle* handle, size_t* size); + + static std::vector get_xmp_metadata(const struct heif_image_handle* handle); +}; + +#endif // EXAMPLE_ENCODER_H \ No newline at end of file diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder.h b/src/FileOnQ.Imaging.Heif.Encoders/encoder.h index 7bf94ad..ce7b070 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder.h +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder.h @@ -1,9 +1,10 @@ /* - libheif example application "convert". + libheif example application. MIT License Copyright (c) 2017 struktur AG, Joachim Bauch + Copyright (c) 2023 Dirk Farin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -29,33 +30,34 @@ #include #include -#include +#include "libheif/heif.h" +#include class Encoder { public: - virtual ~Encoder() - {} + virtual ~Encoder() = default; - virtual heif_colorspace colorspace(bool has_alpha) const = 0; + virtual heif_colorspace colorspace(bool has_alpha) const = 0; - virtual heif_chroma chroma(bool has_alpha, int bit_depth) const = 0; + virtual heif_chroma chroma(bool has_alpha, int bit_depth) const = 0; - virtual void UpdateDecodingOptions(const struct heif_image_handle* handle, - struct heif_decoding_options* options) const - { - // Override if necessary. - } + virtual void UpdateDecodingOptions(const struct heif_image_handle* handle, + struct heif_decoding_options* options) const + { + // Override if necessary. + } - virtual bool Encode(const struct heif_image_handle* handle, - const struct heif_image* image, unsigned char** buffer, - unsigned long* buffer_size) = 0; + virtual bool Encode(const struct heif_image_handle* handle, + const struct heif_image* image, const std::string& filename) = 0; protected: - static bool HasExifMetaData(const struct heif_image_handle* handle); + static bool HasExifMetaData(const struct heif_image_handle* handle); - static uint8_t* GetExifMetaData(const struct heif_image_handle* handle, size_t* size); + static uint8_t* GetExifMetaData(const struct heif_image_handle* handle, size_t* size); + + static std::vector get_xmp_metadata(const struct heif_image_handle* handle); }; -#endif // EXAMPLE_ENCODER_H +#endif // EXAMPLE_ENCODER_H \ No newline at end of file diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.cpp b/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.cpp index 63e2400..2828ca0 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.cpp +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.cpp @@ -1,5 +1,5 @@ /* - libheif example application "convert". + libheif example application. MIT License @@ -23,47 +23,56 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#if defined(HAVE_CONFIG_H) -#include "config.h" -#endif -#include -#include -#include +#include +#include -#include +#include +#include #include "encoder_jpeg.h" +#include "exif.h" + +#include + +#define JPEG_XMP_MARKER (JPEG_APP0+1) /* JPEG marker code for XMP */ +#define JPEG_XMP_MARKER_ID "http://ns.adobe.com/xap/1.0/" + + +struct ErrorHandler +{ + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ +}; + + JpegEncoder::JpegEncoder(int quality) : quality_(quality) { - if (quality_ < 0 || quality_ > 100) { - quality_ = kDefaultQuality; - } + if (quality_ < 0 || quality_ > 100) { + quality_ = kDefaultQuality; + } } void JpegEncoder::UpdateDecodingOptions(const struct heif_image_handle* handle, - struct heif_decoding_options* options) const + struct heif_decoding_options* options) const { - if (HasExifMetaData(handle)) { - options->ignore_transformations = 1; - } - - options->convert_hdr_to_8bit = 1; + options->convert_hdr_to_8bit = 1; } // static -void JpegEncoder::OnJpegError(j_common_ptr cinfo) +static void OnJpegError(j_common_ptr cinfo) { - ErrorHandler* handler = reinterpret_cast(cinfo->err); - longjmp(handler->setjmp_buffer, 1); + ErrorHandler* handler = reinterpret_cast(cinfo->err); + longjmp(handler->setjmp_buffer, 1); } +#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ + #if !defined(HAVE_JPEG_WRITE_ICC_PROFILE) #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ -#define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ #define MAX_DATA_BYTES_IN_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) /* @@ -77,153 +86,229 @@ void JpegEncoder::OnJpegError(j_common_ptr cinfo) static void jpeg_write_icc_profile(j_compress_ptr cinfo, const JOCTET* icc_data_ptr, - unsigned int icc_data_len) + unsigned int icc_data_len) { - unsigned int num_markers; /* total number of markers we'll write */ - int cur_marker = 1; /* per spec, counting starts at 1 */ - unsigned int length; /* number of bytes to write in this marker */ - - /* Calculate the number of markers we'll need, rounding up of course */ - num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER; - if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len) - num_markers++; - - while (icc_data_len > 0) { - /* length of profile to put in this marker */ - length = icc_data_len; - if (length > MAX_DATA_BYTES_IN_MARKER) - length = MAX_DATA_BYTES_IN_MARKER; - icc_data_len -= length; - - /* Write the JPEG marker header (APP2 code and marker length) */ - jpeg_write_m_header(cinfo, ICC_MARKER, - (unsigned int)(length + ICC_OVERHEAD_LEN)); - - /* Write the marker identifying string "ICC_PROFILE" (null-terminated). We - * code it in this less-than-transparent way so that the code works even if - * the local character set is not ASCII. - */ - jpeg_write_m_byte(cinfo, 0x49); - jpeg_write_m_byte(cinfo, 0x43); - jpeg_write_m_byte(cinfo, 0x43); - jpeg_write_m_byte(cinfo, 0x5F); - jpeg_write_m_byte(cinfo, 0x50); - jpeg_write_m_byte(cinfo, 0x52); - jpeg_write_m_byte(cinfo, 0x4F); - jpeg_write_m_byte(cinfo, 0x46); - jpeg_write_m_byte(cinfo, 0x49); - jpeg_write_m_byte(cinfo, 0x4C); - jpeg_write_m_byte(cinfo, 0x45); - jpeg_write_m_byte(cinfo, 0x0); - - /* Add the sequencing info */ - jpeg_write_m_byte(cinfo, cur_marker); - jpeg_write_m_byte(cinfo, (int)num_markers); - - /* Add the profile data */ - while (length--) { - jpeg_write_m_byte(cinfo, *icc_data_ptr); - icc_data_ptr++; - } - cur_marker++; - } + unsigned int num_markers; /* total number of markers we'll write */ + int cur_marker = 1; /* per spec, counting starts at 1 */ + unsigned int length; /* number of bytes to write in this marker */ + + /* Calculate the number of markers we'll need, rounding up of course */ + num_markers = icc_data_len / MAX_DATA_BYTES_IN_MARKER; + if (num_markers * MAX_DATA_BYTES_IN_MARKER != icc_data_len) + num_markers++; + + while (icc_data_len > 0) { + /* length of profile to put in this marker */ + length = icc_data_len; + if (length > MAX_DATA_BYTES_IN_MARKER) + length = MAX_DATA_BYTES_IN_MARKER; + icc_data_len -= length; + + /* Write the JPEG marker header (APP2 code and marker length) */ + jpeg_write_m_header(cinfo, ICC_MARKER, + (unsigned int) (length + ICC_OVERHEAD_LEN)); + + /* Write the marker identifying string "ICC_PROFILE" (null-terminated). We + * code it in this less-than-transparent way so that the code works even if + * the local character set is not ASCII. + */ + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x43); + jpeg_write_m_byte(cinfo, 0x5F); + jpeg_write_m_byte(cinfo, 0x50); + jpeg_write_m_byte(cinfo, 0x52); + jpeg_write_m_byte(cinfo, 0x4F); + jpeg_write_m_byte(cinfo, 0x46); + jpeg_write_m_byte(cinfo, 0x49); + jpeg_write_m_byte(cinfo, 0x4C); + jpeg_write_m_byte(cinfo, 0x45); + jpeg_write_m_byte(cinfo, 0x0); + + /* Add the sequencing info */ + jpeg_write_m_byte(cinfo, cur_marker); + jpeg_write_m_byte(cinfo, (int) num_markers); + + /* Add the profile data */ + while (length--) { + jpeg_write_m_byte(cinfo, *icc_data_ptr); + icc_data_ptr++; + } + cur_marker++; + } } #endif // !defined(HAVE_JPEG_WRITE_ICC_PROFILE) bool JpegEncoder::Encode(const struct heif_image_handle* handle, - const struct heif_image* image, unsigned char** data, - unsigned long* data_size) + const struct heif_image* image, const std::string& filename) { - struct jpeg_compress_struct cinfo = {}; - struct ErrorHandler jerr = {}; - - cinfo.err = jpeg_std_error(reinterpret_cast(&jerr)); - jerr.pub.error_exit = &JpegEncoder::OnJpegError; - if (setjmp(jerr.setjmp_buffer)) { - cinfo.err->output_message(reinterpret_cast(&cinfo)); - jpeg_destroy_compress(&cinfo); - return false; - } - - jpeg_create_compress(&cinfo); - - int width = heif_image_get_width(image, heif_channel_Y); - int height = heif_image_get_height(image, heif_channel_Y); - - // malloc the size of the pointer so it can be released - *data = (unsigned char*)malloc(width * height); - *data_size = width * height; - - jpeg_mem_dest(&cinfo, data, data_size); - - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - jpeg_set_defaults(&cinfo); - static const boolean kForceBaseline = TRUE; - jpeg_set_quality(&cinfo, quality_, kForceBaseline); - static const boolean kWriteAllTables = TRUE; - jpeg_start_compress(&cinfo, kWriteAllTables); - - size_t exifsize = 0; - uint8_t* exifdata = GetExifMetaData(handle, &exifsize); - if (exifdata && exifsize > 4) { - static const uint8_t kExifMarker = JPEG_APP0 + 1; - jpeg_write_marker(&cinfo, kExifMarker, exifdata + 4, - static_cast(exifsize - 4)); - free(exifdata); - } - - size_t profile_size = heif_image_handle_get_raw_color_profile_size(handle); - if (profile_size > 0) { - uint8_t* profile_data = static_cast(malloc(profile_size)); - heif_image_handle_get_raw_color_profile(handle, profile_data); - jpeg_write_icc_profile(&cinfo, profile_data, (unsigned int)profile_size); - free(profile_data); - } - - if (heif_image_get_bits_per_pixel(image, heif_channel_Y) != 8) { - fprintf(stderr, "JPEG writer cannot handle image with >8 bpp.\n"); - return false; - } - - int stride_y; - const uint8_t* row_y = heif_image_get_plane_readonly(image, heif_channel_Y, - &stride_y); - int stride_u; - const uint8_t* row_u = heif_image_get_plane_readonly(image, heif_channel_Cb, - &stride_u); - int stride_v; - const uint8_t* row_v = heif_image_get_plane_readonly(image, heif_channel_Cr, - &stride_v); - - JSAMPARRAY buffer = cinfo.mem->alloc_sarray( - reinterpret_cast(&cinfo), JPOOL_IMAGE, - cinfo.image_width * cinfo.input_components, 1); - JSAMPROW row[1] = { buffer[0] }; - - while (cinfo.next_scanline < cinfo.image_height) { - size_t offset_y = cinfo.next_scanline * stride_y; - const uint8_t* start_y = &row_y[offset_y]; - size_t offset_u = (cinfo.next_scanline / 2) * stride_u; - const uint8_t* start_u = &row_u[offset_u]; - size_t offset_v = (cinfo.next_scanline / 2) * stride_v; - const uint8_t* start_v = &row_v[offset_v]; - - JOCTET* bufp = buffer[0]; - for (JDIMENSION x = 0; x < cinfo.image_width; ++x) { - *bufp++ = start_y[x]; - *bufp++ = start_u[x / 2]; - *bufp++ = start_v[x / 2]; - } - - jpeg_write_scanlines(&cinfo, row, 1); - } - - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - return true; -} + FILE* fp = fopen(filename.c_str(), "wb"); + if (!fp) { + fprintf(stderr, "Can't open %s: %s\n", filename.c_str(), strerror(errno)); + return false; + } + + struct jpeg_compress_struct cinfo; + struct ErrorHandler jerr; + cinfo.err = jpeg_std_error(reinterpret_cast(&jerr)); + jerr.pub.error_exit = &OnJpegError; + if (setjmp(jerr.setjmp_buffer)) { + cinfo.err->output_message(reinterpret_cast(&cinfo)); + jpeg_destroy_compress(&cinfo); + fclose(fp); + return false; + } + + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, fp); + + cinfo.image_width = heif_image_get_width(image, heif_channel_Y); + cinfo.image_height = heif_image_get_height(image, heif_channel_Y); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + jpeg_set_defaults(&cinfo); + static const boolean kForceBaseline = TRUE; + jpeg_set_quality(&cinfo, quality_, kForceBaseline); + static const boolean kWriteAllTables = TRUE; + jpeg_start_compress(&cinfo, kWriteAllTables); + + // --- Write EXIF + + size_t exifsize = 0; + uint8_t* exifdata = GetExifMetaData(handle, &exifsize); + if (exifdata) { + if (exifsize > 4) { + static const uint8_t kExifMarker = JPEG_APP0 + 1; + + uint32_t skip = (exifdata[0]<<24) | (exifdata[1]<<16) | (exifdata[2]<<8) | exifdata[3]; + if (skip > (exifsize - 4)) { + fprintf(stderr, "Invalid EXIF data (offset too large)\n"); + free(exifdata); + jpeg_destroy_compress(&cinfo); + fclose(fp); + return false; + } + skip += 4; + + uint8_t* ptr = exifdata + skip; + size_t size = exifsize - skip; + + if (size > std::numeric_limits::max()) { + fprintf(stderr, "EXIF larger than 4GB is not supported"); + free(exifdata); + jpeg_destroy_compress(&cinfo); + fclose(fp); + return false; + } + + auto size32 = static_cast(size); + + // libheif by default normalizes the image orientation, so that we have to set the EXIF Orientation to "Horizontal (normal)" + modify_exif_orientation_tag_if_it_exists(ptr, size32, 1); + overwrite_exif_image_size_if_it_exists(ptr, size32, cinfo.image_width, cinfo.image_height); + + // We have to limit the size for the memcpy, otherwise GCC warns that we exceed the maximum size. + if (size>0x1000000) { + size = 0x1000000; + } + + std::vector jpegExifMarkerData(6+size); + memcpy(jpegExifMarkerData.data()+6, ptr, size); + jpegExifMarkerData[0]='E'; + jpegExifMarkerData[1]='x'; + jpegExifMarkerData[2]='i'; + jpegExifMarkerData[3]='f'; + jpegExifMarkerData[4]=0; + jpegExifMarkerData[5]=0; + + ptr = jpegExifMarkerData.data(); + size = jpegExifMarkerData.size(); + + while (size > MAX_BYTES_IN_MARKER) { + jpeg_write_marker(&cinfo, kExifMarker, ptr, + static_cast(MAX_BYTES_IN_MARKER)); + + ptr += MAX_BYTES_IN_MARKER; + size -= MAX_BYTES_IN_MARKER; + } + + jpeg_write_marker(&cinfo, kExifMarker, ptr, + static_cast(size)); + } + + free(exifdata); + } + + // --- Write XMP + + // spec: https://raw.githubusercontent.com/adobe/xmp-docs/master/XMPSpecifications/XMPSpecificationPart3.pdf + + auto xmp = get_xmp_metadata(handle); + if (xmp.size() > 65502) { + fprintf(stderr, "XMP data too large, ExtendedXMP is not supported yet.\n"); + } + else if (!xmp.empty()) { + std::vector xmpWithId; + xmpWithId.resize(xmp.size() + strlen(JPEG_XMP_MARKER_ID)+1); + strcpy((char*)xmpWithId.data(), JPEG_XMP_MARKER_ID); + memcpy(xmpWithId.data() + strlen(JPEG_XMP_MARKER_ID) + 1, xmp.data(), xmp.size()); + + jpeg_write_marker(&cinfo, JPEG_XMP_MARKER, xmpWithId.data(), static_cast(xmpWithId.size())); + } + + // --- Write ICC + + size_t profile_size = heif_image_handle_get_raw_color_profile_size(handle); + if (profile_size > 0) { + uint8_t* profile_data = static_cast(malloc(profile_size)); + heif_image_handle_get_raw_color_profile(handle, profile_data); + jpeg_write_icc_profile(&cinfo, profile_data, (unsigned int) profile_size); + free(profile_data); + } + + + if (heif_image_get_bits_per_pixel(image, heif_channel_Y) != 8) { + fprintf(stderr, "JPEG writer cannot handle image with >8 bpp.\n"); + jpeg_destroy_compress(&cinfo); + fclose(fp); + return false; + } + + + int stride_y; + const uint8_t* row_y = heif_image_get_plane_readonly(image, heif_channel_Y, + &stride_y); + int stride_u; + const uint8_t* row_u = heif_image_get_plane_readonly(image, heif_channel_Cb, + &stride_u); + int stride_v; + const uint8_t* row_v = heif_image_get_plane_readonly(image, heif_channel_Cr, + &stride_v); + + JSAMPARRAY buffer = cinfo.mem->alloc_sarray( + reinterpret_cast(&cinfo), JPOOL_IMAGE, + cinfo.image_width * cinfo.input_components, 1); + JSAMPROW row[1] = {buffer[0]}; + + while (cinfo.next_scanline < cinfo.image_height) { + size_t offset_y = cinfo.next_scanline * stride_y; + const uint8_t* start_y = &row_y[offset_y]; + size_t offset_u = (cinfo.next_scanline / 2) * stride_u; + const uint8_t* start_u = &row_u[offset_u]; + size_t offset_v = (cinfo.next_scanline / 2) * stride_v; + const uint8_t* start_v = &row_v[offset_v]; + + JOCTET* bufp = buffer[0]; + for (JDIMENSION x = 0; x < cinfo.image_width; ++x) { + *bufp++ = start_y[x]; + *bufp++ = start_u[x / 2]; + *bufp++ = start_v[x / 2]; + } + jpeg_write_scanlines(&cinfo, row, 1); + } + jpeg_finish_compress(&cinfo); + fclose(fp); + jpeg_destroy_compress(&cinfo); + return true; +} \ No newline at end of file diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.h b/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.h index 03b96f7..0dc0090 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.h +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder_jpeg.h @@ -1,9 +1,10 @@ /* - libheif example application "convert". + libheif example application. MIT License Copyright (c) 2017 struktur AG, Joachim Bauch + Copyright (c) 2023 Dirk Farin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,8 +31,6 @@ #include #include -#include - #include #include "encoder.h" @@ -39,37 +38,28 @@ class JpegEncoder : public Encoder { public: - JpegEncoder(int quality); + JpegEncoder(int quality); - heif_colorspace colorspace(bool has_alpha) const override - { - return heif_colorspace_YCbCr; - } + heif_colorspace colorspace(bool has_alpha) const override + { + return heif_colorspace_YCbCr; + } - heif_chroma chroma(bool has_alpha, int bit_depth) const override - { - return heif_chroma_420; - } + heif_chroma chroma(bool has_alpha, int bit_depth) const override + { + return heif_chroma_420; + } - void UpdateDecodingOptions(const struct heif_image_handle* handle, - struct heif_decoding_options* options) const override; + void UpdateDecodingOptions(const struct heif_image_handle* handle, + struct heif_decoding_options* options) const override; - bool Encode(const struct heif_image_handle* handle, - const struct heif_image* image, unsigned char** buffer, - unsigned long* buffer_size) override; + bool Encode(const struct heif_image_handle* handle, + const struct heif_image* image, const std::string& filename) override; private: - static const int kDefaultQuality = 90; - - struct ErrorHandler - { - struct jpeg_error_mgr pub; /* "public" fields */ - jmp_buf setjmp_buffer; /* for return to caller */ - }; - - static void OnJpegError(j_common_ptr cinfo); + static const int kDefaultQuality = 90; - int quality_; + int quality_; }; -#endif // EXAMPLE_ENCODER_JPEG_H +#endif // EXAMPLE_ENCODER_JPEG_H \ No newline at end of file diff --git a/src/FileOnQ.Imaging.Heif/Build/libheif.targets b/src/FileOnQ.Imaging.Heif/Build/libheif.targets index 8ead888..ce2a439 100644 --- a/src/FileOnQ.Imaging.Heif/Build/libheif.targets +++ b/src/FileOnQ.Imaging.Heif/Build/libheif.targets @@ -28,12 +28,12 @@ - + - + From e6ef6ac27e56764d4ebe49d5e465d882feb07dc3 Mon Sep 17 00:00:00 2001 From: kenny-sellers Date: Sun, 20 Apr 2025 22:33:49 -0500 Subject: [PATCH 2/4] more things to try --- src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp | 2 +- src/FileOnQ.Imaging.Heif.Encoders/encoder.h | 2 +- src/FileOnQ.Imaging.Heif.Encoders/encoders_api.cpp | 2 +- src/FileOnQ.Imaging.Heif.Encoders/encoders_api.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp b/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp index ce7b070..e48b3b0 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder.cpp @@ -30,7 +30,7 @@ #include #include -#include "libheif/heif.h" +#include "libheif/api/libheif/heif.h" #include diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoder.h b/src/FileOnQ.Imaging.Heif.Encoders/encoder.h index ce7b070..e48b3b0 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoder.h +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoder.h @@ -30,7 +30,7 @@ #include #include -#include "libheif/heif.h" +#include "libheif/api/libheif/heif.h" #include diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.cpp b/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.cpp index d236861..d1c287c 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.cpp +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include "encoders_api.h" #include "encoder.h" diff --git a/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.h b/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.h index 05e4ea8..6143271 100644 --- a/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.h +++ b/src/FileOnQ.Imaging.Heif.Encoders/encoders_api.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include "encoder_jpeg.h" From 7b7aa1f8ef8d605d1a11939349929463eb86dac8 Mon Sep 17 00:00:00 2001 From: Kenny Sellers Date: Wed, 23 Apr 2025 12:27:12 -0500 Subject: [PATCH 3/4] Maybe? --- FileOnQ.Imaging.Heif.sln | 46 ++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/FileOnQ.Imaging.Heif.sln b/FileOnQ.Imaging.Heif.sln index f0cebbc..b345b95 100644 --- a/FileOnQ.Imaging.Heif.sln +++ b/FileOnQ.Imaging.Heif.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30114.105 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35828.75 d17.13 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileOnQ.Imaging.Heif", "src\FileOnQ.Imaging.Heif\FileOnQ.Imaging.Heif.csproj", "{9AD1EDEC-092B-4086-B71F-1FA5C58BC59C}" EndProject @@ -24,8 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".Build", ".Build", "{4457DF EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{3EF903A9-C6EE-4846-919B-0A31F52DFAEC}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileOnQ.Imaging.Heif.Encoders", "src\FileOnQ.Imaging.Heif.Encoders\FileOnQ.Imaging.Heif.Encoders.vcxproj", "{09C5AF2A-3783-4195-BE48-334ADC7BF3BD}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ConsoleApp", "ConsoleApp", "{FB7CB06D-2D84-4A04-BE62-EF54E2DC44A9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp.net5.AnyCPU", "samples\ConsoleApp\ConsoleApp.net5.AnyCPU\ConsoleApp.net5.AnyCPU.csproj", "{3D96E2F6-D66F-47A5-9A8B-421F2B3DA310}" @@ -83,22 +81,6 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileOnQ.Imaging.Heif.Benchmarks", "benchmarks\tools\FileOnQ.Imaging.Heif.Benchmarks.csproj", "{5E8DF849-30D0-460A-81CB-C343D4D5536B}" EndProject Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{1e597879-fed0-47bd-8710-78330d370699}*SharedItemsImports = 5 - tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{255253a7-7608-4870-93d0-78008bcfcc28}*SharedItemsImports = 5 - tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{2dd69f56-35ec-4d14-a1bf-b93b19750f69}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{3423f1f2-984a-4946-ae90-8553413bbbdd}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{3d96e2f6-d66f-47a5-9a8b-421f2b3da310}*SharedItemsImports = 5 - tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{52ebf464-611c-4f0d-8263-77a2c7001b13}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{54cc71e7-1ee6-4214-b435-21e41b1c0053}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{595e88f2-b685-46bb-a9c7-538c1d8f7708}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{7e516116-cbf9-4d83-b4b2-e1c0ac1b7074}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{836d4878-b6f6-4c62-9f5b-807785b29e34}*SharedItemsImports = 5 - tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{c5c19cd4-383d-4a2c-b55e-d3b8ff611a2d}*SharedItemsImports = 13 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{db6160f1-37a7-4096-8e02-9748d6225efe}*SharedItemsImports = 5 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{f10ea7da-142c-42db-a8cb-817f81a4a9e1}*SharedItemsImports = 13 - samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{fc3e32ea-710c-4440-bddb-85f5cf1e0d95}*SharedItemsImports = 5 - EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x64 = Debug|x64 @@ -120,14 +102,6 @@ Global {9AD1EDEC-092B-4086-B71F-1FA5C58BC59C}.Release|x64.Build.0 = Release|Any CPU {9AD1EDEC-092B-4086-B71F-1FA5C58BC59C}.Release|x86.ActiveCfg = Release|Any CPU {9AD1EDEC-092B-4086-B71F-1FA5C58BC59C}.Release|x86.Build.0 = Release|Any CPU - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Debug|Any CPU.ActiveCfg = Debug|Win32 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Debug|x64.ActiveCfg = Debug|x64 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Debug|x86.ActiveCfg = Debug|Win32 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Release|Any CPU.ActiveCfg = Release|Win32 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Release|x64.ActiveCfg = Release|x64 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Release|x64.Build.0 = Release|x64 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Release|x86.ActiveCfg = Release|Win32 - {09C5AF2A-3783-4195-BE48-334ADC7BF3BD}.Release|x86.Build.0 = Release|Win32 {3D96E2F6-D66F-47A5-9A8B-421F2B3DA310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D96E2F6-D66F-47A5-9A8B-421F2B3DA310}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D96E2F6-D66F-47A5-9A8B-421F2B3DA310}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -337,4 +311,20 @@ Global GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF811503-BFBF-48C0-AFBA-872CBA57D6F2} EndGlobalSection + GlobalSection(SharedMSBuildProjectFiles) = preSolution + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{1e597879-fed0-47bd-8710-78330d370699}*SharedItemsImports = 5 + tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{255253a7-7608-4870-93d0-78008bcfcc28}*SharedItemsImports = 5 + tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{2dd69f56-35ec-4d14-a1bf-b93b19750f69}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{3423f1f2-984a-4946-ae90-8553413bbbdd}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{3d96e2f6-d66f-47a5-9a8b-421f2b3da310}*SharedItemsImports = 5 + tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{52ebf464-611c-4f0d-8263-77a2c7001b13}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{54cc71e7-1ee6-4214-b435-21e41b1c0053}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{595e88f2-b685-46bb-a9c7-538c1d8f7708}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{7e516116-cbf9-4d83-b4b2-e1c0ac1b7074}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{836d4878-b6f6-4c62-9f5b-807785b29e34}*SharedItemsImports = 5 + tests\FileOnQ.Imaging.Heif.Tests\FileOnQ.Imaging.Heif.Tests.projitems*{c5c19cd4-383d-4a2c-b55e-d3b8ff611a2d}*SharedItemsImports = 13 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{db6160f1-37a7-4096-8e02-9748d6225efe}*SharedItemsImports = 5 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{f10ea7da-142c-42db-a8cb-817f81a4a9e1}*SharedItemsImports = 13 + samples\ConsoleApp\ConsoleApp.Shared\ConsoleApp.Shared.projitems*{fc3e32ea-710c-4440-bddb-85f5cf1e0d95}*SharedItemsImports = 5 + EndGlobalSection EndGlobal From b6f858596f26c341b653d6675bd7c483e67ae6ff Mon Sep 17 00:00:00 2001 From: mahendrana Date: Fri, 2 May 2025 19:05:35 +0200 Subject: [PATCH 4/4] Update libde265.targets to use v1.015 of libde265 Update libde265.targets to use v1.015 of libde265 --- src/FileOnQ.Imaging.Heif/Build/libde265.targets | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FileOnQ.Imaging.Heif/Build/libde265.targets b/src/FileOnQ.Imaging.Heif/Build/libde265.targets index 665f164..7fe6374 100644 --- a/src/FileOnQ.Imaging.Heif/Build/libde265.targets +++ b/src/FileOnQ.Imaging.Heif/Build/libde265.targets @@ -3,12 +3,12 @@ - + - + @@ -25,4 +25,4 @@ - \ No newline at end of file +