Coverage Report

Created: 2024-05-21 06:41

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