libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

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