天天看點

Android縮略圖類源代碼

轉自:http://www.android123.com.cn/androidkaifa/626.html

  Android 2.2開始新增的縮略圖類ThumbnailUtils的主要方法是靜态的,對于Android 2.2或API Level8以下的工程可以直接使用,本類相對于我們正常的縮略圖類考慮更周全,除了尺寸比例優化外,針對OOM的記憶體管理方面有更周全的處理方式,完整代碼如下,使用方法和介紹請檢視 ThumbnailUtils - Android2.2新增類 一文

public class ThumbnailUtils {

    private static final String TAG = "ThumbnailUtils";

    private static final int MAX_NUM_PIXELS_THUMBNAIL = 512 * 384;

    private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 128 * 128;

    private static final int UNCONSTRAINED = -1;

    private static final int OPTIONS_NONE = 0x0;

    private static final int OPTIONS_SCALE_UP = 0x1;

    public static final int OPTIONS_RECYCLE_INPUT = 0x2;

    public static final int TARGET_SIZE_MINI_THUMBNAIL = 320;

    public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96;

    public static Bitmap createImageThumbnail(String filePath, int kind) {

        boolean wantMini = (kind == Images.Thumbnails.MINI_KIND);

        int targetSize = wantMini

                ? TARGET_SIZE_MINI_THUMBNAIL

                : TARGET_SIZE_MICRO_THUMBNAIL;

        int maxPixels = wantMini

                ? MAX_NUM_PIXELS_THUMBNAIL

                : MAX_NUM_PIXELS_MICRO_THUMBNAIL;

        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) {

            try {

                FileDescriptor fd = new FileInputStream(filePath).getFD();

                BitmapFactory.Options options = new BitmapFactory.Options();

                options.inSampleSize = 1;

                options.inJustDecodeBounds = true;

                BitmapFactory.decodeFileDescriptor(fd, null, options);

                if (options.mCancel || options.outWidth == -1

                        || options.outHeight == -1) {

                    return null;

                }

                options.inSampleSize = computeSampleSize(

                        options, targetSize, maxPixels);

                options.inJustDecodeBounds = false;

                options.inDither = false;

                options.inPreferredConfig = Bitmap.Config.ARGB_8888;

                bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);

            } catch (IOException ex) {

                Log.e(TAG, "", ex);

            }

        }

        if (kind == Images.Thumbnails.MICRO_KIND) {

            // now we make it a "square thumbnail" for MICRO_KIND thumbnail

            bitmap = extractThumbnail(bitmap,

                    TARGET_SIZE_MICRO_THUMBNAIL,

                    TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT);

        }

        return bitmap;

    }

    public static Bitmap createVideoThumbnail(String filePath, int kind) {

        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.

            }

        }

        if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) {

            bitmap = extractThumbnail(bitmap,

                    TARGET_SIZE_MICRO_THUMBNAIL,

                    TARGET_SIZE_MICRO_THUMBNAIL,

                    OPTIONS_RECYCLE_INPUT);

        }

        return bitmap;

    }

    public static Bitmap extractThumbnail(

            Bitmap source, int width, int height) {

        return extractThumbnail(source, width, height, OPTIONS_NONE);

    }

    public static Bitmap extractThumbnail(

            Bitmap source, int width, int height, int options) {

        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 thumbnail = transform(matrix, source, width, height,

                OPTIONS_SCALE_UP | options);

        return thumbnail;

    }

    private static int computeSampleSize(BitmapFactory.Options options,

            int minSideLength, int maxNumOfPixels) {

        int initialSize = computeInitialSampleSize(options, minSideLength,

                maxNumOfPixels);

        int roundedSize;

        if (initialSize <= 8 ) {

            roundedSize = 1;

            while (roundedSize < initialSize) {

                roundedSize <<= 1;

            }

        } else {

            roundedSize = (initialSize + 7) / 8 * 8;

        }

        return roundedSize;

    }

    private static int computeInitialSampleSize(BitmapFactory.Options options,

            int minSideLength, int maxNumOfPixels) {

        double w = options.outWidth;

        double h = options.outHeight;

        int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :

                (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));

        int upperBound = (minSideLength == UNCONSTRAINED) ? 128 :

                (int) Math.min(Math.floor(w / minSideLength),

                Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {

            // return the larger one when there is no overlapping zone.

            return lowerBound;

        }

        if ((maxNumOfPixels == UNCONSTRAINED) &&

                (minSideLength == UNCONSTRAINED)) {

            return 1;

        } else if (minSideLength == UNCONSTRAINED) {

            return lowerBound;

        } else {

            return upperBound;

        }

    }

    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;

            if (options == null) options = new BitmapFactory.Options();

            FileDescriptor fd = pfd.getFileDescriptor();

            options.inSampleSize = 1;

            options.inJustDecodeBounds = true;

            BitmapFactory.decodeFileDescriptor(fd, null, options);

            if (options.mCancel || options.outWidth == -1

                    || options.outHeight == -1) {

                return null;

            }

            options.inSampleSize = computeSampleSize(

                    options, minSideLength, maxNumOfPixels);

            options.inJustDecodeBounds = false;

            options.inDither = false;

            options.inPreferredConfig = Bitmap.Config.ARGB_8888;

            b = BitmapFactory.decodeFileDescriptor(fd, null, options);

        } catch (OutOfMemoryError ex) {

            Log.e(TAG, "Got oom exception ", ex);

            return null;

        } finally {

            closeSilently(pfd);

        }

        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;

        }

    }

    private static Bitmap transform(Matrix scaler,

            Bitmap source,

            int targetWidth,

            int targetHeight,

            int options) {

        boolean scaleUp = (options & OPTIONS_SCALE_UP) != 0;

        boolean recycle = (options & OPTIONS_RECYCLE_INPUT) != 0;

        int deltaX = source.getWidth() - targetWidth;

        int deltaY = source.getHeight() - targetHeight;

        if (!scaleUp && (deltaX < 0 || deltaY < 0)) {

            Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,

            Bitmap.Config.ARGB_8888);

            Canvas c = new Canvas(b2);

            int deltaXHalf = Math.max(0, deltaX / 2);

            int deltaYHalf = Math.max(0, deltaY / 2);

            Rect src = new Rect(

            deltaXHalf,

            deltaYHalf,

            deltaXHalf + Math.min(targetWidth, source.getWidth()),

            deltaYHalf + Math.min(targetHeight, source.getHeight()));

            int dstX = (targetWidth  - src.width())  / 2;

            int dstY = (targetHeight - src.height()) / 2;

            Rect dst = new Rect(

                    dstX,

                    dstY,

                    targetWidth - dstX,

                    targetHeight - dstY);

            c.drawBitmap(source, src, dst, null);

            if (recycle) {

                source.recycle();

            }

            return b2;

        }

        float bitmapWidthF = source.getWidth();

        float bitmapHeightF = source.getHeight();

        float bitmapAspect = bitmapWidthF / bitmapHeightF;

        float viewAspect   = (float) targetWidth / targetHeight;

        if (bitmapAspect > viewAspect) {

            float scale = targetHeight / bitmapHeightF;

            if (scale < .9F || scale > 1F) {

                scaler.setScale(scale, scale);

            } else {

                scaler = null;

            }

        } else {

            float scale = targetWidth / bitmapWidthF;

            if (scale < .9F || scale > 1F) {

                scaler.setScale(scale, scale);

            } else {

                scaler = null;

            }

        }

        Bitmap b1;

        if (scaler != null) {

            // this is used for minithumb and crop, so we want to filter here.

            b1 = Bitmap.createBitmap(source, 0, 0,

            source.getWidth(), source.getHeight(), scaler, true);

        } else {

            b1 = source;

        }

        if (recycle && b1 != source) {

            source.recycle();

        }

        int dx1 = Math.max(0, b1.getWidth() - targetWidth);

        int dy1 = Math.max(0, b1.getHeight() - targetHeight);

        Bitmap b2 = Bitmap.createBitmap(

                b1,

                dx1 / 2,

                dy1 / 2,

                targetWidth,

                targetHeight);

        if (b2 != b1) {

            if (recycle || b1 != source) {

                b1.recycle();

            }

        }

        return b2;

    }

    private static class SizedThumbnailBitmap {

        public byte[] mThumbnailData;

        public Bitmap mBitmap;

        public int mThumbnailWidth;

        public int mThumbnailHeight;

    }

    private static void createThumbnailFromEXIF(String filePath, int targetSize,

            int maxPixels, SizedThumbnailBitmap sizedThumbBitmap) {

        if (filePath == null) return;

        ExifInterface exif = null;

        byte [] thumbData = null;

        try {

            exif = new ExifInterface(filePath);

            if (exif != null) {

                thumbData = exif.getThumbnail();

            }

        } catch (IOException ex) {

            Log.w(TAG, ex);

        }

        BitmapFactory.Options fullOptions = new BitmapFactory.Options();

        BitmapFactory.Options exifOptions = new BitmapFactory.Options();

        int exifThumbWidth = 0;

        int fullThumbWidth = 0;

        // Compute exifThumbWidth.

        if (thumbData != null) {

            exifOptions.inJustDecodeBounds = true;

            BitmapFactory.decodeByteArray(thumbData, 0, thumbData.length, exifOptions);

            exifOptions.inSampleSize = computeSampleSize(exifOptions, targetSize, maxPixels);

            exifThumbWidth = exifOptions.outWidth / exifOptions.inSampleSize;

        }

        // Compute fullThumbWidth.

        fullOptions.inJustDecodeBounds = true;

        BitmapFactory.decodeFile(filePath, fullOptions);

        fullOptions.inSampleSize = computeSampleSize(fullOptions, targetSize, maxPixels);

        fullThumbWidth = fullOptions.outWidth / fullOptions.inSampleSize;

        // Choose the larger thumbnail as the returning sizedThumbBitmap.

        if (thumbData != null && exifThumbWidth >= fullThumbWidth) {

            int width = exifOptions.outWidth;

            int height = exifOptions.outHeight;

            exifOptions.inJustDecodeBounds = false;

            sizedThumbBitmap.mBitmap = BitmapFactory.decodeByteArray(thumbData, 0,

                    thumbData.length, exifOptions);

            if (sizedThumbBitmap.mBitmap != null) {

                sizedThumbBitmap.mThumbnailData = thumbData;

                sizedThumbBitmap.mThumbnailWidth = width;

                sizedThumbBitmap.mThumbnailHeight = height;

            }

        } else {

            fullOptions.inJustDecodeBounds = false;

            sizedThumbBitmap.mBitmap = BitmapFactory.decodeFile(filePath, fullOptions);

        }

    }

}