Loading core/jni/android/graphics/Bitmap.cpp +3 −54 Original line number Diff line number Diff line Loading @@ -457,15 +457,6 @@ static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, sk_ref_sp(bitmap->info().colorSpace()))); } // These must match the int values in Bitmap.java enum JavaEncodeFormat { kJPEG_JavaEncodeFormat = 0, kPNG_JavaEncodeFormat = 1, kWEBP_JavaEncodeFormat = 2, kWEBP_LOSSY_JavaEncodeFormat = 3, kWEBP_LOSSLESS_JavaEncodeFormat = 4, }; static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, jint format, jint quality, jobject jstream, jbyteArray jstorage) { Loading @@ -479,51 +470,9 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, return JNI_FALSE; } SkBitmap skbitmap; bitmap->getSkBitmap(&skbitmap); if (skbitmap.colorType() == kRGBA_F16_SkColorType) { // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace // for wide gamuts. auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(std::move(cs)); SkBitmap p3; if (!p3.tryAllocPixels(info)) { return JNI_FALSE; } SkPixmap pm; SkAssertResult(p3.peekPixels(&pm)); // should always work if tryAllocPixels() did. if (!skbitmap.readPixels(pm)) { return JNI_FALSE; } skbitmap = p3; } SkEncodedImageFormat fm; switch (format) { case kJPEG_JavaEncodeFormat: fm = SkEncodedImageFormat::kJPEG; break; case kPNG_JavaEncodeFormat: fm = SkEncodedImageFormat::kPNG; break; case kWEBP_JavaEncodeFormat: fm = SkEncodedImageFormat::kWEBP; break; case kWEBP_LOSSY_JavaEncodeFormat: case kWEBP_LOSSLESS_JavaEncodeFormat: { SkWebpEncoder::Options options; options.fQuality = quality; options.fCompression = format == kWEBP_LOSSY_JavaEncodeFormat ? SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless; return SkWebpEncoder::Encode(strm.get(), skbitmap.pixmap(), options) ? JNI_TRUE : JNI_FALSE; } default: return JNI_FALSE; } return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; auto fm = static_cast<Bitmap::JavaCompressFormat>(format); auto result = bitmap->bitmap().compress(fm, quality, strm.get()); return result == Bitmap::CompressResult::Success ? JNI_TRUE : JNI_FALSE; } static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color, Loading core/jni/android/graphics/apex/android_bitmap.cpp +135 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <GraphicsJNI.h> #include <hwui/Bitmap.h> #include <utils/Color.h> using namespace android; Loading Loading @@ -122,6 +123,7 @@ AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { return getInfo(bitmap->info(), bitmap->rowBytes()); } namespace { static bool nearlyEqual(float a, float b) { // By trial and error, this is close enough to match for the ADataSpaces we // compare for. Loading Loading @@ -156,6 +158,7 @@ static constexpr skcms_Matrix3x3 kDCIP3 = {{ {0.226676, 0.710327, 0.0629966}, {0.000800549, 0.0432385, 0.78275}, }}; } // anonymous namespace ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) { Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); Loading Loading @@ -243,3 +246,135 @@ void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) { } return bitmap->notifyPixelsChanged(); } namespace { SkAlphaType getAlphaType(const AndroidBitmapInfo* info) { switch (info->flags & ANDROID_BITMAP_FLAGS_ALPHA_MASK) { case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: return kOpaque_SkAlphaType; case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: return kPremul_SkAlphaType; case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType; default: return kUnknown_SkAlphaType; } } class CompressWriter : public SkWStream { public: CompressWriter(void* userContext, AndroidBitmap_compress_write_fn fn) : mUserContext(userContext), mFn(fn), mBytesWritten(0) {} bool write(const void* buffer, size_t size) override { if (mFn(mUserContext, buffer, size)) { mBytesWritten += size; return true; } return false; } size_t bytesWritten() const override { return mBytesWritten; } private: void* mUserContext; AndroidBitmap_compress_write_fn mFn; size_t mBytesWritten; }; } // anonymous namespace int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels, AndroidBitmapCompressFormat inFormat, int32_t quality, void* userContext, AndroidBitmap_compress_write_fn fn) { Bitmap::JavaCompressFormat format; switch (inFormat) { case ANDROID_BITMAP_COMPRESS_FORMAT_JPEG: format = Bitmap::JavaCompressFormat::Jpeg; break; case ANDROID_BITMAP_COMPRESS_FORMAT_PNG: format = Bitmap::JavaCompressFormat::Png; break; case ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY: format = Bitmap::JavaCompressFormat::WebpLossy; break; case ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS: format = Bitmap::JavaCompressFormat::WebpLossless; break; default: // kWEBP_JavaEncodeFormat is a valid parameter for Bitmap::compress, // for the deprecated Bitmap.CompressFormat.WEBP, but it should not // be provided via the NDK. Other integers are likewise invalid. return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } SkColorType colorType; switch (info->format) { case ANDROID_BITMAP_FORMAT_RGBA_8888: colorType = kN32_SkColorType; break; case ANDROID_BITMAP_FORMAT_RGB_565: colorType = kRGB_565_SkColorType; break; case ANDROID_BITMAP_FORMAT_A_8: // FIXME b/146637821: Should this encode as grayscale? We should // make the same decision as for encoding an android.graphics.Bitmap. // Note that encoding kAlpha_8 as WebP or JPEG will fail. Encoding // it to PNG encodes as GRAY+ALPHA with a secret handshake that we // only care about the alpha. I'm not sure whether Android decoding // APIs respect that handshake. colorType = kAlpha_8_SkColorType; break; case ANDROID_BITMAP_FORMAT_RGBA_F16: colorType = kRGBA_F16_SkColorType; break; default: return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } auto alphaType = getAlphaType(info); if (alphaType == kUnknown_SkAlphaType) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } sk_sp<SkColorSpace> cs; if (info->format == ANDROID_BITMAP_FORMAT_A_8) { // FIXME: A Java Bitmap with ALPHA_8 never has a ColorSpace. So should // we force that here (as I'm doing now) or should we treat anything // besides ADATASPACE_UNKNOWN as an error? cs = nullptr; } else { cs = uirenderer::DataSpaceToColorSpace((android_dataspace) dataSpace); // DataSpaceToColorSpace treats UNKNOWN as SRGB, but compress forces the // client to specify SRGB if that is what they want. if (!cs || dataSpace == ADATASPACE_UNKNOWN) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } } { size_t size; if (!Bitmap::computeAllocationSize(info->stride, info->height, &size)) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } } auto imageInfo = SkImageInfo::Make(info->width, info->height, colorType, alphaType, std::move(cs)); SkBitmap bitmap; // We are not going to modify the pixels, but installPixels expects them to // not be const, since for all it knows we might want to draw to the SkBitmap. if (!bitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } CompressWriter stream(userContext, fn); switch (Bitmap::compress(bitmap, format, quality, &stream)) { case Bitmap::CompressResult::Success: return ANDROID_BITMAP_RESULT_SUCCESS; case Bitmap::CompressResult::AllocationFailed: return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED; case Bitmap::CompressResult::Error: return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } } core/jni/android/graphics/apex/include/android/graphics/bitmap.h +5 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,11 @@ void ABitmap_notifyPixelsChanged(ABitmap* bitmap); AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj); jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); // NDK access int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels, AndroidBitmapCompressFormat format, int32_t quality, void* userContext, AndroidBitmap_compress_write_fn); __END_DECLS #ifdef __cplusplus Loading libs/hwui/hwui/Bitmap.cpp +56 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ #include <SkCanvas.h> #include <SkImagePriv.h> #include <SkWebpEncoder.h> #include <SkHighContrastFilter.h> #include <limits> Loading Loading @@ -471,4 +471,59 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, return BitmapPalette::Unknown; } Bitmap::CompressResult Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* stream) { SkBitmap skbitmap; getSkBitmap(&skbitmap); return compress(skbitmap, format, quality, stream); } Bitmap::CompressResult Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format, int32_t quality, SkWStream* stream) { SkBitmap skbitmap = bitmap; if (skbitmap.colorType() == kRGBA_F16_SkColorType) { // Convert to P3 before encoding. This matches // SkAndroidCodec::computeOutputColorSpace for wide gamuts. Now that F16 // could already be P3, we still want to convert to 8888. auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(std::move(cs)); SkBitmap p3; if (!p3.tryAllocPixels(info)) { return CompressResult::AllocationFailed; } SkPixmap pm; SkAssertResult(p3.peekPixels(&pm)); // should always work if tryAllocPixels() did. if (!skbitmap.readPixels(pm)) { return CompressResult::Error; } skbitmap = p3; } SkEncodedImageFormat fm; switch (format) { case JavaCompressFormat::Jpeg: fm = SkEncodedImageFormat::kJPEG; break; case JavaCompressFormat::Png: fm = SkEncodedImageFormat::kPNG; break; case JavaCompressFormat::Webp: fm = SkEncodedImageFormat::kWEBP; break; case JavaCompressFormat::WebpLossy: case JavaCompressFormat::WebpLossless: { SkWebpEncoder::Options options; options.fQuality = quality; options.fCompression = format == JavaCompressFormat::WebpLossy ? SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless; return SkWebpEncoder::Encode(stream, skbitmap.pixmap(), options) ? CompressResult::Success : CompressResult::Error; } } return SkEncodeImage(stream, skbitmap, fm, quality) ? CompressResult::Success : CompressResult::Error; } } // namespace android libs/hwui/hwui/Bitmap.h +22 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <android/hardware_buffer.h> #endif class SkWStream; namespace android { enum class PixelStorageType { Loading Loading @@ -142,6 +144,26 @@ public: // and places that value in size. static bool computeAllocationSize(size_t rowBytes, int height, size_t* size); // These must match the int values of CompressFormat in Bitmap.java, as well as // AndroidBitmapCompressFormat. enum class JavaCompressFormat { Jpeg = 0, Png = 1, Webp = 2, WebpLossy = 3, WebpLossless = 4, }; enum class CompressResult { Success, AllocationFailed, Error, }; CompressResult compress(JavaCompressFormat format, int32_t quality, SkWStream* stream); static CompressResult compress(const SkBitmap& bitmap, JavaCompressFormat format, int32_t quality, SkWStream* stream); private: static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); Loading Loading
core/jni/android/graphics/Bitmap.cpp +3 −54 Original line number Diff line number Diff line Loading @@ -457,15 +457,6 @@ static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, sk_ref_sp(bitmap->info().colorSpace()))); } // These must match the int values in Bitmap.java enum JavaEncodeFormat { kJPEG_JavaEncodeFormat = 0, kPNG_JavaEncodeFormat = 1, kWEBP_JavaEncodeFormat = 2, kWEBP_LOSSY_JavaEncodeFormat = 3, kWEBP_LOSSLESS_JavaEncodeFormat = 4, }; static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, jint format, jint quality, jobject jstream, jbyteArray jstorage) { Loading @@ -479,51 +470,9 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, return JNI_FALSE; } SkBitmap skbitmap; bitmap->getSkBitmap(&skbitmap); if (skbitmap.colorType() == kRGBA_F16_SkColorType) { // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace // for wide gamuts. auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(std::move(cs)); SkBitmap p3; if (!p3.tryAllocPixels(info)) { return JNI_FALSE; } SkPixmap pm; SkAssertResult(p3.peekPixels(&pm)); // should always work if tryAllocPixels() did. if (!skbitmap.readPixels(pm)) { return JNI_FALSE; } skbitmap = p3; } SkEncodedImageFormat fm; switch (format) { case kJPEG_JavaEncodeFormat: fm = SkEncodedImageFormat::kJPEG; break; case kPNG_JavaEncodeFormat: fm = SkEncodedImageFormat::kPNG; break; case kWEBP_JavaEncodeFormat: fm = SkEncodedImageFormat::kWEBP; break; case kWEBP_LOSSY_JavaEncodeFormat: case kWEBP_LOSSLESS_JavaEncodeFormat: { SkWebpEncoder::Options options; options.fQuality = quality; options.fCompression = format == kWEBP_LOSSY_JavaEncodeFormat ? SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless; return SkWebpEncoder::Encode(strm.get(), skbitmap.pixmap(), options) ? JNI_TRUE : JNI_FALSE; } default: return JNI_FALSE; } return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; auto fm = static_cast<Bitmap::JavaCompressFormat>(format); auto result = bitmap->bitmap().compress(fm, quality, strm.get()); return result == Bitmap::CompressResult::Success ? JNI_TRUE : JNI_FALSE; } static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color, Loading
core/jni/android/graphics/apex/android_bitmap.cpp +135 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <GraphicsJNI.h> #include <hwui/Bitmap.h> #include <utils/Color.h> using namespace android; Loading Loading @@ -122,6 +123,7 @@ AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { return getInfo(bitmap->info(), bitmap->rowBytes()); } namespace { static bool nearlyEqual(float a, float b) { // By trial and error, this is close enough to match for the ADataSpaces we // compare for. Loading Loading @@ -156,6 +158,7 @@ static constexpr skcms_Matrix3x3 kDCIP3 = {{ {0.226676, 0.710327, 0.0629966}, {0.000800549, 0.0432385, 0.78275}, }}; } // anonymous namespace ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) { Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); Loading Loading @@ -243,3 +246,135 @@ void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) { } return bitmap->notifyPixelsChanged(); } namespace { SkAlphaType getAlphaType(const AndroidBitmapInfo* info) { switch (info->flags & ANDROID_BITMAP_FLAGS_ALPHA_MASK) { case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: return kOpaque_SkAlphaType; case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: return kPremul_SkAlphaType; case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType; default: return kUnknown_SkAlphaType; } } class CompressWriter : public SkWStream { public: CompressWriter(void* userContext, AndroidBitmap_compress_write_fn fn) : mUserContext(userContext), mFn(fn), mBytesWritten(0) {} bool write(const void* buffer, size_t size) override { if (mFn(mUserContext, buffer, size)) { mBytesWritten += size; return true; } return false; } size_t bytesWritten() const override { return mBytesWritten; } private: void* mUserContext; AndroidBitmap_compress_write_fn mFn; size_t mBytesWritten; }; } // anonymous namespace int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels, AndroidBitmapCompressFormat inFormat, int32_t quality, void* userContext, AndroidBitmap_compress_write_fn fn) { Bitmap::JavaCompressFormat format; switch (inFormat) { case ANDROID_BITMAP_COMPRESS_FORMAT_JPEG: format = Bitmap::JavaCompressFormat::Jpeg; break; case ANDROID_BITMAP_COMPRESS_FORMAT_PNG: format = Bitmap::JavaCompressFormat::Png; break; case ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY: format = Bitmap::JavaCompressFormat::WebpLossy; break; case ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS: format = Bitmap::JavaCompressFormat::WebpLossless; break; default: // kWEBP_JavaEncodeFormat is a valid parameter for Bitmap::compress, // for the deprecated Bitmap.CompressFormat.WEBP, but it should not // be provided via the NDK. Other integers are likewise invalid. return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } SkColorType colorType; switch (info->format) { case ANDROID_BITMAP_FORMAT_RGBA_8888: colorType = kN32_SkColorType; break; case ANDROID_BITMAP_FORMAT_RGB_565: colorType = kRGB_565_SkColorType; break; case ANDROID_BITMAP_FORMAT_A_8: // FIXME b/146637821: Should this encode as grayscale? We should // make the same decision as for encoding an android.graphics.Bitmap. // Note that encoding kAlpha_8 as WebP or JPEG will fail. Encoding // it to PNG encodes as GRAY+ALPHA with a secret handshake that we // only care about the alpha. I'm not sure whether Android decoding // APIs respect that handshake. colorType = kAlpha_8_SkColorType; break; case ANDROID_BITMAP_FORMAT_RGBA_F16: colorType = kRGBA_F16_SkColorType; break; default: return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } auto alphaType = getAlphaType(info); if (alphaType == kUnknown_SkAlphaType) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } sk_sp<SkColorSpace> cs; if (info->format == ANDROID_BITMAP_FORMAT_A_8) { // FIXME: A Java Bitmap with ALPHA_8 never has a ColorSpace. So should // we force that here (as I'm doing now) or should we treat anything // besides ADATASPACE_UNKNOWN as an error? cs = nullptr; } else { cs = uirenderer::DataSpaceToColorSpace((android_dataspace) dataSpace); // DataSpaceToColorSpace treats UNKNOWN as SRGB, but compress forces the // client to specify SRGB if that is what they want. if (!cs || dataSpace == ADATASPACE_UNKNOWN) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } } { size_t size; if (!Bitmap::computeAllocationSize(info->stride, info->height, &size)) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } } auto imageInfo = SkImageInfo::Make(info->width, info->height, colorType, alphaType, std::move(cs)); SkBitmap bitmap; // We are not going to modify the pixels, but installPixels expects them to // not be const, since for all it knows we might want to draw to the SkBitmap. if (!bitmap.installPixels(imageInfo, const_cast<void*>(pixels), info->stride)) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } CompressWriter stream(userContext, fn); switch (Bitmap::compress(bitmap, format, quality, &stream)) { case Bitmap::CompressResult::Success: return ANDROID_BITMAP_RESULT_SUCCESS; case Bitmap::CompressResult::AllocationFailed: return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED; case Bitmap::CompressResult::Error: return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } }
core/jni/android/graphics/apex/include/android/graphics/bitmap.h +5 −0 Original line number Diff line number Diff line Loading @@ -58,6 +58,11 @@ void ABitmap_notifyPixelsChanged(ABitmap* bitmap); AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj); jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); // NDK access int ABitmap_compress(const AndroidBitmapInfo* info, ADataSpace dataSpace, const void* pixels, AndroidBitmapCompressFormat format, int32_t quality, void* userContext, AndroidBitmap_compress_write_fn); __END_DECLS #ifdef __cplusplus Loading
libs/hwui/hwui/Bitmap.cpp +56 −1 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ #include <SkCanvas.h> #include <SkImagePriv.h> #include <SkWebpEncoder.h> #include <SkHighContrastFilter.h> #include <limits> Loading Loading @@ -471,4 +471,59 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, return BitmapPalette::Unknown; } Bitmap::CompressResult Bitmap::compress(JavaCompressFormat format, int32_t quality, SkWStream* stream) { SkBitmap skbitmap; getSkBitmap(&skbitmap); return compress(skbitmap, format, quality, stream); } Bitmap::CompressResult Bitmap::compress(const SkBitmap& bitmap, JavaCompressFormat format, int32_t quality, SkWStream* stream) { SkBitmap skbitmap = bitmap; if (skbitmap.colorType() == kRGBA_F16_SkColorType) { // Convert to P3 before encoding. This matches // SkAndroidCodec::computeOutputColorSpace for wide gamuts. Now that F16 // could already be P3, we still want to convert to 8888. auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(std::move(cs)); SkBitmap p3; if (!p3.tryAllocPixels(info)) { return CompressResult::AllocationFailed; } SkPixmap pm; SkAssertResult(p3.peekPixels(&pm)); // should always work if tryAllocPixels() did. if (!skbitmap.readPixels(pm)) { return CompressResult::Error; } skbitmap = p3; } SkEncodedImageFormat fm; switch (format) { case JavaCompressFormat::Jpeg: fm = SkEncodedImageFormat::kJPEG; break; case JavaCompressFormat::Png: fm = SkEncodedImageFormat::kPNG; break; case JavaCompressFormat::Webp: fm = SkEncodedImageFormat::kWEBP; break; case JavaCompressFormat::WebpLossy: case JavaCompressFormat::WebpLossless: { SkWebpEncoder::Options options; options.fQuality = quality; options.fCompression = format == JavaCompressFormat::WebpLossy ? SkWebpEncoder::Compression::kLossy : SkWebpEncoder::Compression::kLossless; return SkWebpEncoder::Encode(stream, skbitmap.pixmap(), options) ? CompressResult::Success : CompressResult::Error; } } return SkEncodeImage(stream, skbitmap, fm, quality) ? CompressResult::Success : CompressResult::Error; } } // namespace android
libs/hwui/hwui/Bitmap.h +22 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,8 @@ #include <android/hardware_buffer.h> #endif class SkWStream; namespace android { enum class PixelStorageType { Loading Loading @@ -142,6 +144,26 @@ public: // and places that value in size. static bool computeAllocationSize(size_t rowBytes, int height, size_t* size); // These must match the int values of CompressFormat in Bitmap.java, as well as // AndroidBitmapCompressFormat. enum class JavaCompressFormat { Jpeg = 0, Png = 1, Webp = 2, WebpLossy = 3, WebpLossless = 4, }; enum class CompressResult { Success, AllocationFailed, Error, }; CompressResult compress(JavaCompressFormat format, int32_t quality, SkWStream* stream); static CompressResult compress(const SkBitmap& bitmap, JavaCompressFormat format, int32_t quality, SkWStream* stream); private: static sk_sp<Bitmap> allocateAshmemBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& i, size_t rowBytes); Loading