您的位置:首页 > 移动开发 > Android开发

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

2014-12-04 10:45 656 查看
 1,Bitmap对象的获取

      首先说一下Bitmap,Bitmap是Android系统中的图像处理的最重要类之一。用它可以获取图像文件信息,进行图像剪切、旋转、缩放等操作,并可以指定格式保存图像文件,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直接对拿来的图片读取字节码了, 不会根据机器的各种分辨率来自动适应。

  补充:

  使用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上,然后在调用显示方法,繁琐是有一点,不过这样可以对图片进行变换和保存等操作)。

1 protected void onDraw(Canvas canvas) { //绘制矩形 2 Paint mpaint = new Paint(); 3 mpaint.setColor(mcolorfill); 4 mpaint.setStyle(Paint.Style.FILL); 5 mpaint.setStrokeWidth(1.0f); 6 canvas.drawLine(mleft, mtop, mleft+mwidth, mtop, mpaint); 7 canvas.drawLine(mleft, mtop, mleft, mtop+mheight, mpaint); 8 canvas.drawLine(mleft+mwidth, mtop, mleft+mwidth, mtop+mheight, mpaint); 9 canvas.drawLine(mleft, mtop+mheight, mleft+mwidth, mtop+mheight, mpaint); 10 super.onDraw(canvas); 11 }


  补充:上面绘制矩形时同时使用了paint和canvas对象,我们可以这样理解,Android中paint和canvas联合起来就相当于java中的画笔Graphics,只不过Android中的画笔分工更明确,paint对象用来设置画笔的具体特征,如颜色、粗细及样式等,而canvas对象用来绘制点,线,图。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Bitmap
相关文章推荐