blob: 7588bd01e4b3d38e835400018be93900c404e4ed [file] [log] [blame]
/*
* 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<uint32_t>(pmap.width()) ? SkToU32(pmap.width()) : 0,
.height = SkTFitsIn<uint32_t>(pmap.height()) ? SkToU32(pmap.height()) : 0,
.stride = SkTFitsIn<uint32_t>(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<SkWStream*>(userContext)->write(data, size);
};
return ANDROID_BITMAP_RESULT_SUCCESS == AndroidBitmap_compress(&info,
SkNDKConversions::toDataSpace(pmap.colorSpace()), pmap.addr(), androidFormat, quality,
reinterpret_cast<void*>(stream), write_to_stream);
}
namespace SkPngEncoder {
std::unique_ptr<SkEncoder> 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<SkData> 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<SkData> 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<SkEncoder> Make(SkWStream*, const SkPixmap&, const Options&) {
SkDEBUGFAIL("Making an encoder is not supported via the NDK");
return nullptr;
}
std::unique_ptr<SkEncoder> 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<SkData> 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 SkEncoder::Frame>, const Options&) {
SkDEBUGFAIL("Encoding Animated WebP images is not supported with the NDK.");
return false;
}
} // namespace SkWebpEncoder