andriod图片的加载、处理

Bitmap 相关 

1. Bitmap比较特别 因为其不可创建 而只能借助于BitmapFactory 而根据图像来源又可分以下几种情况: 

* png图片 如:R.drawable.tianjin 

Java代码 
  1. Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.tianjin);   

* 图像文件 如: /sdcard/dcim/tianjin.jpeg 

Java代码 
  1. Bitmap bmp = BitmapFactory.decodeFile("/sdcard/dcoim/tianjin.jpeg")    

2. Bitmap 相关应用 

- 本地保存 即 把 Bitmap 保存在sdcard中 
* 创建目标文件的File 
Java代码
  1. File fImage = new File("/sdcard/dcim","beijing.jpeg");     
  2.     
  3. FileOutputStream iStream = new FileOutputStream(fImage);   
  

* 取出Bitmap oriBmp 
Java代码 
  1. oriBmp.compress(CompressFormat.JPEG, 100, iStream);   


参照Bitmap 的API方法 compress(Bitmap.CompressFormat format, int quality, OutputStream stream) 
Write a compressed version of the bitmap to the specified outputstream. 
写到输出流里,就保存到文件了。 


可以保存为几种格式:png,gif等: 
Java代码
  1. public void saveMyBitmap(String bitName) throws IOException {  
  2.                         File f = new File("/sdcard/Note/" + bitName + ".png");  
  3.                         f.createNewFile();  
  4.                         FileOutputStream fOut = null;  
  5.                         try {  
  6.                                 fOut = new FileOutputStream(f);  
  7.                         } catch (FileNotFoundException e) {  
  8.                                 e.printStackTrace();  
  9.                         }  
  10.                         mBitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);  
  11.                         try {  
  12.                                 fOut.flush();  
  13.                         } catch (IOException e) {  
  14.                                 e.printStackTrace();  
  15.                         }  
  16.                         try {  
  17.                                 fOut.close();  
  18.                         } catch (IOException e) {  
  19.                                 e.printStackTrace();  
  20.                         }  
  21.                 }  

- 得到网路图片  * 定义网络图片对应的BufferedInputStream 

Java代码 
  1. String icoURI = "http://202.140.96.134:8080/FS-RSS/img/RN.png";     
  2.     
  3. URL imgURL = new URL(iu);     
  4. URLConnection conn = imgURL.openConnection();     
  5.                  
  6. conn.connect();     
  7. InputStream is = conn.getInputStream();     
  8.                  
  9. BufferedInputStream bis = new BufferedInputStream(is);    

* 下载
  1. Bitmap bmp = BitmapFactory.decodeStream(bis);  
  
* 关闭Stream 
  1. bis.close();     
  2. is.close();    


位图是我们开发中最常用的资源,毕竟一个漂亮的界面对用户是最有吸引力的。 
1. 从资源中获取位图 
可以使用BitmapDrawable或者BitmapFactory来获取资源中的位图。 
当然,首先需要获取资源: 
Resources res=getResources(); 
使用BitmapDrawable获取位图 
   1. 
      使用BitmapDrawable (InputStream is)构造一个BitmapDrawable; 
   2. 
      使用BitmapDrawable类的getBitmap()获取得到位图; 

// 读取InputStream并得到位图 
  1. InputStream is=res.openRawResource(R.drawable.pic180);  
  2. BitmapDrawable bmpDraw=new BitmapDrawable(is);  
  3. Bitmap bmp=bmpDraw.getBitmap();  

或者采用下面的方式: 
  1. BitmapDrawable bmpDraw=(BitmapDrawable)res.getDrawable(R.drawable.pic180);  
  2. Bitmap bmp=bmpDraw.getBitmap();  

使用BitmapFactory获取位图 
(Creates Bitmap objects from various sources, including files, streams, and byte-arrays.) 

使用BitmapFactory类decodeStream(InputStream is)解码位图资源,获取位图。 
     Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180); 
BitmapFactory的所有函数都是static,这个辅助类可以通过资源ID、路径、文件、数据流等方式来获取位图。 

