libjxl

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

color_encoding_internal.cc (7153B)


      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/jxl/color_encoding_internal.h"
      7 
      8 #include <array>
      9 
     10 #include "lib/jxl/base/common.h"
     11 #include "lib/jxl/cms/color_encoding_cms.h"
     12 #include "lib/jxl/cms/jxl_cms_internal.h"
     13 #include "lib/jxl/fields.h"
     14 #include "lib/jxl/pack_signed.h"
     15 
     16 namespace jxl {
     17 
     18 bool CustomTransferFunction::SetImplicit() {
     19   if (nonserialized_color_space == ColorSpace::kXYB) {
     20     if (!storage_.SetGamma(1.0 / 3)) JXL_ASSERT(false);
     21     return true;
     22   }
     23   return false;
     24 }
     25 
     26 std::array<ColorEncoding, 2> ColorEncoding::CreateC2(Primaries pr,
     27                                                      TransferFunction tf) {
     28   std::array<ColorEncoding, 2> c2;
     29 
     30   ColorEncoding* c_rgb = c2.data() + 0;
     31   c_rgb->SetColorSpace(ColorSpace::kRGB);
     32   c_rgb->storage_.white_point = WhitePoint::kD65;
     33   c_rgb->storage_.primaries = pr;
     34   c_rgb->storage_.tf.SetTransferFunction(tf);
     35   JXL_CHECK(c_rgb->CreateICC());
     36 
     37   ColorEncoding* c_gray = c2.data() + 1;
     38   c_gray->SetColorSpace(ColorSpace::kGray);
     39   c_gray->storage_.white_point = WhitePoint::kD65;
     40   c_gray->storage_.primaries = pr;
     41   c_gray->storage_.tf.SetTransferFunction(tf);
     42   JXL_CHECK(c_gray->CreateICC());
     43 
     44   return c2;
     45 }
     46 
     47 const ColorEncoding& ColorEncoding::SRGB(bool is_gray) {
     48   static std::array<ColorEncoding, 2> c2 =
     49       CreateC2(Primaries::kSRGB, TransferFunction::kSRGB);
     50   return c2[is_gray ? 1 : 0];
     51 }
     52 const ColorEncoding& ColorEncoding::LinearSRGB(bool is_gray) {
     53   static std::array<ColorEncoding, 2> c2 =
     54       CreateC2(Primaries::kSRGB, TransferFunction::kLinear);
     55   return c2[is_gray ? 1 : 0];
     56 }
     57 
     58 Status ColorEncoding::SetWhitePointType(const WhitePoint& wp) {
     59   JXL_DASSERT(storage_.have_fields);
     60   storage_.white_point = wp;
     61   return true;
     62 }
     63 
     64 Status ColorEncoding::SetPrimariesType(const Primaries& p) {
     65   JXL_DASSERT(storage_.have_fields);
     66   JXL_ASSERT(HasPrimaries());
     67   storage_.primaries = p;
     68   return true;
     69 }
     70 
     71 void ColorEncoding::DecideIfWantICC(const JxlCmsInterface& cms) {
     72   if (storage_.icc.empty()) return;
     73 
     74   JxlColorEncoding c;
     75   JXL_BOOL cmyk;
     76   if (!cms.set_fields_from_icc(cms.set_fields_data, storage_.icc.data(),
     77                                storage_.icc.size(), &c, &cmyk)) {
     78     return;
     79   }
     80   if (cmyk) return;
     81 
     82   std::vector<uint8_t> icc;
     83   if (!MaybeCreateProfile(c, &icc)) return;
     84 
     85   want_icc_ = false;
     86 }
     87 
     88 Customxy::Customxy() { Bundle::Init(this); }
     89 Status Customxy::VisitFields(Visitor* JXL_RESTRICT visitor) {
     90   uint32_t ux = PackSigned(storage_.x);
     91   JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(19), BitsOffset(19, 524288),
     92                                          BitsOffset(20, 1048576),
     93                                          BitsOffset(21, 2097152), 0, &ux));
     94   storage_.x = UnpackSigned(ux);
     95   uint32_t uy = PackSigned(storage_.y);
     96   JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(19), BitsOffset(19, 524288),
     97                                          BitsOffset(20, 1048576),
     98                                          BitsOffset(21, 2097152), 0, &uy));
     99   storage_.y = UnpackSigned(uy);
    100   return true;
    101 }
    102 
    103 CustomTransferFunction::CustomTransferFunction() { Bundle::Init(this); }
    104 Status CustomTransferFunction::VisitFields(Visitor* JXL_RESTRICT visitor) {
    105   if (visitor->Conditional(!SetImplicit())) {
    106     JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &storage_.have_gamma));
    107 
    108     if (visitor->Conditional(storage_.have_gamma)) {
    109       // Gamma is represented as a 24-bit int, the exponent used is
    110       // gamma_ / 1e7. Valid values are (0, 1]. On the low end side, we also
    111       // limit it to kMaxGamma/1e7.
    112       JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(
    113           24, ::jxl::cms::CustomTransferFunction::kGammaMul, &storage_.gamma));
    114       if (storage_.gamma > ::jxl::cms::CustomTransferFunction::kGammaMul ||
    115           static_cast<uint64_t>(storage_.gamma) *
    116                   ::jxl::cms::CustomTransferFunction::kMaxGamma <
    117               ::jxl::cms::CustomTransferFunction::kGammaMul) {
    118         return JXL_FAILURE("Invalid gamma %u", storage_.gamma);
    119       }
    120     }
    121 
    122     if (visitor->Conditional(!storage_.have_gamma)) {
    123       JXL_QUIET_RETURN_IF_ERROR(
    124           visitor->Enum(TransferFunction::kSRGB, &storage_.transfer_function));
    125     }
    126   }
    127 
    128   return true;
    129 }
    130 
    131 ColorEncoding::ColorEncoding() { Bundle::Init(this); }
    132 Status ColorEncoding::VisitFields(Visitor* JXL_RESTRICT visitor) {
    133   if (visitor->AllDefault(*this, &all_default)) {
    134     // Overwrite all serialized fields, but not any nonserialized_*.
    135     visitor->SetDefault(this);
    136     return true;
    137   }
    138 
    139   JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &want_icc_));
    140 
    141   // Always send even if want_icc_ because this affects decoding.
    142   // We can skip the white point/primaries because they do not.
    143   JXL_QUIET_RETURN_IF_ERROR(
    144       visitor->Enum(ColorSpace::kRGB, &storage_.color_space));
    145 
    146   if (visitor->Conditional(!WantICC())) {
    147     // Serialize enums. NOTE: we set the defaults to the most common values so
    148     // ImageMetadata.all_default is true in the common case.
    149 
    150     if (visitor->Conditional(!ImplicitWhitePoint())) {
    151       JXL_QUIET_RETURN_IF_ERROR(
    152           visitor->Enum(WhitePoint::kD65, &storage_.white_point));
    153       if (visitor->Conditional(storage_.white_point == WhitePoint::kCustom)) {
    154         white_.storage_ = storage_.white;
    155         JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&white_));
    156         storage_.white = white_.storage_;
    157       }
    158     }
    159 
    160     if (visitor->Conditional(HasPrimaries())) {
    161       JXL_QUIET_RETURN_IF_ERROR(
    162           visitor->Enum(Primaries::kSRGB, &storage_.primaries));
    163       if (visitor->Conditional(storage_.primaries == Primaries::kCustom)) {
    164         red_.storage_ = storage_.red;
    165         JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&red_));
    166         storage_.red = red_.storage_;
    167         green_.storage_ = storage_.green;
    168         JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&green_));
    169         storage_.green = green_.storage_;
    170         blue_.storage_ = storage_.blue;
    171         JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&blue_));
    172         storage_.blue = blue_.storage_;
    173       }
    174     }
    175 
    176     tf_.nonserialized_color_space = storage_.color_space;
    177     tf_.storage_ = storage_.tf;
    178     JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&tf_));
    179     storage_.tf = tf_.storage_;
    180 
    181     JXL_QUIET_RETURN_IF_ERROR(
    182         visitor->Enum(RenderingIntent::kRelative, &storage_.rendering_intent));
    183 
    184     // We didn't have ICC, so all fields should be known.
    185     if (storage_.color_space == ColorSpace::kUnknown ||
    186         storage_.tf.IsUnknown()) {
    187       return JXL_FAILURE(
    188           "No ICC but cs %u and tf %u%s",
    189           static_cast<unsigned int>(storage_.color_space),
    190           storage_.tf.have_gamma
    191               ? 0
    192               : static_cast<unsigned int>(storage_.tf.transfer_function),
    193           storage_.tf.have_gamma ? "(gamma)" : "");
    194     }
    195 
    196     JXL_RETURN_IF_ERROR(CreateICC());
    197   }
    198 
    199   if (WantICC() && visitor->IsReading()) {
    200     // Haven't called SetICC() yet, do nothing.
    201   } else {
    202     if (ICC().empty()) return JXL_FAILURE("Empty ICC");
    203   }
    204 
    205   return true;
    206 }
    207 
    208 }  // namespace jxl