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 != null && 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 != null && 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