BitmapRegionDecoder.cpp revision 5e49b497ae2019586937aae0e8159292363728b5
1e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin/* 2e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Copyright (C) 2010 The Android Open Source Project 3e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * 4e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Licensed under the Apache License, Version 2.0 (the "License"); 5e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * you may not use this file except in compliance with the License. 6e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * You may obtain a copy of the License at 7e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * 8e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * http://www.apache.org/licenses/LICENSE-2.0 9e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * 10e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * Unless required by applicable law or agreed to in writing, software 11e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * distributed under the License is distributed on an "AS IS" BASIS, 12e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * See the License for the specific language governing permissions and 14e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin * limitations under the License. 15e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin */ 16e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin 17e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#define LOG_TAG "BitmapRegionDecoder" 18e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin 191b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "SkBitmap.h" 20e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkData.h" 21e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkImageEncoder.h" 22e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "GraphicsJNI.h" 23e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkUtils.h" 24e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkTemplates.h" 25e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkPixelRef.h" 26e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "SkStream.h" 27e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "BitmapFactory.h" 28e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "AutoDecodeCancel.h" 291b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "CreateJavaOutputStreamAdaptor.h" 301b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "Utils.h" 311b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "JNIHelp.h" 321b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 33e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include <android_runtime/AndroidRuntime.h> 34e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "android_util_Binder.h" 35e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin#include "android_nio_utils.h" 361b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include "CreateJavaOutputStreamAdaptor.h" 371b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 381b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <binder/Parcel.h> 391b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <jni.h> 401b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <androidfw/Asset.h> 411b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#include <sys/stat.h> 421b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 431b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#if 0 441b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin #define TRACE_BITMAP(code) code 451b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#else 461b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin #define TRACE_BITMAP(code) 471b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin#endif 481b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 491b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinusing namespace android; 501b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 511b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinclass SkBitmapRegionDecoder { 521b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinpublic: 531b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkBitmapRegionDecoder(SkImageDecoder* decoder, int width, int height) { 541b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin fDecoder = decoder; 551b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin fWidth = width; 561b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin fHeight = height; 571b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin } 581b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin ~SkBitmapRegionDecoder() { 591b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkDELETE(fDecoder); 601b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin } 611b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 621b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin bool decodeRegion(SkBitmap* bitmap, const SkIRect& rect, 631b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkBitmap::Config pref, int sampleSize) { 64e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin fDecoder->setSampleSize(sampleSize); 651b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin return fDecoder->decodeRegion(bitmap, rect, pref); 661b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin } 671b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 681b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkImageDecoder* getDecoder() const { return fDecoder; } 691b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int getWidth() const { return fWidth; } 701b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int getHeight() const { return fHeight; } 711b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 721b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinprivate: 731b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkImageDecoder* fDecoder; 741b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int fWidth; 751b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int fHeight; 761b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin}; 771b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 781b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject createBitmapRegionDecoder(JNIEnv* env, SkStreamRewindable* stream) { 791b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkImageDecoder* decoder = SkImageDecoder::Factory(stream); 801b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int width, height; 811b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin if (NULL == decoder) { 821b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin doThrowIOE(env, "Image format not supported"); 831b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin return nullObjectReturn("SkImageDecoder::Factory returned null"); 841b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin } 85e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin 86e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env); 87e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin decoder->setAllocator(javaAllocator); 88e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin javaAllocator->unref(); 89e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin 90e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin if (!decoder->buildTileIndex(stream, &width, &height)) { 91e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin char msg[100]; 92e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder", 93e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin decoder->getFormatName()); 941b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin doThrowIOE(env, msg); 951b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkDELETE(decoder); 96e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin return nullObjectReturn("decoder->buildTileIndex returned false"); 97e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin } 98e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin 99e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height); 100e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin return GraphicsJNI::createBitmapRegionDecoder(env, bm); 101e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin} 1021b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 1031b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray, 1041b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin int offset, int length, jboolean isShareable) { 1051b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin /* If isShareable we could decide to just wrap the java array and 1061b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin share it, but that means adding a globalref to the java array object 1071b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin For now we just always copy the array's data if isShareable. 1081b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin */ 1091b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin AutoJavaByteArray ar(env, byteArray); 1101b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkStreamRewindable* stream = new SkMemoryStream(ar.ptr() + offset, length, true); 1111b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 1121b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin jobject brd = createBitmapRegionDecoder(env, stream); 1131b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin SkSafeUnref(stream); // the decoder now holds a reference 1141b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin return brd; 1151b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin} 1161b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 1171b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolinstatic jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz, 1181b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin jobject fileDescriptor, jboolean isShareable) { 1191b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin NPE_CHECK_RETURN_ZERO(env, fileDescriptor); 1201b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 1211b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); 1221b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 1231b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin struct stat fdStat; 1241b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin if (fstat(descriptor, &fdStat) == -1) { 1251b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin doThrowIOE(env, "broken file descriptor"); 1261b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin return nullObjectReturn("fstat return -1"); 1271b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin } 1281b15ba5d194c1db71d0a34ee110bd1ab169c8a29Luca Zanolin 129e6d368218918f911b1954296dab25bf84147b4c6Luca Zanolin SkAutoTUnref<SkData> data(SkData::NewFromFD(descriptor)); 130 SkMemoryStream* stream = new SkMemoryStream(data); 131 132 jobject brd = createBitmapRegionDecoder(env, stream); 133 SkSafeUnref(stream); // the decoder now holds a reference 134 return brd; 135} 136 137static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz, 138 jobject is, // InputStream 139 jbyteArray storage, // byte[] 140 jboolean isShareable) { 141 jobject brd = NULL; 142 // for now we don't allow shareable with java inputstreams 143 SkStreamRewindable* stream = CopyJavaInputStream(env, is, storage); 144 145 if (stream) { 146 brd = createBitmapRegionDecoder(env, stream); 147 stream->unref(); // the decoder now holds a reference 148 } 149 return brd; 150} 151 152static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz, 153 jint native_asset, // Asset 154 jboolean isShareable) { 155 Asset* asset = reinterpret_cast<Asset*>(native_asset); 156 SkAutoTUnref<SkMemoryStream> stream(CopyAssetToStream(asset)); 157 if (NULL == stream.get()) { 158 return NULL; 159 } 160 161 jobject brd = createBitmapRegionDecoder(env, stream.get()); 162 // The decoder now holds a reference to stream. 163 return brd; 164} 165 166/* 167 * nine patch not supported 168 * 169 * purgeable not supported 170 * reportSizeToVM not supported 171 */ 172static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd, 173 int start_x, int start_y, int width, int height, jobject options) { 174 jobject tileBitmap = NULL; 175 SkImageDecoder *decoder = brd->getDecoder(); 176 int sampleSize = 1; 177 SkBitmap::Config prefConfig = SkBitmap::kNo_Config; 178 bool doDither = true; 179 bool preferQualityOverSpeed = false; 180 bool requireUnpremultiplied = false; 181 182 if (NULL != options) { 183 sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID); 184 // initialize these, in case we fail later on 185 env->SetIntField(options, gOptions_widthFieldID, -1); 186 env->SetIntField(options, gOptions_heightFieldID, -1); 187 env->SetObjectField(options, gOptions_mimeFieldID, 0); 188 189 jobject jconfig = env->GetObjectField(options, gOptions_configFieldID); 190 prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig); 191 doDither = env->GetBooleanField(options, gOptions_ditherFieldID); 192 preferQualityOverSpeed = env->GetBooleanField(options, 193 gOptions_preferQualityOverSpeedFieldID); 194 // Get the bitmap for re-use if it exists. 195 tileBitmap = env->GetObjectField(options, gOptions_bitmapFieldID); 196 requireUnpremultiplied = !env->GetBooleanField(options, gOptions_premultipliedFieldID); 197 } 198 199 decoder->setDitherImage(doDither); 200 decoder->setPreferQualityOverSpeed(preferQualityOverSpeed); 201 decoder->setRequireUnpremultipliedColors(requireUnpremultiplied); 202 AutoDecoderCancel adc(options, decoder); 203 204 // To fix the race condition in case "requestCancelDecode" 205 // happens earlier than AutoDecoderCancel object is added 206 // to the gAutoDecoderCancelMutex linked list. 207 if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) { 208 return nullObjectReturn("gOptions_mCancelID");; 209 } 210 211 SkIRect region; 212 region.fLeft = start_x; 213 region.fTop = start_y; 214 region.fRight = start_x + width; 215 region.fBottom = start_y + height; 216 SkBitmap* bitmap = NULL; 217 SkAutoTDelete<SkBitmap> adb; 218 219 if (tileBitmap != NULL) { 220 // Re-use bitmap. 221 bitmap = GraphicsJNI::getNativeBitmap(env, tileBitmap); 222 } 223 if (bitmap == NULL) { 224 bitmap = new SkBitmap; 225 adb.reset(bitmap); 226 } 227 228 if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) { 229 return nullObjectReturn("decoder->decodeRegion returned false"); 230 } 231 232 // update options (if any) 233 if (NULL != options) { 234 env->SetIntField(options, gOptions_widthFieldID, bitmap->width()); 235 env->SetIntField(options, gOptions_heightFieldID, bitmap->height()); 236 // TODO: set the mimeType field with the data from the codec. 237 // but how to reuse a set of strings, rather than allocating new one 238 // each time? 239 env->SetObjectField(options, gOptions_mimeFieldID, 240 getMimeTypeString(env, decoder->getFormat())); 241 } 242 243 if (tileBitmap != NULL) { 244 return tileBitmap; 245 } 246 247 // detach bitmap from its autodeleter, since we want to own it now 248 adb.detach(); 249 250 JavaPixelAllocator* allocator = (JavaPixelAllocator*) decoder->getAllocator(); 251 jbyteArray buff = allocator->getStorageObjAndReset(); 252 253 int bitmapCreateFlags = 0; 254 if (!requireUnpremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied; 255 return GraphicsJNI::createBitmap(env, bitmap, buff, bitmapCreateFlags, NULL, NULL, -1); 256} 257 258static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) { 259 return brd->getHeight(); 260} 261 262static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) { 263 return brd->getWidth(); 264} 265 266static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) { 267 delete brd; 268} 269 270/////////////////////////////////////////////////////////////////////////////// 271 272#include <android_runtime/AndroidRuntime.h> 273 274static JNINativeMethod gBitmapRegionDecoderMethods[] = { 275 { "nativeDecodeRegion", 276 "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;", 277 (void*)nativeDecodeRegion}, 278 279 { "nativeGetHeight", "(I)I", (void*)nativeGetHeight}, 280 281 { "nativeGetWidth", "(I)I", (void*)nativeGetWidth}, 282 283 { "nativeClean", "(I)V", (void*)nativeClean}, 284 285 { "nativeNewInstance", 286 "([BIIZ)Landroid/graphics/BitmapRegionDecoder;", 287 (void*)nativeNewInstanceFromByteArray 288 }, 289 290 { "nativeNewInstance", 291 "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;", 292 (void*)nativeNewInstanceFromStream 293 }, 294 295 { "nativeNewInstance", 296 "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;", 297 (void*)nativeNewInstanceFromFileDescriptor 298 }, 299 300 { "nativeNewInstance", 301 "(IZ)Landroid/graphics/BitmapRegionDecoder;", 302 (void*)nativeNewInstanceFromAsset 303 }, 304}; 305 306#define kClassPathName "android/graphics/BitmapRegionDecoder" 307 308int register_android_graphics_BitmapRegionDecoder(JNIEnv* env) 309{ 310 return android::AndroidRuntime::registerNativeMethods(env, kClassPathName, 311 gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods)); 312} 313