1 // Created on: 2019-03-22
2 // Created by: Timur Izmaylov
3 // Copyright (c) 2019 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <Quantity_ColorRGBA.hxx>
18 #include <Graphic3d_Vec4.hxx>
19 #include <Standard_Dump.hxx>
26 //! The integer type used to represent some color or color component
27 typedef unsigned int ColorInteger;
29 //! Defines all possible lengths of strings representing color in hex format
32 HexColorLength_ShortRGB = 3, //!< short RGB hex color format
33 HexColorLength_ShortRGBA = 4, //!< short RGBA hex color format
34 HexColorLength_RGB = 6, //!< RGB hex color format
35 HexColorLength_RGBA = 8 //!< RGBA hex color format
38 //! Takes next color component from the integer representing a color (it is a step in a process of a conversion
39 //! implemented by the function ConvertIntegerToColorRGBA)
40 //! @param theColorInteger the integer representing a color
41 //! @param theColorComponentBase the base of the numeral system used to represent a color
42 //! @return a color component taken from the integer
43 static Standard_ShortReal takeColorComponentFromInteger (ColorInteger& theColorInteger,
44 const ColorInteger theColorComponentBase)
46 Standard_ASSERT_RETURN (theColorComponentBase >= 2,
47 __FUNCTION__ ": 'theColorComponentBase' must be greater than 1.",
49 const ColorInteger aColorComponentMaxValue = theColorComponentBase - 1;
50 const ColorInteger aColorComponentAsInteger = theColorInteger % theColorComponentBase;
51 const Standard_ShortReal aColorComponent = aColorComponentAsInteger * 1.0f / aColorComponentMaxValue;
52 theColorInteger /= theColorComponentBase;
53 return aColorComponent;
56 //! Converts the integer representing a color to a RGBA color object
57 //! @param theColorInteger the integer representing a color (using the numerical system based
58 //! on theColorComponentBase value, where color components represent digits:
59 //! an alpha component is a low number and a red component is a high number)
60 //! @param theColorComponentBase the base of the numeral system used to represent a color
61 //! @param hasAlphaComponent true if the integer to be converted contains an alpha component value
62 //! @param theColor a color that is a result of a conversion
63 //! @return true if a conversion was successful, or false otherwise
64 static bool convertIntegerToColorRGBA (ColorInteger theColorInteger,
65 const ColorInteger theColorComponentBase,
66 const bool hasAlphaComponent,
67 Quantity_ColorRGBA& theColor)
69 Standard_ASSERT_RETURN (theColorComponentBase >= 2,
70 __FUNCTION__ ": 'theColorComponentBase' must be greater than 1.",
72 Graphic3d_Vec4 aColor (1.0f);
73 if (hasAlphaComponent)
75 const Standard_ShortReal anAlphaComponent = takeColorComponentFromInteger (theColorInteger,
76 theColorComponentBase);
77 aColor.a() = anAlphaComponent;
79 for (Standard_Integer aColorComponentIndex = 2; aColorComponentIndex >= 0; --aColorComponentIndex)
81 const Standard_ShortReal aColorComponent = takeColorComponentFromInteger (theColorInteger, theColorComponentBase);
82 aColor[aColorComponentIndex] = aColorComponent;
84 if (theColorInteger != 0)
88 theColor = Quantity_ColorRGBA (aColor);
92 //! Converts the string to an integer number using the number base
93 //! @tparam TheNumber the type of a resulting number
94 //! @param theString the string to be converted
95 //! @param theNumber a number that is the result of the conversion
96 //! @param theBase the base of a numeral system used to represent a number in a string form
97 //! @return true if a conversion was successful, or false otherwise
98 template <typename TheNumber>
99 static bool convertStringToInteger (const char* const theString, TheNumber& theNumber, const TheNumber theBase = 10)
101 std::stringstream aConversionStringStream;
102 aConversionStringStream << std::setbase (theBase) << theString;
103 if (aConversionStringStream.fail())
107 aConversionStringStream >> theNumber;
108 if (aConversionStringStream.fail())
115 //! Checks if the character is a hexadecimal digit (0 .. 9, a .. f, A .. F)
116 //! @param theCharacter the character to be checked
117 //! @return true if the checking character is a hexadecimal digit, or false otherwise
118 static bool isHexDigit (const char theCharacter)
120 return std::isxdigit (static_cast<unsigned char> (theCharacter)) != 0;
123 //! Checks if the string consists only of hexadecimal digits (0 .. 9, a .. f, A .. F)
124 //! @param theString the string to be checked
125 //! @param theLength the length of the checked string
126 //! @return true if the checking string consists only of hexadecimal digits, or false otherwise
127 //! an empty string is not interpreted as a hex string
128 static bool isHexString (const char* const theString, const std::size_t theLength)
134 // std::all_of is not used due to VS2008 compilability limitation
135 return std::count_if (theString, theString + theLength, isHexDigit) == static_cast<std::ptrdiff_t> (theLength);
140 //=======================================================================
141 // function : ColorFromHex
143 //=======================================================================
144 bool Quantity_ColorRGBA::ColorFromHex (const char* const theHexColorString,
145 Quantity_ColorRGBA& theColor,
146 const bool theAlphaComponentIsOff)
148 std::size_t aHexColorStringLength = std::strlen (theHexColorString);
149 if (aHexColorStringLength == 0)
154 const bool hasPrefix = (theHexColorString[0] == '#');
155 const std::size_t aPrefixLength = hasPrefix ? 1 : 0;
156 const char* const aHexColorString = theHexColorString + aPrefixLength;
157 aHexColorStringLength -= aPrefixLength;
158 if (!isHexString (aHexColorString, aHexColorStringLength))
163 ColorInteger aHexColorInteger;
164 if (!convertStringToInteger (aHexColorString, aHexColorInteger, 16u))
169 bool hasAlphaComponent = false;
170 bool isShort = false;
171 switch (static_cast<HexColorLength> (aHexColorStringLength))
173 case HexColorLength_ShortRGBA:
174 hasAlphaComponent = true;
176 case HexColorLength_ShortRGB:
179 case HexColorLength_RGBA:
180 hasAlphaComponent = true;
182 case HexColorLength_RGB:
187 if (theAlphaComponentIsOff && hasAlphaComponent)
191 // to distinguish with a usual integer color component value
192 if (isShort && !hasAlphaComponent && !hasPrefix)
197 const ColorInteger THE_HEX_COLOR_COMPONENT_BASE = 1 << 8;
198 const ColorInteger THE_HEX_COLOR_COMPONENT_SHORT_BASE = 1 << 4;
199 const ColorInteger aColorComponentBase = isShort ? THE_HEX_COLOR_COMPONENT_SHORT_BASE : THE_HEX_COLOR_COMPONENT_BASE;
200 return convertIntegerToColorRGBA (aHexColorInteger, aColorComponentBase, hasAlphaComponent, theColor);
203 //=======================================================================
204 //function : DumpJson
206 //=======================================================================
207 void Quantity_ColorRGBA::DumpJson (Standard_OStream& theOStream, const Standard_Integer theDepth) const
209 OCCT_DUMP_CLASS_BEGIN (theOStream, Quantity_ColorRGBA);
211 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myRgb);
212 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myAlpha);