Make createVideoThumbnail and createImageThumbnail look consistent.
Change-Id: I9a4798fefe3968ac847d46100036a6dde39791c9
This commit is contained in:
@@ -86123,6 +86123,8 @@
|
||||
>
|
||||
<parameter name="filePath" type="java.lang.String">
|
||||
</parameter>
|
||||
<parameter name="kind" type="int">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="extractThumbnail"
|
||||
return="android.graphics.Bitmap"
|
||||
@@ -86171,28 +86173,6 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="TARGET_SIZE_MICRO_THUMBNAIL"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="96"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="TARGET_SIZE_MINI_THUMBNAIL"
|
||||
type="int"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value="320"
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
<class name="ToneGenerator"
|
||||
extends="java.lang.Object"
|
||||
|
||||
@@ -374,8 +374,8 @@ public final class MediaStore {
|
||||
|
||||
// We probably run out of space, so create the thumbnail in memory.
|
||||
if (bitmap == null) {
|
||||
Log.v(TAG, "We probably run out of space, so create the thumbnail in memory.");
|
||||
|
||||
Log.v(TAG, "Create the thumbnail in memory: origId=" + origId
|
||||
+ ", kind=" + kind + ", isVideo="+isVideo);
|
||||
Uri uri = Uri.parse(
|
||||
baseUri.buildUpon().appendPath(String.valueOf(origId))
|
||||
.toString().replaceFirst("thumbnails", "media"));
|
||||
@@ -388,16 +388,9 @@ public final class MediaStore {
|
||||
filePath = c.getString(1);
|
||||
}
|
||||
if (isVideo) {
|
||||
bitmap = ThumbnailUtils.createVideoThumbnail(filePath);
|
||||
if (kind == MICRO_KIND && bitmap != null) {
|
||||
bitmap = ThumbnailUtils.extractThumbnail(bitmap,
|
||||
ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL,
|
||||
ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL,
|
||||
ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
|
||||
}
|
||||
bitmap = ThumbnailUtils.createVideoThumbnail(filePath, kind);
|
||||
} else {
|
||||
bitmap = ThumbnailUtils.createImageThumbnail(cr, filePath, uri, origId,
|
||||
kind, false);
|
||||
bitmap = ThumbnailUtils.createImageThumbnail(filePath, kind);
|
||||
}
|
||||
}
|
||||
} catch (SQLiteException ex) {
|
||||
@@ -613,8 +606,12 @@ public final class MediaStore {
|
||||
}
|
||||
|
||||
long id = ContentUris.parseId(url);
|
||||
Bitmap miniThumb = StoreThumbnail(cr, source, id, 320F, 240F, Images.Thumbnails.MINI_KIND);
|
||||
Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F, Images.Thumbnails.MICRO_KIND);
|
||||
// Wait until MINI_KIND thumbnail is generated.
|
||||
Bitmap miniThumb = Images.Thumbnails.getThumbnail(cr, id,
|
||||
Images.Thumbnails.MINI_KIND, null);
|
||||
// This is for backward compatibility.
|
||||
Bitmap microThumb = StoreThumbnail(cr, miniThumb, id, 50F, 50F,
|
||||
Images.Thumbnails.MICRO_KIND);
|
||||
} else {
|
||||
Log.e(TAG, "Failed to create thumbnail, removing original");
|
||||
cr.delete(url, null, null);
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.provider.MediaStore.Images;
|
||||
import android.provider.MediaStore.Images.Thumbnails;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
@@ -61,14 +62,14 @@ public class ThumbnailUtils {
|
||||
public static final int OPTIONS_RECYCLE_INPUT = 0x2;
|
||||
|
||||
/**
|
||||
* Constant used to indicate the dimension of mini thumbnail in
|
||||
* {@link #extractThumbnail(Bitmap, int, int, int)}.
|
||||
* Constant used to indicate the dimension of mini thumbnail.
|
||||
* @hide Only used by media framework and media provider internally.
|
||||
*/
|
||||
public static final int TARGET_SIZE_MINI_THUMBNAIL = 320;
|
||||
|
||||
/**
|
||||
* Constant used to indicate the dimension of micro thumbnail in
|
||||
* {@link #extractThumbnail(Bitmap, int, int, int)}.
|
||||
* Constant used to indicate the dimension of micro thumbnail.
|
||||
* @hide Only used by media framework and media provider internally.
|
||||
*/
|
||||
public static final int TARGET_SIZE_MICRO_THUMBNAIL = 96;
|
||||
|
||||
@@ -80,23 +81,20 @@ public class ThumbnailUtils {
|
||||
*
|
||||
* This method always returns a "square thumbnail" for MICRO_KIND thumbnail.
|
||||
*
|
||||
* @param cr ContentResolver
|
||||
* @param filePath file path needed by EXIF interface
|
||||
* @param uri URI of original image
|
||||
* @param origId image id
|
||||
* @param kind either MINI_KIND or MICRO_KIND
|
||||
* @param saveMini Whether to save MINI_KIND thumbnail obtained in this method.
|
||||
* @param filePath the path of image file
|
||||
* @param kind could be MINI_KIND or MICRO_KIND
|
||||
* @return Bitmap
|
||||
*
|
||||
* @hide This method is only used by media framework and media provider internally.
|
||||
*/
|
||||
public static Bitmap createImageThumbnail(ContentResolver cr, String filePath, Uri uri,
|
||||
long origId, int kind, boolean saveMini) {
|
||||
boolean wantMini = (kind == Images.Thumbnails.MINI_KIND || saveMini);
|
||||
int targetSize = wantMini ?
|
||||
TARGET_SIZE_MINI_THUMBNAIL : TARGET_SIZE_MICRO_THUMBNAIL;
|
||||
int maxPixels = wantMini ?
|
||||
MAX_NUM_PIXELS_THUMBNAIL : MAX_NUM_PIXELS_MICRO_THUMBNAIL;
|
||||
public static Bitmap createImageThumbnail(String filePath, int kind) {
|
||||
boolean wantMini = (kind == Images.Thumbnails.MINI_KIND);
|
||||
int targetSize = wantMini
|
||||
? TARGET_SIZE_MINI_THUMBNAIL
|
||||
: TARGET_SIZE_MICRO_THUMBNAIL;
|
||||
int maxPixels = wantMini
|
||||
? MAX_NUM_PIXELS_THUMBNAIL
|
||||
: MAX_NUM_PIXELS_MICRO_THUMBNAIL;
|
||||
SizedThumbnailBitmap sizedThumbnailBitmap = new SizedThumbnailBitmap();
|
||||
Bitmap bitmap = null;
|
||||
MediaFileType fileType = MediaFile.getFileType(filePath);
|
||||
@@ -106,21 +104,25 @@ public class ThumbnailUtils {
|
||||
}
|
||||
|
||||
if (bitmap == null) {
|
||||
bitmap = makeBitmap(targetSize, maxPixels, uri, cr);
|
||||
}
|
||||
try {
|
||||
FileDescriptor fd = new FileInputStream(filePath).getFD();
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = 1;
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFileDescriptor(fd, null, options);
|
||||
if (options.mCancel || options.outWidth == -1
|
||||
|| options.outHeight == -1) {
|
||||
return null;
|
||||
}
|
||||
options.inSampleSize = computeSampleSize(
|
||||
options, targetSize, maxPixels);
|
||||
options.inJustDecodeBounds = false;
|
||||
|
||||
if (bitmap == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (saveMini) {
|
||||
if (sizedThumbnailBitmap.mThumbnailData != null) {
|
||||
storeThumbnail(cr, origId,
|
||||
sizedThumbnailBitmap.mThumbnailData,
|
||||
sizedThumbnailBitmap.mThumbnailWidth,
|
||||
sizedThumbnailBitmap.mThumbnailHeight);
|
||||
} else {
|
||||
storeThumbnail(cr, origId, bitmap);
|
||||
options.inDither = false;
|
||||
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,9 +139,10 @@ public class ThumbnailUtils {
|
||||
* Create a video thumbnail for a video. May return null if the video is
|
||||
* corrupt or the format is not supported.
|
||||
*
|
||||
* @param filePath
|
||||
* @param filePath the path of video file
|
||||
* @param kind could be MINI_KIND or MICRO_KIND
|
||||
*/
|
||||
public static Bitmap createVideoThumbnail(String filePath) {
|
||||
public static Bitmap createVideoThumbnail(String filePath, int kind) {
|
||||
Bitmap bitmap = null;
|
||||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||||
try {
|
||||
@@ -157,6 +160,12 @@ public class ThumbnailUtils {
|
||||
// Ignore failures while cleaning up.
|
||||
}
|
||||
}
|
||||
if (kind == Images.Thumbnails.MICRO_KIND && bitmap != null) {
|
||||
bitmap = extractThumbnail(bitmap,
|
||||
TARGET_SIZE_MICRO_THUMBNAIL,
|
||||
TARGET_SIZE_MICRO_THUMBNAIL,
|
||||
OPTIONS_RECYCLE_INPUT);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@@ -262,25 +271,6 @@ public class ThumbnailUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
|
||||
* The image data will be read from specified ContentResolver.
|
||||
*/
|
||||
private static Bitmap makeBitmap(int minSideLength, int maxNumOfPixels,
|
||||
Uri uri, ContentResolver cr) {
|
||||
ParcelFileDescriptor input = null;
|
||||
try {
|
||||
input = cr.openFileDescriptor(uri, "r");
|
||||
return makeBitmap(minSideLength, maxNumOfPixels, uri, cr, input,
|
||||
null);
|
||||
} catch (IOException ex) {
|
||||
Log.e(TAG, "", ex);
|
||||
return null;
|
||||
} finally {
|
||||
closeSilently(input);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a bitmap from a given Uri, minimal side length, and maximum number of pixels.
|
||||
* The image data will be read from specified pfd if it's not null, otherwise
|
||||
@@ -438,81 +428,6 @@ public class ThumbnailUtils {
|
||||
return b2;
|
||||
}
|
||||
|
||||
private static final String[] THUMB_PROJECTION = new String[] {
|
||||
BaseColumns._ID // 0
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up thumbnail uri by given imageId, it will be automatically created if it's not created
|
||||
* yet. Most of the time imageId is identical to thumbId, but it's not always true.
|
||||
*/
|
||||
private static Uri getImageThumbnailUri(ContentResolver cr, long origId, int width, int height) {
|
||||
Uri thumbUri = Images.Thumbnails.EXTERNAL_CONTENT_URI;
|
||||
Cursor c = cr.query(thumbUri, THUMB_PROJECTION,
|
||||
Thumbnails.IMAGE_ID + "=?",
|
||||
new String[]{String.valueOf(origId)}, null);
|
||||
if (c == null) return null;
|
||||
try {
|
||||
if (c.moveToNext()) {
|
||||
return ContentUris.withAppendedId(thumbUri, c.getLong(0));
|
||||
}
|
||||
} finally {
|
||||
if (c != null) c.close();
|
||||
}
|
||||
|
||||
ContentValues values = new ContentValues(4);
|
||||
values.put(Thumbnails.KIND, Thumbnails.MINI_KIND);
|
||||
values.put(Thumbnails.IMAGE_ID, origId);
|
||||
values.put(Thumbnails.HEIGHT, height);
|
||||
values.put(Thumbnails.WIDTH, width);
|
||||
try {
|
||||
return cr.insert(thumbUri, values);
|
||||
} catch (Exception ex) {
|
||||
Log.w(TAG, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a given thumbnail in the database. (Bitmap)
|
||||
*/
|
||||
private static boolean storeThumbnail(ContentResolver cr, long origId, Bitmap thumb) {
|
||||
if (thumb == null) return false;
|
||||
try {
|
||||
Uri uri = getImageThumbnailUri(cr, origId, thumb.getWidth(), thumb.getHeight());
|
||||
if (uri == null) return false;
|
||||
OutputStream thumbOut = cr.openOutputStream(uri);
|
||||
thumb.compress(Bitmap.CompressFormat.JPEG, 85, thumbOut);
|
||||
thumbOut.close();
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Unable to store thumbnail", t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a given thumbnail in the database. (byte array)
|
||||
*/
|
||||
private static boolean storeThumbnail(ContentResolver cr, long origId, byte[] jpegThumbnail,
|
||||
int width, int height) {
|
||||
if (jpegThumbnail == null) return false;
|
||||
|
||||
Uri uri = getImageThumbnailUri(cr, origId, width, height);
|
||||
if (uri == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
OutputStream thumbOut = cr.openOutputStream(uri);
|
||||
thumbOut.write(jpegThumbnail);
|
||||
thumbOut.close();
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
Log.e(TAG, "Unable to store thumbnail", t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SizedThumbnailBitmap contains the bitmap, which is downsampled either from
|
||||
* the thumbnail in exif or the full image.
|
||||
|
||||
Reference in New Issue
Block a user