/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2021, Raspberry Pi (Trading) Limited * * color_space.cpp - color spaces. */ #include #include #include #include #include #include /** * \file color_space.h * \brief Class and enums to represent color spaces */ namespace libcamera { /** * \class ColorSpace * \brief Class to describe a color space * * The ColorSpace class defines the color primaries, the transfer function, * the Y'CbCr encoding associated with the color space, and the range * (sometimes also referred to as the quantisation) of the color space. * * Certain combinations of these fields form well-known standard color * spaces such as "JPEG" or "REC709". * * In the strictest sense a "color space" formally only refers to the * color primaries and white point. Here, however, the ColorSpace class * adopts the common broader usage that includes the transfer function, * Y'CbCr encoding method and quantisation. * * For more information on the specific color spaces described here, please * see: * * - sRGB * - JPEG * - SMPTE 170M * - Rec.709 * - Rec.2020 */ /** * \enum ColorSpace::Primaries * \brief The color primaries for this color space * * \var ColorSpace::Primaries::Raw * \brief These are raw colors directly from a sensor, the primaries are * unspecified * * \var ColorSpace::Primaries::Smpte170m * \brief SMPTE 170M color primaries * * \var ColorSpace::Primaries::Rec709 * \brief Rec.709 color primaries * * \var ColorSpace::Primaries::Rec2020 * \brief Rec.2020 color primaries */ /** * \enum ColorSpace::TransferFunction * \brief The transfer function used for this color space * * \var ColorSpace::TransferFunction::Linear * \brief This color space uses a linear (identity) transfer function * * \var ColorSpace::TransferFunction::Srgb * \brief sRGB transfer function * * \var ColorSpace::TransferFunction::Rec709 * \brief Rec.709 transfer function */ /** * \enum ColorSpace::YcbcrEncoding * \brief The Y'CbCr encoding * * \var ColorSpace::YcbcrEncoding::None * \brief There is no defined Y'CbCr encoding (used for non-YUV formats) * * \var ColorSpace::YcbcrEncoding::Rec601 * \brief Rec.601 Y'CbCr encoding * * \var ColorSpace::YcbcrEncoding::Rec709 * \brief Rec.709 Y'CbCr encoding * * \var ColorSpace::YcbcrEncoding::Rec2020 * \brief Rec.2020 Y'CbCr encoding */ /** * \enum ColorSpace::Range * \brief The range (sometimes "quantisation") for this color space * * \var ColorSpace::Range::Full * \brief This color space uses full range pixel values * * \var ColorSpace::Range::Limited * \brief This color space uses limited range pixel values, being * 16 to 235 for Y' and 16 to 240 for Cb and Cr (8 bits per sample) * or 64 to 940 for Y' and 16 to 960 for Cb and Cr (10 bits) */ /** * \fn ColorSpace::ColorSpace(Primaries p, TransferFunction t, Encoding e, Range r) * \brief Construct a ColorSpace from explicit values * \param[in] p The color primaries * \param[in] t The transfer function for the color space * \param[in] e The Y'CbCr encoding * \param[in] r The range of the pixel values in this color space */ /** * \brief Assemble and return a readable string representation of the * ColorSpace * * If the color space matches a standard ColorSpace (such as ColorSpace::Jpeg) * then the short name of the color space ("JPEG") is returned. Otherwise * the four constituent parts of the ColorSpace are assembled into a longer * string. * * \return A string describing the ColorSpace */ std::string ColorSpace::toString() const { /* Print out a brief name only for standard color spaces. */ static const std::array, 6> colorSpaceNames = { { { ColorSpace::Raw, "RAW" }, { ColorSpace::Jpeg, "JPEG" }, { ColorSpace::Srgb, "sRGB" }, { ColorSpace::Smpte170m, "SMPTE170M" }, { ColorSpace::Rec709, "Rec709" }, { ColorSpace::Rec2020, "Rec2020" }, } }; auto it = std::find_if(colorSpaceNames.begin(), colorSpaceNames.end(), [this](const auto &item) { return *this == item.first; }); if (it != colorSpaceNames.end()) return std::string(it->second); /* Assemble a name made of the constituent fields. */ static const std::map primariesNames = { { Primaries::Raw, "RAW" }, { Primaries::Smpte170m, "SMPTE170M" }, { Primaries::Rec709, "Rec709" }, { Primaries::Rec2020, "Rec2020" }, }; static const std::map transferNames = { { TransferFunction::Linear, "Linear" }, { TransferFunction::Srgb, "sRGB" }, { TransferFunction::Rec709, "Rec709" }, }; static const std::map encodingNames = { { YcbcrEncoding::None, "None" }, { YcbcrEncoding::Rec601, "Rec601" }, { YcbcrEncoding::Rec709, "Rec709" }, { YcbcrEncoding::Rec2020, "Rec2020" }, }; static const std::map rangeNames = { { Range::Full, "Full" }, { Range::Limited, "Limited" }, }; auto itPrimaries = primariesNames.find(primaries); std::string primariesName = itPrimaries == primariesNames.end() ? "Invalid" : itPrimaries->second; auto itTransfer = transferNames.find(transferFunction); std::string transferName = itTransfer == transferNames.end() ? "Invalid" : itTransfer->second; auto itEncoding = encodingNames.find(ycbcrEncoding); std::string encodingName = itEncoding == encodingNames.end() ? "Invalid" : itEncoding->second; auto itRange = rangeNames.find(range); std::string rangeName = itRange == rangeNames.end() ? "Invalid" : itRange->second; std::stringstream ss; ss << primariesName << "/" << transferName << "/" << encodingName << "/" << rangeName; return ss.str(); } /** * \brief Assemble and return a readable string representation of an * optional ColorSpace * * This is a convenience helper to easily obtain a string representation * for a ColorSpace in parts of the libcamera API where it is stored in a * std::optional<>. If the ColorSpace is set, this function returns * \a colorSpace.toString(), otherwise it returns "Unset". * * \return A string describing the optional ColorSpace */ std::string ColorSpace::toString(const std::optional &colorSpace) { if (!colorSpace) return "Unset"; return colorSpace->toString(); } /** * \var ColorSpace::primaries * \brief The color primaries of this color space */ /** * \var ColorSpace::transferFunction * \brief The transfer function used by this color space */ /** * \var ColorSpace::ycbcrEncoding * \brief The Y'CbCr encoding used by this color space */ /** * \var ColorSpace::range * \brief The pixel range used with by color space */ /** * \brief A constant representing a raw color space (from a sensor) */ const ColorSpace ColorSpace::Raw = { Primaries::Raw, TransferFunction::Linear, YcbcrEncoding::None, Range::Full }; /** * \brief A constant representing the JPEG color space used for * encoding JPEG images */ const ColorSpace ColorSpace::Jpeg = { Primaries::Rec709, TransferFunction::Srgb, YcbcrEncoding::Rec601, Range::Full }; /** * \brief A constant representing the sRGB color space * * This is identical to the JPEG color space except that the Y'CbCr * range is limited rather than full. */ const ColorSpace ColorSpace::Srgb = { Primaries::Rec709, TransferFunction::Srgb, YcbcrEncoding::Rec601, Range::Limited }; /** * \brief A constant representing the SMPTE170M color space */ const ColorSpace ColorSpace::Smpte170m = { Primaries::Smpte170m, TransferFunction::Rec709, YcbcrEncoding::Rec601, Range::Limited }; /** * \brief A constant representing the Rec.709 color space */ const ColorSpace ColorSpace::Rec709 = { Primaries::Rec709, TransferFunction::Rec709, YcbcrEncoding::Rec709, Range::Limited }; /** * \brief A constant representing the Rec.2020 color space */ const ColorSpace ColorSpace::Rec2020 = { Primaries::Rec2020, TransferFunction::Rec709, YcbcrEncoding::Rec2020, Range::Limited }; /** * \brief Compare color spaces for equality * \return True if the two color spaces are identical, false otherwise */ bool operator==(const ColorSpace &lhs, const ColorSpace &rhs) { return lhs.primaries == rhs.primaries && lhs.transferFunction == rhs.transferFunction && lhs.ycbcrEncoding == rhs.ycbcrEncoding && lhs.range == rhs.range; } /** * \fn bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs) * \brief Compare color spaces for inequality * \return True if the two color spaces are not identical, false otherwise */ } /* namespace libcamera */