libjxl

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

image_loading.cc (4430B)


      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 "tools/comparison_viewer/image_loading.h"
      7 
      8 #include <jxl/cms.h>
      9 
     10 #include <QRgb>
     11 #include <QThread>
     12 #include <cstdint>
     13 #include <vector>
     14 
     15 #include "lib/extras/codec.h"
     16 #include "lib/extras/dec/color_hints.h"
     17 #include "lib/jxl/image_bundle.h"
     18 #include "lib/jxl/image_metadata.h"
     19 #include "tools/file_io.h"
     20 #include "tools/thread_pool_internal.h"
     21 #include "tools/viewer/load_jxl.h"
     22 
     23 namespace jpegxl {
     24 namespace tools {
     25 
     26 using jxl::CodecInOut;
     27 using jxl::ColorEncoding;
     28 using jxl::IccBytes;
     29 using jxl::Image3F;
     30 using jxl::ImageBundle;
     31 using jxl::Rect;
     32 using jxl::Span;
     33 using jxl::Status;
     34 using jxl::ThreadPool;
     35 using jxl::extras::ColorHints;
     36 
     37 namespace {
     38 
     39 Status loadFromFile(const QString& filename, const ColorHints& color_hints,
     40                     CodecInOut* const decoded, ThreadPool* const pool) {
     41   std::vector<uint8_t> compressed;
     42   JXL_RETURN_IF_ERROR(
     43       jpegxl::tools::ReadFile(filename.toStdString(), &compressed));
     44   const Span<const uint8_t> compressed_span(compressed);
     45   return jxl::SetFromBytes(compressed_span, color_hints, decoded, pool,
     46                            nullptr);
     47 }
     48 
     49 }  // namespace
     50 
     51 bool canLoadImageWithExtension(QString extension) {
     52   extension = extension.toLower();
     53   if (extension == "jxl" || extension == "j" || extension == "brn") {
     54     return true;
     55   }
     56   const auto codec = jxl::extras::CodecFromPath("." + extension.toStdString());
     57   return codec != jxl::extras::Codec::kUnknown;
     58 }
     59 
     60 QImage loadImage(const QString& filename, const QByteArray& targetIccProfile,
     61                  const float intensityTarget,
     62                  const QString& sourceColorSpaceHint) {
     63   qint64 elapsed;
     64   QImage img = loadJxlImage(filename, targetIccProfile, &elapsed);
     65   if (img.width() != 0 && img.height() != 0) {
     66     return img;
     67   }
     68   static ThreadPoolInternal pool(QThread::idealThreadCount());
     69 
     70   CodecInOut decoded;
     71   ColorHints color_hints;
     72   if (!sourceColorSpaceHint.isEmpty()) {
     73     color_hints.Add("color_space", sourceColorSpaceHint.toStdString());
     74   }
     75   if (!loadFromFile(filename, color_hints, &decoded, &pool)) {
     76     return QImage();
     77   }
     78   decoded.metadata.m.SetIntensityTarget(intensityTarget);
     79   const ImageBundle& ib = decoded.Main();
     80 
     81   ColorEncoding targetColorSpace;
     82   bool use_fallback_profile = true;
     83   if (!targetIccProfile.isEmpty()) {
     84     IccBytes icc;
     85     icc.assign(reinterpret_cast<const uint8_t*>(targetIccProfile.data()),
     86                reinterpret_cast<const uint8_t*>(targetIccProfile.data() +
     87                                                 targetIccProfile.size()));
     88     use_fallback_profile =
     89         !targetColorSpace.SetICC(std::move(icc), JxlGetDefaultCms());
     90   }
     91   if (use_fallback_profile) {
     92     targetColorSpace = ColorEncoding::SRGB(ib.IsGray());
     93   }
     94   Image3F converted;
     95   if (!ib.CopyTo(Rect(ib), targetColorSpace, *JxlGetDefaultCms(), &converted,
     96                  &pool)) {
     97     return QImage();
     98   }
     99 
    100   QImage image(converted.xsize(), converted.ysize(), QImage::Format_ARGB32);
    101 
    102   const auto ScaleAndClamp = [](const float x) {
    103     return jxl::Clamp1(x * 255 + .5f, 0.f, 255.f);
    104   };
    105 
    106   if (ib.HasAlpha()) {
    107     for (int y = 0; y < image.height(); ++y) {
    108       QRgb* const row = reinterpret_cast<QRgb*>(image.scanLine(y));
    109       const float* const alphaRow = ib.alpha().ConstRow(y);
    110       const float* const redRow = converted.ConstPlaneRow(0, y);
    111       const float* const greenRow = converted.ConstPlaneRow(1, y);
    112       const float* const blueRow = converted.ConstPlaneRow(2, y);
    113       for (int x = 0; x < image.width(); ++x) {
    114         row[x] = qRgba(ScaleAndClamp(redRow[x]), ScaleAndClamp(greenRow[x]),
    115                        ScaleAndClamp(blueRow[x]), ScaleAndClamp(alphaRow[x]));
    116       }
    117     }
    118   } else {
    119     for (int y = 0; y < image.height(); ++y) {
    120       QRgb* const row = reinterpret_cast<QRgb*>(image.scanLine(y));
    121       const float* const redRow = converted.ConstPlaneRow(0, y);
    122       const float* const greenRow = converted.ConstPlaneRow(1, y);
    123       const float* const blueRow = converted.ConstPlaneRow(2, y);
    124       for (int x = 0; x < image.width(); ++x) {
    125         row[x] = qRgb(ScaleAndClamp(redRow[x]), ScaleAndClamp(greenRow[x]),
    126                       ScaleAndClamp(blueRow[x]));
    127       }
    128     }
    129   }
    130 
    131   return image;
    132 }
    133 
    134 }  // namespace tools
    135 }  // namespace jpegxl