最简单的ndk调用!通过libjpeg库来加载图片,避免了oom~

我在这里说下显而易见的优势:大量节省上传流量,处理后的图片效果和前期原图基本没啥变化,但是质量可以相差10倍!!是不是狠diao~,
老司机先上图,最简单的ndk调用!通过libjpeg库来加载图片,避免了oom~_第1张图片
有没有一种被惊艳的感觉~!

  • 再看看点击原图片查看详细内容:
  • 最简单的ndk调用!通过libjpeg库来加载图片,避免了oom~_第2张图片

    • 接下来看看 处理后的图片查看详细内容:
  • 最简单的ndk调用!通过libjpeg库来加载图片,避免了oom~_第3张图片

图是最好的说明!有没有被震撼到呢?开始开车吧。

  • 我们平常的图片压缩,如果通过java去处理,是比较麻烦的,要么就是质量压缩代码如下:
微信的缩略图要求是不大于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 );
  第二个使用的是这个方法,可以将图片压缩到足够小,但是也有一些问题。因为采样率是整数,所以不能很好的保证图片的质量。如我们需要的是在23采样率之间,用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这个库来使用。

  • 看下代码结构:
    最简单的ndk调用!通过libjpeg库来加载图片,避免了oom~_第4张图片

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里面的方法。

  • 关于jni调用和ndk开发环境集成,这里就不说了,网上一大推~如果想详细查看的话c里面的代码可以到这里

你可能感兴趣的:(Android常见问题,android,图片处理)