// 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. #include "lib/jxl/enc_debug_image.h" #include #include #include "lib/jxl/base/status.h" #include "lib/jxl/color_encoding_internal.h" #include "lib/jxl/dec_external_image.h" #include "lib/jxl/enc_params.h" #include "lib/jxl/image_ops.h" namespace jxl { namespace { template StatusOr ConvertToFloat(const Image3& from) { float factor = 1.0f / std::numeric_limits::max(); if (std::is_same::value || std::is_same::value) { factor = 1.0f; } JXL_ASSIGN_OR_RETURN(Image3F to, Image3F::Create(from.xsize(), from.ysize())); for (size_t c = 0; c < 3; ++c) { for (size_t y = 0; y < from.ysize(); ++y) { const From* const JXL_RESTRICT row_from = from.ConstPlaneRow(c, y); float* const JXL_RESTRICT row_to = to.PlaneRow(c, y); for (size_t x = 0; x < from.xsize(); ++x) { row_to[x] = row_from[x] * factor; } } } return to; } template Status DumpImageT(const CompressParams& cparams, const char* label, const ColorEncoding& color_encoding, const Image3& image) { if (!cparams.debug_image) return true; JXL_ASSIGN_OR_RETURN(Image3F float_image, ConvertToFloat(image)); JxlColorEncoding color = color_encoding.ToExternal(); size_t num_pixels = 3 * image.xsize() * image.ysize(); std::vector pixels(num_pixels); const ImageF* channels[3]; for (int c = 0; c < 3; ++c) { channels[c] = &float_image.Plane(c); } JXL_CHECK(ConvertChannelsToExternal( channels, 3, 16, false, JXL_BIG_ENDIAN, 6 * image.xsize(), nullptr, pixels.data(), 2 * num_pixels, PixelCallback(), Orientation::kIdentity)); (*cparams.debug_image)(cparams.debug_image_opaque, label, image.xsize(), image.ysize(), &color, pixels.data()); return true; } template Status DumpPlaneNormalizedT(const CompressParams& cparams, const char* label, const Plane& image) { T min; T max; ImageMinMax(image, &min, &max); JXL_ASSIGN_OR_RETURN(Image3B normalized, Image3B::Create(image.xsize(), image.ysize())); for (size_t c = 0; c < 3; ++c) { float mul = min == max ? 0 : (255.0f / (max - min)); for (size_t y = 0; y < image.ysize(); ++y) { const T* JXL_RESTRICT row_in = image.ConstRow(y); uint8_t* JXL_RESTRICT row_out = normalized.PlaneRow(c, y); for (size_t x = 0; x < image.xsize(); ++x) { row_out[x] = static_cast((row_in[x] - min) * mul); } } } return DumpImageT(cparams, label, ColorEncoding::SRGB(), normalized); } } // namespace Status DumpImage(const CompressParams& cparams, const char* label, const Image3& image) { return DumpImageT(cparams, label, ColorEncoding::SRGB(), image); } Status DumpImage(const CompressParams& cparams, const char* label, const Image3& image) { return DumpImageT(cparams, label, ColorEncoding::SRGB(), image); } Status DumpXybImage(const CompressParams& cparams, const char* label, const Image3F& image) { if (!cparams.debug_image) return true; JXL_ASSIGN_OR_RETURN(Image3F linear, Image3F::Create(image.xsize(), image.ysize())); OpsinParams opsin_params; opsin_params.Init(kDefaultIntensityTarget); OpsinToLinear(image, Rect(linear), nullptr, &linear, opsin_params); return DumpImageT(cparams, label, ColorEncoding::LinearSRGB(), linear); } Status DumpPlaneNormalized(const CompressParams& cparams, const char* label, const Plane& image) { return DumpPlaneNormalizedT(cparams, label, image); } Status DumpPlaneNormalized(const CompressParams& cparams, const char* label, const Plane& image) { return DumpPlaneNormalizedT(cparams, label, image); } } // namespace jxl