// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #ifndef LIB_JXL_CODEC_IN_OUT_H_ #define LIB_JXL_CODEC_IN_OUT_H_ // Holds inputs/outputs for decoding/encoding images. #include #include #include #include "lib/jxl/base/data_parallel.h" #include "lib/jxl/common.h" #include "lib/jxl/frame_header.h" #include "lib/jxl/headers.h" #include "lib/jxl/image.h" #include "lib/jxl/image_bundle.h" #include "lib/jxl/luminance.h" #include "lib/jxl/size_constraints.h" namespace jxl { // Per-channel interval, used to convert between (full-range) external and // (bounded or unbounded) temp values. See external_image.cc for the definitions // of temp/external. struct CodecInterval { CodecInterval() = default; constexpr CodecInterval(float min, float max) : min(min), width(max - min) {} // Defaults for temp. float min = 0.0f; float width = 1.0f; }; template ::value>::type> Status VerifyDimensions(const SizeConstraints* constraints, T xs, T ys) { if (!constraints) return true; if (xs == 0 || ys == 0) return JXL_FAILURE("Empty image."); if (xs > constraints->dec_max_xsize) return JXL_FAILURE("Image too wide."); if (ys > constraints->dec_max_ysize) return JXL_FAILURE("Image too tall."); const uint64_t num_pixels = static_cast(xs) * ys; if (num_pixels > constraints->dec_max_pixels) { return JXL_FAILURE("Image too big."); } return true; } using CodecIntervals = std::array; // RGB[A] or Y[A] // Optional text/EXIF metadata. struct Blobs { std::vector exif; std::vector iptc; std::vector jumbf; std::vector xmp; }; // Holds a preview, a main image or one or more frames, plus the inputs/outputs // to/from decoding/encoding. class CodecInOut { public: CodecInOut() : preview_frame(&metadata.m) { frames.reserve(1); frames.emplace_back(&metadata.m); } // Move-only. CodecInOut(CodecInOut&&) = default; CodecInOut& operator=(CodecInOut&&) = default; size_t LastStillFrame() const { JXL_DASSERT(!frames.empty()); size_t last = 0; for (size_t i = 0; i < frames.size(); i++) { last = i; if (frames[i].duration > 0) break; } return last; } ImageBundle& Main() { return frames[LastStillFrame()]; } const ImageBundle& Main() const { return frames[LastStillFrame()]; } // If c_current.IsGray(), all planes must be identical. void SetFromImage(Image3F&& color, const ColorEncoding& c_current) { Main().SetFromImage(std::move(color), c_current); SetIntensityTarget(this); SetSize(Main().xsize(), Main().ysize()); } void SetSize(size_t xsize, size_t ysize) { JXL_CHECK(metadata.size.Set(xsize, ysize)); } void CheckMetadata() const { JXL_CHECK(metadata.m.bit_depth.bits_per_sample != 0); JXL_CHECK(!metadata.m.color_encoding.ICC().empty()); if (preview_frame.xsize() != 0) preview_frame.VerifyMetadata(); JXL_CHECK(preview_frame.metadata() == &metadata.m); for (const ImageBundle& ib : frames) { ib.VerifyMetadata(); JXL_CHECK(ib.metadata() == &metadata.m); } } size_t xsize() const { return metadata.size.xsize(); } size_t ysize() const { return metadata.size.ysize(); } void ShrinkTo(size_t xsize, size_t ysize) { // preview is unaffected. for (ImageBundle& ib : frames) { ib.ShrinkTo(xsize, ysize); } SetSize(xsize, ysize); } // Calls TransformTo for each ImageBundle (preview/frames). Status TransformTo(const ColorEncoding& c_desired, const JxlCmsInterface& cms, ThreadPool* pool = nullptr) { if (metadata.m.have_preview) { JXL_RETURN_IF_ERROR(preview_frame.TransformTo(c_desired, cms, pool)); } for (ImageBundle& ib : frames) { JXL_RETURN_IF_ERROR(ib.TransformTo(c_desired, cms, pool)); } return true; } // Calls PremultiplyAlpha for each ImageBundle (preview/frames). void PremultiplyAlpha() { ExtraChannelInfo* eci = metadata.m.Find(ExtraChannel::kAlpha); if (eci == nullptr || eci->alpha_associated) return; // nothing to do if (metadata.m.have_preview) { preview_frame.PremultiplyAlpha(); } for (ImageBundle& ib : frames) { ib.PremultiplyAlpha(); } eci->alpha_associated = true; return; } // -- DECODER INPUT: SizeConstraints constraints; // -- DECODER OUTPUT: // Total number of pixels decoded (may differ from #frames * xsize * ysize // if frames are cropped) uint64_t dec_pixels = 0; // -- DECODER OUTPUT, ENCODER INPUT: // Metadata stored into / retrieved from bitstreams. Blobs blobs; CodecMetadata metadata; // applies to preview and all frames // If metadata.have_preview: ImageBundle preview_frame; std::vector frames; // size=1 if !metadata.have_animation bool use_sjpeg = false; // If the image should be written to a JPEG, use this quality for encoding. size_t jpeg_quality; }; } // namespace jxl #endif // LIB_JXL_CODEC_IN_OUT_H_