Android Bitmap使用

本文介绍了Android开发中处理图片的方法,包括BitmapFactory的各种用法及其可能导致的内存溢出问题,并详细探讨了如何利用BitmapFactory.Options进行图片的采样压缩,减少内存占用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Android开发中,跟图片打交道在正常不过了。不过如果图片处理不当就会造成内存溢出(OOM),所以了解Bitmap相关用法就有必要了,Bitmap在Android中指的是一张图片,图片类型可以是png、jpg等。

1、BitmapFactory

BitmapFactory进一步封装了获取Bitmap对象,BitmapFactory提供获取Bitmap对象的方法有以下:

    1、decodeByteArray     从指定字节数组中获取

    用法:

private void getBitmap(){
        //主要是把网络图片的数据流读入到内存中
        new Thread(new Runnable() {
            @Override
            public void run() {
                //Android4.0以后,网络请求一定要在子线程中进行
                final byte[] data = getImages("http://img5.imgtn.bdimg.com/it/u=274881988,3237971911&fm=27&gp=0.jpg");
                //更新UI可以在runOnUiThread这个方法或通过handler
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
                        mImage.setImageBitmap(bitmap);
                    }
                });

            }
        }).start();
    }

private byte[] getImages(String path){
        try {
            URL url = new URL(path);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setReadTimeout(6*1000);
            InputStream inputStream = null;
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = -1;
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
                inputStream = httpURLConnection.getInputStream();
                while ((len = inputStream.read(buffer)) !=-1){
                    outputStream.write(buffer,0,len);
                }
                outputStream.close();
                inputStream.close();
            }
            return outputStream.toByteArray();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

注:网络请求一定要在子线程中来做,否则就会抛NetworkOnMainThreadException异常


    2、decodeFile、decodeFileDescriptor   从指定文件中获取

    用法:

private void getDecodeFileBitmap() {
        String fileName = "/sdcard/daniulivelogo.png";  //自己手机sd图片路径
        File file = new File(fileName);
        if (file.exists()) {
            Bitmap bm = BitmapFactory.decodeFile(fileName);
            mImage.setImageBitmap(bm);
        } else {
            Log.v("hjz","文件不存在");
        }
    }

    注:sd相对路径

        有外置内存:/sdcard/Android/data/<application package>/cache

        无外置内存:/data/data/Android/data/<application package>/cache

    3、decodeResource   从指定本地资源获取
private void getDecodeResourceBitmap(){
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
        mImage.setImageBitmap(bitmap);
    }

    4、decodeStream   从输入流中获取

    用法:

private void getDecodeStreamBitmap(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                final Bitmap bitmap = getImageFromNet("http://img5.imgtn.bdimg.com/it/u=274881988,3237971911&fm=27&gp=0.jpg");
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mImage.setImageBitmap(bitmap);
                    }
                });
            }
        }).start();
    }

