ImageUtils.java revision 9418aa1ad5f48066e41b3b5405c6c03caf3653d9
1/* 2 * Copyright (C) 2011 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.ex.photo.util; 19 20import android.content.ContentResolver; 21import android.graphics.Bitmap; 22import android.graphics.BitmapFactory; 23import android.graphics.Point; 24import android.graphics.Rect; 25import android.net.Uri; 26import android.os.Build; 27import android.util.Log; 28 29import com.android.ex.photo.PhotoViewActivity; 30 31import java.io.FileNotFoundException; 32import java.io.IOException; 33import java.io.InputStream; 34 35/** 36 * Image utilities 37 */ 38public class ImageUtils { 39 // Logging 40 private static final String TAG = "ImageUtils"; 41 42 /** Minimum class memory class to use full-res photos */ 43 private final static long MIN_NORMAL_CLASS = 32; 44 /** Minimum class memory class to use small photos */ 45 private final static long MIN_SMALL_CLASS = 24; 46 47 public static enum ImageSize { 48 EXTRA_SMALL, 49 SMALL, 50 NORMAL, 51 } 52 53 public static final ImageSize sUseImageSize; 54 static { 55 // On HC and beyond, assume devices are more capable 56 if (Build.VERSION.SDK_INT >= 11) { 57 sUseImageSize = ImageSize.NORMAL; 58 } else { 59 if (PhotoViewActivity.sMemoryClass >= MIN_NORMAL_CLASS) { 60 // We have plenty of memory; use full sized photos 61 sUseImageSize = ImageSize.NORMAL; 62 } else if (PhotoViewActivity.sMemoryClass >= MIN_SMALL_CLASS) { 63 // We have slight less memory; use smaller sized photos 64 sUseImageSize = ImageSize.SMALL; 65 } else { 66 // We have little memory; use very small sized photos 67 sUseImageSize = ImageSize.EXTRA_SMALL; 68 } 69 } 70 } 71 72 /** 73 * @return true if the MimeType type is image 74 */ 75 public static boolean isImageMimeType(String mimeType) { 76 return mimeType != null && mimeType.startsWith("image/"); 77 } 78 79 /** 80 * Create a bitmap from a local URI 81 * 82 * @param resolver The ContentResolver 83 * @param uri The local URI 84 * @param maxSize The maximum size (either width or height) 85 * 86 * @return The new bitmap 87 */ 88 public static Bitmap createLocalBitmap(ContentResolver resolver, Uri uri, int maxSize) { 89 InputStream inputStream = null; 90 try { 91 final BitmapFactory.Options opts = new BitmapFactory.Options(); 92 final Point bounds = getImageBounds(resolver, uri); 93 94 inputStream = resolver.openInputStream(uri); 95 opts.inSampleSize = Math.max(bounds.x / maxSize, bounds.y / maxSize); 96 97 final Bitmap decodedBitmap = decodeStream(inputStream, null, opts); 98 99 // Correct thumbnail orientation as necessary 100 // TODO: Fix rotation if it's actually a problem 101 //return rotateBitmap(resolver, uri, decodedBitmap); 102 return decodedBitmap; 103 104 } catch (FileNotFoundException exception) { 105 // Do nothing - the photo will appear to be missing 106 } catch (IOException exception) { 107 // Do nothing - the photo will appear to be missing 108 } finally { 109 try { 110 if (inputStream != null) { 111 inputStream.close(); 112 } 113 } catch (IOException ignore) { 114 } 115 } 116 return null; 117 } 118 119 /** 120 * Wrapper around {@link BitmapFactory#decodeStream(InputStream, Rect, 121 * BitmapFactory.Options)} that returns {@code null} on {@link 122 * OutOfMemoryError}. 123 * 124 * @param is The input stream that holds the raw data to be decoded into a 125 * bitmap. 126 * @param outPadding If not null, return the padding rect for the bitmap if 127 * it exists, otherwise set padding to [-1,-1,-1,-1]. If 128 * no bitmap is returned (null) then padding is 129 * unchanged. 130 * @param opts null-ok; Options that control downsampling and whether the 131 * image should be completely decoded, or just is size returned. 132 * @return The decoded bitmap, or null if the image data could not be 133 * decoded, or, if opts is non-null, if opts requested only the 134 * size be returned (in opts.outWidth and opts.outHeight) 135 */ 136 public static Bitmap decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts) { 137 try { 138 return BitmapFactory.decodeStream(is, outPadding, opts); 139 } catch (OutOfMemoryError oome) { 140 Log.e(TAG, "ImageUtils#decodeStream(InputStream, Rect, Options) threw an OOME", oome); 141 return null; 142 } 143 } 144 145 /** 146 * Gets the image bounds 147 * 148 * @param resolver The ContentResolver 149 * @param uri The uri 150 * 151 * @return The image bounds 152 */ 153 private static Point getImageBounds(ContentResolver resolver, Uri uri) 154 throws IOException { 155 final BitmapFactory.Options opts = new BitmapFactory.Options(); 156 InputStream inputStream = null; 157 158 try { 159 opts.inJustDecodeBounds = true; 160 inputStream = resolver.openInputStream(uri); 161 decodeStream(inputStream, null, opts); 162 163 return new Point(opts.outWidth, opts.outHeight); 164 } finally { 165 try { 166 if (inputStream != null) { 167 inputStream.close(); 168 } 169 } catch (IOException ignore) { 170 } 171 } 172 } 173} 174