diff options
author | Ray Chen <raychen@google.com> | 2010-01-26 14:43:35 -0800 |
---|---|---|
committer | Ray Chen <raychen@google.com> | 2010-01-29 14:30:05 -0800 |
commit | bf124e7e41f7850ac1b7be808221a462db6f3447 (patch) | |
tree | e831e6443bc122c5c8f35c4560517cd09ec7852b /media/java/android | |
parent | c88ed5dc5de7b2a7a02f975c83ee12e0fc1df27f (diff) | |
download | frameworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.zip frameworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.tar.gz frameworks_base-bf124e7e41f7850ac1b7be808221a462db6f3447.tar.bz2 |
Unhide ThumbnailUtils to support Camera unbundling.
http://b/2375978
Diffstat (limited to 'media/java/android')
-rw-r--r-- | media/java/android/media/MiniThumbFile.java | 1 | ||||
-rw-r--r-- | media/java/android/media/ThumbnailUtils.java (renamed from media/java/android/media/ThumbnailUtil.java) | 414 |
2 files changed, 230 insertions, 185 deletions
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java index f6e6317..df141c1 100644 --- a/media/java/android/media/MiniThumbFile.java +++ b/media/java/android/media/MiniThumbFile.java @@ -17,7 +17,6 @@ package android.media; import android.graphics.Bitmap; -import android.media.ThumbnailUtil; import android.net.Uri; import android.os.Environment; import android.util.Log; diff --git a/media/java/android/media/ThumbnailUtil.java b/media/java/android/media/ThumbnailUtils.java index 0cf4e76..225d4b6 100644 --- a/media/java/android/media/ThumbnailUtil.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -16,13 +16,6 @@ package android.media; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; -import android.provider.MediaStore.Images; -import android.provider.MediaStore.Images.Thumbnails; -import android.util.Log; - import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -34,47 +27,171 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.media.MediaMetadataRetriever; import android.media.MediaFile.MediaFileType; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.provider.BaseColumns; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Images.Thumbnails; +import android.util.Log; import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; /** - * Thumbnail generation routines for media provider. This class should only be used internaly. - * {@hide} THIS IS NOT FOR PUBLIC API. + * Thumbnail generation routines for media provider. */ -public class ThumbnailUtil { - private static final String TAG = "ThumbnailUtil"; - //Whether we should recycle the input (unless the output is the input). +public class ThumbnailUtils { + private static final String TAG = "ThumbnailUtils"; + + /* Maximum pixels size for created bitmap. */ + private static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384; + private static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128; + private static final int UNCONSTRAINED = -1; + + /* Whether we should rotate the resulting bitmap. */ + private static final boolean ROTATE_AS_NEEDED = true; + private static final boolean NO_ROTATE = false; + + /* Whether we should create bitmap in native memory. */ + private static final boolean USE_NATIVE = true; + private static final boolean NO_NATIVE = false; + + /** + * Constant used to indicate we should recycle the input in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)} unless the output is the input. + */ public static final boolean RECYCLE_INPUT = true; + + /** + * Constant used to indicate we should not recycle the input in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final boolean NO_RECYCLE_INPUT = false; - public static final boolean ROTATE_AS_NEEDED = true; - public static final boolean NO_ROTATE = false; - public static final boolean USE_NATIVE = true; - public static final boolean NO_NATIVE = false; + /** + * Constant used to indicate the dimension of normal thumbnail in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final int THUMBNAIL_TARGET_SIZE = 320; + + /** + * Constant used to indicate the dimension of mini thumbnail in + * {@link #extractMiniThumb(Bitmap, int, int, boolean)}. + */ public static final int MINI_THUMB_TARGET_SIZE = 96; - public static final int THUMBNAIL_MAX_NUM_PIXELS = 512 * 384; - public static final int MINI_THUMB_MAX_NUM_PIXELS = 128 * 128; - public static final int UNCONSTRAINED = -1; - // Returns Options that set the native alloc flag for Bitmap decode. - public static BitmapFactory.Options createNativeAllocOptions() { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inNativeAlloc = true; - return options; + /** + * This method first examines if the thumbnail embedded in EXIF is bigger than our target + * size. If not, then it'll create a thumbnail from original image. Due to efficiency + * consideration, we want to let MediaThumbRequest avoid calling this method twice for + * both kinds, so it only requests for MICRO_KIND and set saveImage to true. + * + * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. + * + * @param cr ContentResolver + * @param filePath file path needed by EXIF interface + * @param uri URI of original image + * @param origId image id + * @param kind either MINI_KIND or MICRO_KIND + * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method. + * @return Bitmap + */ + public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri, + long origId, int kind, boolean saveMini) { + boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini); + int targetSize = wantMini ? + THUMBNAIL_TARGET_SIZE : MINI_THUMB_TARGET_SIZE; + int maxPixels = wantMini ? + THUMBNAIL_MAX_NUM_PIXELS : MINI_THUMB_MAX_NUM_PIXELS; + SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); + Bitmap bitmap = null; + MediaFileType fileType = MediaFile.getFileType(filePath); + if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) { + createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); + bitmap = sizedThumbnailBitmap.mBitmap; + } + + if (bitmap == null) { + bitmap = makeBitmap(targetSize, maxPixels, uri, cr); + } + + if (bitmap == null) { + return null; + } + + if (saveMini) { + if (sizedThumbnailBitmap.mThumbnailData != null) { + storeThumbnail(cr, origId, + sizedThumbnailBitmap.mThumbnailData, + sizedThumbnailBitmap.mThumbnailWidth, + sizedThumbnailBitmap.mThumbnailHeight); + } else { + storeThumbnail(cr, origId, bitmap); + } + } + + if (kind == Images.Thumbnails.MICRO_KIND) { + // now we make it a "square thumbnail" for MICRO_KIND thumbnail + bitmap = extractMiniThumb(bitmap, + MINI_THUMB_TARGET_SIZE, + MINI_THUMB_TARGET_SIZE, RECYCLE_INPUT); + } + return bitmap; } + /** - * Make a bitmap from a given Uri. + * Create a video thumbnail for a video. May return null if the video is + * corrupt. * - * @param uri + * @param filePath */ - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, - Uri uri, ContentResolver cr) { - return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, - NO_NATIVE); + public static Bitmap createVideoThumbnail(String filePath) { + Bitmap bitmap = null; + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + try { + retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); + retriever.setDataSource(filePath); + bitmap = retriever.captureFrame(); + } catch (IllegalArgumentException ex) { + // Assume this is a corrupt video file + } catch (RuntimeException ex) { + // Assume this is a corrupt video file. + } finally { + try { + retriever.release(); + } catch (RuntimeException ex) { + // Ignore failures while cleaning up. + } + } + return bitmap; + } + + /** + * Creates a centered bitmap of the desired size. + * + * @param source original bitmap source + * @param width targeted width + * @param height targeted height + * @param recycle whether we want to recycle the input + */ + public static Bitmap extractMiniThumb( + Bitmap source, int width, int height, boolean recycle) { + if (source == null) { + return null; + } + + float scale; + if (source.getWidth() < source.getHeight()) { + scale = width / (float) source.getWidth(); + } else { + scale = height / (float) source.getHeight(); + } + Matrix matrix = new Matrix(); + matrix.setScale(scale, scale); + Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle); + return miniThumbnail; } /* @@ -96,7 +213,7 @@ public class ThumbnailUtil { * For example, BitmapFactory downsamples an image by 2 even though the * request is 3. So we round up the sample size to avoid OOM. */ - public static int computeSampleSize(BitmapFactory.Options options, + private static int computeSampleSize(BitmapFactory.Options options, int minSideLength, int maxNumOfPixels) { int initialSize = computeInitialSampleSize(options, minSideLength, maxNumOfPixels); @@ -140,7 +257,30 @@ public class ThumbnailUtil { } } - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + /** + * Returns Options that set the native alloc flag for Bitmap decode. + */ + private static BitmapFactory.Options createNativeAllocOptions() { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inNativeAlloc = true; + return options; + } + + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + Uri uri, ContentResolver cr) { + return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, + NO_NATIVE); + } + + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + * The image data will be read from specified ContentResolver and clients are allowed to specify + * whether they want the Bitmap be created in native memory. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, Uri uri, ContentResolver cr, boolean useNative) { ParcelFileDescriptor input = null; try { @@ -159,49 +299,18 @@ public class ThumbnailUtil { } } - // Rotates the bitmap by the specified degree. - // If a new bitmap is created, the original bitmap is recycled. - public static Bitmap rotate(Bitmap b, int degrees) { - if (degrees != 0 && b != null) { - Matrix m = new Matrix(); - m.setRotate(degrees, - (float) b.getWidth() / 2, (float) b.getHeight() / 2); - try { - Bitmap b2 = Bitmap.createBitmap( - b, 0, 0, b.getWidth(), b.getHeight(), m, true); - if (b != b2) { - b.recycle(); - b = b2; - } - } catch (OutOfMemoryError ex) { - // We have no memory to rotate. Return the original bitmap. - } - } - return b; - } - - private static void closeSilently(ParcelFileDescriptor c) { - if (c == null) return; - try { - c.close(); - } catch (Throwable t) { - // do nothing - } - } - - private static ParcelFileDescriptor makeInputStream( - Uri uri, ContentResolver cr) { - try { - return cr.openFileDescriptor(uri, "r"); - } catch (IOException ex) { - return null; - } - } - - public static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, - Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, - BitmapFactory.Options options) { - Bitmap b = null; + /** + * Make a bitmap from a given Uri, minimal side length, and maximum number of pixels. + * The image data will be read from specified pfd if it's not null, otherwise + * a new input stream will be created using specified ContentResolver. + * + * Clients are allowed to pass their own BitmapFactory.Options used for bitmap decoding. A + * new BitmapFactory.Options will be created if options is null. + */ + private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels, + Uri uri, ContentResolver cr, ParcelFileDescriptor pfd, + BitmapFactory.Options options) { + Bitmap b = null; try { if (pfd == null) pfd = makeInputStream(uri, cr); if (pfd == null) return null; @@ -232,115 +341,50 @@ public class ThumbnailUtil { } /** - * Creates a centered bitmap of the desired size. - * @param source - * @param recycle whether we want to recycle the input - */ - public static Bitmap extractMiniThumb( - Bitmap source, int width, int height, boolean recycle) { - if (source == null) { - return null; - } - - float scale; - if (source.getWidth() < source.getHeight()) { - scale = width / (float) source.getWidth(); - } else { - scale = height / (float) source.getHeight(); - } - Matrix matrix = new Matrix(); - matrix.setScale(scale, scale); - Bitmap miniThumbnail = transform(matrix, source, width, height, true, recycle); - return miniThumbnail; - } - - /** - * Create a video thumbnail for a video. May return null if the video is - * corrupt. - * - * @param filePath + * Rotates the bitmap by the specified degree. + * If a new bitmap is created, the original bitmap is recycled. */ - public static Bitmap createVideoThumbnail(String filePath) { - Bitmap bitmap = null; - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - try { - retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY); - retriever.setDataSource(filePath); - bitmap = retriever.captureFrame(); - } catch (IllegalArgumentException ex) { - // Assume this is a corrupt video file - } catch (RuntimeException ex) { - // Assume this is a corrupt video file. - } finally { + private static Bitmap rotate(Bitmap b, int degrees) { + if (degrees != 0 && b != null) { + Matrix m = new Matrix(); + m.setRotate(degrees, + (float) b.getWidth() / 2, (float) b.getHeight() / 2); try { - retriever.release(); - } catch (RuntimeException ex) { - // Ignore failures while cleaning up. + Bitmap b2 = Bitmap.createBitmap( + b, 0, 0, b.getWidth(), b.getHeight(), m, true); + if (b != b2) { + b.recycle(); + b = b2; + } + } catch (OutOfMemoryError ex) { + // We have no memory to rotate. Return the original bitmap. } } - return bitmap; + return b; } - /** - * This method first examines if the thumbnail embedded in EXIF is bigger than our target - * size. If not, then it'll create a thumbnail from original image. Due to efficiency - * consideration, we want to let MediaThumbRequest avoid calling this method twice for - * both kinds, so it only requests for MICRO_KIND and set saveImage to true. - * - * This method always returns a "square thumbnail" for MICRO_KIND thumbnail. - * - * @param cr ContentResolver - * @param filePath file path needed by EXIF interface - * @param uri URI of original image - * @param origId image id - * @param kind either MINI_KIND or MICRO_KIND - * @param saveMini Whether to save MINI_KIND thumbnail obtained in this method. - * @return Bitmap - */ - public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri, - long origId, int kind, boolean saveMini) { - boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini); - int targetSize = wantMini ? - ThumbnailUtil.THUMBNAIL_TARGET_SIZE : ThumbnailUtil.MINI_THUMB_TARGET_SIZE; - int maxPixels = wantMini ? - ThumbnailUtil.THUMBNAIL_MAX_NUM_PIXELS : ThumbnailUtil.MINI_THUMB_MAX_NUM_PIXELS; - SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap(); - Bitmap bitmap = null; - MediaFileType fileType = MediaFile.getFileType(filePath); - if (fileType != null && fileType.fileType == MediaFile.FILE_TYPE_JPEG) { - createThumbnailFromEXIF(filePath, targetSize, maxPixels, sizedThumbnailBitmap); - bitmap = sizedThumbnailBitmap.mBitmap; - } - - if (bitmap == null) { - bitmap = ThumbnailUtil.makeBitmap(targetSize, maxPixels, uri, cr); - } + private static void closeSilently(ParcelFileDescriptor c) { + if (c == null) return; + try { + c.close(); + } catch (Throwable t) { + // do nothing + } + } - if (bitmap == null) { + private static ParcelFileDescriptor makeInputStream( + Uri uri, ContentResolver cr) { + try { + return cr.openFileDescriptor(uri, "r"); + } catch (IOException ex) { return null; } - - if (saveMini) { - if (sizedThumbnailBitmap.mThumbnailData != null) { - ThumbnailUtil.storeThumbnail(cr, origId, - sizedThumbnailBitmap.mThumbnailData, - sizedThumbnailBitmap.mThumbnailWidth, - sizedThumbnailBitmap.mThumbnailHeight); - } else { - ThumbnailUtil.storeThumbnail(cr, origId, bitmap); - } - } - - if (kind == Images.Thumbnails.MICRO_KIND) { - // now we make it a "square thumbnail" for MICRO_KIND thumbnail - bitmap = ThumbnailUtil.extractMiniThumb(bitmap, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, - ThumbnailUtil.MINI_THUMB_TARGET_SIZE, ThumbnailUtil.RECYCLE_INPUT); - } - return bitmap; } - public static Bitmap transform(Matrix scaler, + /** + * Transform source Bitmap to targeted width and height. + */ + private static Bitmap transform(Matrix scaler, Bitmap source, int targetWidth, int targetHeight, @@ -441,10 +485,6 @@ public class ThumbnailUtil { /** * Look up thumbnail uri by given imageId, it will be automatically created if it's not created * yet. Most of the time imageId is identical to thumbId, but it's not always true. - * @param req - * @param width - * @param height - * @return Uri Thumbnail uri */ private static Uri getImageThumbnailUri(ContentResolver cr, long origId, int width, int height) { Uri thumbUri = Images.Thumbnails.EXTERNAL_CONTENT_URI; @@ -513,10 +553,14 @@ public class ThumbnailUtil { } } - // SizedThumbnailBitmap contains the bitmap, which is downsampled either from - // the thumbnail in exif or the full image. - // mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail is not null. - // The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. + /** + * SizedThumbnailBitmap contains the bitmap, which is downsampled either from + * the thumbnail in exif or the full image. + * mThumbnailData, mThumbnailWidth and mThumbnailHeight are set together only if mThumbnail + * is not null. + * + * The width/height of the sized bitmap may be different from mThumbnailWidth/mThumbnailHeight. + */ private static class SizedThumbnailBitmap { public byte[] mThumbnailData; public Bitmap mBitmap; @@ -524,9 +568,11 @@ public class ThumbnailUtil { public int mThumbnailHeight; } - // Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. - // The functions returns a SizedThumbnailBitmap, - // which contains a downsampled bitmap and the thumbnail data in EXIF if exists. + /** + * Creates a bitmap by either downsampling from the thumbnail in EXIF or the full image. + * The functions returns a SizedThumbnailBitmap, + * which contains a downsampled bitmap and the thumbnail data in EXIF if exists. + */ private static void createThumbnailFromEXIF(String filePath, int targetSize, int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) { if (filePath == null) return; |