674 lines
23 KiB
Java
674 lines
23 KiB
Java
package com.mogo.utils;
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.content.ContentUris;
|
||
import android.content.Context;
|
||
import android.content.Intent;
|
||
import android.database.Cursor;
|
||
import android.graphics.Bitmap;
|
||
import android.graphics.BitmapFactory;
|
||
import android.graphics.Canvas;
|
||
import android.graphics.Matrix;
|
||
import android.graphics.Paint;
|
||
import android.graphics.PorterDuff;
|
||
import android.graphics.PorterDuffXfermode;
|
||
import android.graphics.RectF;
|
||
import android.media.ExifInterface;
|
||
import android.media.MediaMetadataRetriever;
|
||
import android.net.Uri;
|
||
import android.opengl.GLES10;
|
||
import android.os.Build;
|
||
import android.provider.DocumentsContract;
|
||
import android.provider.MediaStore;
|
||
import android.text.TextUtils;
|
||
import android.util.Base64;
|
||
import android.util.Log;
|
||
|
||
import java.io.ByteArrayOutputStream;
|
||
import java.io.File;
|
||
import java.io.FileOutputStream;
|
||
import java.io.InputStream;
|
||
|
||
import javax.microedition.khronos.egl.EGL10;
|
||
import javax.microedition.khronos.egl.EGLConfig;
|
||
import javax.microedition.khronos.egl.EGLContext;
|
||
import javax.microedition.khronos.egl.EGLDisplay;
|
||
|
||
/**
|
||
* @author wangzhiyuan
|
||
* @since 2017/8/30
|
||
*/
|
||
|
||
public class BitmapHelper {
|
||
private static final String TAG = "BitmapHelper";
|
||
|
||
static int ONE_KB = 1024;
|
||
static int ONE_MB = ONE_KB * 1024;
|
||
|
||
static int SIZE_DEFAULT = 2048;
|
||
static int SIZE_LIMIT = 2048;
|
||
|
||
/**
|
||
* 根据原图添加圆角
|
||
*
|
||
* @param source
|
||
* @return
|
||
*/
|
||
public static Bitmap createRoundCornerImage( Bitmap source, float corner ) {
|
||
final Paint paint = new Paint();
|
||
paint.setAntiAlias( true );
|
||
Bitmap target = Bitmap.createBitmap( source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888 );
|
||
Canvas canvas = new Canvas( target );
|
||
RectF rect = new RectF( 0, 0, source.getWidth(), source.getHeight() );
|
||
canvas.drawRoundRect( rect, corner, corner, paint );
|
||
paint.setXfermode( new PorterDuffXfermode( PorterDuff.Mode.SRC_IN ) );
|
||
canvas.drawBitmap( source, 0, 0, paint );
|
||
return target;
|
||
}
|
||
|
||
public static byte[] bitmapToBytes( Bitmap bitmap ) {
|
||
if ( bitmap == null ) {
|
||
return null;
|
||
}
|
||
|
||
ByteArrayOutputStream bos = null;
|
||
byte[] result = null;
|
||
|
||
try {
|
||
bos = new ByteArrayOutputStream();
|
||
bitmap.compress( Bitmap.CompressFormat.JPEG, 100, bos );
|
||
result = bos.toByteArray();
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
result = null;
|
||
} finally {
|
||
IOUtils.closeSilently( bos );
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Use quality compression to compress bitmap's size to be smaller than a max size, and convert it to bytes thereafter.
|
||
* Note that this method will not report compressing ratio related data.
|
||
*
|
||
* @param bitmap data source
|
||
* @param maxSize unit in kb
|
||
* @return bytes after compressing bitmap to a size smaller than a specific max size.
|
||
*/
|
||
public static byte[] bitmapToBytes( Bitmap bitmap, int maxSize ) {
|
||
final long start = System.currentTimeMillis();
|
||
|
||
if ( bitmap == null ) {
|
||
return null;
|
||
}
|
||
|
||
final int maxSizeOfBytes = maxSize * ONE_KB;
|
||
ByteArrayOutputStream bos = null;
|
||
byte[] result = null;
|
||
|
||
try {
|
||
bos = new ByteArrayOutputStream();
|
||
int quality = 100;
|
||
int fullSize = 0;
|
||
|
||
do {
|
||
bos.reset();
|
||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||
if ( quality == 100 ) {
|
||
fullSize = bos.size();
|
||
}
|
||
Log.i( TAG, "quality<---->size, " + quality + "<---->" + bos.size() / 1024 );
|
||
}
|
||
while ( bos.size() > maxSizeOfBytes && ( quality -= ( fullSize > ONE_MB ) ? 10 : 5 ) >= 0 );
|
||
|
||
result = bos.toByteArray();
|
||
|
||
final long end = System.currentTimeMillis();
|
||
Log.i( TAG,
|
||
"bitmap to bytes costs " + ( end - start ) + "ms, \n" +
|
||
"bitmap full size is " + ( fullSize / 1024 ) + "kb, \n" +
|
||
"bitmap final size is " + ( bos.size() / 1024 ) + "kb, \n" +
|
||
"bitmap quality is " + quality );
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
result = null;
|
||
} finally {
|
||
IOUtils.closeSilently( bos );
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Use quality compression to compress bitmap to be smaller than a specific max size.
|
||
*
|
||
* @param bitmap data source
|
||
* @param maxSize a specific max size which's unit is kb.
|
||
* @return a compressed bitmap smaller than the max size.
|
||
*/
|
||
public static Bitmap compressBitmap( Bitmap bitmap, int maxSize, final OnCompressListener listener ) {
|
||
if ( bitmap == null || bitmap.isRecycled() ) {
|
||
return null;
|
||
}
|
||
listener.onBeforeCompress();
|
||
ByteArrayOutputStream bos = null;
|
||
Bitmap target = null;
|
||
|
||
try {
|
||
bos = new ByteArrayOutputStream();
|
||
int quality = 100;
|
||
|
||
do {
|
||
bos.reset();
|
||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||
}
|
||
while ( bos.size() / 1024 > maxSize && ( quality -= 5 ) >= 0 );
|
||
|
||
byte[] result = bos.toByteArray();
|
||
target = bytesToBitmap( result );
|
||
if ( listener != null ) {
|
||
listener.onCompressSuccess( result );
|
||
}
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
target = null;
|
||
if ( listener != null ) {
|
||
listener.onCompressFailed( "压缩失败" );
|
||
}
|
||
} finally {
|
||
IOUtils.closeSilently( bos );
|
||
}
|
||
|
||
return target;
|
||
}
|
||
|
||
|
||
public static Bitmap compressBitmap( Bitmap bitmap, int maxSize ) {
|
||
if ( bitmap == null ) {
|
||
return null;
|
||
}
|
||
|
||
ByteArrayOutputStream bos = null;
|
||
Bitmap target = null;
|
||
|
||
try {
|
||
bos = new ByteArrayOutputStream();
|
||
int quality = 100;
|
||
|
||
do {
|
||
bos.reset();
|
||
bitmap.compress( Bitmap.CompressFormat.JPEG, quality, bos );
|
||
}
|
||
while ( bos.size() / 1024 > maxSize && ( quality -= 5 ) >= 0 );
|
||
|
||
byte[] result = bos.toByteArray();
|
||
target = bytesToBitmap( result );
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
target = null;
|
||
} finally {
|
||
IOUtils.closeSilently( bos );
|
||
}
|
||
|
||
return target;
|
||
}
|
||
|
||
/**
|
||
* Decode an immutable bitmap from the specified byte array.
|
||
*
|
||
* @param b byte array of compressed image data
|
||
* @return an immutable bitmap or null in case of exception.
|
||
*/
|
||
public static Bitmap bytesToBitmap( byte[] b ) {
|
||
if ( b != null && b.length != 0 ) {
|
||
return BitmapFactory.decodeByteArray( b, 0, b.length );
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Decode an immutable bitmap from the specified byte array.
|
||
*
|
||
* @param b byte array of compressed image data
|
||
* @param options Options that control downsampling and whether the
|
||
* image should be completely decoded, or just is size returned.
|
||
* @return an immutable bitmap or null in case of exception.
|
||
*/
|
||
public static Bitmap bytesToBitmap( byte[] b, BitmapFactory.Options options ) {
|
||
if ( b.length != 0 ) {
|
||
return BitmapFactory.decodeByteArray( b, 0, b.length, options );
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get max supported image size which will differ from different devices.
|
||
*
|
||
* @return max size related to the device.
|
||
*/
|
||
public static int getMaxSupportedImageSize() {
|
||
int textureLimit = getMaxTextureSize();
|
||
if ( textureLimit == 0 ) {
|
||
return SIZE_DEFAULT;
|
||
} else {
|
||
return Math.min( textureLimit, SIZE_LIMIT );
|
||
}
|
||
}
|
||
|
||
public static int getMaxTextureSize2() {
|
||
// The OpenGL texture size is the maximum size that can be drawn in an ImageView
|
||
int[] maxSize = new int[1];
|
||
GLES10.glGetIntegerv( GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0 );
|
||
return maxSize[0];
|
||
}
|
||
|
||
/**
|
||
* Decode a bitmap's input stream to find a proper inSampleSize according to device's max supported size.
|
||
*
|
||
* @param is bitmap's data source
|
||
* @param close whether to close input stream after work is done.
|
||
* @return a proper inSampleSize
|
||
*/
|
||
public static int findProperInSampleSize( InputStream is, boolean close ) {
|
||
// Just decode image size into options
|
||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||
options.inJustDecodeBounds = true;
|
||
|
||
try {
|
||
BitmapFactory.decodeStream( is, null, options );
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
} finally {
|
||
if ( close ) IOUtils.closeSilently( is );
|
||
}
|
||
|
||
int maxSize = getMaxSupportedImageSize();
|
||
int sampleSize = 1;
|
||
|
||
while ( options.outHeight / sampleSize > maxSize || options.outWidth / sampleSize > maxSize ) {
|
||
sampleSize = sampleSize << 1;
|
||
}
|
||
|
||
Log.i( TAG, "sample size is " + sampleSize );
|
||
return sampleSize;
|
||
}
|
||
|
||
/**
|
||
* Read a picture's degree from a file.
|
||
*
|
||
* @param file data source of a picture
|
||
* @return degrees range from 0 to 360
|
||
*/
|
||
public static int readPictureDegree( File file ) {
|
||
return readPictureDegree( file.getAbsolutePath() );
|
||
}
|
||
|
||
/**
|
||
* Read a picture's degree from a file, we use {@link ExifInterface} instead of {@link android.media.ExifInterface}
|
||
* to avoid some unexpected bugs.
|
||
*
|
||
* @param filePath file's absolute path which we can read data source of a picture from.
|
||
* @return degrees range from 0 to 360
|
||
*/
|
||
public static int readPictureDegree( String filePath ) {
|
||
int degree = 0;
|
||
|
||
try {
|
||
ExifInterface exifInterface = new ExifInterface( filePath );
|
||
int orientation = exifInterface.getAttributeInt( ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL );
|
||
switch ( orientation ) {
|
||
case ExifInterface.ORIENTATION_ROTATE_90:
|
||
degree = 90;
|
||
break;
|
||
case ExifInterface.ORIENTATION_ROTATE_180:
|
||
degree = 180;
|
||
break;
|
||
case ExifInterface.ORIENTATION_ROTATE_270:
|
||
degree = 270;
|
||
break;
|
||
}
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
}
|
||
Log.i( TAG, "ExifInterface, degree is " + degree );
|
||
|
||
return degree;
|
||
}
|
||
|
||
/**
|
||
* Rotate an bitmap to a specific angle.
|
||
*
|
||
* @param angle target angle
|
||
* @param bitmap data source
|
||
* @return Returns an immutable bitmap from subset of the source bitmap,
|
||
* transformed by the optional matrix. The new bitmap may be the
|
||
* same object as source, or a copy may have been made. It is
|
||
* initialized with the same density as the original bitmap.
|
||
* <p>
|
||
* If the source bitmap is immutable and the requested subset is the
|
||
* same as the source bitmap itself, then the source bitmap is
|
||
* returned and no new bitmap is created.
|
||
*/
|
||
public static Bitmap rotateBitmap( int angle, Bitmap bitmap ) {
|
||
if ( bitmap == null ) {
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
int width = bitmap.getWidth();
|
||
int height = bitmap.getHeight();
|
||
Matrix matrix = new Matrix();
|
||
matrix.preRotate( angle );
|
||
return Bitmap.createBitmap( bitmap, 0, 0, width, height, matrix, true );
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
return bitmap;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Get picture's absolute path according to its uri.
|
||
*
|
||
* @param context context
|
||
* @param uri picture's uri
|
||
* @return absolute path of uri.
|
||
*/
|
||
public static String getRealPathFromUri( Context context, Uri uri ) {
|
||
int sdkVersion = Build.VERSION.SDK_INT;
|
||
if ( sdkVersion >= 19 ) {
|
||
return getRealPathFromUriAboveApi19( context, uri );
|
||
} else {
|
||
return getRealPathFromUriBelowAPI19( context, uri );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create a default {@link BitmapFactory.Options} .
|
||
* Note this options use rgb_565 and a proper inSampleSize in order to save memory.
|
||
*
|
||
* @param is data source of picture
|
||
* @param close whether to close data source
|
||
* @return options containing rgb_565 config and a proper inSampleSize.
|
||
*/
|
||
public static BitmapFactory.Options newDefaultOptions( InputStream is, boolean close ) {
|
||
final BitmapFactory.Options options = new BitmapFactory.Options();
|
||
options.inPreferredConfig = Bitmap.Config.RGB_565;
|
||
options.inSampleSize = BitmapHelper.findProperInSampleSize( is, close );
|
||
|
||
return options;
|
||
}
|
||
|
||
/**
|
||
* Save picture to local file.
|
||
*
|
||
* @param bitmap data source
|
||
* @param file local file to store picture.
|
||
*/
|
||
public static void savePicture( Bitmap bitmap, File file ) {
|
||
final long start = System.currentTimeMillis();
|
||
|
||
if ( bitmap == null || file == null ) {
|
||
Log.i( TAG, "保存失败, bitmap or file is null." );
|
||
return;
|
||
}
|
||
if ( file.getParentFile() != null && !file.getParentFile().exists() ) {
|
||
file.getParentFile().mkdirs();
|
||
}
|
||
|
||
try {
|
||
final FileOutputStream fos = new FileOutputStream( file );
|
||
bitmap.compress( Bitmap.CompressFormat.JPEG, 100, fos );
|
||
fos.flush();
|
||
fos.close();
|
||
|
||
if ( file.exists() ) {
|
||
Log.i( TAG, "保存成功" );
|
||
}
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
Log.i( TAG, "saving picture costs " + ( System.currentTimeMillis() - start ) + "ms" );
|
||
}
|
||
|
||
/**
|
||
* 适配api19以下(不包括api19),根据uri获取图片的绝对路径
|
||
*
|
||
* @param context 上下文对象
|
||
* @param uri 图片的Uri
|
||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||
*/
|
||
private static String getRealPathFromUriBelowAPI19( Context context, Uri uri ) {
|
||
return getDataColumn( context, uri, null, null );
|
||
}
|
||
|
||
/**
|
||
* 适配api19及以上,根据uri获取图片的绝对路径
|
||
*
|
||
* @param context 上下文对象
|
||
* @param uri 图片的Uri
|
||
* @return 如果Uri对应的图片存在, 那么返回该图片的绝对路径, 否则返回null
|
||
*/
|
||
@SuppressLint( "NewApi" )
|
||
private static String getRealPathFromUriAboveApi19( Context context, Uri uri ) {
|
||
String filePath = null;
|
||
|
||
try {
|
||
// 如果是document类型的 uri, 则通过document id来进行处理
|
||
if ( DocumentsContract.isDocumentUri( context, uri ) ) {
|
||
String documentId = DocumentsContract.getDocumentId( uri );
|
||
if ( isMediaDocument( uri ) ) {
|
||
// 使用':'分割
|
||
String id = documentId.split( ":" )[1];
|
||
String selection = MediaStore.Images.Media._ID + "=?";
|
||
String[] selectionArgs = {id};
|
||
filePath = getDataColumn( context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs );
|
||
} else if ( isDownloadsDocument( uri ) ) {
|
||
Uri contentUri = ContentUris.withAppendedId( Uri.parse( "content://downloads/public_downloads" ), Long.valueOf( documentId ) );
|
||
filePath = getDataColumn( context, contentUri, null, null );
|
||
}
|
||
} else if ( "content".equalsIgnoreCase( uri.getScheme() ) ) {
|
||
filePath = getDataColumn( context, uri, null, null );
|
||
} else if ( "file".equals( uri.getScheme() ) ) {
|
||
filePath = uri.getPath();
|
||
}
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
return filePath;
|
||
}
|
||
|
||
/**
|
||
* 获取数据库表中的 _data 列,即返回Uri对应的文件路径
|
||
*/
|
||
private static String getDataColumn( Context context, Uri uri, String selection, String[] selectionArgs ) {
|
||
String path = null;
|
||
String[] projection = new String[]{MediaStore.Images.Media.DATA};
|
||
Cursor cursor = null;
|
||
|
||
try {
|
||
cursor = context.getContentResolver().query( uri, projection, selection, selectionArgs, null );
|
||
|
||
if ( cursor != null && cursor.moveToFirst() ) {
|
||
int columnIndex = cursor.getColumnIndexOrThrow( projection[0] );
|
||
path = cursor.getString( columnIndex );
|
||
}
|
||
} catch ( Exception e ) {
|
||
if ( cursor != null ) {
|
||
cursor.close();
|
||
cursor = null;
|
||
}
|
||
} finally {
|
||
if ( cursor != null ) {
|
||
cursor.close();
|
||
cursor = null;
|
||
}
|
||
}
|
||
|
||
return path;
|
||
}
|
||
|
||
/**
|
||
* @param uri the Uri to check
|
||
* @return Whether the Uri authority is MediaProvider
|
||
*/
|
||
private static boolean isMediaDocument( Uri uri ) {
|
||
return "com.android.providers.media.documents".equals( uri.getAuthority() );
|
||
}
|
||
|
||
/**
|
||
* @param uri the Uri to check
|
||
* @return Whether the Uri authority is DownloadsProvider
|
||
*/
|
||
private static boolean isDownloadsDocument( Uri uri ) {
|
||
return "com.android.providers.downloads.documents".equals( uri.getAuthority() );
|
||
}
|
||
|
||
public static int getMaxTextureSize() {
|
||
try {
|
||
// Safe minimum default size
|
||
final int IMAGE_MAX_BITMAP_DIMENSION = SIZE_DEFAULT;
|
||
|
||
// Get EGL Display
|
||
EGL10 egl = ( EGL10 ) EGLContext.getEGL();
|
||
EGLDisplay display = egl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY );
|
||
|
||
// Initialise
|
||
int[] version = new int[2];
|
||
egl.eglInitialize( display, version );
|
||
|
||
// Query total number of configurations
|
||
int[] totalConfigurations = new int[1];
|
||
egl.eglGetConfigs( display, null, 0, totalConfigurations );
|
||
|
||
// Query actual list configurations
|
||
EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
|
||
egl.eglGetConfigs( display, configurationsList, totalConfigurations[0], totalConfigurations );
|
||
|
||
int[] textureSize = new int[1];
|
||
int maximumTextureSize = 0;
|
||
|
||
// Iterate through all the configurations to located the maximum texture size
|
||
for ( int i = 0; i < totalConfigurations[0]; i++ ) {
|
||
// Only need to check for width since opengl textures are always squared
|
||
egl.eglGetConfigAttrib( display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize );
|
||
|
||
// Keep trackCustomEvent of the maximum texture size
|
||
if ( maximumTextureSize < textureSize[0] )
|
||
maximumTextureSize = textureSize[0];
|
||
}
|
||
|
||
// Release
|
||
egl.eglTerminate( display );
|
||
|
||
// Return largest texture size found, or default
|
||
return Math.max( maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION );
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
public static String bitmapToBase64( Bitmap bitmap ) {
|
||
String result = null;
|
||
try {
|
||
if ( bitmap != null ) {
|
||
result = Base64.encodeToString( bitmapToBytes( bitmap ), Base64.DEFAULT );
|
||
}
|
||
} catch ( Exception e ) {
|
||
e.printStackTrace();
|
||
}
|
||
return result;
|
||
}
|
||
|
||
public static Bitmap base64ToBitmap( String base64Data ) {
|
||
byte[] bytes = Base64.decode( base64Data, Base64.DEFAULT );
|
||
return BitmapFactory.decodeByteArray( bytes, 0, bytes.length );
|
||
}
|
||
|
||
/**
|
||
* 在系统返回的intent中获取图片信息,并转化为uri
|
||
*
|
||
* @param data
|
||
* @return
|
||
*/
|
||
public static Uri convertUri( Context context, Intent data ) {
|
||
if ( data == null || data.getData() == null ) {
|
||
return null;
|
||
}
|
||
Uri localUri = data.getData();
|
||
String scheme = localUri.getScheme();
|
||
String imagePath = "";
|
||
if ( "content".equals( scheme ) ) {
|
||
String[] filePathColumns = {MediaStore.Images.Media.DATA};
|
||
Cursor c = context.getContentResolver().query( localUri, filePathColumns, null, null, null );
|
||
if ( c != null ) {
|
||
c.moveToFirst();
|
||
int columnIndex = c.getColumnIndex( filePathColumns[0] );
|
||
imagePath = c.getString( columnIndex );
|
||
c.close();
|
||
}
|
||
} else if ( "file".equals( scheme ) ) {//小米4选择云相册中的图片是根据此方法获得路径
|
||
imagePath = localUri.getPath();
|
||
}
|
||
if ( TextUtils.isEmpty( imagePath ) ) {
|
||
return localUri;
|
||
}
|
||
Uri uri = Uri.fromFile( new File( imagePath ) );
|
||
return uri != null ? uri : localUri;
|
||
}
|
||
|
||
public static Bitmap colorToBitmap( Context context, int colorResId ) {// drawable 转换成bitmap
|
||
Bitmap.Config config = Bitmap.Config.ARGB_8888;// 取drawable的颜色格式
|
||
Bitmap bitmap = Bitmap.createBitmap( 1, 1, config );// 建立对应bitmap
|
||
bitmap.eraseColor( context.getResources().getColor( colorResId ) );
|
||
return bitmap;
|
||
}
|
||
|
||
public static String getAlphaHexValue( float alpha ) {
|
||
String color = Integer.toHexString( ( int ) alpha * 255 );
|
||
return TextUtils.isEmpty( color ) ? color : color.toUpperCase();
|
||
}
|
||
|
||
/**
|
||
* 抓取本地视频缩略图(操作可能耗时,尽量异步进行)
|
||
*
|
||
* @param filePath
|
||
* @return
|
||
*/
|
||
public static Bitmap getVideoThumbnail( String filePath ) {
|
||
Bitmap b = null;
|
||
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
|
||
try {
|
||
retriever.setDataSource( filePath );
|
||
b = retriever.getFrameAtTime();
|
||
} catch ( IllegalArgumentException e ) {
|
||
e.printStackTrace();
|
||
} catch ( RuntimeException e ) {
|
||
e.printStackTrace();
|
||
|
||
} finally {
|
||
try {
|
||
retriever.release();
|
||
} catch ( RuntimeException e ) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
return b;
|
||
}
|
||
|
||
public interface OnCompressListener {
|
||
|
||
void onCompressSuccess( byte[] data );
|
||
|
||
void onCompressFailed( String msg );
|
||
|
||
void onBeforeCompress();
|
||
}
|
||
}
|