zoukankan      html  css  js  c++  java
  • Android压缩图片到100K以下并保持不失真的高效方法

    前言:目前一般手机的相机都能达到800万像素,像我的Galaxy Nexus才500万像素,拍摄的照片也有1.5M左右。这么大的照片上传到服务器,不仅浪费流量,同时还浪费时间。

    在开发Android企业应用时,会经常上传图片到服务器,而我们公司目前维护的一个项目便是如此。该项目是通过私有apn与服务器进行交互的,联通的还好,但移动的速度实在太慢,客户在使用软件的过程中,由于上传的信息中可能包含多张图片,会经常出现上传图片失败的问题,为了解决这个问题,我们决定把照片压缩到100k以下,并且保证图片不失真(目前图片经过压缩后,大约300k左右)。于是我就重新研究了一下Android的图片压缩技术。

    Android端目录结构如下图所示:

    其中ksoap2-android-xxx.jar是Android用来调用webservice的,gson-xx.jar是把JavaBean转成Json数据格式的。 本篇博客主要讲解图片压缩的,核心代码如下:

    1. //计算图片的缩放值  
    2. public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {  
    3.     final int height = options.outHeight;  
    4.     final int width = options.outWidth;  
    5.     int inSampleSize = 1;  
    6.   
    7.     if (height > reqHeight || width > reqWidth) {  
    8.              final int heightRatio = Math.round((float) height/ (float) reqHeight);  
    9.              final int widthRatio = Math.round((float) width / (float) reqWidth);  
    10.              inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
    11.     }  
    12.         return inSampleSize;  
    13. }  
    //计算图片的缩放值
    public static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth, int reqHeight) {
    	final int height = options.outHeight;
    	final int width = options.outWidth;
    	int inSampleSize = 1;
    
    	if (height > reqHeight || width > reqWidth) {
                 final int heightRatio = Math.round((float) height/ (float) reqHeight);
                 final int widthRatio = Math.round((float) width / (float) reqWidth);
                 inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    	}
            return inSampleSize;
    }
    1. // 根据路径获得图片并压缩,返回bitmap用于显示  
    2. public static Bitmap getSmallBitmap(String filePath) {  
    3.         final BitmapFactory.Options options = new BitmapFactory.Options();  
    4.         options.inJustDecodeBounds = true;  
    5.         BitmapFactory.decodeFile(filePath, options);  
    6.   
    7.         // Calculate inSampleSize  
    8.     options.inSampleSize = calculateInSampleSize(options, 480, 800);  
    9.   
    10.         // Decode bitmap with inSampleSize set  
    11.     options.inJustDecodeBounds = false;  
    12.   
    13.     return BitmapFactory.decodeFile(filePath, options);  
    14.     }  
    // 根据路径获得图片并压缩,返回bitmap用于显示
    public static Bitmap getSmallBitmap(String filePath) {
    		final BitmapFactory.Options options = new BitmapFactory.Options();
    		options.inJustDecodeBounds = true;
    		BitmapFactory.decodeFile(filePath, options);
    
    		// Calculate inSampleSize
    	options.inSampleSize = calculateInSampleSize(options, 480, 800);
    
    		// Decode bitmap with inSampleSize set
    	options.inJustDecodeBounds = false;
    
    	return BitmapFactory.decodeFile(filePath, options);
    	}
    1. //把bitmap转换成String  
    2. public static String bitmapToString(String filePath) {  
    3.   
    4.         Bitmap bm = getSmallBitmap(filePath);  
    5.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    6.         bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);  
    7.         byte[] b = baos.toByteArray();  
    8.         return Base64.encodeToString(b, Base64.DEFAULT);  
    9.     }  
    //把bitmap转换成String
    public static String bitmapToString(String filePath) {
    
    		Bitmap bm = getSmallBitmap(filePath);
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		bm.compress(Bitmap.CompressFormat.JPEG, 40, baos);
    		byte[] b = baos.toByteArray();
    		return Base64.encodeToString(b, Base64.DEFAULT);
    	}

    查看全部源码,请访问: https://github.com/feicien/StudyDemo/tree/master/FileUploadDemo
    压缩原理讲解:压缩一张图片。我们需要知道这张图片的原始大小,然后根据我们设定的压缩比例进行压缩。 这样我们就需要做3件事: 1.获取原始图片的长和宽

    1. BitmapFactory.Options options = new BitmapFactory.Options();  
    2.         options.inJustDecodeBounds = true;  
    3.         BitmapFactory.decodeFile(filePath, options);  
    4.                 int height = options.outHeight;  
    5.             int width = options.outWidth;  
    BitmapFactory.Options options = new BitmapFactory.Options();
    		options.inJustDecodeBounds = true;
    		BitmapFactory.decodeFile(filePath, options);
                    int height = options.outHeight;
    	        int width = options.outWidth;

    以上代码是对图片进行解码,inJustDecodeBounds设置为true,可以不把图片读到内存中,但依然可以计算出图片的大小,这正好可以满足我们第一步的需要。 2.计算压缩比例

    1. int height = options.outHeight;  
    2.      int width = options.outWidth;   
    3.      int inSampleSize = 1;  
    4.      int reqHeight=800;  
    5.      int reqWidth=480;  
    6.      if (height > reqHeight || width > reqWidth) {  
    7.     final int heightRatio = Math.round((float) height/ (float) reqHeight);  
    8.     final int widthRatio = Math.round((float) width / (float) reqWidth);              
    9.     inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;  
    10.      }  
    int height = options.outHeight;
         int width = options.outWidth; 
         int inSampleSize = 1;
         int reqHeight=800;
         int reqWidth=480;
         if (height > reqHeight || width > reqWidth) {
    	final int heightRatio = Math.round((float) height/ (float) reqHeight);
    	final int widthRatio = Math.round((float) width / (float) reqWidth);			
    	inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
         }

    一般手机的分辨率为 480*800 ,所以我们压缩后图片期望的宽带定为480,高度设为800,这2个值只是期望的宽度与高度,实际上压缩后的实际宽度也高度会比期望的要大。如果图片的原始高度或者宽带大约我们期望的宽带和高度,我们需要计算出缩放比例的数值。否则就不缩放。heightRatio是图片原始高度与压缩后高度的倍数,widthRatio是图片原始宽度与压缩后宽度的倍数。inSampleSize为heightRatio与widthRatio中最小的那个,inSampleSize就是缩放值。 inSampleSize为1表示宽度和高度不缩放,为2表示压缩后的宽度与高度为原来的1/2 3.缩放并压缩图片

    1. //在内存中创建bitmap对象,这个对象按照缩放大小创建的  
    2.              options.inSampleSize = calculateInSampleSize(options, 480, 800);  
    3.         options.inJustDecodeBounds = false;  
    4.         Bitmap bitmap= BitmapFactory.decodeFile(filePath, options);  
    5.   
    6.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    7.         bm.compress(Bitmap.CompressFormat.JPEG, 60, baos);  
    8.         byte[] b = baos.toByteArray();  
    //在内存中创建bitmap对象,这个对象按照缩放大小创建的
                 options.inSampleSize = calculateInSampleSize(options, 480, 800);
    		options.inJustDecodeBounds = false;
    		Bitmap bitmap= BitmapFactory.decodeFile(filePath, options);
    
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		bm.compress(Bitmap.CompressFormat.JPEG, 60, baos);
    		byte[] b = baos.toByteArray();

    前3行的代码其实已经得到了一个缩放的bitmap对象,如果你在应用中显示图片,就可以使用这个bitmap对象了。由于考虑到网络流量的问题。我们好需要牺牲图片的质量来换取一部分空间,这里调用bm.compress()方法进行压缩,这个方法的第二个参数,如果是100,表示不压缩,我这里设置的是60,你也可以更加你的需要进行设置,在实验的过程中我设置为30,图片都不会失真。 压缩效果:本demo可以把1.5M左右的图片压缩到100K左右,并且没有失真。 效果图如下:

    转自:http://my.eoe.cn/575776/archive/564.html

  • 相关阅读:
    linux常用命令
    mysql 开发基础系列20 事务控制和锁定语句(上)
    sql server 性能调优之 资源等待 CXPACKET
    mysql 开发基础系列19 触发器
    mysql 开发基础系列18 存储过程和函数(下)
    mysql 开发基础系列17 存储过程和函数(上)
    sql server 性能调优之 资源等待PAGEIOLATCH
    mysql 开发基础系列16 视图
    mysql 开发基础系列15 索引的设计和使用
    sql server 性能调优之 当前用户请求分析 (1)
  • 原文地址:https://www.cnblogs.com/hudabing/p/4571193.html
Copyright © 2011-2022 走看看