Android视频图片缩略图的获取
Android视频图片缩略图的获取
这次项目中使用到拍照和拍摄视频的功能,那么既然是拍照和拍视频肯定涉及到缩略图的处理。所以接下来我们要学习下载android中如何处理图片和视频来获取我们需要的缩略图。幸运的是,android已经给我们提供好了具体的工具类,所以我们只需要学习这么工具类的api如何使用。
现在直接切入正题,对于获取视频缩略图,android系统中提供了ThumbnailUtils、android.provider.MediaStore.Images.Thumbnails、android.provider.MediaStore.Video.Thumbnails、MediaMetadataRetriever几个类可以使用,在这篇文章中,我仅仅对ThumbnailsUtils进行分析,肯能后续文章会介绍下后面三个类。
ThumbnailUtils
ThumbnailUtils方法是在android2.2(api8)之后新增的一个,该类为我们提供了三个静态方法供我们使用。
- ThumbnailUtils.createVideoThumbnail(filePath, kind):
创建视频缩略图,filePath:文件路径,kind:MINI_KIND or MICRO_KIND - ThumbnailUtils.extractThumbnail(bitmap, width, height):
将bitmap裁剪为指定的大小 - ThumbnailUtils.extractThumbnail(bitmap, width, height, options):将bitmap裁剪为指定的大小,可以有参数BitmapFactory.Options参数
下面我们分别介绍下这三个方法:
(1)、createVideoThumbnail:
我们先看看它的源码:
/** * Create a video thumbnail for a video. May return null if the video is * corrupt or the format is not supported. * * @param filePath the path of video file * @param kind could be MINI_KIND or MICRO_KIND */ public static Bitmap createVideoThumbnail(String filePath, int kind) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePath); bitmap = retriever.getFrameAtTime(-1); } catch (IllegalArgumentException ex) { // Assume this is a corrupt video file } catch (RuntimeException ex) { // Assume this is a corrupt video file. } finally { try { retriever.release(); } catch (RuntimeException ex) { // Ignore failures while cleaning up. } } if (bitmap == null) return null; if (kind == Images.Thumbnails.MINI_KIND) { // Scale down the bitmap if it's too large. int width = bitmap.getWidth(); int height = bitmap.getHeight(); int max = Math.max(width, height); if (max > 512) { float scale = 512f / max; int w = Math.round(scale * width); int h = Math.round(scale * height); bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true); } } else if (kind == Images.Thumbnails.MICRO_KIND) { bitmap = extractThumbnail(bitmap, TARGET_SIZE_MICRO_THUMBNAIL, TARGET_SIZE_MICRO_THUMBNAIL, OPTIONS_RECYCLE_INPUT); } return bitmap; }
通过观看源码:我们发现该方法的内部也是使用了一个MediaMetadataRetriever的对象,那这个对象究竟是何方神圣呢?容我们稍后再说,反正就是通过这个对象获得了一个bitmap对象,然后再根据kind的类型进行图片的压缩。源码的总体思路就是这样。
参数说明:
- filePath表示视频文件路径
- kind表示类型,可以有两个选项,分别是Images.Thumbnails.MICRO_KIND和Images.Thumbnails.MINI_KIND,其中,MINI_KIND: 512 x 384,MICRO_KIND: 96 x 96,当然读了代码你会发现,你也可以传入任意的int型数字,只是不起作用罢了。
(2)、extractThumbnail(Bitmap source, int width, int height):进行图片的裁剪
我们先看看源码:
/** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height */ public static Bitmap extractThumbnail( Bitmap source, int width, int height) { return extractThumbnail(source, width, height, OPTIONS_NONE); }
源码很简单,就是调用了 extractThumbnail的兄弟。
参数说明:
- source:表示图片源文件(Bitmap类型)
- width:表示压缩成后的宽度
- height:表示压缩成后的高度
(3)、extractThumbnail( Bitmap source, int width, int height, int options):进行图片的额裁剪,指定options选项。
看看源码:
/** * Creates a centered bitmap of the desired size. * * @param source original bitmap source * @param width targeted width * @param height targeted height * @param options options used during thumbnail extraction */ public static Bitmap extractThumbnail( Bitmap source, int width, int height, int options) { if (source == null) { return null; } float scale; if (source.getWidth() < source.getHeight()) { scale = width / (float) source.getWidth(); } else { scale = height / (float) source.getHeight(); } Matrix matrix = new Matrix(); matrix.setScale(scale, scale); Bitmap thumbnail = transform(matrix, source, width, height, OPTIONS_SCALE_UP | options); return thumbnail; }
源码中的处理采用Matrix对象进行变换操作,也不是很复杂,对Matrix不是很熟悉的同学可以搜下用法。在我们自定义view中还是很有用途的。
参数说明:
- source:表示图片源文件(Bitmap类型)
- width:表示压缩成后的宽度
- height:表示压缩成后的高度
- options:表示缩略图抽取时的选项,如果options定义为OPTIONS_RECYCLE_INPUT,则回收@param source这个资源文件(除非缩略图等于@param source)
ThumbnailUtils类的核心就是这三个方法,我们只需要知道如何使用即可。更多内容参考欧阳鹏写的这篇文章。
下面我们通过一个案例来介绍下它的使用。案例的需求就是:调用系统的相机进行拍照和拍摄视频功能,然后展示缩略图。需求很简单,核心就是利用ThumbnailUtils工具类进行缩略图的处理。现在我们开始来完成这个需求。我们在eclipse中创建工程PicturePhotoDemo。
1、首先进行我们的主页面布局搭建:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.dsw.picturephotodemo.MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:textSize="20sp" android:padding="10dp" android:text="@string/hello_world" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" android:gravity="center_horizontal" android:orientation="horizontal"> <Button android:id="@+id/take_picture" android:layout_height="wrap_content" android:layout_width="100dp" android:text="@string/take_picture" android:textSize="17sp"/> <Button android:id="@+id/take_video" android:layout_height="wrap_content" android:layout_width="100dp" android:text="@string/take_video" android:textSize="17sp"/> </LinearLayout> <com.dsw.horizonlistview.HorizontalListView android:id="@+id/horizontalListView" android:layout_width="match_parent" android:layout_gravity="center_vertical" android:spacing="5dp" android:layout_height="100dp" android:scrollbars="@null"> </com.dsw.horizonlistview.HorizontalListView> </LinearLayout>
效果图如下:
在上面的布局中,我们使用了一个自定义View名为HorizontalListView(一个大牛写的,拿来用了)。HorizontalListView的源码就不贴了,太多了,而且不是我们的重点,有兴趣研究的同学可以稍后下载demo工程,在工程中有。我们只需知道HorizontalListView是一个横向的ListView,使用方法同ListView,同样需要Adapter的使用。
2、我们新建一个MeadiaInformation的实体,用于存储我们的照片信息。
public class MeadiaInformation { //图片路径 public String srcPath; //图片:type=0 视频:type=1 public int type; //bitmap资源图片 public Bitmap bitmap; }
3、我们自定义HorizontalListViewAdapter适配器,用于处理我们的图片展示。
public class HorizontalListViewAdapter extends BaseAdapter{ private Context mContext; private LayoutInflater mInflater; Bitmap iconBitmap; private int selectIndex; private List<MeadiaInformation> list; public HorizontalListViewAdapter(Context context, List<MeadiaInformation> list){ this.mContext = context; this.list = list; mInflater=(LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);//LayoutInflater.from(mContext); } @Override public int getCount() { return list == null ? 0 : list.size(); } @Override public Object getItem(int position) { return list == null ? null : list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if(convertView==null){ holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.horizontal_list_item, null); holder.mImage=(ImageView)convertView.findViewById(R.id.img_list_item); holder.mVideoImage = (ImageView) convertView.findViewById(R.id.img_video); convertView.setTag(holder); }else{ holder=(ViewHolder)convertView.getTag(); } //判断当前项是否为选中项 if(position == selectIndex){ convertView.setSelected(true); }else{ convertView.setSelected(false); } if(list != null && list.size() > 0){ iconBitmap = list.get(position).bitmap; holder.mImage.setImageBitmap(iconBitmap); if(list.get(position).type == 1){//如果是视频,就显示视频播放按钮 holder.mVideoImage.setVisibility(View.VISIBLE); }else{//如果不是视频就不显示该播放按钮 holder.mVideoImage.setVisibility(View.INVISIBLE); } } return convertView; } private static class ViewHolder { //展示图片的额ImageView private ImageView mImage; //展示视频中间的播放图片 private ImageView mVideoImage; } /** * 添加展示项 * @param infor */ public void addInformation(MeadiaInformation infor){ list.add(infor); notifyDataSetChanged(); } /** * 添加音频集合信息 * @param listInfo */ public void addInformationList(List<MeadiaInformation> listInfo){ list.addAll(listInfo); notifyDataSetChanged(); } /** * 添加选中的item * @param i */ public void setSelectIndex(int i){ selectIndex = i; } /** * 获取当前选中项 * @return */ public int getSelectIndex(){ return this.selectIndex; } }
3、万事具备,我们需要在MainActivity中处理我们的拍照逻辑,然后处理缩略图。本来我是想贴处理那部分的代码的,但是感觉逻辑有点接不上了,所以还是把MainActivity都贴出来吧!
public class MainActivity extends Activity { //拍照的请求码 private static final int REQUEST_TAKE_PITURE = 100; //拍视频的请求码 private static final int REQUEST_TAKE_VIDEO = 200; private MainActivity _this; //拍照按钮 private Button btn_takePicture; //拍视频按钮 private Button btn_takeVideo; //文件存储路径 private String path; //文件file private File photoFile; //图片展示的ListView private HorizontalListView listView; //ListView的适配器 private HorizontalListViewAdapter listViewAdapter; //构造的多媒体对象 private MeadiaInformation infor; private DisplayMetrics metrics; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); _this =this; btn_takePicture = (Button) findViewById(R.id.take_picture); btn_takeVideo = (Button) findViewById(R.id.take_video); listView = (HorizontalListView) findViewById(R.id.horizontalListView); metrics = getResources().getDisplayMetrics(); setOnListener(); initAdapter(); initPath(); } /** * 初始化存储路径 */ private void initPath(){ //判断是否有存储卡 if(Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())){ //有存储卡获取路径 path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/PhotoDemo/"; }else{ //没有存储卡的时候,存储到这个路径 path = getApplicationContext().getFilesDir().getPath()+ "/PhotoDemo/"; } File file = new File(path); if(!file.exists()){ file.mkdirs(); } } /** * 设置适配器的初始化 */ private void initAdapter(){ List<MeadiaInformation> list = new ArrayList<MeadiaInformation>(); listViewAdapter = new HorizontalListViewAdapter(_this, list); listView.setAdapter(listViewAdapter); } /** * 设置控件监听 */ private void setOnListener(){ btn_takePicture.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Date date = new Date(); String name = path + "/" + date.getTime() + ".jpg"; photoFile = new File(name); Uri uri = Uri.fromFile(photoFile); Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 10); //启动照相 startActivityForResult(intent, REQUEST_TAKE_PITURE); } }); btn_takeVideo.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Date date = new Date(); String name = path + "/" + date.getTime() + ".3gp"; photoFile = new File(name); Uri uri = Uri.fromFile(photoFile); Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 10); //启动照相 startActivityForResult(intent, REQUEST_TAKE_VIDEO); } }); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long arg3) { listViewAdapter.setSelectIndex(position); listViewAdapter.notifyDataSetChanged(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { //通过requestCode判断类型,通过resultCode判断是否成功 if(resultCode == RESULT_OK){ infor = new MeadiaInformation(); infor.srcPath = photoFile.getAbsolutePath(); switch(requestCode){ case REQUEST_TAKE_PITURE: infor.type =0; break; case REQUEST_TAKE_VIDEO: infor.type =1; break; } getBitmapFromFile(); //将此MeadiaInformation添加到Adapter listViewAdapter.addInformation(infor); } } //根据文件路径获取缩略图 private void getBitmapFromFile() { /** * android系统中为我们提供了ThumbnailUtils工具类来获取缩略图的处理。 * ThumbnailUtils.createVideoThumbnail(filePath, kind) * 创建视频缩略图,filePath:文件路径,kind:MINI_KIND or MICRO_KIND * ThumbnailUtils.extractThumbnail(bitmap, width, height) * 将bitmap裁剪为指定的大小 * ThumbnailUtils.extractThumbnail(bitmap, width, height, options) * 将bitmap裁剪为指定的大小,可以有参数BitmapFactory.Options参数 * */ Bitmap bitmap = null; if(infor.type == 0){//若果是图片,即拍照 //直接通过路径利用BitmapFactory来形成bitmap bitmap = BitmapFactory.decodeFile(infor.srcPath); }else if(infor.type == 1){//如果是视频,即拍摄视频 //利用ThumnailUtils bitmap = ThumbnailUtils.createVideoThumbnail(infor.srcPath, Images.Thumbnails.MINI_KIND); } //获取图片后,我们队图片进行压缩,获取指定大小 if(bitmap != null){ //裁剪大小 bitmap = ThumbnailUtils.extractThumbnail(bitmap, (int)(100*metrics.density), (int)(100*metrics.density)); }else{//如果为空,采用我们的默认图片 bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); } infor.bitmap = bitmap; } }
在MainActivity中我们点击【拍照】、【拍视频】按钮进行拍照和拍视屏,然后重写onActivityResult方法,进行拍摄回来的视频处理,接着最后就是对图片或视频进行获取缩略图处理,最后添加到listviewAdatper中进行展示。总体的处理逻辑就是这样,代码注释的也很详细,有兴趣的同学可以下载demo玩玩。先贴几张效果图:
源码下载
========================================
作者:mr_dsw 欢迎转载,与人分享是进步的源泉!
转载请保留地址:http://blog.csdn.net/mr_dsw
更多相关文章
- android 设置bitmap 设置图片的大小
- Android开发(十一)——ImageView的尺寸设置scaleType
- android webview 访问https链接中http的图片或视频
- Android(安卓)中的ListView选中项的背景颜色怎么设置?
- RatingBar 修改 颜色 大小 图片
- Android(安卓)图片的浏览、缩放、拖动和自动居中
- Android中使用ffmpeg库进行音视频开发
- android音频、视频、拍照基础操作
- [Android] Json格式解析和文字图片传输