Android视频图片缩略图的获取

这次项目中使用到拍照和拍摄视频的功能,那么既然是拍照和拍视频肯定涉及到缩略图的处理。所以接下来我们要学习下载android中如何处理图片和视频来获取我们需要的缩略图。幸运的是,android已经给我们提供好了具体的工具类,所以我们只需要学习这么工具类的api如何使用。

现在直接切入正题,对于获取视频缩略图,android系统中提供了ThumbnailUtilsandroid.provider.MediaStore.Images.Thumbnailsandroid.provider.MediaStore.Video.ThumbnailsMediaMetadataRetriever几个类可以使用,在这篇文章中,我仅仅对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>

效果图如下:
Android视频图片缩略图的获取_第1张图片

在上面的布局中,我们使用了一个自定义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玩玩。先贴几张效果图:

Android视频图片缩略图的获取_第2张图片
Android视频图片缩略图的获取_第3张图片

源码下载

========================================
作者:mr_dsw 欢迎转载,与人分享是进步的源泉!

转载请保留地址:http://blog.csdn.net/mr_dsw

更多相关文章

  1. [Android] Json格式解析和文字图片传输
  2. Android中使用ffmpeg库进行音视频开发
  3. Android 图片的浏览、缩放、拖动和自动居中
  4. 有需要免费视频的,Android ,IOS,H5,React Native,PHP都有!!
  5. android 从matrix获取处理过的图片的实际宽度
  6. Android 拍照 录音 拍视频 旋转 裁剪 压缩图片
  7. Android中imageView图片放大缩小及旋转功能示例代码

随机推荐

  1. Linux的网络设置
  2. Linux 批量添加和删除用户
  3. 没有光驱,但是有安装光盘,我可以通过网路进
  4. LINUX下CVS服务器安装及权限简单配置
  5. 〖Linux〗使用Qt5.2.0开发Android的NDK应
  6. 将现有数组中的所有元素传递给xargs
  7. linux安装flume及问题
  8. linux包之nc之nc命令
  9. 【Linux】鸟哥的Linux私房菜基础学习篇整
  10. linux利用CMakeLists编译cuda程序