BitmapRegionDecoder.cpp revision c02977e3bbfaaedcb1b1d67e1692becc7dddd59b
1cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber/* 2cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Copyright (C) 2010 The Android Open Source Project 3cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 4cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * you may not use this file except in compliance with the License. 6cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * You may obtain a copy of the License at 7cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 8cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * 10cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * Unless required by applicable law or agreed to in writing, software 11cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * See the License for the specific language governing permissions and 14cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber * limitations under the License. 15cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber */ 16cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 17cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#define LOG_TAG "BitmapRegionDecoder" 18cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 19cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkBitmap.h" 20cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkData.h" 21cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkImageEncoder.h" 22cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "GraphicsJNI.h" 23cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkUtils.h" 24cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkTemplates.h" 25cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "SkPixelRef.h" 265bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "SkStream.h" 275bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "BitmapFactory.h" 28cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "AutoDecodeCancel.h" 29cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "CreateJavaOutputStreamAdaptor.h" 30cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "Utils.h" 31cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "JNIHelp.h" 32cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 33cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "core_jni_helpers.h" 34cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include "android_util_Binder.h" 355bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "android_nio_utils.h" 365bc087c573c70c84c6a39946457590b42d392a33Andreas Huber#include "CreateJavaOutputStreamAdaptor.h" 37cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 38cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <binder/Parcel.h> 39cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <jni.h> 40cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <androidfw/Asset.h> 41cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber#include <sys/stat.h> 42cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 43cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberusing namespace android; 4414f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huber 4514f7672b5d450ed26a06fd3bb3ce045ea78b11b2Andreas Huberclass SkBitmapRegionDecoder { 46cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberpublic: 47cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber SkBitmapRegionDecoder(SkImageDecoder* decoder, int width, int height) { 48bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber fDecoder = decoder; 49bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber fWidth = width; 50bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber fHeight = height; 51bfd4d0d9fe0033abf3f55b94f30f6a58846a875eAndreas Huber } 52f933441648ef6a71dee783d733aac17b9508b452Andreas Huber ~SkBitmapRegionDecoder() { 53f933441648ef6a71dee783d733aac17b9508b452Andreas Huber SkDELETE(fDecoder); 54cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber } 5532f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber 5632f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect, 5732f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber SkColorType pref, int sampleSize) { 5832f3cefa373cd55e63deda36ca9d07c7fe22eaafAndreas Huber fDecoder->setSampleSize(sampleSize); 59cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber return fDecoder->decodeSubset(bitmap, rect, pref); 60cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber } 61f933441648ef6a71dee783d733aac17b9508b452Andreas Huber 62f933441648ef6a71dee783d733aac17b9508b452Andreas Huber SkImageDecoder* getDecoder() const { return fDecoder; } 63b50e83eca302a12f0fced6e7bab1b8617d63deaaRoger Jönsson int getWidth() const { return fWidth; } 64b50e83eca302a12f0fced6e7bab1b8617d63deaaRoger Jönsson int getHeight() const { return fHeight; } 65cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 66cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huberprivate: 67cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber SkImageDecoder* fDecoder; 68cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int fWidth; 69cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber int fHeight; 70cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber}; 71cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 726e3d311b6631b12aac2879d1b08c3534aece78b1Andreas Huberstatic jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) { 73cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber SkImageDecoder* decoder = SkImageDecoder::Factory(stream); 74b50e83eca302a12f0fced6e7bab1b8617d63deaaRoger Jönsson int width, height; 75cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber if (NULL == decoder) { 76cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber doThrowIOE(env, "Image format not supported"); 77cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber return nullObjectReturn("SkImageDecoder::Factory returned null"); 786e3d311b6631b12aac2879d1b08c3534aece78b1Andreas Huber } 796e3d311b6631b12aac2879d1b08c3534aece78b1Andreas Huber 80cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env); 81cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber decoder->setAllocator(javaAllocator); 82cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber javaAllocator->unref(); 83cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber 84cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber if (!decoder->buildTileIndex(stream, &width, &height)) { 85cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber char msg[100]; 86cda17c606b0fe3ccda4dc68a6d43882410ea2462Andreas Huber snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder", 87 decoder->getFormatName()); 88 doThrowIOE(env, msg); 89 SkDELETE(decoder); 90 return nullObjectReturn("decoder->buildTileIndex returned false"); 91 } 92 93 SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height); 94 return GraphicsJNI::createBitmapRegionDecoder(env, bm); 95} 96 97static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 98 jint offset, jint length, jboolean isShareable) { 99 /* If isShareable we could decide to just wrap the java array and 100 share it, but that means adding a globalref to the java array object 101 For now we just always copy the array's data if isShareable. 102 */ 103 AutoJavaByteArray ar(env, byteArray); 104 SkMemoryStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true); 105 106 jobject brd = createBitmapRegionDecoder(env, stream); 107 SkSafeUnref(stream); // the decoder now holds a reference 108 return brd; 109} 110 111static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, 112 jobject fileDescriptor, jboolean isShareable) { 113 NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 114 115 jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 116 117 struct stat fdStat; 118 if (fstat(descriptor, &fdStat) == -1) { 119 doThrowIOE(env, "broken file descriptor"); 120 return nullObjectReturn("fstat return -1"); 121 } 122 123 SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor)); 124 SkMemoryStream* stream = new SkMemoryStream(data); 125 126 jobject brd = createBitmapRegionDecoder(env, stream); 127 SkSafeUnref(stream); // the decoder now holds a reference 128 return brd; 129} 130 131static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, 132 jobject is, // InputStream 133 jbyteArray storage, // byte[] 134 jboolean isShareable) { 135 jobject brd = NULL; 136 // for now we don't allow shareable with java inputstreams 137 SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage); 138 139 if (stream) { 140 brd = createBitmapRegionDecoder(env, stream); 141 stream->unref(); // the decoder now holds a reference 142 } 143 return brd; 144} 145 146static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, 147 jlong native_asset, // Asset 148 jboolean isShareable) { 149 Asset* asset = reinterpret_cast<Asset*>(native_asset); 150 SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset)); 151 if (NULL == stream.get()) { 152 return NULL; 153 } 154 155 jobject brd = createBitmapRegionDecoder(env, stream.get()); 156 // The decoder now holds a reference to stream. 157 return brd; 158} 159 160/* 161 * nine patch not supported 162 * 163 * purgeable not supported 164 * reportSizeToVM not supported 165 */ 166static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, 167 jint start_x, jint start_y, jint width, jint height, jobject options) { 168 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); 169 jobject tileBitmap = NULL; 170 SkImageDecoder *decoder = brd->getDecoder(); 171 int sampleSize = 1; 172 SkColorType prefColorType = kUnknown_SkColorType; 173 bool doDither = true; 174 bool preferQualityOverSpeed = false; 175 bool requireUnpremultiplied = false; 176 177 if (NULL != options) { 178 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 179 // initialize these, in case we fail later on 180 env->SetIntField(options, gOptions_widthFieldID, -1); 181 env->SetIntField(options, gOptions_heightFieldID, -1); 182 env->SetObjectField(options, gOptions_mimeFieldID, 0); 183 184 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 185 prefColorType = GraphicsJNI::getNativeBitmapColorType(env, jconfig); 186 doDither = env->GetBooleanField(options, gOptions_ditherFieldID); 187 preferQualityOverSpeed = env->GetBooleanField(options, 188 gOptions_preferQualityOverSpeedFieldID); 189 // Get the bitmap for re-use if it exists. 190 tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); 191 requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID); 192 } 193 194 decoder->setDitherImage(doDither); 195 decoder->setPreferQualityOverSpeed(preferQualityOverSpeed); 196 decoder->setRequireUnpremultipliedColors(requireUnpremultiplied); 197 AutoDecoderCancel adc(options, decoder); 198 199 // To fix the race condition in case "requestCancelDecode" 200 // happens earlier than AutoDecoderCancel object is added 201 // to the gAutoDecoderCancelMutex linked list. 202 if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { 203 return nullObjectReturn("gOptions_mCancelID");; 204 } 205 206 SkIRect region; 207 region.fLeft = start_x; 208 region.fTop = start_y; 209 region.fRight = start_x + width; 210 region.fBottom = start_y + height; 211 SkBitmap* bitmap = NULL; 212 SkAutoTDelete<SkBitmap> adb; 213 214 if (tileBitmap != NULL) { 215 // Re-use bitmap. 216 bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap); 217 } 218 if (bitmap == NULL) { 219 bitmap = new SkBitmap; 220 adb.reset(bitmap); 221 } 222 223 if (!brd->decodeRegion(bitmap, region, prefColorType, sampleSize)) { 224 return nullObjectReturn("decoder->decodeRegion returned false"); 225 } 226 227 // update options (if any) 228 if (NULL != options) { 229 env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); 230 env->SetIntField(options, gOptions_heightFieldID, bitmap->height()); 231 // TODO: set the mimeType field with the data from the codec. 232 // but how to reuse a set of strings, rather than allocating new one 233 // each time? 234 env->SetObjectField(options, gOptions_mimeFieldID, 235 getMimeTypeString(env, decoder->getFormat())); 236 } 237 238 if (tileBitmap != NULL) { 239 bitmap->notifyPixelsChanged(); 240 return tileBitmap; 241 } 242 243 // detach bitmap from its autodeleter, since we want to own it now 244 adb.detach(); 245 246 JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator(); 247 jbyteArray buff = allocator->getStorageObjAndReset(); 248 249 int bitmapCreateFlags = 0; 250 if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied; 251 return GraphicsJNI::createBitmap(env, bitmap, buff, bitmapCreateFlags, NULL, NULL, -1); 252} 253 254static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) { 255 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); 256 return static_cast<jint>(brd->getHeight()); 257} 258 259static jint nativeGetWidth(JNIEnv* env, jobject, jlong brdHandle) { 260 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); 261 return static_cast<jint>(brd->getWidth()); 262} 263 264static void nativeClean(JNIEnv* env, jobject, jlong brdHandle) { 265 SkBitmapRegionDecoder *brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle); 266 delete brd; 267} 268 269/////////////////////////////////////////////////////////////////////////////// 270 271static JNINativeMethod gBitmapRegionDecoderMethods[] = { 272 { "nativeDecodeRegion", 273 "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 274 (void*)nativeDecodeRegion}, 275 276 { "nativeGetHeight", "(J)I", (void*)nativeGetHeight}, 277 278 { "nativeGetWidth", "(J)I", (void*)nativeGetWidth}, 279 280 { "nativeClean", "(J)V", (void*)nativeClean}, 281 282 { "nativeNewInstance", 283 "([BIIZ)Landroid/graphics/BitmapRegionDecoder;", 284 (void*)nativeNewInstanceFromByteArray 285 }, 286 287 { "nativeNewInstance", 288 "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;", 289 (void*)nativeNewInstanceFromStream 290 }, 291 292 { "nativeNewInstance", 293 "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;", 294 (void*)nativeNewInstanceFromFileDescriptor 295 }, 296 297 { "nativeNewInstance", 298 "(JZ)Landroid/graphics/BitmapRegionDecoder;", 299 (void*)nativeNewInstanceFromAsset 300 }, 301}; 302 303int register_android_graphics_BitmapRegionDecoder(JNIEnv* env) 304{ 305 return android::RegisterMethodsOrDie(env, "android/graphics/BitmapRegionDecoder", 306 gBitmapRegionDecoderMethods, NELEM(gBitmapRegionDecoderMethods)); 307} 308