Merge "Gainmap: Implement gainmap support in BitmapFactory"
This commit is contained in:
committed by
Android (Google) Code Review
commit
934b9209ff
@@ -2,6 +2,20 @@
|
||||
#define LOG_TAG "BitmapFactory"
|
||||
|
||||
#include "BitmapFactory.h"
|
||||
|
||||
#include <Gainmap.h>
|
||||
#include <HardwareBitmapUploader.h>
|
||||
#include <androidfw/Asset.h>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <fcntl.h>
|
||||
#include <nativehelper/JNIPlatformHelp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "CreateJavaOutputStreamAdaptor.h"
|
||||
#include "FrontBufferedStream.h"
|
||||
#include "GraphicsJNI.h"
|
||||
@@ -13,6 +27,7 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkColorSpace.h"
|
||||
#include "SkEncodedImageFormat.h"
|
||||
#include "SkGainmapInfo.h"
|
||||
#include "SkImageInfo.h"
|
||||
#include "SkPaint.h"
|
||||
#include "SkPixelRef.h"
|
||||
@@ -24,17 +39,6 @@
|
||||
#include "SkString.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <HardwareBitmapUploader.h>
|
||||
#include <nativehelper/JNIPlatformHelp.h>
|
||||
#include <androidfw/Asset.h>
|
||||
#include <androidfw/ResourceTypes.h>
|
||||
#include <cutils/compiler.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
jfieldID gOptions_justBoundsFieldID;
|
||||
jfieldID gOptions_sampleSizeFieldID;
|
||||
jfieldID gOptions_configFieldID;
|
||||
@@ -182,6 +186,115 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
|
||||
needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
|
||||
}
|
||||
|
||||
static bool decodeGainmap(std::unique_ptr<SkStream> gainmapStream, const SkGainmapInfo& gainmapInfo,
|
||||
sp<uirenderer::Gainmap>* outGainmap, const int sampleSize, float scale) {
|
||||
std::unique_ptr<SkAndroidCodec> codec;
|
||||
codec = SkAndroidCodec::MakeFromStream(std::move(gainmapStream), nullptr);
|
||||
if (!codec) {
|
||||
ALOGE("Can not create a codec for Gainmap.");
|
||||
return false;
|
||||
}
|
||||
SkColorType decodeColorType = codec->computeOutputColorType(kN32_SkColorType);
|
||||
sk_sp<SkColorSpace> decodeColorSpace = codec->computeOutputColorSpace(decodeColorType, nullptr);
|
||||
|
||||
SkISize size = codec->getSampledDimensions(sampleSize);
|
||||
|
||||
int scaledWidth = size.width();
|
||||
int scaledHeight = size.height();
|
||||
bool willScale = false;
|
||||
|
||||
// Apply a fine scaling step if necessary.
|
||||
if (needsFineScale(codec->getInfo().dimensions(), size, sampleSize) || scale != 1.0f) {
|
||||
willScale = true;
|
||||
// The operation below may loose precision (integer division), but it is put this way to
|
||||
// mimic main image scale calculation
|
||||
scaledWidth = static_cast<int>((codec->getInfo().width() / sampleSize) * scale + 0.5f);
|
||||
scaledHeight = static_cast<int>((codec->getInfo().height() / sampleSize) * scale + 0.5f);
|
||||
}
|
||||
|
||||
SkAlphaType alphaType = codec->computeOutputAlphaType(false);
|
||||
|
||||
const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType,
|
||||
alphaType, decodeColorSpace);
|
||||
|
||||
const SkImageInfo& bitmapInfo = decodeInfo;
|
||||
SkBitmap decodeBitmap;
|
||||
sk_sp<Bitmap> nativeBitmap = nullptr;
|
||||
|
||||
if (!decodeBitmap.setInfo(bitmapInfo)) {
|
||||
ALOGE("Failed to setInfo.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (willScale) {
|
||||
if (!decodeBitmap.tryAllocPixels(nullptr)) {
|
||||
ALOGE("OOM allocating gainmap pixels.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
nativeBitmap = android::Bitmap::allocateHeapBitmap(&decodeBitmap);
|
||||
if (!nativeBitmap) {
|
||||
ALOGE("OOM allocating gainmap pixels.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Use SkAndroidCodec to perform the decode.
|
||||
SkAndroidCodec::AndroidOptions codecOptions;
|
||||
codecOptions.fZeroInitialized = SkCodec::kYes_ZeroInitialized;
|
||||
codecOptions.fSampleSize = sampleSize;
|
||||
SkCodec::Result result = codec->getAndroidPixels(decodeInfo, decodeBitmap.getPixels(),
|
||||
decodeBitmap.rowBytes(), &codecOptions);
|
||||
switch (result) {
|
||||
case SkCodec::kSuccess:
|
||||
case SkCodec::kIncompleteInput:
|
||||
break;
|
||||
default:
|
||||
ALOGE("Error decoding gainmap.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (willScale) {
|
||||
SkBitmap gainmapBitmap;
|
||||
const float scaleX = scaledWidth / float(decodeBitmap.width());
|
||||
const float scaleY = scaledHeight / float(decodeBitmap.height());
|
||||
|
||||
SkColorType scaledColorType = decodeBitmap.colorType();
|
||||
gainmapBitmap.setInfo(
|
||||
bitmapInfo.makeWH(scaledWidth, scaledHeight).makeColorType(scaledColorType));
|
||||
|
||||
nativeBitmap = android::Bitmap::allocateHeapBitmap(&gainmapBitmap);
|
||||
if (!nativeBitmap) {
|
||||
ALOGE("OOM allocating gainmap pixels.");
|
||||
return false;
|
||||
}
|
||||
|
||||
SkPaint paint;
|
||||
// kSrc_Mode instructs us to overwrite the uninitialized pixels in
|
||||
// outputBitmap. Otherwise we would blend by default, which is not
|
||||
// what we want.
|
||||
paint.setBlendMode(SkBlendMode::kSrc);
|
||||
|
||||
SkCanvas canvas(gainmapBitmap, SkCanvas::ColorBehavior::kLegacy);
|
||||
canvas.scale(scaleX, scaleY);
|
||||
decodeBitmap.setImmutable(); // so .asImage() doesn't make a copy
|
||||
canvas.drawImage(decodeBitmap.asImage(), 0.0f, 0.0f,
|
||||
SkSamplingOptions(SkFilterMode::kLinear), &paint);
|
||||
}
|
||||
|
||||
auto gainmap = sp<uirenderer::Gainmap>::make();
|
||||
if (!gainmap) {
|
||||
ALOGE("OOM allocating Gainmap");
|
||||
return false;
|
||||
}
|
||||
|
||||
gainmap->info = gainmapInfo;
|
||||
gainmap->bitmap = std::move(nativeBitmap);
|
||||
*outGainmap = std::move(gainmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
|
||||
jobject padding, jobject options, jlong inBitmapHandle,
|
||||
jlong colorSpaceHandle) {
|
||||
@@ -485,6 +598,19 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
|
||||
return nullObjectReturn("Got null SkPixelRef");
|
||||
}
|
||||
|
||||
bool hasGainmap = false;
|
||||
SkGainmapInfo gainmapInfo;
|
||||
std::unique_ptr<SkStream> gainmapStream = nullptr;
|
||||
sp<uirenderer::Gainmap> gainmap = nullptr;
|
||||
if (result == SkCodec::kSuccess) {
|
||||
hasGainmap = codec->getAndroidGainmap(&gainmapInfo, &gainmapStream);
|
||||
}
|
||||
|
||||
if (hasGainmap) {
|
||||
hasGainmap =
|
||||
decodeGainmap(std::move(gainmapStream), gainmapInfo, &gainmap, sampleSize, scale);
|
||||
}
|
||||
|
||||
if (!isMutable && javaBitmap == NULL) {
|
||||
// promise we will never change our pixels (great for sharing and pictures)
|
||||
outputBitmap.setImmutable();
|
||||
@@ -492,6 +618,9 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
|
||||
|
||||
bool isPremultiplied = !requireUnpremultiplied;
|
||||
if (javaBitmap != nullptr) {
|
||||
if (hasGainmap) {
|
||||
reuseBitmap->setGainmap(std::move(gainmap));
|
||||
}
|
||||
bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
|
||||
outputBitmap.notifyPixelsChanged();
|
||||
// If a java bitmap was passed in for reuse, pass it back
|
||||
@@ -507,13 +636,22 @@ static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
|
||||
if (!hardwareBitmap.get()) {
|
||||
return nullObjectReturn("Failed to allocate a hardware bitmap");
|
||||
}
|
||||
if (hasGainmap) {
|
||||
hardwareBitmap->setGainmap(std::move(gainmap));
|
||||
}
|
||||
|
||||
return bitmap::createBitmap(env, hardwareBitmap.release(), bitmapCreateFlags,
|
||||
ninePatchChunk, ninePatchInsets, -1);
|
||||
}
|
||||
|
||||
Bitmap* heapBitmap = defaultAllocator.getStorageObjAndReset();
|
||||
if (hasGainmap && heapBitmap != nullptr) {
|
||||
heapBitmap->setGainmap(std::move(gainmap));
|
||||
}
|
||||
|
||||
// now create the java bitmap
|
||||
return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
|
||||
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
|
||||
return bitmap::createBitmap(env, heapBitmap, bitmapCreateFlags, ninePatchChunk, ninePatchInsets,
|
||||
-1);
|
||||
}
|
||||
|
||||
static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
|
||||
|
||||
Reference in New Issue
Block a user