| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.camera.data; |
| |
| import android.graphics.Bitmap; |
| import android.graphics.BitmapFactory; |
| import android.graphics.Matrix; |
| import android.graphics.Point; |
| import android.media.MediaMetadataRetriever; |
| |
| import com.android.camera.debug.Log; |
| |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| import javax.microedition.khronos.opengles.GL11; |
| |
| /** |
| * An utility class for data in content provider. |
| */ |
| public class LocalDataUtil { |
| |
| private static final Log.Tag TAG = new Log.Tag("LocalDataUtil"); |
| |
| /** |
| * @param mimeType The MIME type to check. |
| * @return Whether the MIME is a video type. |
| */ |
| public static boolean isMimeTypeVideo(String mimeType) { |
| return mimeType != null && mimeType.startsWith("video/"); |
| } |
| |
| /** |
| * @param mimeType The MIME type to check. |
| * @return Whether the MIME is a image type. |
| */ |
| public static boolean isMimeTypeImage(String mimeType) { |
| return mimeType != null && mimeType.startsWith("image/"); |
| } |
| |
| /** |
| * Decodes the dimension of a bitmap. |
| * |
| * @param path The path to the bitmap. |
| * @return The decoded width/height is stored in Point.x/Point.y |
| * respectively. |
| */ |
| public static Point decodeBitmapDimension(String path) { |
| Point size = null; |
| InputStream is = null; |
| try { |
| is = new FileInputStream(path); |
| size = decodeBitmapDimension(is); |
| } catch (FileNotFoundException e) { |
| e.printStackTrace(); |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch (IOException e) { } |
| } |
| } |
| return size; |
| } |
| |
| /** |
| * Decodes the dimension of a bitmap. |
| * |
| * @param is An input stream with the data of the bitmap. |
| * @return The decoded width/height is stored in Point.x/Point.y |
| * respectively. |
| */ |
| public static Point decodeBitmapDimension(InputStream is) { |
| Point size = null; |
| BitmapFactory.Options justBoundsOpts = new BitmapFactory.Options(); |
| justBoundsOpts.inJustDecodeBounds = true; |
| BitmapFactory.decodeStream(is, null, justBoundsOpts); |
| if (justBoundsOpts.outWidth > 0 && justBoundsOpts.outHeight > 0) { |
| size = new Point(justBoundsOpts.outWidth, justBoundsOpts.outHeight); |
| } else { |
| Log.e(TAG, "Bitmap dimension decoding failed"); |
| } |
| return size; |
| } |
| |
| /** |
| * Load the thumbnail of an image from an {@link java.io.InputStream}. |
| * |
| * @param stream The input stream of the image. |
| * @param imageWidth Image width. |
| * @param imageHeight Image height. |
| * @param widthBound The bound of the width of the decoded image. |
| * @param heightBound The bound of the height of the decoded image. |
| * @param orientation The orientation of the image. The image will be rotated |
| * clockwise in degrees. |
| * @param maximumPixels The bound for the number of pixels of the decoded image. |
| * @return {@code null} if the decoding failed. |
| */ |
| public static Bitmap loadImageThumbnailFromStream(InputStream stream, int imageWidth, |
| int imageHeight, int widthBound, int heightBound, int orientation, |
| int maximumPixels) { |
| |
| /** 32K buffer. */ |
| byte[] decodeBuffer = new byte[32 * 1024]; |
| |
| if (orientation % 180 != 0) { |
| int dummy = imageHeight; |
| imageHeight = imageWidth; |
| imageWidth = dummy; |
| } |
| |
| // Generate Bitmap of maximum size that fits into widthBound x heightBound. |
| // Algorithm: start with full size and step down in powers of 2. |
| int targetWidth = imageWidth; |
| int targetHeight = imageHeight; |
| int sampleSize = 1; |
| while (targetHeight > heightBound || targetWidth > widthBound || |
| targetHeight > GL11.GL_MAX_TEXTURE_SIZE || targetWidth > GL11.GL_MAX_TEXTURE_SIZE || |
| targetHeight * targetWidth > maximumPixels) { |
| sampleSize <<= 1; |
| targetWidth = imageWidth / sampleSize; |
| targetHeight = imageWidth / sampleSize; |
| } |
| |
| // For large (> MAXIMUM_TEXTURE_SIZE) high aspect ratio (panorama) |
| // Bitmap requests: |
| // Step 1: ask for double size. |
| // Step 2: scale maximum edge down to MAXIMUM_TEXTURE_SIZE. |
| // |
| // Here's the step 1: double size. |
| if ((heightBound > GL11.GL_MAX_TEXTURE_SIZE || widthBound > GL11.GL_MAX_TEXTURE_SIZE) && |
| targetWidth * targetHeight < maximumPixels / 4 && sampleSize > 1) { |
| sampleSize >>= 2; |
| } |
| |
| BitmapFactory.Options opts = new BitmapFactory.Options(); |
| opts.inSampleSize = sampleSize; |
| opts.inTempStorage = decodeBuffer; |
| Bitmap b = BitmapFactory.decodeStream(stream, null, opts); |
| |
| if (b == null) { |
| return null; |
| } |
| |
| // Step 2: scale maximum edge down to maximum texture size. |
| // If Bitmap maximum edge > MAXIMUM_TEXTURE_SIZE, which can happen for panoramas, |
| // scale to fit in MAXIMUM_TEXTURE_SIZE. |
| if (b.getWidth() > GL11.GL_MAX_TEXTURE_SIZE || b.getHeight() > |
| GL11.GL_MAX_TEXTURE_SIZE) { |
| int maxEdge = Math.max(b.getWidth(), b.getHeight()); |
| b = Bitmap.createScaledBitmap(b, b.getWidth() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, |
| b.getHeight() * GL11.GL_MAX_TEXTURE_SIZE / maxEdge, false); |
| } |
| |
| // Not called often because most modes save image data non-rotated. |
| if (orientation != 0 && b != null) { |
| Matrix m = new Matrix(); |
| m.setRotate(orientation); |
| b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, false); |
| } |
| |
| return b; |
| } |
| |
| /** |
| * Loads the thumbnail of a video. |
| * |
| * @param path The path to the video file. |
| * @return {@code null} if the loading failed. |
| */ |
| public static Bitmap loadVideoThumbnail(String path) { |
| Bitmap bitmap = null; |
| MediaMetadataRetriever retriever = new MediaMetadataRetriever(); |
| try { |
| retriever.setDataSource(path); |
| byte[] data = retriever.getEmbeddedPicture(); |
| if (data != null) { |
| bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); |
| } |
| if (bitmap == null) { |
| bitmap = retriever.getFrameAtTime(); |
| } |
| } catch (IllegalArgumentException e) { |
| Log.e(TAG, "MediaMetadataRetriever.setDataSource() fail:" + e.getMessage()); |
| } |
| retriever.release(); |
| return bitmap; |
| } |
| } |