`
Jclick
  • 浏览: 189115 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android 缩放图片引起的内存溢出

阅读更多
编写:徐建祥(netpirate@gmail.com)
日期:2010/12/06
网址:http://www.anymobile.org

传输文件,或者设置头像,我们一般都会检查原始图片的大小,作缩放处理。

常用的Java版缩放图片代码:

view plaincopy to clipboardprint?

    public Bitmap getZoomImage(Bitmap src, int desW, int desH) 
    { 
        Bitmap desImg = null; 
        int srcW = src.getWidth(); // 原始图像宽 
        int srcH = src.getHeight(); // 原始图像高 
        int[] srcBuf = new int[srcW * srcH]; // 原始图片像素信息缓存 
         
        src.getPixels(srcBuf, 0, srcW, 0, 0, srcW, srcH); 
         
        // 计算插值表 
        int[] tabY = new int[desH]; 
        int[] tabX = new int[desW]; 
         
        int sb = 0; 
        int db = 0; 
        int tems = 0; 
        int temd = 0; 
        int distance = srcH > desH ? srcH : desH; 
        for (int i = 0; i <= distance; i++) 
        {/* 垂直方向 */ 
            tabY[db] = sb; 
            tems += srcH; 
            temd += desH; 
            if (tems > distance) 
            { 
                tems -= distance; 
                sb++; 
            } 
            if (temd > distance) 
            { 
                temd -= distance; 
                db++; 
            } 
        } 
         
        sb = 0; 
        db = 0; 
        tems = 0; 
        temd = 0; 
        distance = srcW > desW ? srcW : desW; 
         
        for (int i = 0; i <= distance; i++) 
        {/* 水平方向 */ 
            tabX[db] = (short) sb; 
            tems += srcW; 
            temd += desW; 
            if (tems > distance) 
            { 
                tems -= distance; 
                sb++; 
            } 
            if (temd > distance) 
            { 
                temd -= distance; 
                db++; 
            } 
        } 
         
        // 生成放大缩小后图形像素 
        int[] desBuf = new int[desW * desH]; 
        int dx = 0; 
        int dy = 0; 
        int sy = 0; 
        int oldy = -1; 
         
        for (int i = 0; i < desH; i++) 
        { 
            if (oldy == tabY[i]) 
            { 
                System.arraycopy(desBuf, dy - desW, desBuf, dy, desW); 
            } 
            else 
            { 
                dx = 0; 
                for (int j = 0; j < desW; j++) 
                { 
                    desBuf[dy + dx] = srcBuf[sy + tabX[j]]; 
                    dx++; 
                } 
                sy += (tabY[i] - oldy) * srcW; 
            } 
            oldy = tabY[i]; 
            dy += desW; 
        } 
        // 生成图片 
        desImg = Bitmap.createBitmap(desBuf, desW, desH, Bitmap.Config.ARGB_8888); 
         
        return desImg; 
    } 



常用的Android版缩放图片代码:

view plaincopy to clipboardprint?

    ContentResolver cr = this.getContentResolver(); 
    try 
    { 
        InputStream in = cr.openInputStream(uri); 
        Bitmap bitmap = BitmapFactory.decodeStream(in); 
        try 
        { 
            in.close(); 
        } 
        catch (IOException e) 
        { 
            e.printStackTrace(); 
        } 
        if(null  == bitmap) 
        { 
            Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000); 
        } 
        //原始图片的尺寸 
        int bmpWidth  = bitmap.getWidth(); 
        int bmpHeight = bitmap.getHeight(); 
         
        //缩放图片的尺寸 
        float scaleWidth  = (float) 40 / bmpWidth; 
        float scaleHeight = (float) 40 / bmpHeight; 
        Matrix matrix = new Matrix(); 
        matrix.postScale(scaleWidth, scaleHeight); 
         
        //产生缩放后的Bitmap对象 
        Bitmap resizeBitmap = Bitmap.createBitmap( 
            bitmap, 0, 0, bmpWidth, bmpHeight, matrix, false); 
        bitmap.recycle(); 
        //Bitmap to byte[] 
        byte[] photoData = Bitmap2Bytes(resizeBitmap); 
         
        //save file 
        String fileName = "/sdcard/test.jpg"; 
        FileUtil.writeToFile(fileName, photoData); 
         
        //save photo check sum to db 
        DataCenter.GetInstance().ModifyIMMUser(); 
        //refresh ImageView 
    } 
    catch (FileNotFoundException exp) 
    { 
        exp.printStackTrace(); 
    } 



如果图片非常大,在执行BitmapFactory.decodeStream的时候就会抛出OOM异常。

我们来看看系统应用MMS是如何处理的,SMS添加了多媒体附件后就作MMS处理了,当附加文件原图超过300K,也会做个缩放处理,具体参考:com.android.mms.ui/.UriImage:

view plaincopy to clipboardprint?

    package com.android.mms.ui; 
    public class UriImage 
    { 
        private int mWidth; 
        private int mHeight; 
        ... ... 
        // 
        private void decodeBoundsInfo() 
        { 
            InputStream input = null; 
            try 
            { 
                input = mContext.getContentResolver().openInputStream(mUri); 
                BitmapFactory.Options opt = new BitmapFactory.Options(); 
                opt.inJustDecodeBounds = true;//只描边,不读取数据 
                BitmapFactory.decodeStream(input, null, opt); 
                mWidth = opt.outWidth; 
                mHeight = opt.outHeight; 
            } 
            catch (FileNotFoundException e) 
            { 
                // Ignore 
                Log.e(TAG, "IOException caught while opening stream", e); 
            } 
            finally 
            { 
                if (null != input) { 
                    try { 
                        input.close(); 
                    } catch (IOException e) { 
                        // Ignore 
                        Log.e(TAG, "IOException caught while closing stream", e); 
                    } 
                } 
            } 
        } 
        private byte[] getResizedImageData(int widthLimit, int heightLimit) 
        { 
            int outWidth = mWidth; 
            int outHeight = mHeight; 
            int s = 1; 
            while ((outWidth / s > widthLimit) || (outHeight / s > heightLimit)) 
            { 
                s *= 2; 
            } 
            //先设置选项 
            BitmapFactory.Options options = new BitmapFactory.Options(); 
            //returning a smaller image to save memory. 
            options.inSampleSize = s; 
            InputStream input = null; 
            try 
            { 
                input = mContext.getContentResolver().openInputStream(mUri); 
                Bitmap b = BitmapFactory.decodeStream(input, null, options);//注意看options的用法 
                if (b == null) { 
                    return null; 
                } 
                ByteArrayOutputStream os = new ByteArrayOutputStream(); 
                b.compress(CompressFormat.JPEG, MessageUtils.IMAGE_COMPRESSION_QUALITY, os); 
                return os.toByteArray(); 
            } catch (FileNotFoundException e) { 
                Log.e(TAG, e.getMessage(), e); 
                return null; 
            } finally { 
                if (input != null) { 
                    try { 
                        input.close(); 
                    } catch (IOException e) { 
                        Log.e(TAG, e.getMessage(), e); 
                    } 
                } 
            } 
        } 
        ... ... 
    } 



可以看出,MMS应用的方法是:先设置缩放选项,再读取缩放的图片数据到内存,规避了内存引起的OOM。

修改后的代码:

view plaincopy to clipboardprint?

        ContentResolver cr = this.getContentResolver(); 
        try 
        { 
            InputStream in = cr.openInputStream(uri); 
               BitmapFactory.Options options = new BitmapFactory.Options(); 
               options.inJustDecodeBounds = true; 
               BitmapFactory.decodeStream(in, null, options); 
            try 
            { 
        in.close(); 
    } 
            catch (IOException e) 
            { 
        e.printStackTrace(); 
    } 
               int mWidth = options.outWidth; 
               int mHeight = options.outHeight; 
                
               int sWidth  = 40; 
               int sHeight = 40; 
                
            int s = 1; 
            while ((mWidth / s > sWidth * 2) || (mHeight / s > sHeight * 2)) 
            { 
                s *= 2; 
            } 
               options = new BitmapFactory.Options(); 
            options.inSampleSize = s; 
            in = cr.openInputStream(uri); 
            Bitmap bitmap = BitmapFactory.decodeStream(in, null, options); 
            try 
            { 
        in.close(); 
    } 
            catch (IOException e) 
            { 
        e.printStackTrace(); 
    } 
            if(null  == bitmap) 
            { 
                Toast.makeText(this, "Head is not set successful,Decode bitmap failure", 2000); 
                return ; 
            } 
            //原始图片的尺寸 
            int bmpWidth  = bitmap.getWidth(); 
            int bmpHeight = bitmap.getHeight(); 
             
            //缩放图片的尺寸 
            float scaleWidth  = (float) sWidth / bmpWidth; 
            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); 



view plaincopy to clipboardprint?

    private byte[] bitmap2Bytes(Bitmap bm) 
    { 
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        bm.compress(Bitmap.CompressFormat.JPEG, 100, baos); 
        return baos.toByteArray(); 
    } 



OVER!
分享到:
评论
2 楼 Jclick 2011-04-06  
hongmeikaile 写道
我是刚学android的,不懂的地方,还得请教你一下,借鉴了

我们都一样~~
1 楼 hongmeikaile 2011-04-02  
我是刚学android的,不懂的地方,还得请教你一下,借鉴了

相关推荐

    listview 内存溢出的简单解决方案

    总结来说,解决ListView中图片引起的内存溢出问题,我们需要做到以下几点: 1. 利用ListView的视图复用机制,通过ViewHolder重用ImageView。 2. 使用适当的图片解码策略,如设置`inSampleSize`,降低图片内存占用。 ...

    Android 图片浏览器

    在Android中,加载大尺寸图片可能会导致内存溢出(Out Of Memory,OOM)问题,因为原生的Bitmap对象会占用大量内存。为解决这个问题,我们需要采用合适的图片解码策略,如按需加载和缩放图片。例如,可以使用`...

    Android拍照、相册选取、截图综合

    4. **解决Bitmap引起的内存溢出** - **内存优化策略**:使用`BitmapFactory.Options.inSampleSize`来降低图片的解码大小,减少内存消耗。合理设置这个参数,可以在不失真的情况下减小图像的分辨率。 - **使用...

    Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存?1

    Bitmap 的不当使用很容易导致内存溢出(OOM),严重影响应用的性能和稳定性。因此,了解 Bitmap 占用的内存大小至关重要。本文将深入探讨 Bitmap 内存计算的原理,并提供一种预测 Bitmap 内存占用的方法。 首先,...

    图片oom,解决方法

    在Android开发中,"图片OOM"是一个常见的问题,全称为"Out Of Memory",即内存溢出异常。...通过合理的图片处理方式和利用现有的优秀库,可以有效地避免和处理图片引起的内存溢出问题,提升应用性能和用户体验。

    Android基础面试笔记

    #### 二、如何避免OOM(内存溢出)异常 **OOM异常产生的原因**: - Android应用运行在一个Dalvik虚拟机环境中,默认堆内存通常较小,这使得Android应用更容易发生OOM异常。 - 当程序尝试分配一大块内存但虚拟机无法...

    Android编程实现压缩图片并加载显示的方法

    在Android开发中,图片处理是一项常见的任务,尤其是在创建应用程序时,可能会遇到图片过大导致内存溢出或者加载速度过慢的问题。本篇文章将详细介绍如何在Android编程中实现图片的压缩和加载显示,帮助开发者掌握...

    Picasso jar包

    通过这些转换,Picasso能有效地减少内存消耗,尤其是对于大图或者高清图,它可以防止因图片过大而引起的内存溢出。同时,Picasso还可以根据设备的屏幕分辨率自动调整图片大小,进一步优化内存使用。 3. **简单的API...

    BitmapFunc.rar

    创建时应考虑到内存管理,避免内存溢出。 2. **内存管理**:Bitmap占用的内存大小是其宽度、高度和颜色深度的乘积。Android系统提供了几种配置来控制Bitmap在内存中的存储方式,如ARGB_8888(每个像素4字节),RGB_...

    Android中对图像进行Base64编码

    确保考虑到内存管理,避免因加载大图导致内存溢出。可以使用`Options`参数来指定解码尺寸和缩放比例。 2. **转换为字节数组**: 调用`Bitmap`对象的`compress()`方法,将Bitmap压缩为JPEG或PNG格式的字节数组。...

    android+java面试

    - 通常由未捕获的异常、资源泄漏、内存溢出等问题引起。 以上内容涵盖了Android开发中的关键知识点,对于面试和实际工作都具有很高的参考价值。理解并掌握这些概念,将有助于提升Android开发技能和应对面试挑战。

    EditText插入图片

    总结,插入图片到`EditText`是通过`SpannableString`和`ImageSpan`实现的,而防止图片引起的OOM问题则需要合理管理图片资源,包括压缩、使用合适分辨率、缓存以及及时释放。在实际项目中,结合`ImageTextDemo`的代码...

    ListViewAsyncy异步加载图片速度很快

    3. **磁盘缓存**:当内存不足以存放所有图片时,可以将部分图片存储到磁盘,避免内存溢出,同时提供离线访问能力。 4. **图片解码**:对下载的图片进行适当的解码处理,比如缩放、裁剪,以适应ListView的item大小,...

    Android开发之图片压缩实现方法分析

    本文将深入探讨Android图片压缩的原理和实现方法,以及如何避免因图片过大导致的内存溢出(Out Of Memory,简称OOM)问题。 首先,Android系统对每个应用的内存分配是有限制的,如果直接加载大尺寸的图片,可能导致...

    ImageView获取宽度和高度

    要注意的是,Bitmap占用内存较大,不建议在内存中大量存储,尤其是对于高清大图,可能引起内存溢出。使用后记得及时回收(`bitmap.recycle()`),并考虑使用`BitmapFactory.Options`进行解码优化。 总之,获取...

    完善的压缩bitmap测试工程

    在安卓开发中,Bitmap是用于处理图像数据的重要类,它占据了大量的内存,特别是在处理高清图片时,可能会引发内存溢出(OutOfMemoryError)问题。因此,对Bitmap进行压缩是优化应用性能的关键环节。这个“完善的压缩...

    Android的多媒体管理库Glide的基本使用示例

    3. **图片压缩**:Glide支持在加载图片前进行压缩,减小内存占用,防止内存溢出。 4. **自定义网络栈**:虽然默认使用HttpUrlConnection,但Glide允许开发者集成其他网络库,如Volley或OkHttp,以适应不同的网络...

Global site tag (gtag.js) - Google Analytics