`

(转)Android: 缩放图片文件引起的OOM异常

 
阅读更多

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

 

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

	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版缩放图片代码:

 

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:

 

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。

 

修改后的代码:

 	 				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);

 

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

 

分享到:
评论

相关推荐

    Android加载大图片OOM异常解决

    Android 加载大图片 OOM 异常解决方案 在 Android 开发中,加载大图片...通过手动干涉 Dalvik 的堆内存处理效率、手动指定 Android 堆大小、手动指定回收内存、指定 GC 和图片缩放,我们可以更好地解决 OOM 异常问题。

    博客资源:ViewPager加载大量图片oom解决方案demo

    "博客资源:ViewPager加载大量图片oom解决方案demo" 这个标题表明了这是一个关于解决在Android应用中使用ViewPager展示大量图片时出现内存溢出(Out Of Memory,简称OOM)问题的实例教程。ViewPager是Android SDK中...

    Android加载网络图片与本地图片解决OOM问题

    在Android开发中,图片加载是常见的任务,但同时也是导致内存溢出(Out Of Memory, OOM)问题的主要原因之一。特别是当处理大量图片,如在ListView或RecyclerView中滚动时,如果没有正确的图片管理策略,图片加载...

    图片缩放防止OOM

    当Android应用程序在运行时耗尽了可用内存,系统会抛出一个OOM异常,可能导致应用崩溃。图片是内存消耗的主要来源,特别是未经过优化的大尺寸图片,它们在加载时会占用大量内存。 二、图片加载策略 1. **按需加载**...

    Android相册图片解决OOM问题

    2. **大图加载**:Android原生的Bitmap类在处理大图片时特别容易引发OOM。大图片直接加载到内存中会超出分配的内存限制,因此需要对图片进行适当的缩放处理。使用`BitmapFactory.Options`的`inSampleSize`参数可以...

    android加载大图避免oom

    这些第三方库能自动处理图片的加载和缓存,它们会在后台线程中加载图片,避免阻塞UI,并且会根据需要进行图片压缩和缩放,有效防止OOM。 6. LRU缓存策略 使用LRU(Least Recently Used)缓存策略,当内存不足时,...

    Android代码-Android图片浏览全屏缩放.zip

    【Android图片浏览全屏缩放】是一个Android应用开发中的常见需求,主要涉及到图像处理和UI交互方面的技术。在Android平台上,我们通常会使用ImageView组件来显示图片,但是要实现图片的全屏展示以及平滑缩放,需要更...

    android 图片缩放和旋转

    在Android开发中,图片的缩放和旋转是常见的需求,特别是在用户交互或者图像处理的应用中。本文将深入探讨Android中如何实现图片的这两种操作,并提供相关的代码示例。 首先,我们要了解Android中处理图片的基本...

    android解决OOM

    - 大图加载:大图片可能导致OOM,因此需要使用`BitmapFactory.Options`进行缩放,只加载需要的部分。 - 使用LruCache或PooledByteBuffer:缓存图片,减少内存压力。 - 使用 Glide、Picasso 或其他库:这些库可以...

    android图片墙lrucache oom

    本篇文章将深入探讨如何使用LRUCache来解决Android图片墙中的OOM问题。 一、Android OOM简介 当应用程序请求的内存超过系统分配的最大内存时,就会发生OOM。在Android中,每个应用都有自己的Dalvik虚拟机实例,其...

    android Gallery 3d 图片浏览 oom

    然而,由于Android系统默认的图片加载机制,特别是当图片数量大或者图片分辨率高时,容易导致内存消耗过大,从而引发oom异常。 要解决oom问题,我们可以采用以下策略: 1. **使用高效的图片加载库**:如Glide、...

    Android 图片压缩不OOM,超高保真度

    通过分析和学习这个示例,开发者可以更好地理解和掌握Android图片压缩的技巧,以达到在不引发OOM的前提下,保持图片的高保真度。 总结来说,处理Android中的大图,我们需要合理地使用`BitmapFactory.Options`进行...

    Android 图片下载以及内存处理防止OOM内存溢出 源码

    - 利用LruCache或DiskLruCache:Android提供了一种基于最近最少使用原则的缓存策略,可以将频繁使用的图片缓存到内存或磁盘,避免频繁加载。 - 使用Android的内存分区:理解Android的内存模型,如Dalvik/ART虚拟机...

    android 图片内存溢出(OOM)解决

    基本上解决了OOM问题 如果 方便可以直接引用BitmapManager类到 项目中使用 解决blog 地址http://www.cnblogs.com/liongname/articles/2345087.html

    android缩放图片代码实例

    理解Android图片处理的底层机制,合理使用`BitmapFactory`和`BitmapFactory.Options`,以及采取适当的内存管理策略,是防止图片加载导致的OOM的关键。在实际开发中,开发者应结合设备特性,灵活运用这些方法,以实现...

    android 图片下载 防止OOM

    在Android开发中,图片加载...综上所述,防止Android图片下载导致的OOM,需要从图片加载策略、内存管理、缓存策略和资源清理等多方面进行优化。合理利用现有的图片库和性能监控工具,可以大大提高应用的性能和稳定性。

    Android图片异步加载有效控制OOM

    有效控制了Android大图片、多图片加载的OOM异常。

    android gridview 加载大量图片。无OOM

    在Android开发中,GridView是一种常见的布局控件,用于展示多行多列的列表,常用于图片、文件等的网格化展示。然而,当GridView需要加载大量图片时,如果不妥善处理,很容易导致内存溢出(Out-Of-Memory,简称OOM)...

    图片oom,解决方法

    总结来说,解决Android图片OOM问题,需要从图片的大小、加载策略、内存管理等多个方面进行优化。通过合理的图片处理方式和利用现有的优秀库,可以有效地避免和处理图片引起的内存溢出问题,提升应用性能和用户体验。

    Android圆形头像截取,没有OOM

    图像缩放限制---图像最小能缩放到圆形截取框范围 图像四方移动限制---图像移动边缘不会进入圆形截取范围内 图像无限放大---修改CutPicView的最大放大倍数参数即可 不行请联系QQ:2978549783(夜之瞳)资讯

Global site tag (gtag.js) - Google Analytics