blob: 00ace49ad0f3232ac8c056f19edc2c60be5b66ca [file] [log] [blame]
/*
* 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;
}
}