From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../jpeg-xl/lib/extras/dec/color_description.cc | 218 +++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 third_party/jpeg-xl/lib/extras/dec/color_description.cc (limited to 'third_party/jpeg-xl/lib/extras/dec/color_description.cc') diff --git a/third_party/jpeg-xl/lib/extras/dec/color_description.cc b/third_party/jpeg-xl/lib/extras/dec/color_description.cc new file mode 100644 index 0000000000..54f6aa4206 --- /dev/null +++ b/third_party/jpeg-xl/lib/extras/dec/color_description.cc @@ -0,0 +1,218 @@ +// 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/extras/dec/color_description.h" + +#include + +#include + +namespace jxl { + +namespace { + +template +struct EnumName { + const char* name; + T value; +}; + +const EnumName kJxlColorSpaceNames[] = { + {"RGB", JXL_COLOR_SPACE_RGB}, + {"Gra", JXL_COLOR_SPACE_GRAY}, + {"XYB", JXL_COLOR_SPACE_XYB}, + {"CS?", JXL_COLOR_SPACE_UNKNOWN}, +}; + +const EnumName kJxlWhitePointNames[] = { + {"D65", JXL_WHITE_POINT_D65}, + {"Cst", JXL_WHITE_POINT_CUSTOM}, + {"EER", JXL_WHITE_POINT_E}, + {"DCI", JXL_WHITE_POINT_DCI}, +}; + +const EnumName kJxlPrimariesNames[] = { + {"SRG", JXL_PRIMARIES_SRGB}, + {"Cst", JXL_PRIMARIES_CUSTOM}, + {"202", JXL_PRIMARIES_2100}, + {"DCI", JXL_PRIMARIES_P3}, +}; + +const EnumName kJxlTransferFunctionNames[] = { + {"709", JXL_TRANSFER_FUNCTION_709}, + {"TF?", JXL_TRANSFER_FUNCTION_UNKNOWN}, + {"Lin", JXL_TRANSFER_FUNCTION_LINEAR}, + {"SRG", JXL_TRANSFER_FUNCTION_SRGB}, + {"PeQ", JXL_TRANSFER_FUNCTION_PQ}, + {"DCI", JXL_TRANSFER_FUNCTION_DCI}, + {"HLG", JXL_TRANSFER_FUNCTION_HLG}, + {"", JXL_TRANSFER_FUNCTION_GAMMA}, +}; + +const EnumName kJxlRenderingIntentNames[] = { + {"Per", JXL_RENDERING_INTENT_PERCEPTUAL}, + {"Rel", JXL_RENDERING_INTENT_RELATIVE}, + {"Sat", JXL_RENDERING_INTENT_SATURATION}, + {"Abs", JXL_RENDERING_INTENT_ABSOLUTE}, +}; + +template +Status ParseEnum(const std::string& token, const EnumName* enum_values, + size_t enum_len, T* value) { + for (size_t i = 0; i < enum_len; i++) { + if (enum_values[i].name == token) { + *value = enum_values[i].value; + return true; + } + } + return false; +} +#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0])) +#define PARSE_ENUM(type, token, value) \ + ParseEnum(token, k##type##Names, ARRAY_SIZE(k##type##Names), value) + +class Tokenizer { + public: + Tokenizer(const std::string* input, char separator) + : input_(input), separator_(separator) {} + + Status Next(std::string* next) { + const size_t end = input_->find(separator_, start_); + if (end == std::string::npos) { + *next = input_->substr(start_); // rest of string + } else { + *next = input_->substr(start_, end - start_); + } + if (next->empty()) return JXL_FAILURE("Missing token"); + start_ = end + 1; + return true; + } + + private: + const std::string* const input_; // not owned + const char separator_; + size_t start_ = 0; // of next token +}; + +Status ParseDouble(const std::string& num, double* d) { + char* end; + errno = 0; + *d = strtod(num.c_str(), &end); + if (*d == 0.0 && end == num.c_str()) { + return JXL_FAILURE("Invalid double: %s", num.c_str()); + } + if (std::isnan(*d)) { + return JXL_FAILURE("Invalid double: %s", num.c_str()); + } + if (errno == ERANGE) { + return JXL_FAILURE("Double out of range: %s", num.c_str()); + } + return true; +} + +Status ParseDouble(Tokenizer* tokenizer, double* d) { + std::string num; + JXL_RETURN_IF_ERROR(tokenizer->Next(&num)); + return ParseDouble(num, d); +} + +Status ParseColorSpace(Tokenizer* tokenizer, JxlColorEncoding* c) { + std::string str; + JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); + JxlColorSpace cs; + if (PARSE_ENUM(JxlColorSpace, str, &cs)) { + c->color_space = cs; + return true; + } + + return JXL_FAILURE("Unknown ColorSpace %s", str.c_str()); +} + +Status ParseWhitePoint(Tokenizer* tokenizer, JxlColorEncoding* c) { + if (c->color_space == JXL_COLOR_SPACE_XYB) { + // Implicit white point. + c->white_point = JXL_WHITE_POINT_D65; + return true; + } + + std::string str; + JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); + if (PARSE_ENUM(JxlWhitePoint, str, &c->white_point)) return true; + + Tokenizer xy_tokenizer(&str, ';'); + c->white_point = JXL_WHITE_POINT_CUSTOM; + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->white_point_xy + 0)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->white_point_xy + 1)); + return true; +} + +Status ParsePrimaries(Tokenizer* tokenizer, JxlColorEncoding* c) { + if (c->color_space == JXL_COLOR_SPACE_GRAY || + c->color_space == JXL_COLOR_SPACE_XYB) { + // No primaries case. + return true; + } + + std::string str; + JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); + if (PARSE_ENUM(JxlPrimaries, str, &c->primaries)) return true; + + Tokenizer xy_tokenizer(&str, ';'); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_red_xy + 0)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_red_xy + 1)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_green_xy + 0)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_green_xy + 1)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 0)); + JXL_RETURN_IF_ERROR(ParseDouble(&xy_tokenizer, c->primaries_blue_xy + 1)); + c->primaries = JXL_PRIMARIES_CUSTOM; + + return JXL_FAILURE("Invalid primaries %s", str.c_str()); +} + +Status ParseRenderingIntent(Tokenizer* tokenizer, JxlColorEncoding* c) { + std::string str; + JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); + if (PARSE_ENUM(JxlRenderingIntent, str, &c->rendering_intent)) return true; + + return JXL_FAILURE("Invalid RenderingIntent %s\n", str.c_str()); +} + +Status ParseTransferFunction(Tokenizer* tokenizer, JxlColorEncoding* c) { + if (c->color_space == JXL_COLOR_SPACE_XYB) { + // Implicit TF. + c->transfer_function = JXL_TRANSFER_FUNCTION_GAMMA; + c->gamma = 1 / 3.; + return true; + } + + std::string str; + JXL_RETURN_IF_ERROR(tokenizer->Next(&str)); + if (PARSE_ENUM(JxlTransferFunction, str, &c->transfer_function)) { + return true; + } + + if (str[0] == 'g') { + JXL_RETURN_IF_ERROR(ParseDouble(str.substr(1), &c->gamma)); + c->transfer_function = JXL_TRANSFER_FUNCTION_GAMMA; + return true; + } + + return JXL_FAILURE("Invalid gamma %s", str.c_str()); +} + +} // namespace + +Status ParseDescription(const std::string& description, JxlColorEncoding* c) { + *c = {}; + Tokenizer tokenizer(&description, '_'); + JXL_RETURN_IF_ERROR(ParseColorSpace(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseWhitePoint(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParsePrimaries(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseRenderingIntent(&tokenizer, c)); + JXL_RETURN_IF_ERROR(ParseTransferFunction(&tokenizer, c)); + return true; +} + +} // namespace jxl -- cgit v1.2.3