libcamera: color_space: Add fromString() function

Add a ColorSpace:fromString() function to parse a string into a color
space. The string can either contain the name of a well-known color
space, or four color space components separate by a '/' character.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Umang Jain <umang.jain@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2022-08-23 17:16:34 +03:00
parent 994358dab6
commit fbfdaa2d20
2 changed files with 125 additions and 30 deletions

View file

@ -59,6 +59,8 @@ public:
std::string toString() const; std::string toString() const;
static std::string toString(const std::optional<ColorSpace> &colorSpace); static std::string toString(const std::optional<ColorSpace> &colorSpace);
static std::optional<ColorSpace> fromString(const std::string &str);
}; };
bool operator==(const ColorSpace &lhs, const ColorSpace &rhs); bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);

View file

@ -12,6 +12,9 @@
#include <map> #include <map>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include <vector>
#include <libcamera/base/utils.h>
/** /**
* \file color_space.h * \file color_space.h
@ -208,6 +211,44 @@ const ColorSpace ColorSpace::Rec2020 = {
* \brief The pixel range used with by color space * \brief The pixel range used with by color space
*/ */
namespace {
const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {
{ ColorSpace::Raw, "RAW" },
{ ColorSpace::Srgb, "sRGB" },
{ ColorSpace::Sycc, "sYCC" },
{ ColorSpace::Smpte170m, "SMPTE170M" },
{ ColorSpace::Rec709, "Rec709" },
{ ColorSpace::Rec2020, "Rec2020" },
} };
const std::map<ColorSpace::Primaries, std::string> primariesNames = {
{ ColorSpace::Primaries::Raw, "RAW" },
{ ColorSpace::Primaries::Smpte170m, "SMPTE170M" },
{ ColorSpace::Primaries::Rec709, "Rec709" },
{ ColorSpace::Primaries::Rec2020, "Rec2020" },
};
const std::map<ColorSpace::TransferFunction, std::string> transferNames = {
{ ColorSpace::TransferFunction::Linear, "Linear" },
{ ColorSpace::TransferFunction::Srgb, "sRGB" },
{ ColorSpace::TransferFunction::Rec709, "Rec709" },
};
const std::map<ColorSpace::YcbcrEncoding, std::string> encodingNames = {
{ ColorSpace::YcbcrEncoding::None, "None" },
{ ColorSpace::YcbcrEncoding::Rec601, "Rec601" },
{ ColorSpace::YcbcrEncoding::Rec709, "Rec709" },
{ ColorSpace::YcbcrEncoding::Rec2020, "Rec2020" },
};
const std::map<ColorSpace::Range, std::string> rangeNames = {
{ ColorSpace::Range::Full, "Full" },
{ ColorSpace::Range::Limited, "Limited" },
};
} /* namespace */
/** /**
* \brief Assemble and return a readable string representation of the * \brief Assemble and return a readable string representation of the
* ColorSpace * ColorSpace
@ -223,14 +264,6 @@ std::string ColorSpace::toString() const
{ {
/* Print out a brief name only for standard color spaces. */ /* Print out a brief name only for standard color spaces. */
static const std::array<std::pair<ColorSpace, const char *>, 6> colorSpaceNames = { {
{ ColorSpace::Raw, "RAW" },
{ ColorSpace::Srgb, "sRGB" },
{ ColorSpace::Sycc, "sYCC" },
{ ColorSpace::Smpte170m, "SMPTE170M" },
{ ColorSpace::Rec709, "Rec709" },
{ ColorSpace::Rec2020, "Rec2020" },
} };
auto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(), auto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),
[this](const auto &item) { [this](const auto &item) {
return *this == item.first; return *this == item.first;
@ -240,28 +273,6 @@ std::string ColorSpace::toString() const
/* Assemble a name made of the constituent fields. */ /* Assemble a name made of the constituent fields. */
static const std::map<Primaries, std::string> primariesNames = {
{ Primaries::Raw, "RAW" },
{ Primaries::Smpte170m, "SMPTE170M" },
{ Primaries::Rec709, "Rec709" },
{ Primaries::Rec2020, "Rec2020" },
};
static const std::map<TransferFunction, std::string> transferNames = {
{ TransferFunction::Linear, "Linear" },
{ TransferFunction::Srgb, "sRGB" },
{ TransferFunction::Rec709, "Rec709" },
};
static const std::map<YcbcrEncoding, std::string> encodingNames = {
{ YcbcrEncoding::None, "None" },
{ YcbcrEncoding::Rec601, "Rec601" },
{ YcbcrEncoding::Rec709, "Rec709" },
{ YcbcrEncoding::Rec2020, "Rec2020" },
};
static const std::map<Range, std::string> rangeNames = {
{ Range::Full, "Full" },
{ Range::Limited, "Limited" },
};
auto itPrimaries = primariesNames.find(primaries); auto itPrimaries = primariesNames.find(primaries);
std::string primariesName = std::string primariesName =
itPrimaries == primariesNames.end() ? "Invalid" : itPrimaries->second; itPrimaries == primariesNames.end() ? "Invalid" : itPrimaries->second;
@ -303,6 +314,88 @@ std::string ColorSpace::toString(const std::optional<ColorSpace> &colorSpace)
return colorSpace->toString(); return colorSpace->toString();
} }
/**
* \brief Construct a color space from a string
* \param[in] str The string
*
* The string \a str can contain the name of a well-known color space, or be
* made of the four color space components separated by a '/' character, ordered
* as
*
* \verbatim primaries '/' transferFunction '/' ycbcrEncoding '/' range \endverbatim
*
* Any failure to parse the string, either because it doesn't match the expected
* format, or because the one of the names isn't recognized, will cause this
* function to return std::nullopt.
*
* \return The ColorSpace corresponding to the string, or std::nullopt if the
* string doesn't describe a known color space
*/
std::optional<ColorSpace> ColorSpace::fromString(const std::string &str)
{
/* First search for a standard color space name match. */
auto itColorSpace = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(),
[&str](const auto &item) {
return str == item.second;
});
if (itColorSpace != colorSpaceNames.end())
return itColorSpace->first;
/*
* If not found, the string must contain the four color space
* components separated by a '/' character.
*/
const auto &split = utils::split(str, "/");
std::vector<std::string> components{ split.begin(), split.end() };
if (components.size() != 4)
return std::nullopt;
ColorSpace colorSpace = ColorSpace::Raw;
/* Color primaries */
auto itPrimaries = std::find_if(primariesNames.begin(), primariesNames.end(),
[&components](const auto &item) {
return components[0] == item.second;
});
if (itPrimaries == primariesNames.end())
return std::nullopt;
colorSpace.primaries = itPrimaries->first;
/* Transfer function */
auto itTransfer = std::find_if(transferNames.begin(), transferNames.end(),
[&components](const auto &item) {
return components[1] == item.second;
});
if (itTransfer == transferNames.end())
return std::nullopt;
colorSpace.transferFunction = itTransfer->first;
/* YCbCr encoding */
auto itEncoding = std::find_if(encodingNames.begin(), encodingNames.end(),
[&components](const auto &item) {
return components[2] == item.second;
});
if (itEncoding == encodingNames.end())
return std::nullopt;
colorSpace.ycbcrEncoding = itEncoding->first;
/* Quantization range */
auto itRange = std::find_if(rangeNames.begin(), rangeNames.end(),
[&components](const auto &item) {
return components[3] == item.second;
});
if (itRange == rangeNames.end())
return std::nullopt;
colorSpace.range = itRange->first;
return colorSpace;
}
/** /**
* \brief Compare color spaces for equality * \brief Compare color spaces for equality
* \return True if the two color spaces are identical, false otherwise * \return True if the two color spaces are identical, false otherwise