以上方法在编程的时候可以自由选择,在Android SDK中说明可以支持的图片格式如下:png (preferred), jpg (acceptable), gif (discouraged),和bmp(Android SDK Support Media Format)。 
2. 获取位图的信息 
要获取位图信息,比如位图大小、像素、density、透明度、颜色格式等,获取得到Bitmap就迎刃而解了,这些信息在Bitmap的手册中,这里只是辅助说明以下2点: 
      在Bitmap中对RGB颜色格式使用Bitmap.Config定义,仅包括ALPHA_8、ARGB_4444、ARGB_8888、RGB_565,缺少了一些其他的,比如说RGB_555,在开发中可能需要注意这个小问题; 
      Bitmap还提供了compress()接口来压缩图片,不过AndroidSAK只支持PNG、JPG格式的压缩;其他格式的需要Android开发人员自己补充了。 

3. 显示位图 
显示位图可以使用核心类Canvas,通过Canvas类的drawBirmap()显示位图,或者借助于BitmapDrawable来将Bitmap绘制到Canvas。当然,也可以通过BitmapDrawable将位图显示到View中。 

转换为BitmapDrawable对象显示位图 

Java代码   收藏代码
  1.  // 获取位图  
  2.  Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic180);  
  3.  // 转换为BitmapDrawable对象  
  4.  BitmapDrawable bmpDraw=new BitmapDrawable(bmp);  
  5.  // 显示位图  
  6.  ImageView iv2 = (ImageView)findViewById(R.id.ImageView02);  
  7. iv2.setImageDrawable(bmpDraw);  

使用Canvas类显示位图 
这儿采用一个继承自View的子类Panel,在子类的OnDraw中显示 
  1. public class MainActivity extends Activity {  
  2.     /** Called when the activity is first created. */  
  3.     @Override  
  4.     public void onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(new Panel(this));  
  7.     }  
  8.       
  9.     class Panel extends View{            
  10.         public Panel(Context context) {   
  11.             super(context);  
  12.         }       
  13.         public void onDraw(Canvas canvas){   
  14.             Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180);   
  15.             canvas.drawColor(Color.BLACK);   
  16.             canvas.drawBitmap(bmp, 1010null);   
  17.         }   
  18.     }  
  19. }  


4. 位图缩放 
(1)将一个位图按照需求重画一遍,画后的位图就是我们需要的了,与位图的显示几乎一样:drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)。 
(2)在原有位图的基础上,缩放原位图,创建一个新的位图:CreateBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) 
(3)借助Canvas的scale(float sx, float sy) (Preconcat the current matrix with the specified scale.),不过要注意此时整个画布都缩放了。 
(4)借助Matrix: 
            Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); 
            Matrix matrix=new Matrix(); 
            matrix.postScale(0.2f, 0.2f); 
            Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), 
            bmp.getHeight(),matrix,true); 
            canvas.drawColor(Color.BLACK); 
            canvas.drawBitmap(dstbmp, 10, 10, null); 
5. 位图旋转 
同样,位图的旋转也可以借助Matrix或者Canvas来实现。 
            Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pic180); 
            Matrix matrix=new Matrix(); 
            matrix.postScale(0.8f, 0.8f); 
            matrix.postRotate(45); 
            Bitmap dstbmp=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(), 
            bmp.getHeight(),matrix,true); 
            canvas.drawColor(Color.BLACK); 
            canvas.drawBitmap(dstbmp, 10, 10, null); 
6.图片水印的生成方法 
生成水印的过程。其实分为三个环节:第一,载入原始图片;第二,载入水印图片;第三,保存新的图片。 

  1. /** 
  2. *     * create the bitmap from a byte array 
  3. *     * 
  4. *     * @param src the bitmap object you want proecss 
  5. *     * @param watermark the water mark above the src 
  6. *     * @return return a bitmap object ,if paramter's length is 0,return null 
  7. *     */  
  8. *    private Bitmap createBitmap( Bitmap src, Bitmap watermark )   
  9. *    {   
  10. *        String tag = "createBitmap";   
  11. *        Log.d( tag, "create a new bitmap" );   
  12. *        if( src == null )   
  13. *        {   
  14. *            return null;   
  15. *        }   
  16. *   
  17. *        int w = src.getWidth();   
  18. *        int h = src.getHeight();   
  19. *        int ww = watermark.getWidth();   
  20. *        int wh = watermark.getHeight();   
  21. *        //create the new blank bitmap   
  22. *        Bitmap newb = Bitmap.createBitmap( w, h, Config.ARGB_8888 );//创建一个新的和SRC长度宽度一样的位图   
  23. *        Canvas cv = new Canvas( newb );   
  24. *        //draw src into   
  25. *        cv.drawBitmap( src, 00null );//在 0,0坐标开始画入src   
  26. *        //draw watermark into   
  27. *        cv.drawBitmap( watermark, w - ww + 5, h - wh + 5null );//在src的右下角画入水印   
  28. *        //save all clip   
  29. *        cv.save( Canvas.ALL_SAVE_FLAG );//保存   
  30. *        //store   
  31. *        cv.restore();//存储   
  32. *        return newb;   
  33. *    }   


