Android 图片压缩各种方式
第一種方式:采用JNI調用libjpeg庫來進行壓縮
? ? ??
介紹
Android圖片壓縮結合多種壓縮方式,常用的有尺寸壓縮、質量壓縮以及通過JNI調用libjpeg庫來進行壓縮,三種方式結合使用實現指定圖片內存大小,清晰度達到最優。
使用
- 導入lib-bither-compress
- 圖像建議尺寸
- 圖像默認品質
注意:默認將圖像壓縮到 1280*720 的尺寸,品質為 80 ,圖像大小為 1 MB。其他配置可在 lib-bither-compress 中 NativeUtil 下自己配置。
對比
原圖 5.5M
項目的下載地址:https://github.com/jeanboydev/Android-BitherCompress
第二種方式:使用系統自帶的壓縮,并做相應的修改
1.文件形式(即以二進制形式存在于硬盤上)
? ?獲取大小(Byte):File.length()
2.流的形式(即以二進制形式存在于內存中)
? ?獲取大小(Byte):new FileInputStream(File).available()
3.Bitmap形式
? ?獲取大小(Byte):Bitmap.getByteCount()
下面以我拍攝的圖片為例,看下三者的大小區別(所用軟件為自己臨時開發的小工具);
從圖中可以看出:
?1、拍攝完的照片文件大小和讀取到內存中的文件流大小是一樣的,說明文件形式和流的形式對圖片體積大小并沒有影響。
?2、當圖片以Bitmap形式存在時,占用的內存就大的多了,為什么 ? ? ? ? ? ? ?呢,首先我們需要知道Bitmap大小計算的方式
? bitmap大小=圖片長度(px)*圖片寬度(px)*單位像素占用的字節數
單位像素所占字節數又是什么鬼,說白了就是圖片的色彩模式。
在BitmapFactory.Options.inPreferredConfig這里可以找到,一共有4種, ARGB代表:A 透明度 , R 紅色, G 綠色, B 藍色
上面的bitmap在內存中的大小就可以計算了(默認色彩模式為ARGB_8888),
??2368*4224*4/1024/1024=38.15625
看到bitmap占用這么大,所以用完調用Bitmap.recycle()是個好習慣(推薦),不調用也沒關系,因為GC進程會自動回收。
二?圖片的壓縮形式
?問:我們從本地對圖片操作的目的。是
?答:上傳(比如設置頭像,發表圖片)。
上傳的基本步驟
那么問題來了
問:我們為什么要壓縮圖片呢
?答:目的無非就2個,一,避免占用內存過多。二,可能要上傳圖片,如果圖片太大,浪費流量。(有時候需要上傳原圖除外)
?1、避免內存過多的壓縮方法:
歸根結底,圖片是要顯示在界面組件上的,所以還是要用到bitmap,從上面可得出Bitmap的在內存中的大小只和圖片尺寸和色彩模式有關,那么要想改變Bitmap在內存中的大小,要么改變尺寸,要么改變色彩模式。
2、避免上傳浪費流量的壓縮方法:
???改變圖片尺寸,改變色彩模式,改變圖片質量都行。正常情況下,先改變圖片尺寸和色彩模式,再改變圖片質量。
改變圖片質量的壓縮方法:
[java]?view plaincopy改變圖片大小的壓縮算法:[java]?view plaincopy
正常情況下我們應該把兩者相結合的,所以有了下面的算法(在項目中直接用,清晰度在手機上沒問題)
[java]?view plaincopy上面算法中用到的兩個方法:
[java]?view plaincopy該項目的下載地址:https://github.com/lbool/Android-Image-Upload
三。自己搞的一種
public File compress(String srcPath) {File imageFile = new File(srcPath);uri = Uri.fromFile(imageFile);float oldSize = (float)new File(uri.getPath()).length()/1024/1024; //以文件的形式System.out.println("進來大小"+oldSize);DisplayMetrics dm =new DisplayMetrics();WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);manager.getDefaultDisplay().getMetrics(dm);float hh = dm.heightPixels;float ww = dm.widthPixels;BitmapFactory.Options opts = new BitmapFactory.Options();opts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(srcPath, opts);opts.inJustDecodeBounds = false;int w = opts.outWidth;int h = opts.outHeight;int size = 0;if (w <= ww && h <= hh) {size = 1;} else {double scale = w >= h ? w / ww : h / hh;double log = Math.log(scale) / Math.log(2);double logCeil = Math.ceil(log);size = (int) Math.pow(2, logCeil);}opts.inSampleSize = size;bitmap = BitmapFactory.decodeFile(srcPath, opts);File outputFile = new File(createImageFile().getPath());FileOutputStream fileOutputStream;ByteArrayOutputStream baos = new ByteArrayOutputStream();int quality = 100;bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);System.out.println("實際的大小"+baos.toByteArray().length/1024);while (baos.toByteArray().length > 30 * 1024) {baos.reset();bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);quality -= 20;System.out.println("完成的大小"+baos.toByteArray().length/1024);}try {fileOutputStream=new FileOutputStream(outputFile);bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);baos.writeTo(fileOutputStream);fileOutputStream.close();} catch (Exception e) {e.printStackTrace();} finally {try {baos.flush();baos.close();} catch (IOException e) {e.printStackTrace();}}return outputFile;}public static Uri createImageFile(){// Create an image file nameString timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());String imageFileName = "JPEG_" + timeStamp + "_";File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);File image = null;try {image = File.createTempFile(imageFileName, /* prefix */".jpg", /* suffix */storageDir /* directory */);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// Save a file: path for use with ACTION_VIEW intentsreturn Uri.fromFile(image);}public static void copyFileUsingFileChannels(File source, File dest){FileChannel inputChannel = null;FileChannel outputChannel = null;try {try {inputChannel = new FileInputStream(source).getChannel();outputChannel = new FileOutputStream(dest).getChannel();outputChannel.transferFrom(inputChannel, 0, inputChannel.size());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}} finally {try {inputChannel.close();outputChannel.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
第四種(最接近微信的一個)
Luban
項目描述
目前做App開發總繞不開圖片這個元素。但是隨著手機拍照分辨率的提升,圖片的壓縮成為一個很重要的問題。單純對圖片進行裁切,壓縮已經有很多文章介紹。但是裁切成多少,壓縮成多少卻很難控制好,裁切過頭圖片太小,質量壓縮過頭則顯示效果太差。
于是自然想到App巨頭“微信”會是怎么處理,Luban(魯班)就是通過在微信朋友圈發送近100張不同分辨率圖片,對比原圖與微信壓縮后的圖片逆向推算出來的壓縮算法。
因為有其他語言也想要實現Luban,所以描述了一遍算法步驟。
因為是逆向推算,效果還沒法跟微信一模一樣,但是已經很接近微信朋友圈壓縮后的效果,具體看以下對比!
效果與對比
| 截屏 720P | 720*1280,390k | 720*1280,87k | 720*1280,56k |
| 截屏 1080P | 1080*1920,2.21M | 1080*1920,104k | 1080*1920,112k |
| 拍照 13M(4:3) | 3096*4128,3.12M | 1548*2064,141k | 1548*2064,147k |
| 拍照 9.6M(16:9) | 4128*2322,4.64M | 1032*581,97k | 1032*581,74k |
| 滾動截屏 | 1080*6433,1.56M | 1080*6433,351k | 1080*6433,482k |
導入
compile 'top.zibin:Luban:1.1.2'使用
異步調用
Luban內部采用IO線程進行圖片壓縮,外部調用只需設置好結果監聽即可:
Luban.with(this).load(File) //傳人要壓縮的圖片.setCompressListener(new OnCompressListener() { //設置回調@Overridepublic void onStart() {// TODO 壓縮開始前調用,可以在方法內啟動 loading UI}@Overridepublic void onSuccess(File file) {// TODO 壓縮成功后調用,返回壓縮后的圖片文件}@Overridepublic void onError(Throwable e) {// TODO 當壓縮過程出現問題時調用}}).launch(); //啟動壓縮同步調用
同步方法請盡量避免在主線程調用以免阻塞主線程,下面以rxJava調用為例
Flowable.just(file).observeOn(Schedulers.io()).map(new Function<File, File>() {@Override public File apply(@NonNull File file) throws Exception {// 同步方法直接返回壓縮后的文件return Luban.with(MainActivity.this).load(file).get();}}).observeOn(AndroidSchedulers.mainThread()).subscribe();項目下載地址:https://github.com/Curzibn/Luban最后添加幾個壓縮工具類BitmapUtils類public class BitmapUtils {/*** 從本地讀取圖片** @param path* @return*/public static Bitmap getBitmapForPath(String path) {try {FileInputStream in = new FileInputStream(path);Bitmap bitmap = BitmapFactory.decodeStream(in);in.close();return bitmap;} catch (Exception e) {}return null;}/*** 獲取資源文件中的圖片** @param context* @param resourcesId* @return*/public static Drawable getDrawableFormResources(Context context, int resourcesId) {Resources resources = context.getResources();return new BitmapDrawable(resources, BitmapFactory.decodeResource(resources, resourcesId));}/*** 從資源文件中獲取bitmap對象** @param context* @param resourcesId* @return*/public static Bitmap getBitmapFromResources(Context context, int resourcesId) {return BitmapFactory.decodeResource(context.getResources(), resourcesId);}/*** bitmap轉byte數組** @param bitmap* @return*/public static byte[] getBitmapbyte(Bitmap bitmap) {ByteArrayOutputStream baos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);byte[] datas = baos.toByteArray();try {baos.flush();baos.close();} catch (IOException e) {e.printStackTrace();}return datas;}/*** bitmap轉byte數組** @param bitmap* @return*/public static String getBitmapBase64byte(Bitmap bitmap) {ByteArrayOutputStream baos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);byte[] datas = baos.toByteArray();String encodeToString = Base64.encodeToString(datas, Base64.DEFAULT);try {baos.flush();baos.close();} catch (IOException e) {e.printStackTrace();}return encodeToString;}/*** byte轉bitmap數組** @param b* @return*/public static Bitmap getBitmaoFrombyte(byte[] b) {return BitmapFactory.decodeByteArray(b, 0, b.length);}/*** 壓縮0** @param srcPath* @return*/public static Bitmap getimageIcon(String srcPath) {BitmapFactory.Options newOpts = new BitmapFactory.Options();//開始讀入圖片,此時把options.inJustDecodeBounds 設回true了newOpts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此時返回bm為空newOpts.inJustDecodeBounds = false;int w = newOpts.outWidth;int h = newOpts.outHeight;//現在主流手機比較多是800*480分辨率,所以高和寬我們設置為float hh = 312f;//這里設置高度為800ffloat ww = 650f;//這里設置寬度為480f//縮放比。由于是固定比例縮放,只用高或者寬其中一個數據進行計算即可int be = 1;//be=1表示不縮放if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放be = (int) (newOpts.outWidth / ww);} else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放be = (int) (newOpts.outHeight / hh);}if (be <= 0)be = 1;newOpts.inSampleSize = be;//設置縮放比例//重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了bitmap = BitmapFactory.decodeFile(srcPath, newOpts);return compressImage(bitmap);//壓縮好比例大小后再進行質量壓縮}/*** 壓縮1** @param srcPath* @return*/public static Bitmap getimage(String srcPath) {BitmapFactory.Options newOpts = new BitmapFactory.Options();//開始讀入圖片,此時把options.inJustDecodeBounds 設回true了newOpts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此時返回bm為空newOpts.inJustDecodeBounds = false;int w = newOpts.outWidth;int h = newOpts.outHeight;//現在主流手機比較多是800*480分辨率,所以高和寬我們設置為float hh = 800f;//這里設置高度為800ffloat ww = 480f;//這里設置寬度為480f//縮放比。由于是固定比例縮放,只用高或者寬其中一個數據進行計算即可int be = 1;//be=1表示不縮放if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放be = (int) (newOpts.outWidth / ww);} else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放be = (int) (newOpts.outHeight / hh);}if (be <= 0)be = 1;newOpts.inSampleSize = be;//設置縮放比例//重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了bitmap = BitmapFactory.decodeFile(srcPath, newOpts);return compressImage(bitmap);//壓縮好比例大小后再進行質量壓縮}//把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); // }/*** 壓縮2** @param image* @return*/public static Bitmap comp(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);if (baos.toByteArray().length / 1024 > 1024) {//判斷如果圖片大于1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出baos.reset();//重置baos即清空baosimage.compress(Bitmap.CompressFormat.JPEG, 30, baos);//這里壓縮50%,把壓縮后的數據存放到baos中}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());BitmapFactory.Options newOpts = new BitmapFactory.Options();//開始讀入圖片,此時把options.inJustDecodeBounds 設回true了newOpts.inJustDecodeBounds = true;Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);newOpts.inJustDecodeBounds = false;int w = newOpts.outWidth;int h = newOpts.outHeight;//現在主流手機比較多是800*480分辨率,所以高和寬我們設置為float hh = 800f;//這里設置高度為800ffloat ww = 480f;//這里設置寬度為480f//縮放比。由于是固定比例縮放,只用高或者寬其中一個數據進行計算即可int be = 1;//be=1表示不縮放if (w > h && w > ww) {//如果寬度大的話根據寬度固定大小縮放be = (int) (newOpts.outWidth / ww);} else if (w < h && h > hh) {//如果高度高的話根據寬度固定大小縮放be = (int) (newOpts.outHeight / hh);}if (be <= 0)be = 1;newOpts.inSampleSize = be;//設置縮放比例newOpts.inPreferredConfig = Bitmap.Config.RGB_565;//降低圖片從ARGB888到RGB565//重新讀入圖片,注意此時已經把options.inJustDecodeBounds 設回false了isBm = new ByteArrayInputStream(baos.toByteArray());bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);return compressImage(bitmap);//壓縮好比例大小后再進行質量壓縮}/*** 質量壓縮** @param image* @return*/public static Bitmap compressImage(Bitmap image) {ByteArrayOutputStream baos = new ByteArrayOutputStream();image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//質量壓縮方法,這里100表示不壓縮,把壓縮后的數據存放到baos中int options = 100;while (baos.toByteArray().length / 1024 > 100) { //循環判斷如果壓縮后圖片是否大于100kb,大于繼續壓縮baos.reset();//重置baos即清空baosoptions -= 20;//每次都減少10image.compress(Bitmap.CompressFormat.JPEG, options, baos);//這里壓縮options%,把壓縮后的數據存放到baos中}ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把壓縮后的數據baos存放到ByteArrayInputStream中Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream數據生成圖片return bitmap;}/*** 獲取圖片大小** @param bitmap* @return*/public static long getBitmapsize(Bitmap bitmap) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {return bitmap.getByteCount();}return bitmap.getRowBytes() * bitmap.getHeight();}/*** 對圖片進行模糊處理** @param bitmap* @param context* @return*/@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)public static Bitmap blurBitmap(Bitmap bitmap, Context context) {Bitmap outBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);RenderScript rs = RenderScript.create(context.getApplicationContext());ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));Allocation allIn = Allocation.createFromBitmap(rs, bitmap);Allocation allOut = Allocation.createFromBitmap(rs, outBitmap);blurScript.setRadius(25f);blurScript.setInput(allIn);blurScript.forEach(allOut);allOut.copyTo(outBitmap);bitmap.recycle();rs.destroy();return outBitmap;}public static Bitmap drawableToBitmap(Drawable drawable) {Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);Canvas canvas = new Canvas(bitmap);//canvas.setBitmap(bitmap);drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());drawable.draw(canvas);return bitmap;}/*** 水平方向模糊度*/private static float hRadius = 10;/*** 豎直方向模糊度*/private static float vRadius = 10;/*** 模糊迭代度*/private static int iterations = 7;private static float a = 1.3f;/*** 模糊圖片** @param bmp* @return*/public static Drawable BoxBlurFilter(Bitmap bmp) {hRadius = hRadius * a;vRadius = vRadius * a;iterations = (int) (iterations * a);int width = bmp.getWidth();int height = bmp.getHeight();int[] inPixels = new int[width * height];int[] outPixels = new int[width * height];Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);bmp.getPixels(inPixels, 0, width, 0, 0, width, height);for (int i = 0; i < iterations; i++) {blur(inPixels,outPixels, width, height, hRadius);blur(outPixels,inPixels, height, width, vRadius);}blurFractional(inPixels,outPixels, width, height, hRadius);blurFractional(outPixels,inPixels, height, width, vRadius);bitmap.setPixels(inPixels,0,width, 0,0,width, height);Drawable drawable = new BitmapDrawable(bitmap);return drawable;}public static void blur(int[] in, int[] out, int width, int height, float radius) {int widthMinus1 = width - 1;int r = (int) radius;int tableSize = 2 * r + 1;int divide[] = new int[256 * tableSize];for (int i = 0; i < 256 * tableSize; i++)divide[i] = i / tableSize;int inIndex = 0;for (int y = 0; y < height; y++) {int outIndex = y;int ta = 0, tr = 0, tg = 0, tb = 0;for (int i = -r; i <= r; i++) {int rgb = in[inIndex + clamp(i, 0, width - 1)];ta += (rgb >> 24) & 0xff;tr += (rgb >> 16) & 0xff;tg += (rgb >> 8) & 0xff;tb += rgb & 0xff;}for (int x = 0; x < width; x++) {out[outIndex] = (divide[ta] << 24) | (divide[tr] << 16) | (divide[tg] << 8)| divide[tb];int i1 = x + r + 1;if (i1 > widthMinus1)i1 = widthMinus1;int i2 = x - r;if (i2 < 0)i2 = 0;int rgb1 = in[inIndex + i1];int rgb2 = in[inIndex + i2];ta += ((rgb1 >> 24) & 0xff) - ((rgb2 >> 24) & 0xff);tr += ((rgb1 & 0xff0000) - (rgb2 & 0xff0000)) >> 16;tg += ((rgb1 & 0xff00) - (rgb2 & 0xff00)) >> 8;tb += (rgb1 & 0xff) - (rgb2 & 0xff);outIndex += height;}inIndex += width;}}public static void blurFractional(int[] in, int[] out, int width, int height, float radius) {radius -= (int) radius;float f = 1.0f / (1 + 2 * radius);int inIndex = 0;for (int y = 0; y < height; y++) {int outIndex = y;out[outIndex] = in[0];outIndex += height;for (int x = 1; x < width - 1; x++) {int i = inIndex + x;int rgb1 = in[i - 1];int rgb2 = in[i];int rgb3 = in[i + 1];int a1 = (rgb1 >> 24)& 0xff;int r1= (rgb1 >> 16)& 0xff;int g1= (rgb1 >> 8)& 0xff;int b1= rgb1 & 0xff;int a2= (rgb2 >> 24)& 0xff;int r2= (rgb2 >> 16)& 0xff;int g2= (rgb2 >> 8)& 0xff;int b2= rgb2 & 0xff;int a3= (rgb3 >> 24)& 0xff;int r3= (rgb3 >> 16)& 0xff;int g3= (rgb3 >> 8)& 0xff;int b3= rgb3 & 0xff;a1= a2 + (int)((a1 + a3) * radius);r1= r2 + (int)((r1 + r3) * radius);g1= g2 + (int)((g1 + g3) * radius);b1= b2 + (int)((b1 + b3) * radius);a1*= f;r1*= f;g1*= f;b1*= f;out[outIndex]= (a1 << 24)| (r1 << 16)| (g1 << 8)| b1;outIndex+= height;}out[outIndex]= in[width - 1];inIndex+= width;}}public static int clamp(int x,int a,int b) {return (x< a) ? a : (x > b) ? b : x;}public static String getImageUrl(Context context, Uri photoUri) {String res = null;String[] proj = {MediaStore.Images.Media.DATA};Cursor cursor = context.getContentResolver().query(photoUri, proj, null, null, null);if (cursor.moveToFirst()) {;int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);res = cursor.getString(column_index);}cursor.close();return res;}/*** 將Bitmap轉換成文件* 保存文件** @param bm* @param fileName* @throws IOException*/public static File saveFile(Bitmap bm, String path, String fileName) throws IOException {File dirFile = new File(path);if (!dirFile.exists()) {dirFile.mkdir();}File myCaptureFile = new File(path, fileName);BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(myCaptureFile));bm.compress(Bitmap.CompressFormat.JPEG, 80, bos);bos.flush();bos.close();return myCaptureFile;}/*** 路徑轉換成file** @param filePath* @return*/public static File BetyToFile(String filePath) {File file = new File(filePath);BufferedOutputStream stream = null;FileOutputStream fstream = null;byte[] data = new byte[(int) file.length()];try {fstream = new FileOutputStream(file);stream = new BufferedOutputStream(fstream);stream.write(data);} catch (Exception e) {e.printStackTrace();} finally {try {if (stream != null) {stream.close();}if (null != fstream) {fstream.close();}} catch (IOException e1) {e1.printStackTrace();}}return file;}
ImageCompress類
public class ImageCompress {public static final String CONTENT = "content";public static final String FILE = "file";/*** 調用ImageCompress compress = new ImageCompress();ImageCompress.CompressOptions options = new ImageCompress.CompressOptions();options.uri = Uri.fromFile(new File(sourcePath));options.maxWidth=Constants.RESIZEBITMAP_WIDTH;options.maxHeight=Constants.RESIZEBITMAP_HEIGHT;Bitmap bitmap = compress.compressFromUri(UploadWithPhotoBaseActivity.this, options);*//*** 圖片壓縮參數** @author Administrator*/public static class CompressOptions {public static final int DEFAULT_WIDTH = 400;public static final int DEFAULT_HEIGHT = 800;public int maxWidth = DEFAULT_WIDTH;public int maxHeight = DEFAULT_HEIGHT;/*** 壓縮后圖片保存的文件*/public File destFile;/*** 圖片壓縮格式,默認為jpg格式*/public Bitmap.CompressFormat imgFormat = Bitmap.CompressFormat.JPEG;/*** 圖片壓縮比例 默認為30*/public int quality = 30;public Uri uri;}/*** 返回bitmap* @param context* @param compressOptions* @return*/public Bitmap compressFromUri(Context context, CompressOptions compressOptions) {// uri指向的文件路徑String filePath = getFilePath(context, compressOptions.uri);if (null == filePath) {return null;}BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;Bitmap temp = BitmapFactory.decodeFile(filePath, options);int actualWidth = options.outWidth;int actualHeight = options.outHeight;int desiredWidth = getResizedDimension(compressOptions.maxWidth,compressOptions.maxHeight, actualWidth, actualHeight);int desiredHeight = getResizedDimension(compressOptions.maxHeight,compressOptions.maxWidth, actualHeight, actualWidth);options.inJustDecodeBounds = false;options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,desiredWidth, desiredHeight);Bitmap bitmap = null;Bitmap destBitmap = BitmapFactory.decodeFile(filePath, options);// If necessary, scale down to the maximal acceptable size.if (destBitmap.getWidth() > desiredWidth|| destBitmap.getHeight() > desiredHeight) {bitmap = Bitmap.createScaledBitmap(destBitmap, desiredWidth,desiredHeight, true);destBitmap.recycle();} else {bitmap = destBitmap;}// compress file if needif (null != compressOptions.destFile) {compressFile(compressOptions, bitmap);}return bitmap;}/*** 返回file形式* @param context* @param compressOptions* @return*/public File compressFromUriFile(Context context, CompressOptions compressOptions) {// uri指向的文件路徑String filePath = getFilePath(context, compressOptions.uri);File outputFile = new File(filePath);Log.i("INFO", "路徑" + filePath);if (null == filePath) {return null;}BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;Bitmap temp = BitmapFactory.decodeFile(filePath, options);int actualWidth = options.outWidth;int actualHeight = options.outHeight;int desiredWidth = getResizedDimension(compressOptions.maxWidth,compressOptions.maxHeight, actualWidth, actualHeight);int desiredHeight = getResizedDimension(compressOptions.maxHeight,compressOptions.maxWidth, actualHeight, actualWidth);options.inJustDecodeBounds = false;options.inSampleSize = findBestSampleSize(actualWidth, actualHeight,desiredWidth, desiredHeight);Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);outputFile = new File(createImageFile().getPath());FileOutputStream fos = null;try {fos = new FileOutputStream(outputFile);bitmap.compress(Bitmap.CompressFormat.JPEG, 50, fos);fos.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}if (!bitmap.isRecycled()) {bitmap.recycle();} else {File tempFile = outputFile;outputFile = new File(createImageFile().getPath());copyFileUsingFileChannels(tempFile, outputFile);}// compress file if needif (null != compressOptions.destFile) { // compressFile(compressOptions, bitmap);File tempFile = outputFile;outputFile = new File(createImageFile().getPath());copyFileUsingFileChannels(tempFile, outputFile);}return outputFile;}/*** compress file from bitmap with compressOptions** @param compressOptions* @param bitmap*/private void compressFile(CompressOptions compressOptions, Bitmap bitmap) {OutputStream stream = null;try {stream = new FileOutputStream(compressOptions.destFile);} catch (FileNotFoundException e) {Log.e("ImageCompress", e.getMessage());}bitmap.compress(compressOptions.imgFormat, compressOptions.quality,stream);}private static int findBestSampleSize(int actualWidth, int actualHeight,int desiredWidth, int desiredHeight) {double wr = (double) actualWidth / desiredWidth;double hr = (double) actualHeight / desiredHeight;double ratio = Math.min(wr, hr);float n = 1.0f;while ((n * 2) <= ratio) {n *= 2;}return (int) n;}private static int getResizedDimension(int maxPrimary, int maxSecondary,int actualPrimary, int actualSecondary) {// If no dominant value at all, just return the actual.if (maxPrimary == 0 && maxSecondary == 0) {return actualPrimary;}// If primary is unspecified, scale primary to match secondary's scaling// ratio.if (maxPrimary == 0) {double ratio = (double) maxSecondary / (double) actualSecondary;return (int) (actualPrimary * ratio);}if (maxSecondary == 0) {return maxPrimary;}double ratio = (double) actualSecondary / (double) actualPrimary;int resized = maxPrimary;if (resized * ratio > maxSecondary) {resized = (int) (maxSecondary / ratio);}return resized;}/*** 獲取文件的路徑** @param* @return*/private String getFilePath(Context context, Uri uri) {String filePath = null;if (CONTENT.equalsIgnoreCase(uri.getScheme())) {Cursor cursor = context.getContentResolver().query(uri,new String[]{MediaStore.Images.Media.DATA}, null, null, null);if (null == cursor) {return null;}try {if (cursor.moveToNext()) {filePath = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));}} finally {cursor.close();}}// 從文件中選擇if (FILE.equalsIgnoreCase(uri.getScheme())) {filePath = uri.getPath();}return filePath;}/*** 創建一個新的文件夾,保存壓縮后的圖片* @return*/public static Uri createImageFile() {// Create an image file nameString timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new java.util.Date());String imageFileName = "JPEG_" + timeStamp + "_";File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);File image = null;try {image = File.createTempFile(imageFileName, /* prefix */".jpg", /* suffix */storageDir /* directory */);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}// Save a file: path for use with ACTION_VIEW intentsreturn Uri.fromFile(image);}public static void copyFileUsingFileChannels(File source, File dest) {FileChannel inputChannel = null;FileChannel outputChannel = null;try {try {inputChannel = new FileInputStream(source).getChannel();outputChannel = new FileOutputStream(dest).getChannel();outputChannel.transferFrom(inputChannel, 0, inputChannel.size());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}} finally {try {inputChannel.close();outputChannel.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
好了,大概就總結到這了。
總結
以上是生活随笔為你收集整理的Android 图片压缩各种方式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: k8s 创建秘钥
- 下一篇: Android 高德地图中路线规划绘制界