我在这里说下显而易见的优势:大量节省上传流量,处理后的图片效果和前期原图基本没啥变化,但是质量可以相差10倍!!是不是狠diao~,
老司机先上图,
有没有一种被惊艳的感觉~!
图是最好的说明!有没有被震撼到呢?开始开车吧。
微信的缩略图要求是不大于32k,这就需要对我的图片进行压缩。试了几种方法,一一道来。
代码如下
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100 , baos);
int options = 100 ;
while ( baos.toByteArray().length / 1024 > 32 ) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG, options, baos);
options -= 10 ;
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null , null );
最开始使用这个来进行压缩,但是始终压缩不到32k这么小。后来看高手的解释才明白,这种压缩方法之所以称之为质量压缩,是因为它不会减少图片的像素。它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的。进过它压缩的图片文件大小会有改变,但是导入成bitmap后占得内存是不变的。因为要保持像素不变,所以它就无法无限压缩,到达一个值之后就不会继续变小了。显然这个方法并不适用与缩略图,其实也不适用于想通过压缩图片减少内存的适用,仅仅适用于想在保证图片质量的同时减少文件大小的情况而已。
2、采样率压缩法:
代码如下
ByteArrayOutputStream out = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, out);
BitmapFactory.Options newOpts = new BitmapFactory.Options();
int be = 2;
newOpts.inSampleSize = be;
ByteArrayInputStream isBm = new ByteArrayInputStream(out.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null , null );
第二个使用的是这个方法,可以将图片压缩到足够小,但是也有一些问题。因为采样率是整数,所以不能很好的保证图片的质量。如我们需要的是在2和3采样率之间,用2的话图片就大了一点,但是用3的话图片质量就会有很明显的下降。这样也无法完全满足我的需要。不过这个方法的好处是大大的缩小了内存的使用,在读存储器上的图片时,如果不需要高清的效果,可以先只读取图片的边,通过宽和高设定好取样率后再加载图片,这样就不会过多的占用内存。如下
BitmapFactory.Options newOpts = new BitmapFactory.Options();
newOpts.inJustDecodeBounds = true ;
Bitmap bitmap = BitmapFactory.decodeFile(path,newOpts);
newOpts.inJustDecodeBounds = false ;
int w = newOpts.outWidth;
int h = newOpts.outHeight;
//计算出取样率
newOpts.inSampleSize = be;
bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
这样的好处是不会先将大图片读入内存,大大减少了内存的使用,也不必考虑将大图片读入内存后的释放事宜。
但是这不是我想要的结果!,因为它不能保证图片的质量。
-在使用这个库的之前先介绍下这个库吧,以前把它已经嵌入到系统里面的,但是到时考虑手机硬件没那么发达,后来skia出世后就是对它的第二次封装,只不过把以前jpeg的哈夫曼编码这一块屏蔽了(关于哈夫曼编码自己百度吧),但是到了现在我们手机的硬件已经跟上来了,所以以前的那种情况就不用担心了,所以哟~现在直接拿libjpeg这个库来使用。
MainActivity.java:
/*
* Copyright 2014 http://Bither.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.testjpg;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import net.bither.util.NativeUtil;
public class MainActivity extends Activity {
private static final int RESULT = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// testJpeg();
setContentView(R.layout.main);
}
// 加载图片
public void load(View v) {
// 在CODE上查看代码片派生到我的代码片
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RESULT);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == RESULT) {
Uri uri = data.getData();
Log.e("eee", uri.toString());
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), uri);
File dirFile = getExternalCacheDir();
if (!dirFile.exists()) {
dirFile.mkdirs();
}
File truefile = new File(dirFile, "处理后图片.jpeg");
File orignalfile = new File(dirFile, "原图片.jpeg");
NativeUtil.compressBitmap(bitmap, orignalfile.getAbsolutePath(), false);
NativeUtil.compressBitmap(bitmap, 20, truefile.getAbsolutePath(), true);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void testJpeg() {
new Thread(new Runnable() {
public void run() {
try {
int quality = 30;
InputStream in = getResources().getAssets().open("test.jpg");
Bitmap bit = BitmapFactory.decodeStream(in);
File dirFile = getExternalCacheDir();
if (!dirFile.exists()) {
dirFile.mkdirs();
}
File originalFile = new File(dirFile, "original.jpg");
FileOutputStream fileOutputStream = new FileOutputStream(originalFile);
bit.compress(CompressFormat.JPEG, quality, fileOutputStream);
File jpegTrueFile = new File(dirFile, "jpegtrue.jpg");
File jpegFalseFile = new File(dirFile, "jpegfalse.jpg");
NativeUtil.compressBitmap(bit, quality, jpegTrueFile.getAbsolutePath(), true);
NativeUtil.compressBitmap(bit, quality, jpegFalseFile.getAbsolutePath(), false);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
// Uri获取真实路径转换成File的方法
protected String getAbsoluteImagePath(Uri uri) {
// can post image
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, // Which columns to return
null, // WHERE clause; which rows to return (all rows)
null, // WHERE clause selection arguments (none)
null); // Order-by clause (ascending by name)
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
}
NativeUtil.java代码如下:
/*
* Copyright 2014 http://Bither.net
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.bither.util;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.Log;
public class NativeUtil {
private static int DEFAULT_QUALITY = 95;
public static void compressBitmap(Bitmap bit, String fileName,
boolean optimize) {
compressBitmap(bit, DEFAULT_QUALITY, fileName, optimize);
}
public static void compressBitmap(Bitmap bit, int quality, String fileName,
boolean optimize) {
Log.d("native", "compress of native");
if (bit.getConfig() != Config.ARGB_8888) {
Bitmap result = null;
result = Bitmap.createBitmap(bit.getWidth(), bit.getHeight(),
Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Rect rect = new Rect(0, 0, bit.getWidth(), bit.getHeight());
canvas.drawBitmap(bit, null, rect, null);
saveBitmap(result, quality, fileName, optimize);
result.recycle();
} else {
saveBitmap(bit, quality, fileName, optimize);
}
}
private static void saveBitmap(Bitmap bit, int quality, String fileName,
boolean optimize) {
compressBitmap(bit, bit.getWidth(), bit.getHeight(), quality,
fileName.getBytes(), optimize);
}
private static native String compressBitmap(Bitmap bit, int w, int h,
int quality, byte[] fileNameBytes, boolean optimize);
static {
System.loadLibrary("jpegbither");
System.loadLibrary("bitherjni");
}
}
main.xml布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="load"
android:text="找图片" />
LinearLayout>
布局里面放了一个button,点击进入图库选择图片,到activity中的onActivityResult中获取uri,然后调用nativeutil里面的方法。