1 /*
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 */
16 #include "Bitmap.h"
17
18 #include "HardwareBitmapUploader.h"
19 #include "Properties.h"
20 #ifdef __ANDROID__ // Layoutlib does not support render thread
21 #include <private/android/AHardwareBufferHelpers.h>
22 #include <ui/GraphicBuffer.h>
23 #include <ui/GraphicBufferMapper.h>
24
25 #include "renderthread/RenderProxy.h"
26 #endif
27 #include "utils/Color.h"
28 #include <utils/Trace.h>
29
30 #ifndef _WIN32
31 #include <sys/mman.h>
32 #endif
33
34 #include <cutils/ashmem.h>
35 #include <log/log.h>
36
37 #ifndef _WIN32
38 #include <binder/IServiceManager.h>
39 #endif
40
41 #include <Gainmap.h>
42 #include <SkCanvas.h>
43 #include <SkColor.h>
44 #include <SkEncodedImageFormat.h>
45 #include <SkHighContrastFilter.h>
46 #include <SkImageEncoder.h>
47 #include <SkImagePriv.h>
48 #include <SkJpegGainmapEncoder.h>
49 #include <SkPixmap.h>
50 #include <SkRect.h>
51 #include <SkStream.h>
52 #include <SkWebpEncoder.h>
53
54 #include <limits>
55
56 namespace android {
57
58 #ifdef __ANDROID__
AHardwareBuffer_getAllocationSize(AHardwareBuffer * aHardwareBuffer)59 static uint64_t AHardwareBuffer_getAllocationSize(AHardwareBuffer* aHardwareBuffer) {
60 GraphicBuffer* buffer = AHardwareBuffer_to_GraphicBuffer(aHardwareBuffer);
61 auto& mapper = GraphicBufferMapper::get();
62 uint64_t size = 0;
63 auto err = mapper.getAllocationSize(buffer->handle, &size);
64 if (err == OK) {
65 if (size > 0) {
66 return size;
67 } else {
68 ALOGW("Mapper returned size = 0 for buffer format: 0x%x size: %d x %d", buffer->format,
69 buffer->width, buffer->height);
70 // Fall-through to estimate
71 }
72 }
73
74 // Estimation time!
75 // Stride could be = 0 if it's ill-defined (eg, compressed buffer), in which case we use the
76 // width of the buffer instead
77 size = std::max(buffer->width, buffer->stride) * buffer->height;
78 // Require bpp to be at least 1. This is too low for many formats, but it's better than 0
79 // Also while we could make increasingly better estimates, the reality is that mapper@4
80 // should be common enough at this point that we won't ever hit this anyway
81 size *= std::max(1u, bytesPerPixel(buffer->format));
82 return size;
83 }
84 #endif
85
computeAllocationSize(size_t rowBytes,int height,size_t * size)86 bool Bitmap::computeAllocationSize(size_t rowBytes, int height, size_t* size) {
87 return 0 <= height && height <= std::numeric_limits<size_t>::max() &&
88 !__builtin_mul_overflow(rowBytes, (size_t)height, size) &&
89 *size <= std::numeric_limits<int32_t>::max();
90 }
91
92 typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
93
allocateBitmap(SkBitmap * bitmap,AllocPixelRef alloc)94 static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
95 const SkImageInfo& info = bitmap->info();
96 if (info.colorType() == kUnknown_SkColorType) {
97 LOG_ALWAYS_FATAL("unknown bitmap configuration");
98 return nullptr;
99 }
100
101 size_t size;
102
103 // we must respect the rowBytes value already set on the bitmap instead of
104 // attempting to compute our own.
105 const size_t rowBytes = bitmap->rowBytes();
106 if (!Bitmap::computeAllocationSize(rowBytes, bitmap->height(), &size)) {
107 return nullptr;
108 }
109
110 auto wrapper = alloc(size, info, rowBytes);
111 if (wrapper) {
112 wrapper->getSkBitmap(bitmap);
113 }
114 return wrapper;
115 }
116
allocateAshmemBitmap(SkBitmap * bitmap)117 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
118 return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
119 }
120
allocateAshmemBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)121 sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
122 #ifdef __ANDROID__
123 // Create new ashmem region with read/write priv
124 int fd = ashmem_create_region("bitmap", size);
125 if (fd < 0) {
126 return nullptr;
127 }
128
129 void* addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
130 if (addr == MAP_FAILED) {
131 close(fd);
132 return nullptr;
133 }
134
135 if (ashmem_set_prot_region(fd, PROT_READ) < 0) {
136 munmap(addr, size);
137 close(fd);
138 return nullptr;
139 }
140 return sk_sp<Bitmap>(new Bitmap(addr, fd, size, info, rowBytes));
141 #else
142 return Bitmap::allocateHeapBitmap(size, info, rowBytes);
143 #endif
144 }
145
allocateHardwareBitmap(const SkBitmap & bitmap)146 sk_sp<Bitmap> Bitmap::allocateHardwareBitmap(const SkBitmap& bitmap) {
147 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
148 if (bitmap.colorType() == kAlpha_8_SkColorType &&
149 !uirenderer::HardwareBitmapUploader::hasAlpha8Support()) {
150 return nullptr;
151 }
152 return uirenderer::HardwareBitmapUploader::allocateHardwareBitmap(bitmap);
153 #else
154 return Bitmap::allocateHeapBitmap(bitmap.info());
155 #endif
156 }
157
allocateHeapBitmap(SkBitmap * bitmap)158 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
159 return allocateBitmap(bitmap, &Bitmap::allocateHeapBitmap);
160 }
161
allocateHeapBitmap(const SkImageInfo & info)162 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
163 size_t size;
164 if (!computeAllocationSize(info.minRowBytes(), info.height(), &size)) {
165 LOG_ALWAYS_FATAL("trying to allocate too large bitmap");
166 return nullptr;
167 }
168 return allocateHeapBitmap(size, info, info.minRowBytes());
169 }
170
allocateHeapBitmap(size_t size,const SkImageInfo & info,size_t rowBytes)171 sk_sp<Bitmap> Bitmap::allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
172 void* addr = calloc(size, 1);
173 if (!addr) {
174 return nullptr;
175 }
176 return sk_sp<Bitmap>(new Bitmap(addr, size, info, rowBytes));
177 }
178
createFrom(const SkImageInfo & info,SkPixelRef & pixelRef)179 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
180 return sk_sp<Bitmap>(new Bitmap(pixelRef, info));
181 }
182
183
184 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
createFrom(AHardwareBuffer * hardwareBuffer,sk_sp<SkColorSpace> colorSpace,BitmapPalette palette)185 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, sk_sp<SkColorSpace> colorSpace,
186 BitmapPalette palette) {
187 AHardwareBuffer_Desc bufferDesc;
188 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
189 SkImageInfo info = uirenderer::BufferDescriptionToImageInfo(bufferDesc, colorSpace);
190 return createFrom(hardwareBuffer, info, bufferDesc, palette);
191 }
192
createFrom(AHardwareBuffer * hardwareBuffer,SkColorType colorType,sk_sp<SkColorSpace> colorSpace,SkAlphaType alphaType,BitmapPalette palette)193 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, SkColorType colorType,
194 sk_sp<SkColorSpace> colorSpace, SkAlphaType alphaType,
195 BitmapPalette palette) {
196 AHardwareBuffer_Desc bufferDesc;
197 AHardwareBuffer_describe(hardwareBuffer, &bufferDesc);
198 SkImageInfo info = SkImageInfo::Make(bufferDesc.width, bufferDesc.height,
199 colorType, alphaType, colorSpace);
200 return createFrom(hardwareBuffer, info, bufferDesc, palette);
201 }
202
createFrom(AHardwareBuffer * hardwareBuffer,const SkImageInfo & info,const AHardwareBuffer_Desc & bufferDesc,BitmapPalette palette)203 sk_sp<Bitmap> Bitmap::createFrom(AHardwareBuffer* hardwareBuffer, const SkImageInfo& info,
204 const AHardwareBuffer_Desc& bufferDesc, BitmapPalette palette) {
205 // If the stride is 0 we have to use the width as an approximation (eg, compressed buffer)
206 const auto bufferStride = bufferDesc.stride > 0 ? bufferDesc.stride : bufferDesc.width;
207 const size_t rowBytes = info.bytesPerPixel() * bufferStride;
208 return sk_sp<Bitmap>(new Bitmap(hardwareBuffer, info, rowBytes, palette));
209 }
210 #endif
211
createFrom(const SkImageInfo & info,size_t rowBytes,int fd,void * addr,size_t size,bool readOnly)212 sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, size_t rowBytes, int fd, void* addr,
213 size_t size, bool readOnly) {
214 #ifdef _WIN32 // ashmem not implemented on Windows
215 return nullptr;
216 #else
217 if (info.colorType() == kUnknown_SkColorType) {
218 LOG_ALWAYS_FATAL("unknown bitmap configuration");
219 return nullptr;
220 }
221
222 if (!addr) {
223 // Map existing ashmem region if not already mapped.
224 int flags = readOnly ? (PROT_READ) : (PROT_READ | PROT_WRITE);
225 size = ashmem_get_size_region(fd);
226 addr = mmap(NULL, size, flags, MAP_SHARED, fd, 0);
227 if (addr == MAP_FAILED) {
228 return nullptr;
229 }
230 }
231
232 sk_sp<Bitmap> bitmap(new Bitmap(addr, fd, size, info, rowBytes));
233 if (readOnly) {
234 bitmap->setImmutable();
235 }
236 return bitmap;
237 #endif
238 }
239
setColorSpace(sk_sp<SkColorSpace> colorSpace)240 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
241 mInfo = mInfo.makeColorSpace(std::move(colorSpace));
242 }
243
validateAlpha(const SkImageInfo & info)244 static SkImageInfo validateAlpha(const SkImageInfo& info) {
245 // Need to validate the alpha type to filter against the color type
246 // to prevent things like a non-opaque RGB565 bitmap
247 SkAlphaType alphaType;
248 LOG_ALWAYS_FATAL_IF(
249 !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
250 "Failed to validate alpha type!");
251 return info.makeAlphaType(alphaType);
252 }
253
reconfigure(const SkImageInfo & newInfo,size_t rowBytes)254 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes) {
255 mInfo = validateAlpha(newInfo);
256
257 // TODO: Skia intends for SkPixelRef to be immutable, but this method
258 // modifies it. Find another way to support reusing the same pixel memory.
259 this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes);
260 }
261
Bitmap(void * address,size_t size,const SkImageInfo & info,size_t rowBytes)262 Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
263 : SkPixelRef(info.width(), info.height(), address, rowBytes)
264 , mInfo(validateAlpha(info))
265 , mPixelStorageType(PixelStorageType::Heap) {
266 mPixelStorage.heap.address = address;
267 mPixelStorage.heap.size = size;
268 }
269
Bitmap(SkPixelRef & pixelRef,const SkImageInfo & info)270 Bitmap::Bitmap(SkPixelRef& pixelRef, const SkImageInfo& info)
271 : SkPixelRef(info.width(), info.height(), pixelRef.pixels(), pixelRef.rowBytes())
272 , mInfo(validateAlpha(info))
273 , mPixelStorageType(PixelStorageType::WrappedPixelRef) {
274 pixelRef.ref();
275 mPixelStorage.wrapped.pixelRef = &pixelRef;
276 }
277
Bitmap(void * address,int fd,size_t mappedSize,const SkImageInfo & info,size_t rowBytes)278 Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
279 : SkPixelRef(info.width(), info.height(), address, rowBytes)
280 , mInfo(validateAlpha(info))
281 , mPixelStorageType(PixelStorageType::Ashmem) {
282 mPixelStorage.ashmem.address = address;
283 mPixelStorage.ashmem.fd = fd;
284 mPixelStorage.ashmem.size = mappedSize;
285 }
286
287 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
Bitmap(AHardwareBuffer * buffer,const SkImageInfo & info,size_t rowBytes,BitmapPalette palette)288 Bitmap::Bitmap(AHardwareBuffer* buffer, const SkImageInfo& info, size_t rowBytes,
289 BitmapPalette palette)
290 : SkPixelRef(info.width(), info.height(), nullptr, rowBytes)
291 , mInfo(validateAlpha(info))
292 , mPixelStorageType(PixelStorageType::Hardware)
293 , mPalette(palette)
294 , mPaletteGenerationId(getGenerationID()) {
295 mPixelStorage.hardware.buffer = buffer;
296 mPixelStorage.hardware.size = AHardwareBuffer_getAllocationSize(buffer);
297 AHardwareBuffer_acquire(buffer);
298 setImmutable(); // HW bitmaps are always immutable
299 mImage = SkImage::MakeFromAHardwareBuffer(buffer, mInfo.alphaType(), mInfo.refColorSpace());
300 }
301 #endif
302
~Bitmap()303 Bitmap::~Bitmap() {
304 switch (mPixelStorageType) {
305 case PixelStorageType::WrappedPixelRef:
306 mPixelStorage.wrapped.pixelRef->unref();
307 break;
308 case PixelStorageType::Ashmem:
309 #ifndef _WIN32 // ashmem not implemented on Windows
310 munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
311 #endif
312 close(mPixelStorage.ashmem.fd);
313 break;
314 case PixelStorageType::Heap:
315 free(mPixelStorage.heap.address);
316 #ifdef __ANDROID__
317 mallopt(M_PURGE, 0);
318 #endif
319 break;
320 case PixelStorageType::Hardware:
321 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
322 auto buffer = mPixelStorage.hardware.buffer;
323 AHardwareBuffer_release(buffer);
324 mPixelStorage.hardware.buffer = nullptr;
325 #endif
326 break;
327 }
328 }
329
hasHardwareMipMap() const330 bool Bitmap::hasHardwareMipMap() const {
331 return mHasHardwareMipMap;
332 }
333
setHasHardwareMipMap(bool hasMipMap)334 void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
335 mHasHardwareMipMap = hasMipMap;
336 }
337
getAshmemFd() const338 int Bitmap::getAshmemFd() const {
339 switch (mPixelStorageType) {
340 case PixelStorageType::Ashmem:
341 return mPixelStorage.ashmem.fd;
342 default:
343 return -1;
344 }
345 }
346
getAllocationByteCount() const347 size_t Bitmap::getAllocationByteCount() const {
348 switch (mPixelStorageType) {
349 case PixelStorageType::Heap:
350 return mPixelStorage.heap.size;
351 case PixelStorageType::Ashmem:
352 return mPixelStorage.ashmem.size;
353 #ifdef __ANDROID__
354 case PixelStorageType::Hardware:
355 return mPixelStorage.hardware.size;
356 #endif
357 default:
358 return rowBytes() * height();
359 }
360 }
361
reconfigure(const SkImageInfo & info)362 void Bitmap::reconfigure(const SkImageInfo& info) {
363 reconfigure(info, info.minRowBytes());
364 }
365
setAlphaType(SkAlphaType alphaType)366 void Bitmap::setAlphaType(SkAlphaType alphaType) {
367 if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
368 return;
369 }
370
371 mInfo = mInfo.makeAlphaType(alphaType);
372 }
373
getSkBitmap(SkBitmap * outBitmap)374 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
375 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
376 if (isHardware()) {
377 outBitmap->allocPixels(mInfo);
378 uirenderer::renderthread::RenderProxy::copyHWBitmapInto(this, outBitmap);
379 return;
380 }
381 #endif
382 outBitmap->setInfo(mInfo, rowBytes());
383 outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
384 }
385
getBounds(SkRect * bounds) const386 void Bitmap::getBounds(SkRect* bounds) const {
387 SkASSERT(bounds);
388 bounds->setIWH(width(), height());
389 }
390
391 #ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
hardwareBuffer()392 AHardwareBuffer* Bitmap::hardwareBuffer() {
393 if (isHardware()) {
394 return mPixelStorage.hardware.buffer;
395 }
396 return nullptr;
397 }
398 #endif
399
makeImage()400 sk_sp<SkImage> Bitmap::makeImage() {
401 sk_sp<SkImage> image = mImage;
402 if (!image) {
403 SkASSERT(!isHardware());
404 SkBitmap skiaBitmap;
405 skiaBitmap.setInfo(info(), rowBytes());
406 skiaBitmap.setPixelRef(sk_ref_sp(this), 0, 0);
407 // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
408 // internally and ~Bitmap won't be invoked.
409 // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
410 image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
411 }
412 return image;
413 }
414
415 class MinMaxAverage {
416 public:
add(float sample)417 void add(float sample) {
418 if (mCount == 0) {
419 mMin = sample;
420 mMax = sample;
421 } else {
422 mMin = std::min(mMin, sample);
423 mMax = std::max(mMax, sample);
424 }
425 mTotal += sample;
426 mCount++;
427 }
428
average()429 float average() { return mTotal / mCount; }
430
min()431 float min() { return mMin; }
432
max()433 float max() { return mMax; }
434
delta()435 float delta() { return mMax - mMin; }
436
437 private:
438 float mMin = 0.0f;
439 float mMax = 0.0f;
440 float mTotal = 0.0f;
441 int mCount = 0;
442 };
443
computePalette(const SkImageInfo & info,const void * addr,size_t rowBytes)444 BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, size_t rowBytes) {
445 ATRACE_CALL();
446
447 SkPixmap pixmap{info, addr, rowBytes};
448
449 // TODO: This calculation of converting to HSV & tracking min/max is probably overkill
450 // Experiment with something simpler since we just want to figure out if it's "color-ful"
451 // and then the average perceptual lightness.
452
453 MinMaxAverage hue, saturation, value;
454 int sampledCount = 0;
455
456 // Sample a grid of 100 pixels to get an overall estimation of the colors in play
457 const int x_step = std::max(1, pixmap.width() / 10);
458 const int y_step = std::max(1, pixmap.height() / 10);
459 for (int x = 0; x < pixmap.width(); x += x_step) {
460 for (int y = 0; y < pixmap.height(); y += y_step) {
461 SkColor color = pixmap.getColor(x, y);
462 if (!info.isOpaque() && SkColorGetA(color) < 75) {
463 continue;
464 }
465
466 sampledCount++;
467 float hsv[3];
468 SkColorToHSV(color, hsv);
469 hue.add(hsv[0]);
470 saturation.add(hsv[1]);
471 value.add(hsv[2]);
472 }
473 }
474
475 // TODO: Tune the coverage threshold
476 if (sampledCount < 5) {
477 ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d",
478 sampledCount, info.width(), info.height(), (int)info.colorType(),
479 (int)info.alphaType());
480 return BitmapPalette::Unknown;
481 }
482
483 ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = "
484 "%f]",
485 sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(),
486 saturation.average());
487
488 if (hue.delta() <= 20 && saturation.delta() <= .1f) {
489 if (value.average() >= .5f) {
490 return BitmapPalette::Light;
491 } else {
492 return BitmapPalette::Dark;
493 }
494 }
495 return BitmapPalette::Unknown;
496 }
497
compress(JavaCompressFormat format,int32_t quality,SkWStream * stream)498 bool Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* stream) {
499 #ifdef __ANDROID__ // TODO: This isn't built for host for some reason?
500 if (hasGainmap() && format == JavaCompressFormat::Jpeg) {
501 SkBitmap baseBitmap = getSkBitmap();
502 SkBitmap gainmapBitmap = gainmap()->bitmap->getSkBitmap();
503 if (gainmapBitmap.colorType() == SkColorType::kAlpha_8_SkColorType) {
504 SkBitmap greyGainmap;
505 auto greyInfo = gainmapBitmap.info().makeColorType(SkColorType::kGray_8_SkColorType);
506 greyGainmap.setInfo(greyInfo, gainmapBitmap.rowBytes());
507 greyGainmap.setPixelRef(sk_ref_sp(gainmapBitmap.pixelRef()), 0, 0);
508 gainmapBitmap = std::move(greyGainmap);
509 }
510 SkJpegEncoder::Options options{.fQuality = quality};
511 return SkJpegGainmapEncoder::EncodeHDRGM(stream, baseBitmap.pixmap(), options,
512 gainmapBitmap.pixmap(), options, gainmap()->info);
513 }
514 #endif
515
516 SkBitmap skbitmap;
517 getSkBitmap(&skbitmap);
518 return compress(skbitmap, format, quality, stream);
519 }
520
compress(const SkBitmap & bitmap,JavaCompressFormat format,int32_t quality,SkWStream * stream)521 bool Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format,
522 int32_t quality, SkWStream* stream) {
523 if (bitmap.colorType() == kAlpha_8_SkColorType) {
524 // None of the JavaCompressFormats have a sensible way to compress an
525 // ALPHA_8 Bitmap. SkPngEncoder will compress one, but it uses a non-
526 // standard format that most decoders do not understand, so this is
527 // likely not useful.
528 return false;
529 }
530
531 SkEncodedImageFormat fm;
532 switch (format) {
533 case JavaCompressFormat::Jpeg:
534 fm = SkEncodedImageFormat::kJPEG;
535 break;
536 case JavaCompressFormat::Png:
537 fm = SkEncodedImageFormat::kPNG;
538 break;
539 case JavaCompressFormat::Webp:
540 fm = SkEncodedImageFormat::kWEBP;
541 break;
542 case JavaCompressFormat::WebpLossy:
543 case JavaCompressFormat::WebpLossless: {
544 SkWebpEncoder::Options options;
545 options.fQuality = quality;
546 options.fCompression = format == JavaCompressFormat::WebpLossy ?
547 SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless;
548 return SkWebpEncoder::Encode(stream, bitmap.pixmap(), options);
549 }
550 }
551
552 return SkEncodeImage(stream, bitmap, fm, quality);
553 }
554
gainmap() const555 sp<uirenderer::Gainmap> Bitmap::gainmap() const {
556 LOG_ALWAYS_FATAL_IF(!hasGainmap(), "Bitmap doesn't have a gainmap");
557 return mGainmap;
558 }
559
setGainmap(sp<uirenderer::Gainmap> && gainmap)560 void Bitmap::setGainmap(sp<uirenderer::Gainmap>&& gainmap) {
561 mGainmap = std::move(gainmap);
562 }
563
564 } // namespace android
565