private Bitmap getImageFromNet(String path) {
        HttpURLConnection httpURLConnection = null;
        InputStream inputStream = null;
        try {
            URL url = new URL(path);
            httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("GET");
            httpURLConnection.setReadTimeout(6 * 1000);
            if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                inputStream = httpURLConnection.getInputStream();
                return BitmapFactory.decodeStream(inputStream);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (inputStream != null){
                try {
                    inputStream.close();
                    inputStream = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpURLConnection != null){
                httpURLConnection.disconnect();
            }
        }
        return null;
    }

上面是没有添加任何策略的常规用法,容易造成OOM现象。


2、BitmapFactory.Options

    高效加载类图其核心就是BitmapFactory.Options,在开发中很多时候并不需要图片原图大小和原图这么高清,目的对图片进行采样压缩,降低内存占有空间,从而减少了内存溢出(OOM)问题。

    1、BitmapFactory.Options常用方法:

参数说明备注
inJustDecodeBounds

如果设置为true,则只返回bitmap尺寸,没有为

其分配内存

如果设置为false,解码返回位图,为其分配内存

预加载图片,获取图片尺寸
inSampleSize

当设置值>1时,按相关比例缩放bitmap宽高,返回较小图片在保存

当设置值<=1时,就当做1来处理

案例:width=100,height=100,inSampleSize = 2,

则返回width=50,height=50,像素50*50=250  

图片将为了原来1/4

inPreferredConfig

如果这是非空的,解码器将尝试解码到这个内部配置。如果它是null,

或者请求不能满足,解码器将尝试根据系统的屏幕深度选择

最佳匹配配置,以及原始图像的特性,例如它是否具有每像素alpha

(需要配置)。图像加载默认的配置argb_8888。

另外:色彩模式,默认argb_8888,一个像素4byte。如果对透明不做要求,采用rgb_565,一个像素2byte

alpha_8:每个像素1byte

argb_444:每个像素2byte

argb_8888:每个像素4byte

rgb_565:每个像素2byte

场景:如果一张图片分辨率1024*768,

采用argb_8888,占用空间为1024*768*4=3M;

如果采用argb_444内存就能减半

inPremultiplied默认true,返回的bitmap颜色通道上预先附加透明通道

透明通道是计算机图形学术语,指的是“非彩色”通道,

8位灰度通道,使用256级灰度来记录图像中的透明信息,

定义透明、不透明和半透明。如32位存储的图片,

8红+8绿+8蓝+8透明;

inDither抖动解码,默认false,标识不采用抖动解码

Bitmap解码是根据它所记录的节点,按照一定的算法来

补充两个节点之间的数据,可理解为补充像素点的颜色。

一张颜色丰富的图用一个位数比较低的颜色模式解码的话,

会感觉颜色不够用,颜色渐变区域有明显断裂带。

因为一些丰富的颜色在位数较低的颜色模式下并没有,

只能用相近的颜色补充,可能一大片没有,那么这大片

都用一个颜色填充,就形成了断裂色带;如果采用

抖动解码,就会在这些颜色上采用随机噪声色来填充,这样

显示效果更好,色带不那么明显。如果不想有这些色带,就需要采用抖动解码

inScaled设置这个bitmap是否可以被缩放,默认值为true 
inDensity表示这个bitmap的像素密度 
inTargetDensity目标位图的像素密度将被绘制到 
inScreenDensity正在使用的实际屏幕的像素密度

inDensity,inTargetDensity,inScreenDensity

这三个值的目的就是为了确定这个Bitmap的宽高和density。详细算法可以查看

setDensityFromOptions()方法源码实现;

inPurgeable/inInputShareable

一般一起使用,设置为true时,表示空间不够可以被释放,

后者表示是否可以共享引用。Android5.0后被弃用

 
outWidth/outHeight表示bitmap的宽和高,一般和inJustDecodeBounds一起使用获取Bitmap的宽高,但不加载到内存中 
    2、BitmapFactory.Options实战
String fileName = "/sdcard/aa.jpg";
BitmapFactory.Options options = getBitmapFactory(fileName,400,400);
mImage2.setImageBitmap(BitmapFactory.decodeFile(fileName,options));

private BitmapFactory.Options getBitmapFactory(String fileName,int pixelW,int pixelH){
        BitmapFactory.Options options = new BitmapFactory.Options();
        File file = new File(fileName);
        if (file.exists()){
            //inJustDecodeBounds为true,不返回bitmap,只返回这个bitmap的尺寸
            options.inJustDecodeBounds = true;
            //设置图片色彩
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            //预加载图片
            Bitmap bitmap = BitmapFactory.decodeFile(fileName,options);
            //获取原始图片宽高
            int originalW = options.outWidth;
            int originalH = options.outHeight;
            //上面设置为true获取bitmap尺寸大小,在这里一定要重新设置为false,否则位图加载不出来
            options.inJustDecodeBounds = false;
            options.inSampleSize = getSampleSize(originalW,originalH,pixelW,pixelH);
            return options;
        }
        return null;
    }

    /**
     *
     * @param originalW 原图宽
     * @param originalH 原图高
     * @param pixelW 指定图片宽度
     * @param pixelH 指定图片高度
     * @return 返回原图缩放大小
     */
    private int getSampleSize(int originalW, int originalH, int pixelW, int pixelH) {
        int simpleSize = 1;
        if (originalW > originalH && originalW > pixelW){
            simpleSize = originalW / pixelW;
        }else if (originalH > originalW && originalH > pixelH){
            simpleSize = originalH / pixelH;
        }
        if (simpleSize <=0){
            simpleSize = 1;
        }
        return simpleSize;
    }

android Bitmap用法总结 Bitmap用法总结 1、Drawable → Bitmap public static Bitmap drawableToBitmap(Drawable drawable) { Bitmap bitmap = Bitmap .createBitmap( drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); // canvas.setBitmap(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; } 2、从资源中获取Bitmap Resources res=getResources(); Bitmap bmp=BitmapFactory.decodeResource(res, R.drawable.pic); 3、Bitmap → byte[] private byte[] Bitmap2Bytes(Bitmap bm){ ByteArrayOutputStream baos = new ByteArrayOutputStream(); bm.compress(Bitmap.CompressFormat.PNG, 100, baos); return baos.toByteArray(); } 4、byte[] → Bitmap private Bitmap Bytes2Bimap(byte[] b){ if(b.length!=0){ return BitmapFactory.decodeByteArray(b, 0, b.length); } else { return null; } } 5、保存bitmap static boolean saveBitmap2file(Bitmap bmp,String filename){ CompressFormat format= Bitmap.CompressFormat.JPEG; int quality = 100; OutputStream stream = null; try { stream = new FileOutputStream("/sdcard/" + filename); } catch (FileNotFoundException e) { // TODO Auto-generated catch block Generated by Foxit PDF Creator © Foxit Software http://www.foxitsoftware.com For evaluation only. e.printStackTrace(); } return bmp.compress(format, quality, stream); } 6、将图片按自己的要求缩放 // 图片源 Bitmap bm = BitmapFactory.decodeStream(getResources() .openRawResource(R.drawable.dog)); // 获得图片的宽高 int width = bm.getWidth(); int height = bm.getHeight(); // 设置想要的大小 int newWidth = 320; int newHeight = 480; // 计算缩放比例 float scaleWidth = ((float) newWidth) / width; float scaleHeight = ((float) newHeight) / height; // 取得想要缩放的matrix参数 Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); // 得到新的图片 Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true); // 放在画布上 canvas.drawBitmap(newbm, 0, 0, paint); 相关知识链接:http://www.eoeandroid.com/thread-3162-1-1.html 7、bitmap的用法小结 BitmapFactory.Options option = new BitmapFactory.Options(); option.inSampleSize = 2; //将图片设为原来宽高的1/2,防止内存溢出 Bitmap bm = BitmapFactory.decodeFile("",option);//文件流 URL url = new URL(""); InputStream is = url.openStream(); Bitmap bm = BitmapFactory.decodeStream(is); android:scaleType: android:scaleType是控制图片如何resized/moved来匹对ImageView的size。ImageView.ScaleType / android:scaleType值的意义区别: CENTER /center 按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分 显示 CENTER_CROP / centerCrop 按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长 (宽) CENTER_INSIDE / centerInside 将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片 长/宽等于或小于View的长/宽 Generated by Foxit PDF Creator © Foxit Software http://www.foxitsoftware.com For evaluation only. FIT_CENTER / fitCenter 把图片按比例扩大/缩小到View的宽度,居中显示 FIT_END / fitEnd 把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置 FIT_START / fitStart 把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置 FIT_XY / fitXY 把图片 不按比例 扩大/缩小到View的大小显示 MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。 //放大缩小图片 public static Bitmap zoomBitmap(Bitmap bitmap,int w,int h){ int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); float scaleWidht = ((float)w / width); float scaleHeight = ((float)h / height); matrix.postScale(scaleWidht, scaleHeight); Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); return newbmp; } //将Drawable转化为Bitmap public static Bitmap drawableToBitmap(Drawable drawable){ int width = drawable.getIntrinsicWidth(); int height = drawable.getIntrinsicHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0,0,width,height); drawable.draw(canvas); return bitmap; Generated by Foxit PDF Creator © Foxit Software http://www.foxitsoftware.com For evaluation only. } //获得圆角图片的方法 public static Bitmap getRoundedCornerBitmap(Bitmap bitmap,float roundPx){ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); final int color = 0xff424242; final Paint paint = new Paint(); final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); final RectF rectF = new RectF(rect); paint.setAntiAlias(true); canvas.drawARGB(0, 0, 0, 0); paint.setColor(color); canvas.drawRoundRect(rectF, roundPx, roundPx, paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); canvas.drawBitmap(bitmap, rect, rect, paint); return output; } //获得带倒影的图片方法 public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap){ final int reflectionGap = 4; int width = bitmap.getWidth(); int height = bitmap.getHeight(); Matrix matrix = new Matrix(); matrix.preScale(1, -1); Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, height/2, width, height/2, matrix, false); Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + height/2), Config.ARGB_8888); Canvas canvas = new Canvas(bitmapWithReflection); canvas.drawBitmap(bitmap, 0, 0, null); Paint deafalutPaint = new Paint(); Generated by Foxit PDF Creator © Foxit Software http://www.foxitsoftware.com For evaluation only. canvas.drawRect(0, height,width,height + reflectionGap, deafalutPaint); canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null); Paint paint = new Paint(); LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0, bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, TileMode.CLAMP); paint.setShader(shader); // Set the Transfer mode to be porter duff and destination in paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); // Draw a rectangle using the paint with our linear gradient canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint); return bitmapWithReflection; } }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值