diff options
Diffstat (limited to 'lib/extras/codec.cc')
-rw-r--r-- | lib/extras/codec.cc | 257 |
1 files changed, 103 insertions, 154 deletions
diff --git a/lib/extras/codec.cc b/lib/extras/codec.cc index 54f98bb..774b4cc 100644 --- a/lib/extras/codec.cc +++ b/lib/extras/codec.cc @@ -5,21 +5,27 @@ #include "lib/extras/codec.h" -#include "lib/jxl/base/file_io.h" +#include "jxl/decode.h" +#include "jxl/types.h" +#include "lib/extras/packed_image.h" +#include "lib/jxl/base/padded_bytes.h" +#include "lib/jxl/base/status.h" + #if JPEGXL_ENABLE_APNG -#include "lib/extras/codec_apng.h" +#include "lib/extras/enc/apng.h" #endif -#if JPEGXL_ENABLE_EXR -#include "lib/extras/codec_exr.h" +#if JPEGXL_ENABLE_JPEG +#include "lib/extras/enc/jpg.h" #endif -#if JPEGXL_ENABLE_GIF -#include "lib/extras/codec_gif.h" +#if JPEGXL_ENABLE_EXR +#include "lib/extras/enc/exr.h" #endif -#include "lib/extras/codec_jpg.h" -#include "lib/extras/codec_pgx.h" -#include "lib/extras/codec_png.h" -#include "lib/extras/codec_pnm.h" -#include "lib/extras/codec_psd.h" + +#include "lib/extras/dec/decode.h" +#include "lib/extras/enc/pgx.h" +#include "lib/extras/enc/pnm.h" +#include "lib/extras/packed_image_convert.h" +#include "lib/jxl/base/file_io.h" #include "lib/jxl/image_bundle.h" namespace jxl { @@ -30,184 +36,127 @@ constexpr size_t kMinBytes = 9; } // namespace -std::string ExtensionFromCodec(Codec codec, const bool is_gray, - const size_t bits_per_sample) { - switch (codec) { - case Codec::kJPG: - return ".jpg"; - case Codec::kPGX: - return ".pgx"; - case Codec::kPNG: - return ".png"; - case Codec::kPNM: - if (is_gray) return ".pgm"; - return (bits_per_sample == 32) ? ".pfm" : ".ppm"; - case Codec::kGIF: - return ".gif"; - case Codec::kEXR: - return ".exr"; - case Codec::kPSD: - return ".psd"; - case Codec::kUnknown: - return std::string(); - } - JXL_UNREACHABLE; - return std::string(); -} - -Codec CodecFromExtension(const std::string& extension, - size_t* JXL_RESTRICT bits_per_sample) { - if (extension == ".png") return Codec::kPNG; - - if (extension == ".jpg") return Codec::kJPG; - if (extension == ".jpeg") return Codec::kJPG; - - if (extension == ".pgx") return Codec::kPGX; - - if (extension == ".pbm") { - *bits_per_sample = 1; - return Codec::kPNM; - } - if (extension == ".pgm") return Codec::kPNM; - if (extension == ".ppm") return Codec::kPNM; - if (extension == ".pfm") { - *bits_per_sample = 32; - return Codec::kPNM; - } - - if (extension == ".gif") return Codec::kGIF; - - if (extension == ".exr") return Codec::kEXR; - - if (extension == ".psd") return Codec::kPSD; - - return Codec::kUnknown; -} - Status SetFromBytes(const Span<const uint8_t> bytes, - const ColorHints& color_hints, CodecInOut* io, - ThreadPool* pool, Codec* orig_codec) { + const extras::ColorHints& color_hints, CodecInOut* io, + ThreadPool* pool, extras::Codec* orig_codec) { if (bytes.size() < kMinBytes) return JXL_FAILURE("Too few bytes"); - io->metadata.m.bit_depth.bits_per_sample = 0; // (For is-set check below) - - Codec codec; - if (extras::DecodeImagePNG(bytes, color_hints, pool, io)) { - codec = Codec::kPNG; - } -#if JPEGXL_ENABLE_APNG - else if (extras::DecodeImageAPNG(bytes, color_hints, pool, io)) { - codec = Codec::kPNG; - } -#endif - else if (extras::DecodeImagePGX(bytes, color_hints, pool, io)) { - codec = Codec::kPGX; - } else if (extras::DecodeImagePNM(bytes, color_hints, pool, io)) { - codec = Codec::kPNM; - } -#if JPEGXL_ENABLE_GIF - else if (extras::DecodeImageGIF(bytes, color_hints, pool, io)) { - codec = Codec::kGIF; - } -#endif - else if (io->dec_target == DecodeTarget::kQuantizedCoeffs && - extras::DecodeImageJPGCoefficients(bytes, io)) { - // TODO(deymo): In this case the tools should use a different API to - // transcode the input JPEG to JXL. - codec = Codec::kJPG; - } else if (io->dec_target == DecodeTarget::kPixels && - extras::DecodeImageJPG(bytes, color_hints, pool, io)) { - codec = Codec::kJPG; - } else if (extras::DecodeImagePSD(bytes, color_hints, pool, io)) { - codec = Codec::kPSD; + extras::PackedPixelFile ppf; + if (extras::DecodeBytes(bytes, color_hints, io->constraints, &ppf, + orig_codec)) { + return ConvertPackedPixelFileToCodecInOut(ppf, pool, io); } -#if JPEGXL_ENABLE_EXR - else if (extras::DecodeImageEXR(bytes, color_hints, pool, io)) { - codec = Codec::kEXR; - } -#endif - else { - return JXL_FAILURE("Codecs failed to decode"); - } - if (orig_codec) *orig_codec = codec; - - io->CheckMetadata(); - return true; + return JXL_FAILURE("Codecs failed to decode"); } -Status SetFromFile(const std::string& pathname, const ColorHints& color_hints, - CodecInOut* io, ThreadPool* pool, Codec* orig_codec) { - PaddedBytes encoded; +Status SetFromFile(const std::string& pathname, + const extras::ColorHints& color_hints, CodecInOut* io, + ThreadPool* pool, extras::Codec* orig_codec) { + std::vector<uint8_t> encoded; JXL_RETURN_IF_ERROR(ReadFile(pathname, &encoded)); JXL_RETURN_IF_ERROR(SetFromBytes(Span<const uint8_t>(encoded), color_hints, io, pool, orig_codec)); return true; } -Status Encode(const CodecInOut& io, const Codec codec, +Status Encode(const CodecInOut& io, const extras::Codec codec, const ColorEncoding& c_desired, size_t bits_per_sample, - PaddedBytes* bytes, ThreadPool* pool) { + std::vector<uint8_t>* bytes, ThreadPool* pool) { JXL_CHECK(!io.Main().c_current().ICC().empty()); JXL_CHECK(!c_desired.ICC().empty()); io.CheckMetadata(); - if (io.Main().IsJPEG() && codec != Codec::kJPG) { - return JXL_FAILURE( - "Output format has to be JPEG for losslessly recompressed JPEG " - "reconstruction"); + if (io.Main().IsJPEG()) { + JXL_WARNING("Writing JPEG data as pixels"); } - + JxlPixelFormat format = { + 0, // num_channels is ignored by the converter + bits_per_sample <= 8 ? JXL_TYPE_UINT8 : JXL_TYPE_UINT16, JXL_BIG_ENDIAN, + 0}; + const bool floating_point = bits_per_sample > 16; + std::unique_ptr<extras::Encoder> encoder; + std::ostringstream os; switch (codec) { - case Codec::kPNG: - return extras::EncodeImagePNG(&io, c_desired, bits_per_sample, pool, - bytes); - case Codec::kJPG: - if (io.Main().IsJPEG()) { - return extras::EncodeImageJPGCoefficients(&io, bytes); - } else { + case extras::Codec::kPNG: +#if JPEGXL_ENABLE_APNG + encoder = extras::GetAPNGEncoder(); + break; +#else + return JXL_FAILURE("JPEG XL was built without (A)PNG support"); +#endif + case extras::Codec::kJPG: #if JPEGXL_ENABLE_JPEG - return EncodeImageJPG(&io, - io.use_sjpeg ? extras::JpegEncoder::kSJpeg - : extras::JpegEncoder::kLibJpeg, - io.jpeg_quality, YCbCrChromaSubsampling(), pool, - bytes); + format.data_type = JXL_TYPE_UINT8; + encoder = extras::GetJPEGEncoder(); + os << io.jpeg_quality; + encoder->SetOption("q", os.str()); + break; #else - return JXL_FAILURE("JPEG XL was built without JPEG support"); + return JXL_FAILURE("JPEG XL was built without JPEG support"); #endif + case extras::Codec::kPNM: + if (io.Main().HasAlpha()) { + encoder = extras::GetPAMEncoder(); + } else if (io.Main().IsGray()) { + encoder = extras::GetPGMEncoder(); + } else if (!floating_point) { + encoder = extras::GetPPMEncoder(); + } else { + format.data_type = JXL_TYPE_FLOAT; + format.endianness = JXL_NATIVE_ENDIAN; + encoder = extras::GetPFMEncoder(); } - case Codec::kPNM: - return extras::EncodeImagePNM(&io, c_desired, bits_per_sample, pool, - bytes); - case Codec::kPGX: - return extras::EncodeImagePGX(&io, c_desired, bits_per_sample, pool, - bytes); - case Codec::kGIF: + if (!c_desired.IsSRGB()) { + JXL_WARNING( + "PNM encoder cannot store custom ICC profile; decoder " + "will need hint key=color_space to get the same values"); + } + break; + case extras::Codec::kPGX: + encoder = extras::GetPGXEncoder(); + break; + case extras::Codec::kGIF: return JXL_FAILURE("Encoding to GIF is not implemented"); - case Codec::kPSD: - return extras::EncodeImagePSD(&io, c_desired, bits_per_sample, pool, - bytes); - case Codec::kEXR: + case extras::Codec::kEXR: #if JPEGXL_ENABLE_EXR - return extras::EncodeImageEXR(&io, c_desired, pool, bytes); + format.data_type = JXL_TYPE_FLOAT; + encoder = extras::GetEXREncoder(); + break; #else return JXL_FAILURE("JPEG XL was built without OpenEXR support"); #endif - case Codec::kUnknown: + case extras::Codec::kUnknown: return JXL_FAILURE("Cannot encode using Codec::kUnknown"); } - return JXL_FAILURE("Invalid codec"); + if (!encoder) { + return JXL_FAILURE("Invalid codec."); + } + + extras::PackedPixelFile ppf; + JXL_RETURN_IF_ERROR( + ConvertCodecInOutToPackedPixelFile(io, format, c_desired, pool, &ppf)); + extras::EncodedImage encoded_image; + JXL_RETURN_IF_ERROR(encoder->Encode(ppf, &encoded_image, pool)); + JXL_ASSERT(encoded_image.bitstreams.size() == 1); + *bytes = encoded_image.bitstreams[0]; + + return true; } Status EncodeToFile(const CodecInOut& io, const ColorEncoding& c_desired, size_t bits_per_sample, const std::string& pathname, ThreadPool* pool) { const std::string extension = Extension(pathname); - const Codec codec = CodecFromExtension(extension, &bits_per_sample); + const extras::Codec codec = + extras::CodecFromExtension(extension, &bits_per_sample); - // Warn about incorrect usage of PBM/PGM/PGX/PPM - only the latter supports + // Warn about incorrect usage of PGM/PGX/PPM - only the latter supports // color, but CodecFromExtension lumps them all together. - if (codec == Codec::kPNM && extension != ".pfm") { - if (!io.Main().IsGray() && extension != ".ppm") { + if (codec == extras::Codec::kPNM && extension != ".pfm") { + if (io.Main().HasAlpha() && extension != ".pam") { + JXL_WARNING( + "For images with alpha, the filename should end with .pam.\n"); + } else if (!io.Main().IsGray() && extension == ".pgm") { JXL_WARNING("For color images, the filename should end with .ppm.\n"); } else if (io.Main().IsGray() && extension == ".ppm") { JXL_WARNING( @@ -217,15 +166,15 @@ Status EncodeToFile(const CodecInOut& io, const ColorEncoding& c_desired, JXL_WARNING("PPM only supports up to 16 bits per sample"); bits_per_sample = 16; } - } else if (codec == Codec::kPGX && !io.Main().IsGray()) { + } else if (codec == extras::Codec::kPGX && !io.Main().IsGray()) { JXL_WARNING("Storing color image to PGX - use .ppm extension instead.\n"); } - if (bits_per_sample > 16 && codec == Codec::kPNG) { + if (bits_per_sample > 16 && codec == extras::Codec::kPNG) { JXL_WARNING("PNG only supports up to 16 bits per sample"); bits_per_sample = 16; } - PaddedBytes encoded; + std::vector<uint8_t> encoded; return Encode(io, codec, c_desired, bits_per_sample, &encoded, pool) && WriteFile(encoded, pathname); } |