您的位置:首页 > 移动开发 > Android开发

Android应用开发之图片(Bitmap)压缩(二)---------质量压缩

2014-10-30 11:20 471 查看
博客为 有时个哥 原创,如需转载请标明出处:/article/11171953.html

质量压缩:

这种压缩方式是让图片经行重组,通过改变色深和透明度来经行压缩,但是像素是没有改变的,所以是不会减少bitmap占用的内存。质量压缩是使用Bitmap类里面的compress(Bitmap.CompressFormat format,
int quality,OutputStream stream)具体的方法在上一篇(一)中已经说过了,下面做测试的代码如下。通过输出数据来比较各种格式的不同。

package com.example.bitmapdemo.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

public class ImageUtils {
/**
* 从本地读取图片,通过路径,获得bitmap
* @param path 图片路径
* @return Bitmap
*/
public static Bitmap getBitmapFromLocal(String pathName){
Bitmap bitmap = BitmapFactory.decodeFile(pathName);
return bitmap;
}
/**
* 通过给出的bitmap进行质量压缩
* @param bitmap
* @return
*/
public static Bitmap compressBitmap(Bitmap bitmap){
System.out.println("bitmap=="+bitmap.getByteCount());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//通过这里改变压缩类型,其有不同的结果
bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
System.out.println("bos====="+bos.size());
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
System.out.println("bis====="+bis.available());
return BitmapFactory.decodeStream(bis);
}
/**
* 通过给出的图片路径进行图片压缩
* @param pathName
* @return
*/
public static Bitmap compressBitmap(String pathName){
return compressBitmap(getBitmapFromLocal(pathName));
}
/**
* 把图片写入sd卡
* @param bitmap  图片的bitmap形式
*/
public static void writeImage(Bitmap bitmap){
String storageState = Environment.getExternalStorageState();
System.out.println();
if(!storageState.equals(Environment.MEDIA_MOUNTED)){
return;
}
File file =new File(Environment.getExternalStorageDirectory()
.getAbsolutePath()+"/rr");
if(!file.exists()){
file.mkdirs();
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
//		bitmap.compress(Bitmap.CompressFormat.WEBP, 60, bos);
//		bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
bitmap.compress(Bitmap.CompressFormat.PNG, 60, bos);
FileOutputStream fos;
try {
//WEBP
//			File f = new File(file,"song.jpg");
//			File f = new File(file,"song.png");
//			File f = new File(file,"song.webp");
//压缩格式是JPEG的时候,保存成各种格式图片测试
//			File f = new File(file,"song1.jpg");
//			File f = new File(file,"song1.png");
//			File f = new File(file,"song1.webp");
//PNG
//			File f = new File(file,"song2.jpg");
//			File f = new File(file,"song2.png");
//			File f = new File(file,"song2.webp");

//			File f = new File(file,"song_png.jpg");
//			File f = new File(file,"song_png.png");
//			File f = new File(file,"song_png.webp");
//			File f = new File(file,"song_png1.jpg");
//			File f = new File(file,"song_png1.png");
//			File f = new File(file,"song_png1.webp");
//			File f = new File(file,"song_png2.jpg");
//			File f = new File(file,"song_png3.png");
File f = new File(file,"song_png4.webp");
//			System.out.println("fpath==========================>>"+f.getAbsolutePath());
fos = new FileOutputStream(f);
fos.write(bos.toByteArray());
fos.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
}


public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//		String imagePath = "/mnt/sdcard/image.png";
String imagePath = "/mnt/sdcard/5.jpg";
getBitmap(imagePath);
getInputStreanm(imagePath);
getCompess(imagePath);
}

public void getBitmap(String pathName){
//		Bitmap bm = ImageUtils.getBitmapFromLocal(pathName);
Bitmap bm = BitmapFactory.decodeFile(pathName);;
System.out.println("bitmap:::"+bm.getRowBytes()*bm.getHeight());
//		System.out.println("bitmap:::"+bm.getByteCount());
System.out.println("bitmap的另一种求法:::"+bm.getWidth() * bm.getHeight()*4 );
}

public void getInputStreanm(String pathName){
try {
FileInputStream fis = new FileInputStream(pathName);
System.out.println("inputStream:::"+fis.available());
} catch (Exception e) {
e.printStackTrace();
}
}

public void getCompess(String pathName){
Bitmap bm = ImageUtils.compressBitmap(pathName);
System.out.println("bitmap后::"+bm.getRowBytes()*bm.getHeight());
//		System.out.println("bitmap后::"+bm.getByteCount());
ImageUtils.writeImage( bm);
}
}

这就是做质量测试的代码:然后我给出测试结果:

压缩格式设置为jpg时:



压缩格式设置为png时:



前后的bitmap对象的大小是没有改变的,这就说明质量压缩不能改变图片在内存中的占用大小。然后看看压缩前后的大小对比:

压缩前的图片大小9005,差不多快9k。



压缩后的图片质量:



这上面的结果是一张后缀名为jpg的图片,分贝设置成jpg压缩格式或png压缩格式,然后在保存成png或jpg得到的不同结果。song1名字的图片是吧压缩格式设置成JPEG得到的,song2名字的图片是把压缩格式设置成PNG得到的。

从上面结果可以看出只要设定压缩格式之后(即bitmap.compress(Bitmap.CompressFormat.PNG, 60, bos);)无论你的图片再生成什么格式的图片其图片的大小是不会随格式改变了。上面song1.png和song1.jpg是一样大小的。相比较之下,把压缩格式设置成jpeg压缩出来的图片比较小。但是在测试中,如果你要压缩的图片本身如果是JPG格式的话,而设置的压缩格式是PNG,则图片反而会变大,有可能变大十几倍。这是和图片的格式有关,涉及到图片的色深透明度。在相同像素情况下,一般PNG的图片在色彩上要比JPG的鲜艳。所以这一点要注意,不要把Jpg格式的图片压缩是吧压缩格式设置成PNG。当然上面所说的压缩是指的在硬盘活sd卡形成file文件形式的前后对比。通过上面的数据可以看出,bitmap的大小前后没有变化,也就说明其在内存中的占用大小没变,所以说质量压缩没有改变其在内存中占用的大小,只是通过改变图片的色深透明来压缩图片,其像素的个数是没有变化的。大家也可以试试把原图为png的图片,然后设置不同压缩格式的变化,然后再重新生成新的png活jpg格式的图片,看看前后变化。这可以使我们做出更好的选择,一般情况下是设置jpeg压缩格式。不过具体的还是按自己的需求来。

至于质量压缩的工具类可以通过上面经行整理一下就出来了。

质量压缩的工具类:

package com.example.bitmapdemo.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;

public class ImageUtils2 {
/**
* 通过图片路径获得bitmap(无压缩形式)
* @param path 图片路径
* @return Bitmap
*/
public static Bitmap getBitmapFromLocal(String pathName){
Bitmap bitmap = BitmapFactory.decodeFile(pathName);
return bitmap;
}

/**
* 通过bitmap得到输出流(无压缩形式)
* @param bitmap bitmap对象
* @return OutputStream
*/
public static ByteArrayOutputStream getOutStreamFromBitmap(Bitmap bitmap){
return getOutStreamFromBitmap( bitmap,100);
}
/**
* 通过bitmap得到输出流(质量压缩)
* @param bitmap bitmap对象
* @param quality 要压缩到的质量(0-100)
* @return OutputStream
*/
public static ByteArrayOutputStream getOutStreamFromBitmap(Bitmap bitmap,int quality){
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bos;
}
/**
* 通过流获得bitmap
* @param os 输出流
* @return Bitmap
*/
public static Bitmap getBitmapFromOutStream(ByteArrayOutputStream os){
ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
if(bis !=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return 	BitmapFactory.decodeStream(bis);
}
/**
* 通过路径得到图片并对图片进行压缩,并再生成图片(质量压缩)
* @param imagePath 图片的路径
* @param savePath 新图片的保存路径
* @param quality 要压缩到的质量
* @return Boolean true 成功false失败
*/
public static boolean writeCompressImage2File(String imagePath ,String savePath,int quality){
if(TextUtils.isEmpty(imagePath)){
return false;
}
String imageName  = imagePath.substring(imagePath.lastIndexOf("/")+1,imagePath.lastIndexOf("."));
return writeImage2File(getOutStreamFromBitmap(getBitmapFromLocal(imagePath), quality),savePath ,imageName);
}
/**
* 把bitmap写入指定目录下,重新生成图片
* @param bitmap bitmap对象
* @param savePath 新图片保存路径
* @param imageName 新图片的名字,会根据时间来命名
* @return Boolean true 成功false失败
*/
public static boolean writeImage2File(Bitmap bitmap ,String savePath,String imageName){
return writeImage2File(getOutStreamFromBitmap(bitmap),savePath ,imageName);
}
/**
* 通过输出流,重组图片,并保存带指定目录下
* @param bos 图片输入流
* @param savePath 新图片的保存路径
* @param imageName 新图片的名字,字段为空时,会根据时间来命名
* @return Boolean true 成功false失败
*/
public static boolean writeImage2File(ByteArrayOutputStream bos,String savePath,String imageName){
if(TextUtils.isEmpty(savePath)){
return false;
}
File file =new File(savePath);
if(!file.exists()){
file.mkdirs();
}
FileOutputStream fos;
try {
if(TextUtils.isEmpty(imageName)){
imageName = System.currentTimeMillis()+"";
}
File f = new File(file,imageName+".jpg");
fos = new FileOutputStream(f);
fos.write(bos.toByteArray());
fos.flush();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
}


总结:质量压缩只是改变其存储的形式的大小,不改变其在内存中的大小。一般用于不失真压缩,上传图片等。值得注意的事,由于这种压缩不会改变bitmap的大小,所以,大家要注意,不要以这种过程压缩,图片->bitmap->质量压缩->io->bitmap->图片,如果你按照这个流程走,你会发现你重组的图片会变大。因为你又获得bitmap就说明你质量压缩是做无用功,因为他不会改变bitmap大小,这样你重组获得的图片反而会变大。一般是在质量压缩获得流之后,对流直接经行操作,因为你这个流已经经行了压缩。然后对流直接操作,上传,或直接写入文件。

下一篇整理采样率压缩
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: