Android应用程序开发之图片操作(一)——Bitmap,surfaceview,imageview,Canvas

 

  1,Bitmap对象的获取

首先说一下Bitmap,Bitmap是Android系统中的图像处理的最重要类之一,一般位图的文件格式后缀为bmp,作为一种逐像素的显示对象执行效率高,操作方便,但是缺点也很明显存储效率低。用它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,并可以指定格式保存图像文件,Bitmap对象里面存储的是位图数据,这些数据暂存在手机内存中,对图像的操作,其实就是对这些数据的操作。Bitmap定义在android.graphics包中。但是Bitmap类的构造函数是私有的,外面并不能实例化,只能是通过JNI实例化。这必然是 某个辅助类提供了创建Bitmap的接口,而这个类的实现通过JNI接口来实例化Bitmap的,这个类就是BitmapFactory。利用BitmapFactory可以从一个指定文件中,利用decodeFile()解出Bitmap;也可以定义的图片资源中,利用decodeResource()解出Bitmap,常见定义如下:

  Bitmap bm = BitmapFactory.decodeFile(String pathName);      //直接加载手机SDCard中的图像资源的文件路径

  Bitmap bm = BitmapFactory.decodeFile(String pathName, BitmapFactory.Options opts); //opts可指定图像文件的加载到内存的方式,如压缩和编码

  Bitmap bm = BitmapFactory.decodeResource(Resources res, int id);   //加载工程项目中的图像资源,id为该资源的ID号

  Bitmap bm = BitmapFactory.decodeResource(Resources res, int id, BitmapFactory.Options opts);   //同样,opts可指定图像文件的加载到内存的方式

  Bitmap bm = BitmapFactory.decodeStream(InputStream is);  //通过openRawResource方法得到工程项目中的图像资源的Raw数据流

  Bitmap bm = BitmapFactory.decodeStream(InputStream is, Rect outPadding, BitmapFactory.Options opts);   //同上

  Bitmap bm = BitmapFactory.decodeByteArray(byte[] data, int offset, int length); //当图像资源来自网络时,多使用此方法

  Bitmap bm = BitmapFactory.decodeByteArray(byte[] data, int offset, int length, BitmapFactory.Options opts); //同上

  上面一共有8种方法,分为4类,当图片较大时,我们使用decodeStream方法得到Bitmap数据,因为其它三种方法最终都是通过java层的createBitmap来完成的,需要消耗更多内存;decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以更有效减少加载的内存,从而更有效阻止out of Memory异常。但是,使用decodeStream有一个缺陷就是需要在hdpi和mdpi,ldpi中都配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了,因为decodeStream直接d读取图片的字节码,没有处理过程,因此不会根据机器的各种分辨率来自动适应;decodeResource可以直接加载Drawable里面的图片,最大的好处就是图片可以是多种格式,GIF、PNG、JPG,当然也支持BMP,当然还可以使用Drawable对象提供一些高级的可视化对象,比如渐变、旋转等(tween和frame动画-animation),最大的缺点就是在读取完图片数据后,会根据机器的分辨率,进行图片的适配处理,导致增大了很多很多dalvik内存消耗(参考:http://blog.sina.com.cn/s/blog_7139b0e30100xklb.html)。

  补充:

  使用decodeByteArray时,通常会涉及到数据流的操作,在数据流的操作中,经常会用到缓冲技术——ByteArrayOutputStream(),该方法可以定义一个字节数据缓冲区,并且随着数据的增多缓冲区会逐渐增大,这个缓冲区定义在内存中,因此不需要和文件关联(以前在学习java的io流时,经常是将流中的数据写到某一文件中)。并且它有一个一次读取字节缓冲区所有数据的方法,因此这个类在数据存储中用的很多。

 1 public String fileRead(String filenametext) throws Exception   2     {   3         FileInputStream fileinputstream = context.openFileInput(filenametext);//1,将数据读到输入流中       4         ByteArrayOutputStream memory = new ByteArrayOutputStream();               5         byte[] buffer = new byte[1024];   6         int len=0;   7         while((len = fileinputstream.read(buffer))!=-1)   8         {   9             memory.write(buffer, 0, len);//2,将流中的数据写到内存缓冲区里  10         }  11         byte[] data = memory.toByteArray();  //3,读取缓冲区的所有字节数据  12         return new String(data);    13           14     //    return data.toString();  这句话是不对的,因为data是一个数组对象,有默认的toString方法,返回值的byte类对象的哈希值  15     }  16 }

  2,利用Bitmap和Matrix实现图像的剪切、缩放和旋转变换

  Bitmap实现图像的变换,主要使用的是createBitmap()方法。

1 public static Bitmap createBitmap(Bitmap source, int x, int y, intwidth, int height,  Matrix m, boolean filter);    2 public static Bitmap createBitmap(Bitmap source, int x, int y, intwidth, int height);  3 public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight,boolean filter);    

  第一个方法是最终的实现,后两种只是对第一种方法的封装。第二个方法可以从源Bitmap中指定区域(x,y, width, height)中挖出一块来实现剪切;第三个方法可以把源Bitmap缩放为dstWidth x dstHeight的Bitmap。设置Matrix的Rotate(通过setRotate())或者Scale(通过setScale()),传入第一个方法,可同时实现旋转,缩放和剪切。

  3,图片的保存和显示

  有时要对网络中获取的图片或则我们自己绘制图片进行保存,那么首先就要获得图片的Bitmap数据对象,然后使用Bitmap.compress(),此方法的参数format可设置JPEG或PNG格式,表示图片的格式类型;quality可选择压缩质量;fOut是输出流(OutputStream),该方法甚至不需要图片显示在手机UI上。

 1 File file = new File(Environment.getExternalStorageDirectory());                    2 if (!file.exists()) {    3     file.mkdirs();    4     }    5 //第一步:创建文件对象,设置文件路径   6 File f = new File(file,fileName+".PNG");   7 FileOutputStream fout = null;   8 try{   9 //第二步:根据文件路径创建指定文件  10   f.createNewFile();  11 //第三步:创建文件的输出流对象  12    fout = new FileOutputStream(f);  13 //第四步:将Bitmap数据压缩到文件输出流中(为0时不压缩),得到.PNG图片  14    bm.compress(Bitmap.CompressFormat.PNG, 80, fout);  15 //第五步:将流中的数据刷到文件中并关闭流资源  16    fout.flush();  17    fout.close();  18    Toast.makeText(generateQR.this, R.string.save_success, Toast.LENGTH_LONG).show();  19 }catch(IOException e2){  20    e2.printStackTrace();  21 }

  如果要显示一张图片,我们一般会首先定义一个Imageview组件用来显示图片,然后调用该组件的setImageBitmap(Bitmap bitmap)方法或者setImageDrawable(Drawable drawable)方法或则setImageResource(int resId)方法。setImageBitmap(Bitmap bitmap)方法是我们用的最多的显示方法,当得到图片的bitmap数据后,就可使用该方法将图片显示在Imageview上(注意要控制bitmap的大小,不能超过Imageview的显示区域)。此外,当我们要将自己绘制的图片或则网络图片通过setImageBitmap等显示在Imageview上之后,还要进行保存等操作,这时我们可以直接从缓冲区中获取图片的bitmap数据对象:

FileOutputStream fos = new FileOutputStream(file);  imageview.setDrawingCacheEnabled(true);  Bitmap obmp =Bitmap.createBitmap(imageview.getDrawingCache());  imageview.setDrawingCacheEnabled(false);  obmp.compress(Bitmap.CompressFormat.PNG, 100, fos);  fos.flush();  fos.close();

  如果我们仅仅是为了显示我们自己要绘制的图片,而不涉及到图片的变换和保存等操作,我们就会使用surfaceview组件,将图片直接绘制到surfaceview的Canvas上,而不使用Imageview组件,也不需要使用Bitmap对象(使用Imageview显示我们要绘制的图片时,要先将图片绘制到Imageview的Canvas上,然后在调用显示方法,繁琐是有一点,不过这样可以对图片进行变换和保存等操作)。

  protected void onDraw(Canvas canvas) {   //绘制矩形     
Paint mpaint = new Paint();
    mpaint.setColor(mcolorfill);
   mpaint.setStyle(Paint.Style.FILL);
  mpaint.setStrokeWidth(1.0f);
canvas.drawLine(mleft, mtop, mleft+mwidth, mtop, mpaint);
canvas.drawLine(mleft, mtop, mleft, mtop+mheight, mpaint);
canvas.drawLine(mleft+mwidth, mtop, mleft+mwidth, mtop+mheight, mpaint);
canvas.drawLine(mleft, mtop+mheight, mleft+mwidth, mtop+mheight, mpaint);
super.onDraw(canvas);
}

  补充:上面绘制矩形时同时使用了paint和canvas对象,我们可以这样理解,Android中paint和canvas联合起来就相当于java中的画笔Graphics,只不过Android中的画笔分工更明确,paint对象用来设置画笔的具体特征,如颜色、粗细及样式等,而canvas对象用来绘制点,线,图。

参考资料:http://www.open-open.com/lib/view/open1333418945202.html

       http://blog.csdn.net/sweetsnow24/article/details/7968462

       http://developer.android.com/reference/android/graphics/BitmapFactory.html

     http://developer.android.com/reference/android/widget/ImageView.html#setImageBitmap(android.graphics.Bitmap)

来源:http://www.cnblogs.com/pengineer/p/3669449.html

Android应用程序开发之图片操作(一)——Bitmap,surfaceview,imageview,Canvas的更多相关文章

  1. Android应用程序开发之图片操作(二)——工程图片资源的加载及OOM的处理

    (一)工程图片资源的加载方法 在Android应用程序开发之图片操作(一)中,详细说明了如何操作各种资源图片,只是有的没有附上示例代码,在此,我将针对项目工程中的图片资源的显示加载进行说明.官方说明, ...

  2. Visual Studio 2017中使用正则修改部分内容 如何使用ILAsm与ILDasm修改.Net exe(dll)文件 C#学习-图解教程(1):格式化数字字符串 小程序开发之图片转Base64(C#、.Net) jquery遍历table为每一个单元格取值及赋值 。net加密解密相关方法 .net关于坐标之间一些简单操作

    Visual Studio 2017中使用正则修改部分内容   最近在项目中想实现一个小工具,需要根据类的属性<summary>的内容加上相应的[Description]特性,需要实现的效 ...

  3. 关于怎么快速学好Android应用程序开发及其其他编程语言(大牛和高手勿喷,此篇文章也适合刚入门小师弟和小师妹)

    无论你是从.NET转过来的也好 还是从PHP转过来的等等等,能看到这篇文章的人一般都是想快速转行到Android应用程序开发,希望我的这篇文章能勉励到各位的同时,也能勉励我自己. 1.编程语言基本都会 ...

  4. Kotlin 编程语言成为其 Android 应用程序开发人员的首选语言

    今年 5 月,谷歌在 I/O 大会上宣布,Kotlin 编程语言成为其 Android 应用程序开发人员的首选语言. Kotlin 是一种面向现代多平台应用程序的编程语言,成为谷歌开发 Android ...

  5. 【文章内容来自《Android 应用程序开发权威指南》(第四版)】如何设计兼容的用户界面的一些建议(有删改)

    最近一直在看的一本书是<Android 应用程序开发权威指南>(第四版),十分推荐.书中讲到了一些用户界面设计的规范,对于初学者我认为十分有必要,在这里码给大家,希望对我们都有用. 在我们 ...

  6. Android 应用程序窗口显示状态操作(requestWindowFeature()的应用)

     我们在开发程序是常常会须要软件全屏显示.自己定义标题(使用button等控件)和其它的需求,今天这一讲就是怎样控制Android应用程序的窗口显示. 首先介绍一个重要方法那就是requestWi ...

  7. 微信小程序开发之图片预览

    实现图片的展示和大图预览 使用wx.previewImage(OBJECT)来实现 OBJECT参数说明: 参数 类型 必填 说明 current String 否 当前显示图片的链接,不填则默认为 ...

  8. Android应用程序开发疑问

    为什么android.util.log会提供五种不同级别的打印输出方式?(打印输出在Logcat窗口)比如:Log.v()用于打印比较琐碎的信息:Log.d()用于打印调试信息:Log.i()用于打印 ...

  9. Android 应用程序窗体显示状态操作(requestWindowFeature()的应用)

     我们在开发程序是经常会需要软件全屏显示.自定义标题(使用按钮等控件)和其他的需求,今天这一讲就是如何控制Android应用程序的窗体显示. 首先介绍一个重要方法那就是requestWindowF ...

随机推荐

  1. Day14 HTML补充

    一.认识前端 前端开发的核心语言: html - 超文本标记语言 结构 css - 层叠样式表 样式 javascript - 脚本语言 行为 <html></html> 双标 ...

  2. python 时间戳

    import timeprint time.time()输出的结果是(单位:s):1395421406.39 x = time.localtime(x) x = time.strftime('%Y-% ...

  3. Webservices-1.web服务定义简介

    一.WEB服务定义(摘自维基百科)详情:http://zh.wikipedia.org/wiki/Web%E6%9C%8D%E5%8A%A1 Web服务是一种服务导向架构的技术,通过标准的Web协议提 ...

  4. 从NIB中加载VIEW

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ChatMoreView" owner:nil options:nil]; ...

  5. ASP.NET MVC轻教程 Step By Step 2 ——View初探

    在上一节我们完成了一个最简化的MVC程序,最重要的是下面这段代码. public class HomeController : Controller { public string Index() { ...

  6. How to use System.Diagnostics.Process correctly

    I’ve seen many a question on stackoverflow and other places about running a process and capturing it ...

  7. PKU 1064 Cable master

    题目链接:点击打开链接 有n段绳子,给定n段绳子的长度,单位为厘米.求能够把这些绳子分成k段的最长的段的长度.题目中的trick是最小是1cm,长度不能小于1cm,因此要转换成int来解,然后二分可以 ...

  8. Perl ping

    <pre name="code" class="html">use Net::Ping; $p = Net::Ping->new(" ...

  9. logstash 处理各种时间格式

    tomcat access日志: { "@version" => "1", "@timestamp" => "2016 ...

  10. 在InnoDB,记录在 non-clustered indexes(也被称为secondary indexes) 包含了主键值

    In InnoDB, the records in non-clustered indexes (also called secondary indexes) contain the primary ...