1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #include <cstdint> 16 #include <vector> 17 #include <utility> 18 #include <memory> 19 #include <limits> 20 #include <algorithm> 21 #include <math.h> 22 #include <queue> 23 #include "pixel_map.h" 24 #include "effect_type.h" 25 26 27 #ifndef COLOREXTRACT_H 28 #define COLOREXTRACT_H 29 30 #ifdef __cplusplus 31 extern "C" { 32 #endif 33 34 namespace OHOS { 35 namespace Media { 36 class PixelMap; 37 } 38 namespace ColorManager { 39 class Color; 40 } 41 namespace Rosen { 42 43 class ColorExtract { 44 public: ~ColorExtract()45 virtual ~ColorExtract() {}; 46 std::shared_ptr<Media::PixelMap> pixelmap_; 47 48 // Save the ARGB val of picture. 49 std::vector<uint32_t> colorVal_; 50 uint32_t colorValLen_ = 0; 51 uint32_t grayMsd_ = 0; 52 float contrastToWhite_ = 0; 53 54 // The first element is color, the second element is pixel num of this color. 55 std::vector<std::pair<uint32_t, uint32_t>> featureColors_; 56 57 // Specified number of extracted theme colors, default value is 10; 58 int specifiedFeatureColorNum_ = 10; 59 60 std::vector<uint32_t> hist_; 61 int distinctColorCount_ = 0; 62 std::vector<uint32_t> colors_; 63 64 static constexpr uint8_t ARGB_MASK = 0xFF; 65 static constexpr uint8_t ARGB_A_SHIFT = 24; 66 static constexpr uint8_t ARGB_R_SHIFT = 16; 67 static constexpr uint8_t ARGB_G_SHIFT = 8; 68 static constexpr uint8_t ARGB_B_SHIFT = 0; 69 static uint8_t GetARGB32ColorA(unsigned int color); 70 static uint8_t GetARGB32ColorR(unsigned int color); 71 static uint8_t GetARGB32ColorG(unsigned int color); 72 static uint8_t GetARGB32ColorB(unsigned int color); 73 NATIVEEXPORT void SetFeatureColorNum(int N); 74 void GetNFeatureColors(int colorNum); 75 76 protected: 77 ColorExtract(std::shared_ptr<Media::PixelMap> pixmap); 78 ColorExtract(std::shared_ptr<Media::PixelMap> pixmap, double* coordinates); 79 80 private: 81 82 static constexpr int COMPONENT_RED = -3; 83 static constexpr int COMPONENT_GREEN = -2; 84 static constexpr int COMPONENT_BLUE = -1; 85 static constexpr int QUANTIZE_WORD_WIDTH = 5; 86 static constexpr int QUANTIZE_WORD_MASK = (1 << QUANTIZE_WORD_WIDTH) - 1; 87 static uint32_t QuantizedRed(uint32_t color); 88 static uint32_t QuantizedGreen(uint32_t color); 89 static uint32_t QuantizedBlue(uint32_t color); 90 static uint32_t QuantizeFromRGB888(uint32_t color); 91 static uint32_t ModifyWordWidth(uint8_t color, int inWidth, int outWidth); 92 static uint32_t ApproximateToRGB888(uint32_t r, uint32_t g, uint32_t b); 93 static uint32_t ApproximateToRGB888(uint32_t color); 94 static bool cmp(std::pair<uint32_t, uint32_t >& a, std::pair<uint32_t, uint32_t >& b); 95 96 class VBox { 97 private: 98 int lowerIndex_ = INT_MAX; 99 int upperIndex_ = 0; 100 // total pixel nums in this box; 101 int pixelNums_ = 0; 102 uint32_t minRed_ = UINT32_MAX; 103 uint32_t maxRed_ = 0; 104 uint32_t minGreen_ = UINT32_MAX; 105 uint32_t maxGreen_ = 0; 106 uint32_t minBlue_ = UINT32_MAX; 107 uint32_t maxBlue_ = 0; 108 ColorExtract *colorExtract_ = nullptr; 109 110 public: VBox(int lowerIndex,int upperIndex,ColorExtract * colorExtract)111 VBox(int lowerIndex, int upperIndex, ColorExtract *colorExtract) 112 { 113 lowerIndex_ = lowerIndex; 114 upperIndex_ = upperIndex; 115 colorExtract_ = colorExtract; 116 fitBox(); 117 } 118 GetVolume()119 uint32_t GetVolume() const 120 { 121 return (maxRed_ - minRed_ + 1) * (maxGreen_ - minGreen_ + 1) * (maxBlue_ - minBlue_ + 1); 122 } 123 CanSplit()124 bool CanSplit() 125 { 126 return GetColorCount() > 1; 127 } 128 GetColorCount()129 int GetColorCount() const 130 { 131 return 1 + upperIndex_ - lowerIndex_; 132 } 133 134 bool operator < (const VBox &v) const 135 { 136 return this->GetVolume() < v.GetVolume(); 137 } 138 139 // Recomputes the boundaries of this box to tightly fit the color within the box. fitBox()140 void fitBox() 141 { 142 if (colorExtract_ == nullptr) { 143 return; 144 } 145 uint32_t* colors = colorExtract_->colors_.data(); 146 uint32_t* hist = colorExtract_->hist_.data(); 147 if (colors == nullptr || hist == nullptr) { 148 return; 149 } 150 151 uint32_t minR = UINT32_MAX; 152 uint32_t minG = UINT32_MAX; 153 uint32_t minB = UINT32_MAX; 154 uint32_t maxRed = 0; 155 uint32_t maxGreen = 0; 156 uint32_t maxBlue = 0; 157 158 int count = 0; 159 160 for (int i = lowerIndex_; i <= upperIndex_; i++) { 161 uint32_t color = colors[i]; 162 count += static_cast<int>(hist[color]); 163 164 uint32_t r = QuantizedRed(color); 165 uint32_t g = QuantizedGreen(color); 166 uint32_t b = QuantizedBlue(color); 167 if (r > maxRed) { 168 maxRed = r; 169 } 170 if (r < minR) { 171 minR = r; 172 } 173 if (g > maxGreen) { 174 maxGreen = g; 175 } 176 if (g < minG) { 177 minG = g; 178 } 179 if (b > maxBlue) { 180 maxBlue = b; 181 } 182 if (b < minB) { 183 minB = b; 184 } 185 } 186 minRed_ = minR; 187 maxRed_ = maxRed; 188 minGreen_ = minG; 189 maxGreen_ = maxGreen; 190 minBlue_ = minB; 191 maxBlue_ = maxBlue; 192 pixelNums_ = count; 193 } 194 195 // Split the color box at the mid-point along its longest dimension SplitBox()196 VBox SplitBox() 197 { 198 int splitPoint = FindSplitPoint(); 199 200 VBox newBox = VBox(splitPoint + 1, upperIndex_, colorExtract_); 201 upperIndex_ = splitPoint; 202 fitBox(); 203 return newBox; 204 } 205 206 // return the longest dimension of the box GetLongestColorDimension()207 int GetLongestColorDimension() 208 { 209 uint32_t redLen = maxRed_ - minRed_; 210 uint32_t greenLen = maxGreen_ - minGreen_; 211 uint32_t blueLen = maxBlue_ - minBlue_; 212 213 if (redLen >=greenLen && redLen >= blueLen) { 214 return COMPONENT_RED; 215 } else if (greenLen >= redLen && greenLen >= blueLen) { 216 return COMPONENT_GREEN; 217 } else { 218 return COMPONENT_BLUE; 219 } 220 } 221 FindSplitPoint()222 int FindSplitPoint() 223 { 224 int longestDimension = GetLongestColorDimension(); 225 uint32_t *colors = colorExtract_->colors_.data(); 226 uint32_t *hist = colorExtract_->hist_.data(); 227 228 // Sort the color in the box based on the longest color dimension 229 ModifySignificantOctet(colors, longestDimension, lowerIndex_, upperIndex_); 230 std::sort(colors + lowerIndex_, colors + upperIndex_ + 1); 231 // Revert all of the colors so that they are packed as RGB again 232 ModifySignificantOctet(colors, longestDimension, lowerIndex_, upperIndex_); 233 234 int midPoint = pixelNums_ / 2; 235 for (int i = lowerIndex_, count = 0; i <= upperIndex_; i++) { 236 count += static_cast<int>(hist[colors[i]]); 237 if (count >= midPoint) { 238 return std::min(upperIndex_ - 1, i); 239 } 240 } 241 242 return lowerIndex_; 243 } 244 245 /** 246 * Modify the significant octet in a packed color int. Allows sorting based on the value of a 247 * single color component. 248 */ ModifySignificantOctet(uint32_t * colors,int dimension,int lower,int upper)249 void ModifySignificantOctet(uint32_t *colors, int dimension, int lower, int upper) 250 { 251 switch (dimension) { 252 case COMPONENT_RED: 253 break; 254 case COMPONENT_GREEN: 255 for (int i = lower; i <= upper ; i++) { 256 uint32_t color = colors[i]; 257 colors[i] = (QuantizedGreen(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) 258 | (QuantizedRed(color) << QUANTIZE_WORD_WIDTH) 259 | QuantizedBlue(color); 260 } 261 break; 262 case COMPONENT_BLUE: 263 for (int i = lower; i <= upper ; i++) { 264 uint32_t color = colors[i]; 265 colors[i] = (QuantizedBlue(color) << (QUANTIZE_WORD_WIDTH + QUANTIZE_WORD_WIDTH)) 266 | (QuantizedGreen(color) << QUANTIZE_WORD_WIDTH) 267 | QuantizedRed(color); 268 } 269 break; 270 } 271 } 272 273 // Return the average color of the box GetAverageColor()274 std::pair<uint32_t, uint32_t> GetAverageColor() 275 { 276 uint32_t error_color = 0; 277 if (colorExtract_ == nullptr) { 278 return std::make_pair(error_color, error_color); 279 } 280 uint32_t* colors = colorExtract_->colors_.data(); 281 uint32_t* hist = colorExtract_->hist_.data(); 282 if (colors == nullptr || hist == nullptr) { 283 return std::make_pair(error_color, error_color); 284 } 285 uint32_t redSum = 0; 286 uint32_t greenSum = 0; 287 uint32_t blueSum = 0; 288 uint32_t totalPixelNum = 0; 289 for (int i = lowerIndex_; i <=upperIndex_ ; i++) { 290 uint32_t color = colors[i]; 291 uint32_t colorPixelNum = hist[color]; 292 totalPixelNum += colorPixelNum; 293 redSum += colorPixelNum * QuantizedRed(color); 294 greenSum += colorPixelNum * QuantizedGreen(color); 295 blueSum += colorPixelNum * QuantizedBlue(color); 296 } 297 if (totalPixelNum == 0) { 298 return std::make_pair(error_color, error_color); 299 } 300 uint32_t redMean = round(redSum / (float)totalPixelNum); 301 uint32_t greenMean = round(greenSum / (float)totalPixelNum); 302 uint32_t blueMean = round(blueSum / (float)totalPixelNum); 303 304 return std::make_pair(ApproximateToRGB888(redMean, greenMean, blueMean), totalPixelNum); 305 } 306 }; // VBox 307 308 private: 309 static constexpr double RED_GRAY_RATIO = 0.299; 310 static constexpr double GREEN_GRAY_RATIO = 0.587; 311 static constexpr double BLUE_GRAY_RATIO = 0.114; 312 static constexpr double RED_LUMINACE_RATIO = 0.2126; 313 static constexpr double GREEN_LUMINACE_RATIO = 0.7152; 314 static constexpr double BLUE_LUMINACE_RATIO = 0.0722; 315 static uint8_t Rgb2Gray(uint32_t color); 316 uint32_t CalcGrayMsd() const; 317 static float NormalizeRgb(uint32_t val); 318 static float CalcRelativeLum(uint32_t color); 319 float CalcContrastToWhite() const; 320 std::vector<std::pair<uint32_t, uint32_t>> QuantizePixels(int colorNum); 321 void SplitBoxes(std::priority_queue<VBox, std::vector<VBox>, std::less<VBox> > &queue, int maxSize); 322 std::vector<std::pair<uint32_t, uint32_t>> GenerateAverageColors(std::priority_queue<VBox, \ 323 std::vector<VBox>, std::less<VBox> > &queue); 324 }; // ColorExtract 325 } // namespace Rosen 326 } // namespace OHOS 327 328 #ifdef __cplusplus 329 } 330 #endif 331 #endif // COLOREXTRACT_H 332