decode.cc (4116B)
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 Status DecodeBytes(const Span<const uint8_t> bytes, 95 const ColorHints& color_hints, extras::PackedPixelFile* ppf, 96 const SizeConstraints* constraints, Codec* orig_codec) { 97 if (bytes.size() < kMinBytes) return JXL_FAILURE("Too few bytes"); 98 99 *ppf = extras::PackedPixelFile(); 100 101 // Default values when not set by decoders. 102 ppf->info.uses_original_profile = JXL_TRUE; 103 ppf->info.orientation = JXL_ORIENT_IDENTITY; 104 105 const auto choose_codec = [&]() -> Codec { 106 if (DecodeImageAPNG(bytes, color_hints, ppf, constraints)) { 107 return Codec::kPNG; 108 } 109 if (DecodeImagePGX(bytes, color_hints, ppf, constraints)) { 110 return Codec::kPGX; 111 } 112 if (DecodeImagePNM(bytes, color_hints, ppf, constraints)) { 113 return Codec::kPNM; 114 } 115 JXLDecompressParams dparams = {}; 116 for (const uint32_t num_channels : {1, 2, 3, 4}) { 117 dparams.accepted_formats.push_back( 118 {num_channels, JXL_TYPE_FLOAT, JXL_LITTLE_ENDIAN, /*align=*/0}); 119 } 120 dparams.output_bitdepth.type = JXL_BIT_DEPTH_FROM_CODESTREAM; 121 size_t decoded_bytes; 122 if (DecodeImageJXL(bytes.data(), bytes.size(), dparams, &decoded_bytes, 123 ppf) && 124 ApplyColorHints(color_hints, true, ppf->info.num_color_channels == 1, 125 ppf)) { 126 return Codec::kJXL; 127 } 128 if (DecodeImageGIF(bytes, color_hints, ppf, constraints)) { 129 return Codec::kGIF; 130 } 131 if (DecodeImageJPG(bytes, color_hints, ppf, constraints)) { 132 return Codec::kJPG; 133 } 134 if (DecodeImageEXR(bytes, color_hints, ppf, constraints)) { 135 return Codec::kEXR; 136 } 137 return Codec::kUnknown; 138 }; 139 140 Codec codec = choose_codec(); 141 if (codec == Codec::kUnknown) { 142 return JXL_FAILURE("Codecs failed to decode"); 143 } 144 if (orig_codec) *orig_codec = codec; 145 146 return true; 147 } 148 149 } // namespace extras 150 } // namespace jxl