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.FileInputStream;
     28 import java.io.FileNotFoundException;
     29 import java.io.IOException;
     30 import java.io.InputStream;
     31 
     32 import javax.microedition.khronos.opengles.GL11;
     33 
     34 /**
     35  * An utility class for data in content provider.
     36  */
     37 public class LocalDataUtil {
     38 
     39     private static final Log.Tag TAG = new Log.Tag("LocalDataUtil");
     40 
     41     /**
     42      * @param mimeType The MIME type to check.
     43      * @return Whether the MIME is a video type.
     44      */
     45     public static boolean isMimeTypeVideo(String mimeType) {
     46         return mimeType.startsWith("video/");
     47     }
     48 
     49     /**
     50      * @param mimeType The MIME type to check.
     51      * @return Whether the MIME is a image type.
     52      */
     53     public static boolean isMimeTypeImage(String mimeType) {
     54         return mimeType.startsWith("image/");
     55     }
     56 
     57     /**
     58      * Decodes the dimension of a bitmap.
     59      *
     60      * @param path The path to the bitmap.
     61      * @return The decoded width/height is stored in Point.x/Point.y
     62      *         respectively.
     63      */
     64     public static Point decodeBitmapDimension(String path) {
     65         Point size = null;
     66         InputStream is = null;
     67         try {
     68             is = new FileInputStream(path);
     69             size = decodeBitmapDimension(is);
     70         } catch (FileNotFoundException e) {
     71             e.printStackTrace();
     72         } finally {
     73             if (is != null) {
     74                 try {
     75                     is.close();
     76                 } catch (IOException e) { }
     77             }
     78         }
     79         return size;
     80     }
     81 
     82     /**
     83      * Decodes the dimension of a bitmap.
     84      *
     85      * @param is An input stream with the data of the bitmap.
     86      * @return The decoded width/height is stored in Point.x/Point.y
     87      *         respectively.
     88      */
     89     public static Point decodeBitmapDimension(InputStream is) {
     90         Point size = null;
     91         BitmapFactory.Options justBoundsOpts = new BitmapFactory.Options();
     92         justBoundsOpts.inJustDecodeBounds = true;
     93         BitmapFactory.decodeStream(is, null, justBoundsOpts);
     94         if (justBoundsOpts.outWidth > 0 && justBoundsOpts.outHeight > 0) {
     95             size = new Point(justBoundsOpts.outWidth, justBoundsOpts.outHeight);
     96         } else {
     97             Log.e(TAG, "Bitmap dimension decoding failed");
     98         }
     99         return size;
    100     }
    101 
    102     /**
    103      * Load the thumbnail of an image from an {@link java.io.InputStream}.
    104      *
    105      * @param stream The input stream of the image.
    106      * @param imageWidth Image width.
    107      * @param imageHeight Image height.
    108      * @param widthBound The bound of the width of the decoded image.
    109      * @param heightBound The bound of the height of the decoded image.
    110      * @param orientation The orientation of the image. The image will be rotated
    111      *                    clockwise in degrees.
    112      * @param maximumPixels The bound for the number of pixels of the decoded image.
    113      * @return {@code null} if the decoding failed.
    114      */
    115     public static Bitmap loadImageThumbnailFromStream(InputStream stream, int imageWidth,
    116             int imageHeight, int widthBound, int heightBound, int orientation,
    117             int maximumPixels) {
    118 
    119         /** 32K buffer. */
    120         byte[] decodeBuffer = new byte[32 * 1024];
    121 
    122         if (orientation % 180 != 0) {
    123             int dummy = imageHeight;
    124             imageHeight = imageWidth;
    125             imageWidth = dummy;
    126         }
    127 
    128         // Generate Bitmap of maximum size that fits into widthBound x heightBound.
    129         // Algorithm: start with full size and step down in powers of 2.
    130         int targetWidth = imageWidth;
    131         int targetHeight = imageHeight;
    132         int sampleSize = 1;
    133         while (targetHeight > heightBound || targetWidth > widthBound ||
    134                 targetHeight > GL11.GL_MAX_TEXTURE_SIZE || targetWidth > GL11.GL_MAX_TEXTURE_SIZE ||
    135                 targetHeight * targetWidth > maximumPixels) {
    136             sampleSize <<= 1;
    137             targetWidth = imageWidth / sampleSize;
    138             targetHeight = imageWidth / sampleSize;
    139         }
    140 
    141         // For large (> MAXIMUM_TEXTURE_SIZE) high aspect ratio (panorama)
    142         // Bitmap requests:
    143         //   Step 1: ask for double size.
    144         //   Step 2: scale maximum edge down to MAXIMUM_TEXTURE_SIZE.
    145         //
    146         // Here's the step 1: double size.
    147         if ((heightBound > GL11.GL_MAX_TEXTURE_SIZE || widthBound > GL11.GL_MAX_TEXTURE_SIZE) &&
    148                 targetWidth * targetHeight < maximumPixels / 4 && sampleSize > 1) {
    149             sampleSize >>= 2;
    150         }
    151 
    152         BitmapFactory.Options opts = new BitmapFactory.Options();
    153         opts.inSampleSize = sampleSize;
    154         opts.inTempStorage = decodeBuffer;
    155         Bitmap b = BitmapFactory.decodeStream(stream, null, opts);
    156 
    157         if (b == null) {
    158             return null;
    159         }
    160 
    161         // Step 2: scale maximum edge down to maximum texture size.
    162         // If Bitmap maximum edge > MAXIMUM_TEXTURE_SIZE, which can happen for panoramas,
    163         // scale to fit in MAXIMUM_TEXTURE_SIZE.
    164         if (b.getWidth() > GL11.GL_MAX_TEXTURE_SIZE || b.getHeight() >
    165                 GL11.GL_MAX_TEXTURE_SIZE) {
    166             int maxEdge = Math.max(b.getWidth(), b.getHeight());
    167             b = Bitmap.createScaledBitmap(b, b.getWidth() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge,
    168                     b.getHeight() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, false);
    169         }
    170 
    171         // Not called often because most modes save image data non-rotated.
    172         if (orientation != 0 && b != null) {
    173             Matrix m = new Matrix();
    174             m.setRotate(orientation);
    175             b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false);
    176         }
    177 
    178         return b;
    179     }
    180 
    181     /**
    182      * Loads the thumbnail of a video.
    183      *
    184      * @param path The path to the video file.
    185      * @return {@code null} if the loading failed.
    186      */
    187     public static Bitmap loadVideoThumbnail(String path) {
    188         Bitmap bitmap = null;
    189         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    190         try {
    191             retriever.setDataSource(path);
    192             byte[] data = retriever.getEmbeddedPicture();
    193             if (data != null) {
    194                 bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
    195             }
    196             if (bitmap == null) {
    197                 bitmap = retriever.getFrameAtTime();
    198             }
    199         } catch (IllegalArgumentException e) {
    200             Log.e(TAG, "MediaMetadataRetriever.setDataSource() fail:" + e.getMessage());
    201         }
    202         retriever.release();
    203         return bitmap;
    204     }
    205 }
    206