7.Canvas的save和restore 
onDraw方法会传入一个Canvas对象,它是你用来绘制控件视觉界面的画布。 
在onDraw方法里,我们经常会看到调用save和restore方法,它们到底是干什么用的呢? 
save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 
restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。 

save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error。save和restore之间,往往夹杂的是对Canvas的特殊操作。 



  1. public static int computeSampleSize(BitmapFactory.Options options,  
  2.                                       int minSideLength, int maxNumOfPixels) {  
  3.       int initialSize = computeInitialSampleSize(options, minSideLength,maxNumOfPixels);  
  4.   
  5.       int roundedSize;  
  6.       if (initialSize <= 8 ) {  
  7.           roundedSize = 1;  
  8.           while (roundedSize < initialSize) {  
  9.               roundedSize <<= 1;  
  10.           }  
  11.       } else {  
  12.           roundedSize = (initialSize + 7) / 8 * 8;  
  13.       }  
  14.   
  15.       return roundedSize;  
  16.   }  
  17.   
  18.   private static int computeInitialSampleSize(BitmapFactory.Options options,int minSideLength, int maxNumOfPixels) {  
  19.       double w = options.outWidth;  
  20.       double h = options.outHeight;  
  21.   
  22.       int lowerBound = (maxNumOfPixels == -1) ? 1 :  
  23.               (int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));  
  24.       int upperBound = (minSideLength == -1) ? 128 :  
  25.               (int) Math.min(Math.floor(w / minSideLength),  
  26.                       Math.floor(h / minSideLength));  
  27.   
  28.       if (upperBound < lowerBound) {  
  29.           // return the larger one when there is no overlapping zone.  
  30.           return lowerBound;  
  31.       }  
  32.   
  33.       if ((maxNumOfPixels == -1) &&  
  34.               (minSideLength == -1)) {  
  35.           return 1;  
  36.       } else if (minSideLength == -1) {  
  37.           return lowerBound;  
  38.       } else {  
  39.           return upperBound;  
  40.       }  
  41.   }  

引用
在开发图片浏览器等软件是,很多时候要显示图片的缩略图,而一般情况下,我们要将图片按照固定大小取缩略图,一般取缩略图的方法是使用 BitmapFactory的decodeFile方法,然后通过传递进去 BitmapFactory.Option类型的参数进行取缩略图,在Option中,属性值inSampleSize表示缩略图大小为原始图片大小的几 分之一,即如果这个值为2,则取出的缩略图的宽和高都是原始图片的1/2,图片大小就为原始大小的1/4。 
  然而,如果我们想取固定大小的缩略 图就比较困难了,比如,我们想将不同大小的图片去出来的缩略图高度都为200px,而且要保证图片不失真,那怎么办?我们总不能将原始图片加载到内存中再 进行缩放处理吧,要知道在移动开发中,内存是相当宝贵的,而且一张100K的图片,加载完所占用的内存何止 100K? 
  经过研究,发现,Options中有个属性inJustDecodeBounds,研究了一下,终于明白是什么意思了,SDK中的E文是这么说的 
   If set to true, the decoder will return null (no bitmap), but the out... fields will still be set, allowing the caller to query the bitmap without having to allocate the memory for its pixels. 
  意思就是说如果该值设为 true那么将不返回实际的bitmap不给其分配内存空间而里面只包括一些解码边界信息即图片大小信息,那么相应的方法也就出来了,通过设置 inJustDecodeBounds为true,获取到outHeight(图片原始高度)和 outWidth(图片的原始宽度),然后计算一个inSampleSize(缩放值),然后就可以取图片了,这里要注意的是,inSampleSize 可能小于0,必须做判断。 
