decode.cc (4496B)
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/dec/decode.h" 7 8 #include <locale> 9 10 #include "lib/extras/dec/apng.h" 11 #include "lib/extras/dec/exr.h" 12 #include "lib/extras/dec/gif.h" 13 #include "lib/extras/dec/jpg.h" 14 #include "lib/extras/dec/jxl.h" 15 #include "lib/extras/dec/pgx.h" 16 #include "lib/extras/dec/pnm.h" 17 18 namespace jxl { 19 namespace extras { 20 namespace { 21 22 // Any valid encoding is larger (ensures codecs can read the first few bytes) 23 constexpr size_t kMinBytes = 9; 24 25 std::string GetExtension(const std::string& path) { 26 // Pattern: "name.png" 27 size_t pos = path.find_last_of('.'); 28 if (pos != std::string::npos) { 29 return path.substr(pos); 30 } 31 32 // Extension not found 33 return ""; 34 } 35 36 } // namespace 37 38 Codec CodecFromPath(const std::string& path, 39 size_t* JXL_RESTRICT bits_per_sample, 40 std::string* extension) { 41 std::string ext = GetExtension(path); 42 if (extension) { 43 if (extension->empty()) { 44 *extension = ext; 45 } else { 46 ext = *extension; 47 } 48 } 49 std::transform(ext.begin(), ext.end(), ext.begin(), [](char c) { 50 return std::tolower(c, std::locale::classic()); 51 }); 52 if (ext == ".png") return Codec::kPNG; 53 54 if (ext == ".jpg") return Codec::kJPG; 55 if (ext == ".jpeg") return Codec::kJPG; 56 57 if (ext == ".pgx") return Codec::kPGX; 58 59 if (ext == ".pam") return Codec::kPNM; 60 if (ext == ".pnm") return Codec::kPNM; 61 if (ext == ".pgm") return Codec::kPNM; 62 if (ext == ".ppm") return Codec::kPNM; 63 if (ext == ".pfm") { 64 if (bits_per_sample != nullptr) *bits_per_sample = 32; 65 return Codec::kPNM; 66 } 67 68 if (ext == ".gif") return Codec::kGIF; 69 70 if (ext == ".exr") return Codec::kEXR; 71 72 return Codec::kUnknown; 73 } 74 75 bool CanDecode(Codec codec) { 76 switch (codec) { 77 case Codec::kEXR: 78 return CanDecodeEXR(); 79 case Codec::kGIF: 80 return CanDecodeGIF(); 81 case Codec::kJPG: 82 return CanDecodeJPG(); 83 case Codec::kPNG: 84 return CanDecodeAPNG(); 85 case Codec::kPNM: 86 case Codec::kPGX: 87 case Codec::kJXL: 88 return true; 89 default: 90 return false; 91 } 92 } 93 94 std::string ListOfDecodeCodecs() { 95 std::string list_of_codecs("JXL, PPM, PNM, PFM, PAM, PGX"); 96 if (CanDecode(Codec::kPNG)) list_of_codecs.append(", PNG, APNG"); 97 if (CanDecode(Codec::kGIF)) list_of_codecs.append(", GIF"); 98 if (CanDecode(Codec::kJPG)) list_of_codecs.append(", JPEG"); 99 if (CanDecode(Codec::kEXR)) list_of_codecs.append(", EXR"); 100 return list_of_codecs; 101 } 102 103 Status DecodeBytes(const Span<const uint8_t> bytes, 104 const ColorHints& color_hints, extras::PackedPixelFile* ppf, 105 const SizeConstraints* constraints, Codec* orig_codec) { 106 if (bytes.size() < kMinBytes) return JXL_FAILURE("Too few bytes"); 107 108 *ppf = extras::PackedPixelFile(); 109 110 // Default values when not set by decoders. 111 ppf->info.uses_original_profile = JXL_TRUE; 112 ppf->info.orientation = JXL_ORIENT_IDENTITY; 113 114 const auto choose_codec = [&]() -> Codec { 115 if (DecodeImageAPNG(bytes, color_hints, ppf, constraints)) { 116 return Codec::kPNG; 117 } 118 if (DecodeImagePGX(bytes, color_hints, ppf, constraints)) { 119 return Codec::kPGX; 120 } 121 if (DecodeImagePNM(bytes, color_hints, ppf, constraints)) { 122 return Codec::kPNM; 123 } 124 JXLDecompressParams dparams = {}; 125 for (const uint32_t num_channels : {1, 2, 3, 4}) { 126 dparams.accepted_formats.push_back( 127 {num_channels, JXL_TYPE_FLOAT, JXL_LITTLE_ENDIAN, /*align=*/0}); 128 } 129 dparams.output_bitdepth.type = JXL_BIT_DEPTH_FROM_CODESTREAM; 130 size_t decoded_bytes; 131 if (DecodeImageJXL(bytes.data(), bytes.size(), dparams, &decoded_bytes, 132 ppf) && 133 ApplyColorHints(color_hints, true, ppf->info.num_color_channels == 1, 134 ppf)) { 135 return Codec::kJXL; 136 } 137 if (DecodeImageGIF(bytes, color_hints, ppf, constraints)) { 138 return Codec::kGIF; 139 } 140 if (DecodeImageJPG(bytes, color_hints, ppf, constraints)) { 141 return Codec::kJPG; 142 } 143 if (DecodeImageEXR(bytes, color_hints, ppf, constraints)) { 144 return Codec::kEXR; 145 } 146 return Codec::kUnknown; 147 }; 148 149 Codec codec = choose_codec(); 150 if (codec == Codec::kUnknown) { 151 return JXL_FAILURE("Codecs failed to decode"); 152 } 153 if (orig_codec) *orig_codec = codec; 154 155 return true; 156 } 157 158 } // namespace extras 159 } // namespace jxl