diff options
Diffstat (limited to 'lib/extras/enc/encode.cc')
-rw-r--r-- | lib/extras/enc/encode.cc | 124 |
1 files changed, 63 insertions, 61 deletions
diff --git a/lib/extras/enc/encode.cc b/lib/extras/enc/encode.cc index dc593d2..8c9a148 100644 --- a/lib/extras/enc/encode.cc +++ b/lib/extras/enc/encode.cc @@ -7,24 +7,17 @@ #include <locale> -#if JPEGXL_ENABLE_APNG #include "lib/extras/enc/apng.h" -#endif -#if JPEGXL_ENABLE_EXR #include "lib/extras/enc/exr.h" -#endif -#if JPEGXL_ENABLE_JPEG #include "lib/extras/enc/jpg.h" -#endif #include "lib/extras/enc/npy.h" #include "lib/extras/enc/pgx.h" #include "lib/extras/enc/pnm.h" -#include "lib/jxl/base/printf_macros.h" namespace jxl { namespace extras { -Status Encoder::VerifyBasicInfo(const JxlBasicInfo& info) const { +Status Encoder::VerifyBasicInfo(const JxlBasicInfo& info) { if (info.xsize == 0 || info.ysize == 0) { return JXL_FAILURE("Empty image"); } @@ -40,8 +33,34 @@ Status Encoder::VerifyBasicInfo(const JxlBasicInfo& info) const { return true; } -Status Encoder::VerifyPackedImage(const PackedImage& image, - const JxlBasicInfo& info) const { +Status Encoder::VerifyFormat(const JxlPixelFormat& format) const { + for (auto f : AcceptedFormats()) { + if (f.num_channels != format.num_channels) continue; + if (f.data_type != format.data_type) continue; + if (f.data_type == JXL_TYPE_UINT8 || f.endianness == format.endianness) { + return true; + } + } + return JXL_FAILURE("Format is not in the list of accepted formats."); +} + +Status Encoder::VerifyBitDepth(JxlDataType data_type, uint32_t bits_per_sample, + uint32_t exponent_bits) { + if ((data_type == JXL_TYPE_UINT8 && + (bits_per_sample == 0 || bits_per_sample > 8 || exponent_bits != 0)) || + (data_type == JXL_TYPE_UINT16 && + (bits_per_sample <= 8 || bits_per_sample > 16 || exponent_bits != 0)) || + (data_type == JXL_TYPE_FLOAT16 && + (bits_per_sample > 16 || exponent_bits > 5))) { + return JXL_FAILURE( + "Incompatible data_type %d and bit depth %u with exponent bits %u", + (int)data_type, bits_per_sample, exponent_bits); + } + return true; +} + +Status Encoder::VerifyImageSize(const PackedImage& image, + const JxlBasicInfo& info) { if (image.pixels() == nullptr) { return JXL_FAILURE("Invalid image."); } @@ -57,77 +76,60 @@ Status Encoder::VerifyPackedImage(const PackedImage& image, image.format.num_channels != info_num_channels) { return JXL_FAILURE("Frame size does not match image size"); } - if (info.bits_per_sample > - PackedImage::BitsPerChannel(image.format.data_type)) { - return JXL_FAILURE("Bit depth does not fit pixel data type"); - } return true; } -Status SelectFormat(const std::vector<JxlPixelFormat>& accepted_formats, - const JxlBasicInfo& basic_info, JxlPixelFormat* format) { - const size_t original_bit_depth = basic_info.bits_per_sample; - size_t current_bit_depth = 0; - size_t num_alpha_channels = (basic_info.alpha_bits != 0 ? 1 : 0); - size_t num_channels = basic_info.num_color_channels + num_alpha_channels; - for (;;) { - for (const JxlPixelFormat& candidate : accepted_formats) { - if (candidate.num_channels != num_channels) continue; - const size_t candidate_bit_depth = - PackedImage::BitsPerChannel(candidate.data_type); - if ( - // Candidate bit depth is less than what we have and still enough - (original_bit_depth <= candidate_bit_depth && - candidate_bit_depth < current_bit_depth) || - // Or larger than the too-small bit depth we currently have - (current_bit_depth < candidate_bit_depth && - current_bit_depth < original_bit_depth)) { - *format = candidate; - current_bit_depth = candidate_bit_depth; - } - } - if (current_bit_depth == 0) { - if (num_channels > basic_info.num_color_channels) { - // Try dropping the alpha channel. - --num_channels; - continue; - } - return JXL_FAILURE("no appropriate format found"); - } - break; - } - if (current_bit_depth < original_bit_depth) { - JXL_WARNING("encoding %" PRIuS "-bit original to %" PRIuS " bits", - original_bit_depth, current_bit_depth); - } +Status Encoder::VerifyPackedImage(const PackedImage& image, + const JxlBasicInfo& info) const { + JXL_RETURN_IF_ERROR(VerifyImageSize(image, info)); + JXL_RETURN_IF_ERROR(VerifyFormat(image.format)); + JXL_RETURN_IF_ERROR(VerifyBitDepth(image.format.data_type, + info.bits_per_sample, + info.exponent_bits_per_sample)); return true; } +template <int metadata> +class MetadataEncoder : public Encoder { + public: + std::vector<JxlPixelFormat> AcceptedFormats() const override { + std::vector<JxlPixelFormat> formats; + // empty, i.e. no need for actual pixel data + return formats; + } + + Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded, + ThreadPool* pool) const override { + JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info)); + encoded->icc.clear(); + encoded->bitstreams.resize(1); + if (metadata == 0) encoded->bitstreams.front() = ppf.metadata.exif; + if (metadata == 1) encoded->bitstreams.front() = ppf.metadata.xmp; + if (metadata == 2) encoded->bitstreams.front() = ppf.metadata.jumbf; + return true; + } +}; + std::unique_ptr<Encoder> Encoder::FromExtension(std::string extension) { std::transform( extension.begin(), extension.end(), extension.begin(), [](char c) { return std::tolower(c, std::locale::classic()); }); -#if JPEGXL_ENABLE_APNG if (extension == ".png" || extension == ".apng") return GetAPNGEncoder(); -#endif - -#if JPEGXL_ENABLE_JPEG if (extension == ".jpg") return GetJPEGEncoder(); if (extension == ".jpeg") return GetJPEGEncoder(); -#endif - if (extension == ".npy") return GetNumPyEncoder(); - if (extension == ".pgx") return GetPGXEncoder(); - if (extension == ".pam") return GetPAMEncoder(); if (extension == ".pgm") return GetPGMEncoder(); if (extension == ".ppm") return GetPPMEncoder(); + if (extension == ".pnm") return GetPNMEncoder(); if (extension == ".pfm") return GetPFMEncoder(); - -#if JPEGXL_ENABLE_EXR if (extension == ".exr") return GetEXREncoder(); -#endif + if (extension == ".exif") return jxl::make_unique<MetadataEncoder<0>>(); + if (extension == ".xmp") return jxl::make_unique<MetadataEncoder<1>>(); + if (extension == ".xml") return jxl::make_unique<MetadataEncoder<1>>(); + if (extension == ".jumbf") return jxl::make_unique<MetadataEncoder<2>>(); + if (extension == ".jumb") return jxl::make_unique<MetadataEncoder<2>>(); return nullptr; } |