具体代码如下: 
FrameLayout fr=(FrameLayout)findViewById(R.id.FrameLayout01); 
        BitmapFactory.Options options = new BitmapFactory.Options(); 
        options.inJustDecodeBounds = true; 
        Bitmap bitmap = BitmapFactory.decodeFile("/sdcard/test.jpg", options); //此时返回bm为空 
        options.inJustDecodeBounds = false; 
         //缩放比 
        int be = (int)(options.outHeight / (float)200); 
        if (be <= 0) 
            be = 1; 
        options.inSampleSize = be; 
        //重新读入图片,注意这次要把options.inJustDecodeBounds 设为 false哦 
        bitmap=BitmapFactory.decodeFile("/sdcard/test.jpg",options); 
        int w = bitmap.getWidth(); 
        int h = bitmap.getHeight(); 
        System.out.println(w+"   "+h); 
        ImageView iv=new ImageView(this); 
        iv.setImageBitmap(bitmap); 
这样我们就可以读取较大的图片而不会内存溢出了。如果你想把压缩后的图片保存在Sdcard上的话就很简单了: 
File file=new File("/sdcard/feng.png"); 
        try { 
            FileOutputStream out=new FileOutputStream(file); 
            if(bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)){ 
                out.flush(); 
                out.close(); 
            } 
        } catch (FileNotFoundException e) { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
        } catch (IOException e) { 
            // TODO Auto-generated catch block 
            e.printStackTrace(); 
        } 

ok,这样就把图片保存在/sdcard/feng.png这个文件里面了,呵呵。 
但是这里的缩放保存是按长宽比例的,下边也可以按固定大小缩放哦: 

        int bmpWidth  = bitmap.getWidth();  
        int bmpHeight = bitmap.getHeight();  

        //缩放图片的尺寸  
        float scaleWidth  = (float) sWidth / bmpWidth;     //按固定大小缩放  sWidth 写多大就多大 
        float scaleHeight = (float) sHeight / bmpHeight;  // 
        Matrix matrix = new Matrix();  
        matrix.postScale(scaleWidth, scaleHeight);  

        //产生缩放后的Bitmap对象  
        Bitmap resizeBitmap = Bitmap.createBitmap(  
            bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false);  
        bitmap.recycle();  
                Bitmap resizeBitmap = bitmap;  
        //Bitmap to byte[]  
        byte[] photoData = bitmap2Bytes(resizeBitmap);  
        //save file  
        String fileName = "/sdcard/test.jpg";  
        FileUtil.writeToFile(fileName, photoData);


引用
压缩图片质量:     
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fos);     
其中的quality为0~100, 可以压缩图片质量, 不过对于大图必须对图片resize    
  
这个是等比例缩放:  
bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);   
这个是截取图片某部分:  
bitmap = Bitmap.createBitmap(bitmap, x, y, width, height);  
  几个方法都是针对Bitmap的, 不过鉴于Bitmap可以从file中读取, 也可以写入file.    
这是我知道Android自带库里中唯一可以缩放和压缩的图片方法. 


例如:我们先想在画布上绘制一个右向的三角箭头,当然,我们可以直接绘制,另外,我们也可以先把画布旋转90°,画一个向上的箭头,然后再旋转回来(这种旋转操作对于画圆周上的标记非常有用)。然后,我们想在右下角有个20像素的圆,那么,onDraw中的核心代码是: 

  1. int px = getMeasuredWidth();  
  2. int py = getMeasuredWidth();  

  3. // Draw background  
  4. canvas.drawRect(00, px, py, backgroundPaint);  
  5. canvas.save();  
  6. canvas.rotate(90, px/2, py/2);                 
  7.   
  8. // Draw up arrow   
  9. canvas.drawLine(px / 200, py / 2, linePaint);                 
  10. canvas.drawLine(px / 20, px, py / 2, linePaint); 
  11. canvas.drawLine(px / 20, px / 2, py, linePaint);   
  12. canvas.restore();    
  13. // Draw circle    
  14. canvas.drawCircle(px - 10, py - 1010, linePaint);  

从这两个图中,我们就能看到圆圈位置的明显差异。不进行Canvas的save和restore操作的话,所有的图像都是在画布旋转90°后的画布上绘制的。当执行完onDraw方法,系统自动将画布恢复回来。save和restore操作执行的时机不同,就能造成绘制的图形不同。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值