Home | History | Annotate | Download | only in data
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera.data;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.BitmapFactory;
     21 import android.graphics.Matrix;
     22 import android.graphics.Point;
     23 import android.media.MediaMetadataRetriever;
     24 
     25 import com.android.camera.debug.Log;
     26 
     27 import java.io.InputStream;
     28 
     29 import javax.microedition.khronos.opengles.GL11;
     30 
     31 /**
     32  * An utility class for data in content provider.
     33  */
     34 public class FilmstripItemUtils {
     35 
     36     private static final Log.Tag TAG = new Log.Tag("LocalDataUtil");
     37 
     38     /**
     39      * @param mimeType The MIME type to check.
     40      * @return Whether the MIME is a video type.
     41      */
     42     public static boolean isMimeTypeVideo(String mimeType) {
     43         return mimeType != null && mimeType.startsWith("video/");
     44     }
     45 
     46     /**
     47      * Checks whether the MIME type represents an image media item.
     48      *
     49      * @param mimeType The MIME type to check.
     50      * @return Whether the MIME is a image type.
     51      */
     52     public static boolean isMimeTypeImage(String mimeType) {
     53         return mimeType != null && mimeType.startsWith("image/");
     54     }
     55 
     56 
     57     /**
     58      * Decodes the dimension of a bitmap.
     59      *
     60      * @param is An input stream with the data of the bitmap.
     61      * @return The decoded width/height is stored in Point.x/Point.y
     62      *         respectively.
     63      */
     64     public static Point decodeBitmapDimension(InputStream is) {
     65         Point size = null;
     66         BitmapFactory.Options justBoundsOpts = new BitmapFactory.Options();
     67         justBoundsOpts.inJustDecodeBounds = true;
     68         BitmapFactory.decodeStream(is, null, justBoundsOpts);
     69         if (justBoundsOpts.outWidth > 0 && justBoundsOpts.outHeight > 0) {
     70             size = new Point(justBoundsOpts.outWidth, justBoundsOpts.outHeight);
     71         } else {
     72             Log.e(TAG, "Bitmap dimension decoding failed");
     73         }
     74         return size;
     75     }
     76 
     77     /**
     78      * Load the thumbnail of an image from an {@link java.io.InputStream}.
     79      *
     80      * @param stream The input stream of the image.
     81      * @param imageWidth Image width.
     82      * @param imageHeight Image height.
     83      * @param widthBound The bound of the width of the decoded image.
     84      * @param heightBound The bound of the height of the decoded image.
     85      * @param orientation The orientation of the image. The image will be rotated
     86      *                    clockwise in degrees.
     87      * @param maximumPixels The bound for the number of pixels of the decoded image.
     88      * @return {@code null} if the decoding failed.
     89      */
     90     public static Bitmap loadImageThumbnailFromStream(InputStream stream, int imageWidth,
     91             int imageHeight, int widthBound, int heightBound, int orientation,
     92             int maximumPixels) {
     93 
     94         /** 32K buffer. */
     95         byte[] decodeBuffer = new byte[32 * 1024];
     96 
     97         if (orientation % 180 != 0) {
     98             int dummy = imageHeight;
     99             imageHeight = imageWidth;
    100             imageWidth = dummy;
    101         }
    102 
    103         // Generate Bitmap of maximum size that fits into widthBound x heightBound.
    104         // Algorithm: start with full size and step down in powers of 2.
    105         int targetWidth = imageWidth;
    106         int targetHeight = imageHeight;
    107         int sampleSize = 1;
    108         while (targetHeight > heightBound || targetWidth > widthBound ||
    109                 targetHeight > GL11.GL_MAX_TEXTURE_SIZE || targetWidth > GL11.GL_MAX_TEXTURE_SIZE ||
    110                 targetHeight * targetWidth > maximumPixels) {
    111             sampleSize <<= 1;
    112             targetWidth = imageWidth / sampleSize;
    113             targetHeight = imageWidth / sampleSize;
    114         }
    115 
    116         // For large (> MAXIMUM_TEXTURE_SIZE) high aspect ratio (panorama)
    117         // Bitmap requests:
    118         //   Step 1: ask for double size.
    119         //   Step 2: scale maximum edge down to MAXIMUM_TEXTURE_SIZE.
    120         //
    121         // Here's the step 1: double size.
    122         if ((heightBound > GL11.GL_MAX_TEXTURE_SIZE || widthBound > GL11.GL_MAX_TEXTURE_SIZE) &&
    123                 targetWidth * targetHeight < maximumPixels / 4 && sampleSize > 1) {
    124             sampleSize >>= 2;
    125         }
    126 
    127         BitmapFactory.Options opts = new BitmapFactory.Options();
    128         opts.inSampleSize = sampleSize;
    129         opts.inTempStorage = decodeBuffer;
    130         Bitmap b = BitmapFactory.decodeStream(stream, null, opts);
    131 
    132         if (b == null) {
    133             return null;
    134         }
    135 
    136         // Step 2: scale maximum edge down to maximum texture size.
    137         // If Bitmap maximum edge > MAXIMUM_TEXTURE_SIZE, which can happen for panoramas,
    138         // scale to fit in MAXIMUM_TEXTURE_SIZE.
    139         if (b.getWidth() > GL11.GL_MAX_TEXTURE_SIZE || b.getHeight() >
    140                 GL11.GL_MAX_TEXTURE_SIZE) {
    141             int maxEdge = Math.max(b.getWidth(), b.getHeight());
    142             b = Bitmap.createScaledBitmap(b, b.getWidth() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge,
    143                     b.getHeight() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, false);
    144         }
    145 
    146         // Not called often because most modes save image data non-rotated.
    147         if (orientation != 0 && b != null) {
    148             Matrix m = new Matrix();
    149             m.setRotate(orientation);
    150             b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false);
    151         }
    152 
    153         return b;
    154     }
    155 
    156     /**
    157      * Loads the thumbnail of a video.
    158      *
    159      * @param path The path to the video file.
    160      * @return {@code null} if the loading failed.
    161      */
    162     public static Bitmap loadVideoThumbnail(String path) {
    163         Bitmap bitmap = null;
    164         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    165         try {
    166             retriever.setDataSource(path);
    167             byte[] data = retriever.getEmbeddedPicture();
    168             if (data != null) {
    169                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    170             }
    171             if (bitmap == null) {
    172                 bitmap = retriever.getFrameAtTime();
    173             }
    174         } catch (IllegalArgumentException e) {
    175             Log.e(TAG, "MediaMetadataRetriever.setDataSource() fail:" + e.getMessage());
    176         }
    177         retriever.release();
    178         return bitmap;
    179     }
    180 }
    181