/* * Copyright 2020 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkBitmap.h" #include "include/core/SkPixmap.h" #include "include/core/SkStream.h" #include "include/encode/SkJpegEncoder.h" #include "include/encode/SkPngEncoder.h" #include "include/encode/SkWebpEncoder.h" #include "include/private/base/SkTFitsIn.h" #include "include/private/base/SkTo.h" #include "src/encode/SkImageEncoderPriv.h" #include "src/image/SkImage_Base.h" #include "src/ports/SkNDKConversions.h" static AndroidBitmapInfo info_for_pixmap(const SkPixmap& pmap) { // If any of these values is invalid (e.g. set to zero), the info will be rejected by // AndroidBitmap_compress. AndroidBitmapInfo info { .width = SkTFitsIn(pmap.width()) ? SkToU32(pmap.width()) : 0, .height = SkTFitsIn(pmap.height()) ? SkToU32(pmap.height()) : 0, .stride = SkTFitsIn(pmap.rowBytes()) ? SkToU32(pmap.rowBytes()) : 0, .format = SkNDKConversions::toAndroidBitmapFormat(pmap.colorType()) }; switch (pmap.alphaType()) { case kPremul_SkAlphaType: info.flags = ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; break; case kOpaque_SkAlphaType: info.flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; break; case kUnpremul_SkAlphaType: info.flags = ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; break; default: SkDEBUGFAIL("unspecified alphaType"); info.flags = ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; break; } return info; } static bool write_image_to_stream(SkWStream* stream, const SkPixmap& pmap, AndroidBitmapCompressFormat androidFormat, int quality) { AndroidBitmapInfo info = info_for_pixmap(pmap); auto write_to_stream = [](void* userContext, const void* data, size_t size) { return reinterpret_cast(userContext)->write(data, size); }; return ANDROID_BITMAP_RESULT_SUCCESS == AndroidBitmap_compress(&info, SkNDKConversions::toDataSpace(pmap.colorSpace()), pmap.addr(), androidFormat, quality, reinterpret_cast(stream), write_to_stream); } namespace SkPngEncoder { std::unique_ptr Make(SkWStream*, const SkPixmap&, const Options&) { SkDEBUGFAIL("Making an encoder is not supported via the NDK"); return nullptr; } bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) { return write_image_to_stream(dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_PNG, 100); } sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) { if (!img) { return nullptr; } SkBitmap bm; if (!as_IB(img)->getROPixels(ctx, &bm)) { return nullptr; } SkDynamicMemoryWStream stream; if (Encode(&stream, bm.pixmap(), options)) { return stream.detachAsData(); } return nullptr; } } // namespace SkPngEncoder namespace SkJpegEncoder { bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) { return write_image_to_stream(dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_JPEG, options.fQuality); } bool Encode(SkWStream*, const SkYUVAPixmaps&, const SkColorSpace*, const Options&) { SkDEBUGFAIL("encoding a YUVA pixmap is not supported via the NDK"); return false; } sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) { if (!img) { return nullptr; } SkBitmap bm; if (!as_IB(img)->getROPixels(ctx, &bm)) { return nullptr; } SkDynamicMemoryWStream stream; if (Encode(&stream, bm.pixmap(), options)) { return stream.detachAsData(); } return nullptr; } std::unique_ptr Make(SkWStream*, const SkPixmap&, const Options&) { SkDEBUGFAIL("Making an encoder is not supported via the NDK"); return nullptr; } std::unique_ptr Make(SkWStream*, const SkYUVAPixmaps&, const SkColorSpace*, const Options&) { SkDEBUGFAIL("Making an encoder is not supported via the NDK"); return nullptr; } } // namespace SkJpegEncoder namespace SkWebpEncoder { bool Encode(SkWStream* dst, const SkPixmap& src, const Options& options) { if (options.fCompression == Compression::kLossless) { return write_image_to_stream( dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSLESS, options.fQuality); } return write_image_to_stream( dst, src, ANDROID_BITMAP_COMPRESS_FORMAT_WEBP_LOSSY, options.fQuality); } sk_sp Encode(GrDirectContext* ctx, const SkImage* img, const Options& options) { if (!img) { return nullptr; } SkBitmap bm; if (!as_IB(img)->getROPixels(ctx, &bm)) { return nullptr; } SkDynamicMemoryWStream stream; if (Encode(&stream, bm.pixmap(), options)) { return stream.detachAsData(); } return nullptr; } bool EncodeAnimated(SkWStream*, SkSpan, const Options&) { SkDEBUGFAIL("Encoding Animated WebP images is not supported with the NDK."); return false; } } // namespace SkWebpEncoder