encode.cc (5211B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include "lib/extras/enc/encode.h" 7 8 #include <locale> 9 10 #include "lib/extras/enc/apng.h" 11 #include "lib/extras/enc/exr.h" 12 #include "lib/extras/enc/jpg.h" 13 #include "lib/extras/enc/npy.h" 14 #include "lib/extras/enc/pgx.h" 15 #include "lib/extras/enc/pnm.h" 16 17 namespace jxl { 18 namespace extras { 19 20 Status Encoder::VerifyBasicInfo(const JxlBasicInfo& info) { 21 if (info.xsize == 0 || info.ysize == 0) { 22 return JXL_FAILURE("Empty image"); 23 } 24 if (info.num_color_channels != 1 && info.num_color_channels != 3) { 25 return JXL_FAILURE("Invalid number of color channels"); 26 } 27 if (info.alpha_bits > 0 && info.alpha_bits != info.bits_per_sample) { 28 return JXL_FAILURE("Alpha bit depth does not match image bit depth"); 29 } 30 if (info.orientation != JXL_ORIENT_IDENTITY) { 31 return JXL_FAILURE("Orientation must be identity"); 32 } 33 return true; 34 } 35 36 Status Encoder::VerifyFormat(const JxlPixelFormat& format) const { 37 for (auto f : AcceptedFormats()) { 38 if (f.num_channels != format.num_channels) continue; 39 if (f.data_type != format.data_type) continue; 40 if (f.data_type == JXL_TYPE_UINT8 || f.endianness == format.endianness) { 41 return true; 42 } 43 } 44 return JXL_FAILURE("Format is not in the list of accepted formats."); 45 } 46 47 Status Encoder::VerifyBitDepth(JxlDataType data_type, uint32_t bits_per_sample, 48 uint32_t exponent_bits) { 49 if ((data_type == JXL_TYPE_UINT8 && 50 (bits_per_sample == 0 || bits_per_sample > 8 || exponent_bits != 0)) || 51 (data_type == JXL_TYPE_UINT16 && 52 (bits_per_sample <= 8 || bits_per_sample > 16 || exponent_bits != 0)) || 53 (data_type == JXL_TYPE_FLOAT16 && 54 (bits_per_sample > 16 || exponent_bits > 5))) { 55 return JXL_FAILURE( 56 "Incompatible data_type %d and bit depth %u with exponent bits %u", 57 static_cast<int>(data_type), bits_per_sample, exponent_bits); 58 } 59 return true; 60 } 61 62 Status Encoder::VerifyImageSize(const PackedImage& image, 63 const JxlBasicInfo& info) { 64 if (image.pixels() == nullptr) { 65 return JXL_FAILURE("Invalid image."); 66 } 67 if (image.stride != image.xsize * image.pixel_stride()) { 68 return JXL_FAILURE("Invalid image stride."); 69 } 70 if (image.pixels_size != image.ysize * image.stride) { 71 return JXL_FAILURE("Invalid image size."); 72 } 73 size_t info_num_channels = 74 (info.num_color_channels + (info.alpha_bits > 0 ? 1 : 0)); 75 if (image.xsize != info.xsize || image.ysize != info.ysize || 76 image.format.num_channels != info_num_channels) { 77 return JXL_FAILURE("Frame size does not match image size"); 78 } 79 return true; 80 } 81 82 Status Encoder::VerifyPackedImage(const PackedImage& image, 83 const JxlBasicInfo& info) const { 84 JXL_RETURN_IF_ERROR(VerifyImageSize(image, info)); 85 JXL_RETURN_IF_ERROR(VerifyFormat(image.format)); 86 JXL_RETURN_IF_ERROR(VerifyBitDepth(image.format.data_type, 87 info.bits_per_sample, 88 info.exponent_bits_per_sample)); 89 return true; 90 } 91 92 template <int metadata> 93 class MetadataEncoder : public Encoder { 94 public: 95 std::vector<JxlPixelFormat> AcceptedFormats() const override { 96 std::vector<JxlPixelFormat> formats; 97 // empty, i.e. no need for actual pixel data 98 return formats; 99 } 100 101 Status Encode(const PackedPixelFile& ppf, EncodedImage* encoded, 102 ThreadPool* pool) const override { 103 JXL_RETURN_IF_ERROR(VerifyBasicInfo(ppf.info)); 104 encoded->icc.clear(); 105 encoded->bitstreams.resize(1); 106 if (metadata == 0) encoded->bitstreams.front() = ppf.metadata.exif; 107 if (metadata == 1) encoded->bitstreams.front() = ppf.metadata.xmp; 108 if (metadata == 2) encoded->bitstreams.front() = ppf.metadata.jumbf; 109 return true; 110 } 111 }; 112 113 std::unique_ptr<Encoder> Encoder::FromExtension(std::string extension) { 114 std::transform( 115 extension.begin(), extension.end(), extension.begin(), 116 [](char c) { return std::tolower(c, std::locale::classic()); }); 117 if (extension == ".png" || extension == ".apng") return GetAPNGEncoder(); 118 if (extension == ".jpg") return GetJPEGEncoder(); 119 if (extension == ".jpeg") return GetJPEGEncoder(); 120 if (extension == ".npy") return GetNumPyEncoder(); 121 if (extension == ".pgx") return GetPGXEncoder(); 122 if (extension == ".pam") return GetPAMEncoder(); 123 if (extension == ".pgm") return GetPGMEncoder(); 124 if (extension == ".ppm") return GetPPMEncoder(); 125 if (extension == ".pnm") return GetPNMEncoder(); 126 if (extension == ".pfm") return GetPFMEncoder(); 127 if (extension == ".exr") return GetEXREncoder(); 128 if (extension == ".exif") return jxl::make_unique<MetadataEncoder<0>>(); 129 if (extension == ".xmp") return jxl::make_unique<MetadataEncoder<1>>(); 130 if (extension == ".xml") return jxl::make_unique<MetadataEncoder<1>>(); 131 if (extension == ".jumbf") return jxl::make_unique<MetadataEncoder<2>>(); 132 if (extension == ".jumb") return jxl::make_unique<MetadataEncoder<2>>(); 133 134 return nullptr; 135 } 136 137 } // namespace extras 138 } // namespace jxl