blob: 6e0258c9ecb2ee5941008d5da6f4848390ad2020 [file] [log] [blame]
sergeyv163f8812016-10-07 16:57:29 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
sergeyvc1c54062016-10-19 18:47:26 -070016#include "Bitmap.h"
sergeyv163f8812016-10-07 16:57:29 -070017
John Recke170fb62018-05-07 08:12:07 -070018#include "HardwareBitmapUploader.h"
John Reck339cf9b2018-07-18 16:32:27 -070019#include "Properties.h"
sergeyv694d4992016-10-27 10:23:13 -070020#include "renderthread/RenderProxy.h"
Romain Guycaaaa662017-03-27 00:40:21 -070021#include "utils/Color.h"
Stan Iliev564ca3e2018-09-04 22:00:00 +000022#include <utils/Trace.h>
sergeyv163f8812016-10-07 16:57:29 -070023
sergeyv163f8812016-10-07 16:57:29 -070024#include <sys/mman.h>
Mark Salyzyn6f773a02016-09-28 16:15:30 -070025
sergeyv163f8812016-10-07 16:57:29 -070026#include <cutils/ashmem.h>
John Reck1bcacfd2017-11-03 10:12:19 -070027#include <log/log.h>
sergeyv163f8812016-10-07 16:57:29 -070028
sergeyv694d4992016-10-27 10:23:13 -070029#include <binder/IServiceManager.h>
John Reck1bcacfd2017-11-03 10:12:19 -070030#include <private/gui/ComposerService.h>
sergeyv694d4992016-10-27 10:23:13 -070031#include <ui/PixelFormat.h>
32
33#include <SkCanvas.h>
Stan Iliev7bc3bc62017-05-24 13:28:36 -040034#include <SkImagePriv.h>
sergeyv694d4992016-10-27 10:23:13 -070035
John Reck339cf9b2018-07-18 16:32:27 -070036#include <SkHighContrastFilter.h>
John Reck8f45d4a2018-08-15 10:17:12 -070037#include <limits>
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040038
sergeyv163f8812016-10-07 16:57:29 -070039namespace android {
40
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040041// returns true if rowBytes * height can be represented by a positive int32_t value
42// and places that value in size.
sergeyvfc9999502016-10-17 13:07:38 -070043static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
Ben Wagnerdbbc74c2018-05-18 17:46:48 -040044 return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
45 !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
46 *size <= std::numeric_limits<int32_t>::max();
sergeyvc36bd6c2016-10-11 15:49:16 -070047}
48
John Reck1bcacfd2017-11-03 10:12:19 -070049typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -070050
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040051static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
sergeyvc36bd6c2016-10-11 15:49:16 -070052 const SkImageInfo& info = bitmap->info();
53 if (info.colorType() == kUnknown_SkColorType) {
54 LOG_ALWAYS_FATAL("unknown bitmap configuration");
55 return nullptr;
56 }
57
58 size_t size;
sergeyvc36bd6c2016-10-11 15:49:16 -070059
60 // we must respect the rowBytes value already set on the bitmap instead of
61 // attempting to compute our own.
62 const size_t rowBytes = bitmap->rowBytes();
sergeyvfc9999502016-10-17 13:07:38 -070063 if (!computeAllocationSize(rowBytes, bitmap->height(), &size)) {
64 return nullptr;
65 }
66
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040067 auto wrapper = alloc(size, info, rowBytes);
sergeyvc36bd6c2016-10-11 15:49:16 -070068 if (wrapper) {
69 wrapper->getSkBitmap(bitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -070070 }
71 return wrapper;
72}
73
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040074sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
John Reck1bcacfd2017-11-03 10:12:19 -070075 return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
sergeyvc36bd6c2016-10-11 15:49:16 -070076}
77
John Reck1bcacfd2017-11-03 10:12:19 -070078sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
sergeyvc36bd6c2016-10-11 15:49:16 -070079 // Create new ashmem region with read/write priv
80 int fd = ashmem_create_region("bitmap", size);
81 if (fd < 0) {
82 return nullptr;
83 }
84
85 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
86 if (addr == MAP_FAILED) {
87 close(fd);
88 return nullptr;
89 }
90
91 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
92 munmap(addr, size);
93 close(fd);
94 return nullptr;
95 }
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -040096 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
sergeyvc36bd6c2016-10-11 15:49:16 -070097}
98
Derek Sollenbergere2169482018-11-20 10:57:20 -050099sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
100 return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
101}
102
103sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
104 return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
105}
106
107sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
108 size_t size;
109 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
110 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
111 return nullptr;
112 }
113 return allocateHeapBitmap(size, info, info.minRowBytes());
114}
115
116sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
117 void* addr = calloc(size, 1);
118 if (!addr) {
119 return nullptr;
120 }
121 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
122}
123
sergeyvaed7f582016-10-14 16:30:21 -0700124void FreePixelRef(void* addr, void* context) {
John Reck1bcacfd2017-11-03 10:12:19 -0700125 auto pixelRef = (SkPixelRef*)context;
sergeyvaed7f582016-10-14 16:30:21 -0700126 pixelRef->unref();
127}
128
129sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
130 pixelRef.ref();
John Reck1bcacfd2017-11-03 10:12:19 -0700131 return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
132 pixelRef.rowBytes()));
sergeyvaed7f582016-10-14 16:30:21 -0700133}
134
Derek Sollenbergere2169482018-11-20 10:57:20 -0500135
136sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer, sk_sp<SkColorSpace> colorSpace,
137 SkAlphaType alphaType, BitmapPalette palette) {
138 // As we will be effectively texture-sampling the buffer (using either EGL or Vulkan), we can
139 // view the format as RGBA8888.
140 SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
141 kRGBA_8888_SkColorType, alphaType, colorSpace);
142 return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info, palette));
rennb2e9f522018-09-26 10:49:00 -0700143}
144
Derek Sollenbergere2169482018-11-20 10:57:20 -0500145sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
146 size_t size, bool readOnly) {
147 if (info.colorType() == kUnknown_SkColorType) {
148 LOG_ALWAYS_FATAL("unknown bitmap configuration");
149 return nullptr;
150 }
151
152 if (!addr) {
153 // Map existing ashmem region if not already mapped.
154 int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
155 size = ashmem_get_size_region(fd);
156 addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
157 if (addr == MAP_FAILED) {
158 return nullptr;
159 }
160 }
161
162 sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
163 if (readOnly) {
164 bitmap->setImmutable();
165 }
166 return bitmap;
sergeyv9a029872016-11-29 10:13:28 -0800167}
168
Romain Guy82426562017-04-04 19:38:50 -0700169void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400170 mInfo = mInfo.makeColorSpace(std::move(colorSpace));
171}
172
173static SkImageInfo validateAlpha(const SkImageInfo& info) {
174 // Need to validate the alpha type to filter against the color type
175 // to prevent things like a non-opaque RGB565 bitmap
176 SkAlphaType alphaType;
John Reck1bcacfd2017-11-03 10:12:19 -0700177 LOG_ALWAYS_FATAL_IF(
178 !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
Matt Sarett489cfff2017-04-21 18:08:40 -0400179 "Failed to validate alpha type!");
180 return info.makeAlphaType(alphaType);
Romain Guy82426562017-04-04 19:38:50 -0700181}
182
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400183void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
Matt Sarett489cfff2017-04-21 18:08:40 -0400184 mInfo = validateAlpha(newInfo);
sergeyv163f8812016-10-07 16:57:29 -0700185
186 // Dirty hack is dirty
187 // TODO: Figure something out here, Skia's current design makes this
188 // really hard to work with. Skia really, really wants immutable objects,
189 // but with the nested-ref-count hackery going on that's just not
190 // feasible without going insane trying to figure it out
Mike Reed81397c42017-07-18 17:04:16 -0400191 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
sergeyv163f8812016-10-07 16:57:29 -0700192}
193
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400194Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
John Reck1bcacfd2017-11-03 10:12:19 -0700195 : SkPixelRef(info.width(), info.height(), address, rowBytes)
196 , mInfo(validateAlpha(info))
197 , mPixelStorageType(PixelStorageType::Heap) {
sergeyv163f8812016-10-07 16:57:29 -0700198 mPixelStorage.heap.address = address;
199 mPixelStorage.heap.size = size;
sergeyv163f8812016-10-07 16:57:29 -0700200}
201
John Reck1bcacfd2017-11-03 10:12:19 -0700202Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
203 size_t rowBytes)
204 : SkPixelRef(info.width(), info.height(), address, rowBytes)
205 , mInfo(validateAlpha(info))
206 , mPixelStorageType(PixelStorageType::External) {
sergeyv163f8812016-10-07 16:57:29 -0700207 mPixelStorage.external.address = address;
208 mPixelStorage.external.context = context;
209 mPixelStorage.external.freeFunc = freeFunc;
sergeyv163f8812016-10-07 16:57:29 -0700210}
211
John Reck1bcacfd2017-11-03 10:12:19 -0700212Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
213 : SkPixelRef(info.width(), info.height(), address, rowBytes)
214 , mInfo(validateAlpha(info))
215 , mPixelStorageType(PixelStorageType::Ashmem) {
sergeyv163f8812016-10-07 16:57:29 -0700216 mPixelStorage.ashmem.address = address;
217 mPixelStorage.ashmem.fd = fd;
218 mPixelStorage.ashmem.size = mappedSize;
sergeyv163f8812016-10-07 16:57:29 -0700219}
220
John Reck339cf9b2018-07-18 16:32:27 -0700221Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette)
Matt Sarett489cfff2017-04-21 18:08:40 -0400222 : SkPixelRef(info.width(), info.height(), nullptr,
Mike Reed81397c42017-07-18 17:04:16 -0400223 bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride())
Matt Sarett489cfff2017-04-21 18:08:40 -0400224 , mInfo(validateAlpha(info))
John Reck339cf9b2018-07-18 16:32:27 -0700225 , mPixelStorageType(PixelStorageType::Hardware)
226 , mPalette(palette)
227 , mPaletteGenerationId(getGenerationID()) {
sergeyv9a029872016-11-29 10:13:28 -0800228 mPixelStorage.hardware.buffer = buffer;
229 buffer->incStrong(buffer);
John Reck1bcacfd2017-11-03 10:12:19 -0700230 setImmutable(); // HW bitmaps are always immutable
John Reck1072fff2018-04-12 15:20:09 -0700231 mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
John Recke170fb62018-05-07 08:12:07 -0700232 mInfo.alphaType(), mInfo.refColorSpace());
sergeyv694d4992016-10-27 10:23:13 -0700233}
sergeyv9a029872016-11-29 10:13:28 -0800234
sergeyvc1c54062016-10-19 18:47:26 -0700235Bitmap::~Bitmap() {
sergeyv163f8812016-10-07 16:57:29 -0700236 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700237 case PixelStorageType::External:
238 mPixelStorage.external.freeFunc(mPixelStorage.external.address,
239 mPixelStorage.external.context);
240 break;
241 case PixelStorageType::Ashmem:
242 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
243 close(mPixelStorage.ashmem.fd);
244 break;
245 case PixelStorageType::Heap:
246 free(mPixelStorage.heap.address);
Tim Murraye0b5e842018-10-15 16:29:15 -0700247 mallopt(M_PURGE, 0);
John Reck1bcacfd2017-11-03 10:12:19 -0700248 break;
249 case PixelStorageType::Hardware:
250 auto buffer = mPixelStorage.hardware.buffer;
251 buffer->decStrong(buffer);
252 mPixelStorage.hardware.buffer = nullptr;
253 break;
sergeyv163f8812016-10-07 16:57:29 -0700254 }
sergeyv163f8812016-10-07 16:57:29 -0700255}
256
sergeyvc1c54062016-10-19 18:47:26 -0700257bool Bitmap::hasHardwareMipMap() const {
sergeyv163f8812016-10-07 16:57:29 -0700258 return mHasHardwareMipMap;
259}
260
sergeyvc1c54062016-10-19 18:47:26 -0700261void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
sergeyv163f8812016-10-07 16:57:29 -0700262 mHasHardwareMipMap = hasMipMap;
263}
264
sergeyvc1c54062016-10-19 18:47:26 -0700265void* Bitmap::getStorage() const {
sergeyv163f8812016-10-07 16:57:29 -0700266 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700267 case PixelStorageType::External:
268 return mPixelStorage.external.address;
269 case PixelStorageType::Ashmem:
270 return mPixelStorage.ashmem.address;
271 case PixelStorageType::Heap:
272 return mPixelStorage.heap.address;
273 case PixelStorageType::Hardware:
274 return nullptr;
sergeyv163f8812016-10-07 16:57:29 -0700275 }
276}
277
sergeyvc1c54062016-10-19 18:47:26 -0700278int Bitmap::getAshmemFd() const {
sergeyv163f8812016-10-07 16:57:29 -0700279 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700280 case PixelStorageType::Ashmem:
281 return mPixelStorage.ashmem.fd;
282 default:
283 return -1;
sergeyv163f8812016-10-07 16:57:29 -0700284 }
285}
286
sergeyvc1c54062016-10-19 18:47:26 -0700287size_t Bitmap::getAllocationByteCount() const {
sergeyv163f8812016-10-07 16:57:29 -0700288 switch (mPixelStorageType) {
John Reck1bcacfd2017-11-03 10:12:19 -0700289 case PixelStorageType::Heap:
290 return mPixelStorage.heap.size;
291 default:
292 return rowBytes() * height();
sergeyv163f8812016-10-07 16:57:29 -0700293 }
294}
295
sergeyvc1c54062016-10-19 18:47:26 -0700296void Bitmap::reconfigure(const SkImageInfo& info) {
Leon Scroggins IIIf51a80d2017-07-12 10:46:35 -0400297 reconfigure(info, info.minRowBytes());
sergeyv163f8812016-10-07 16:57:29 -0700298}
299
sergeyvc1c54062016-10-19 18:47:26 -0700300void Bitmap::setAlphaType(SkAlphaType alphaType) {
sergeyv163f8812016-10-07 16:57:29 -0700301 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
302 return;
303 }
304
Matt Sarett489cfff2017-04-21 18:08:40 -0400305 mInfo = mInfo.makeAlphaType(alphaType);
sergeyv163f8812016-10-07 16:57:29 -0700306}
307
sergeyvc1c54062016-10-19 18:47:26 -0700308void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
sergeyv694d4992016-10-27 10:23:13 -0700309 if (isHardware()) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400310 outBitmap->allocPixels(mInfo);
Stan Iliev1a025a72018-09-05 16:35:11 -0400311 uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
sergeyv694d4992016-10-27 10:23:13 -0700312 return;
313 }
Matt Sarett489cfff2017-04-21 18:08:40 -0400314 outBitmap->setInfo(mInfo, rowBytes());
Mike Reed826deef2017-04-04 15:32:04 -0400315 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
sergeyv163f8812016-10-07 16:57:29 -0700316}
317
sergeyvec4a4b12016-10-20 18:39:04 -0700318void Bitmap::getBounds(SkRect* bounds) const {
319 SkASSERT(bounds);
Matt Sarett489cfff2017-04-21 18:08:40 -0400320 bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
sergeyvec4a4b12016-10-20 18:39:04 -0700321}
322
sergeyv694d4992016-10-27 10:23:13 -0700323GraphicBuffer* Bitmap::graphicBuffer() {
324 if (isHardware()) {
325 return mPixelStorage.hardware.buffer;
326 }
327 return nullptr;
328}
329
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400330sk_sp<SkImage> Bitmap::makeImage() {
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400331 sk_sp<SkImage> image = mImage;
332 if (!image) {
John Reck1072fff2018-04-12 15:20:09 -0700333 SkASSERT(!isHardware());
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400334 SkBitmap skiaBitmap;
335 skiaBitmap.setInfo(info(), rowBytes());
336 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400337 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
338 // internally and ~Bitmap won't be invoked.
339 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400340 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
341 }
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400342 return image;
343}
344
John Reck339cf9b2018-07-18 16:32:27 -0700345class MinMaxAverage {
346public:
John Reck339cf9b2018-07-18 16:32:27 -0700347 void add(float sample) {
348 if (mCount == 0) {
349 mMin = sample;
350 mMax = sample;
351 } else {
352 mMin = std::min(mMin, sample);
353 mMax = std::max(mMax, sample);
354 }
355 mTotal += sample;
356 mCount++;
357 }
358
John Reck8f45d4a2018-08-15 10:17:12 -0700359 float average() { return mTotal / mCount; }
John Reck339cf9b2018-07-18 16:32:27 -0700360
John Reck8f45d4a2018-08-15 10:17:12 -0700361 float min() { return mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700362
John Reck8f45d4a2018-08-15 10:17:12 -0700363 float max() { return mMax; }
John Reck339cf9b2018-07-18 16:32:27 -0700364
John Reck8f45d4a2018-08-15 10:17:12 -0700365 float delta() { return mMax - mMin; }
John Reck339cf9b2018-07-18 16:32:27 -0700366
367private:
368 float mMin = 0.0f;
369 float mMax = 0.0f;
370 float mTotal = 0.0f;
371 int mCount = 0;
372};
373
374BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
375 ATRACE_CALL();
376
377 SkPixmap pixmap{info, addr, rowBytes};
378
379 // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
380 // Experiment with something simpler since we just want to figure out if it's "color-ful"
381 // and then the average perceptual lightness.
382
383 MinMaxAverage hue, saturation, value;
384 int sampledCount = 0;
385
386 // Sample a grid of 100 pixels to get an overall estimation of the colors in play
387 const int x_step = std::max(1, pixmap.width() / 10);
388 const int y_step = std::max(1, pixmap.height() / 10);
389 for (int x = 0; x < pixmap.width(); x += x_step) {
390 for (int y = 0; y < pixmap.height(); y += y_step) {
391 SkColor color = pixmap.getColor(x, y);
392 if (!info.isOpaque() && SkColorGetA(color) < 75) {
393 continue;
394 }
395
396 sampledCount++;
397 float hsv[3];
398 SkColorToHSV(color, hsv);
399 hue.add(hsv[0]);
400 saturation.add(hsv[1]);
401 value.add(hsv[2]);
402 }
403 }
404
405 // TODO: Tune the coverage threshold
406 if (sampledCount < 5) {
407 ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
John Reck8f45d4a2018-08-15 10:17:12 -0700408 sampledCount, info.width(), info.height(), (int)info.colorType(),
409 (int)info.alphaType());
John Reck339cf9b2018-07-18 16:32:27 -0700410 return BitmapPalette::Unknown;
411 }
412
John Reck8f45d4a2018-08-15 10:17:12 -0700413 ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
414 "%f]",
415 sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
416 saturation.average());
John Reck339cf9b2018-07-18 16:32:27 -0700417
418 if (hue.delta() <= 20 && saturation.delta() <= .1f) {
419 if (value.average() >= .5f) {
420 return BitmapPalette::Light;
421 } else {
422 return BitmapPalette::Dark;
423 }
424 }
425 return BitmapPalette::Unknown;
426}
427
John Reck1bcacfd2017-11-03 10:12:19 -0700428} // namespace android