图片处理的一些方法

Posted xinruzhishui_11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片处理的一些方法相关的知识,希望对你有一定的参考价值。

在请求网络时。我们经常会从服务端获取图片,下面我总结了一些图片的处理方法,希望能够帮助其他人

防止批量加载图片时出现OOM(OutOfMemory)

压缩图片
BitmapUtils 图片操作的工具类
//width 图片显示的宽度 height图片显示的高度
Bitmap loadBitmap(is, width, height){

}

android中图片缓存的实现

Java中的引用
1>强引用 Strong References
就算出现OOM,Java虚拟机都不会销毁该引用。
2>软引用 Soft References
如果Java管理的内存趋于阈值时,GC将会销毁
一部分软引用,释放内存。
3>弱引用 Weak References
比软引用还要弱。
4>虚引用 ………..
不做了解。

SoftReference 软引用对象

SoftReference ref = new SoftReference(bitmap);
Bitmap bitmap=ref.get();

内存缓存(把图片存入内存中)
存图片 (当图片从服务端下载成功后需要存)

Map <String,SoftReference<Bitmap>> cache;
cache.put(path, new SoftReference(bitmap) );

内存中取图片

SoftReference ref=cache.get(path);
if(ref!=null){
  Bitmap b=ref.get();
  if(b!=null){
    设置...
  }
}

文件缓存(把图片存在文件里)
向文件中存图片BitmapUtils.save(bitmap, path);

从文件中读取图片
//path 文件存储路径
Bitmap BitmapUtils.loadBitmap(path);

package cn.tedu.music_player_v4.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;

/**
 * 图片相关工具方法
 */
public class BitmapUtils {

    /**
     * 异步在工作线程中执行图片模糊化处理
     * 
     * @param bitmap
     * @param r
     * @param callback
     */
    public static void loadBluredBitmap(final Bitmap bitmap, final int r,
            final BitmapCallback callback) {
        new AsyncTask<String, String, Bitmap>() {
            protected Bitmap doInBackground(String... params) {
                Bitmap b = createBlurBitmap(bitmap, r);
                return b;
            }

            protected void onPostExecute(Bitmap b) {
                callback.onBitmapLoaded(b);
            }
        }.execute();
    }

    /**
     * 传递bitmap 传递模糊半径 返回一个被模糊的bitmap
     * 
     * @param sentBitmap
     * @param radius
     * @return
     */
    public static Bitmap createBlurBitmap(Bitmap sentBitmap, int radius) {
        Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
        if (radius < 1) {
            return (null);
        }
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);
        int wm = w - 1;
        int hm = h - 1;
        int wh = w * h;
        int div = radius + radius + 1;
        int r[] = new int[wh];
        int g[] = new int[wh];
        int b[] = new int[wh];
        int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
        int vmin[] = new int[Math.max(w, h)];
        int divsum = (div + 1) >> 1;
        divsum *= divsum;
        int dv[] = new int[256 * divsum];
        for (i = 0; i < 256 * divsum; i++) {
            dv[i] = (i / divsum);

        }
        yw = yi = 0;
        int[][] stack = new int[div][3];
        int stackpointer;
        int stackstart;
        int[] sir;
        int rbs;
        int r1 = radius + 1;
        int routsum, goutsum, boutsum;
        int rinsum, ginsum, binsum;
        for (y = 0; y < h; y++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            for (i = -radius; i <= radius; i++) {
                p = pix[yi + Math.min(wm, Math.max(i, 0))];
                sir = stack[i + radius];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rbs = r1 - Math.abs(i);
                rsum += sir[0] * rbs;
                gsum += sir[1] * rbs;
                bsum += sir[2] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];

                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];

                }

            }
            stackpointer = radius;
            for (x = 0; x < w; x++) {
                r[yi] = dv[rsum];
                g[yi] = dv[gsum];
                b[yi] = dv[bsum];
                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;
                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];
                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];
                if (y == 0) {
                    vmin[x] = Math.min(x + radius + 1, wm);

                }
                p = pix[yw + vmin[x]];
                sir[0] = (p & 0xff0000) >> 16;
                sir[1] = (p & 0x00ff00) >> 8;
                sir[2] = (p & 0x0000ff);
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;
                stackpointer = (stackpointer + 1) % div;
                sir = stack[(stackpointer) % div];
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];
                yi++;

            }
            yw += w;

        }
        for (x = 0; x < w; x++) {
            rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
            yp = -radius * w;
            for (i = -radius; i <= radius; i++) {
                yi = Math.max(0, yp) + x;
                sir = stack[i + radius];
                sir[0] = r[yi];
                sir[1] = g[yi];
                sir[2] = b[yi];
                rbs = r1 - Math.abs(i);
                rsum += r[yi] * rbs;
                gsum += g[yi] * rbs;
                bsum += b[yi] * rbs;
                if (i > 0) {
                    rinsum += sir[0];
                    ginsum += sir[1];
                    binsum += sir[2];

                } else {
                    routsum += sir[0];
                    goutsum += sir[1];
                    boutsum += sir[2];

                }
                if (i < hm) {
                    yp += w;
                }
            }
            yi = x;
            stackpointer = radius;
            for (y = 0; y < h; y++) {
                pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
                        | (dv[gsum] << 8) | dv[bsum];
                rsum -= routsum;
                gsum -= goutsum;
                bsum -= boutsum;
                stackstart = stackpointer - radius + div;
                sir = stack[stackstart % div];
                routsum -= sir[0];
                goutsum -= sir[1];
                boutsum -= sir[2];
                if (x == 0) {
                    vmin[y] = Math.min(y + r1, hm) * w;

                }
                p = x + vmin[y];
                sir[0] = r[p];
                sir[1] = g[p];
                sir[2] = b[p];
                rinsum += sir[0];
                ginsum += sir[1];
                binsum += sir[2];
                rsum += rinsum;
                gsum += ginsum;
                bsum += binsum;
                stackpointer = (stackpointer + 1) % div;
                sir = stack[stackpointer];
                routsum += sir[0];
                goutsum += sir[1];
                boutsum += sir[2];
                rinsum -= sir[0];
                ginsum -= sir[1];
                binsum -= sir[2];
                yi += w;

            }

        }
        bitmap.setPixels(pix, 0, w, 0, 0, w, h);
        return (bitmap);
    }

    /**
     * 通过一个网络的路径加载一张图片
     * 
     * @param path
     */
    public static void loadBitmap(Context context, final String path,
            final int width, final int height, final BitmapCallback callback) {
        if(path == null || path.equals("")){
            callback.onBitmapLoaded(null);
            return;
        }
        // 先去文件中找找 看看有没有下载过
        String filename = path.substring(path.lastIndexOf("/") + 1);
        final File file = new File(context.getCacheDir(), filename);
        Bitmap bitmap = loadBitmap(file.getAbsolutePath());
        if (bitmap != null) {
            callback.onBitmapLoaded(bitmap);
            return;
        }
        // 文件中没有图片 则去下载
        new AsyncTask<String, String, Bitmap>() {
            protected Bitmap doInBackground(String... params) {
                try {
                    InputStream is = HttpUtils.get(path);
                    Bitmap b = null;
                    if (width == 0 && height == 0) {
                        b = BitmapFactory.decodeStream(is);
                    } else {
                        b = loadBitmap(is, width, height);
                    }
                    // 图片一旦下载成功 需要存入文件
                    save(b, file.getAbsolutePath());
                    return b;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }

            protected void onPostExecute(Bitmap bitmap) {
                callback.onBitmapLoaded(bitmap);
            }
        }.execute();
    }

    /**
     * 从某个路径下读取一个bitmap
     * 
     * @param path
     * @return
     */
    public static Bitmap loadBitmap(String path) {
        File file = new File(path);
        if (!file.exists()) {
            return null;
        }
        return BitmapFactory.decodeFile(path);
    }

    /**
     * 保存图片
     * 
     * @param bitmap
     * @param path
     *            图片的目标路径
     */
    public static void save(Bitmap bitmap, String path) throws IOException {
        File file = new File(path);
        if (!file.getParentFile().exists()) { // 父目录不存在
            file.getParentFile().mkdirs(); // 创建父目录
        }
        FileOutputStream os = new FileOutputStream(file);
        bitmap.compress(CompressFormat.JPEG, 100, os);
    }

    /**
     * @param is
     *            数据源
     * @param width
     *            图片的目标宽度
     * @param height
     *            图片的目标高度
     * @return 压缩过后的图片
     */
    public static Bitmap loadBitmap(InputStream is, int width, int height)
            throws IOException {
        // 通过is 读取 到一个 byte[]
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int length = 0;
        while ((length = is.read(buffer)) != -1) {
            bos.write(buffer, 0, length);
            bos.flush();
        }
        byte[] bytes = bos.toByteArray();
        // 使用BitmapFactory获取图片的原始宽和高
        Options opts = new Options();
        // 仅仅加载图片的边界属性
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
        // 通过目标宽和高计算图片的压缩比例
        int w = opts.outWidth / width;
        int h = opts.outHeight / height;
        int scale = w > h ? h : w;
        // 给Options属性设置压缩比例
        opts.inJustDecodeBounds = false;
        opts.inSampleSize = scale;
        // 重新解析byte[] 获取Bitmap
        return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
    }

    public interface BitmapCallback {
        void onBitmapLoaded(Bitmap bitmap);
    }

}
package cn.tedu.music_player_v4.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.tedu.music_player_v4.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import android.widget.ListView;

/**
 * 图片异步批量加载的工具类
 * 自动完成 单线程下载图片
 * 内存缓存   文件缓存
 * @author pjy
 *
 */
public class ImageLoader {
    //声明用于实现内存缓存的map
    private Map<String, SoftReference<Bitmap>> cache = new HashMap<String, SoftReference<Bitmap>>();
    private Context context;
    //声明图片下载任务集合
    private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
    //声明用于轮循任务队列的工作线程
    private Thread workThread;
    private boolean isLoop=true;
    private ListView listView;
    // 声明handler 显示图片
    private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case HANDLER_LOAD_IMAGE_SUCCESS: // 图片下载成功
                ImageLoadTask task = (ImageLoadTask) msg.obj;
                Bitmap bitmap = task.bitmap;
                // 通过listView.findViewWithTag()方法获取相应的imageView
                ImageView imageView = (ImageView) listView
                        .findViewWithTag(task.path);
                if (imageView != null) {
                    if (bitmap != null) {
                        imageView.setImageBitmap(bitmap);
                    } else {
                        imageView.setImageResource(R.drawable.ic_launcher);
                    }
                }
                break;
            }
        }
    };

    public static final int HANDLER_LOAD_IMAGE_SUCCESS = 1;


    public ImageLoader(Context context, ListView listView) {
        this.context = context;
        this.listView = listView;
        //初始化并且启动workThread
        workThread = new Thread(){
            public void run() {
                //不断轮循任务集合  一旦有任务  则获取然后执行下载操作
                while(isLoop){
                    if(!tasks.isEmpty()){ //有任务
                        ImageLoadTask task=tasks.remove(0);
                        String path = task.path;
                        //下载图片
                        Bitmap bitmap = loadBitmap(path);
                        task.bitmap = bitmap;
                        //给imageView 设置 Bitmap
                        Message msg = new Message();
                        msg.what = HANDLER_LOAD_IMAGE_SUCCESS;
                        msg.obj = task;
                        handler.sendMessage(msg);

                    }else{ //没有任务  工作线程等待
                        try {
                            synchronized (workThread) {
                                workThread.wait();
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        };
        workThread.start();
    }

    /**
     * 通过path 下载图片
     * 
     * @param path
     * @return
     */
    public Bitmap loadBitmap(String path) {
        try {
            InputStream is = HttpUtils.get(path);
            Bitmap b = BitmapUtils.loadBitmap(is, 50, 50);
            // 下载成功 把b存入内存缓存中
            cache.put(path, new SoftReference<Bitmap>(b));
            // 存入文件缓存目录中
            String filename = path.substring(path.lastIndexOf("/") + 1);
            // f --> /data/data/cn.tedu.music/cache/xxxxx.jpg
            File f = new File(context.getCacheDir(), filename);
            BitmapUtils.save(b, f.getAbsolutePath());
            return b;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 通过path 下载图片 并且把图片显示在相应的ImageView中
     * @param imageView
     * @param path
     */
    public void displayImage(ImageView imageView, String imagePath){

        //设置图片  从缓存中读取图片 
        SoftReference<Bitmap> ref=cache.get(imagePath);
        if(ref!=null){
            Bitmap bitmap=ref.get();
            if(bitmap!=null){ //图片还没有被销毁
                imageView.setImageBitmap(bitmap);
                return;
            }
        }
        //内存缓存中没有图片  则去文件缓存中读取
        String filename = imagePath.substring(imagePath.lastIndexOf("/")+1);
        File f = new File(context.getCacheDir(), filename);
        Bitmap bitmap=BitmapUtils.loadBitmap(f.getAbsolutePath());
        if(bitmap!=null){
            imageView.setImageBitmap(bitmap);
            //向内存缓存中再存一次
            cache.put(imagePath, new SoftReference<Bitmap>(bitmap));
            return;
        }
        // 向任务集合中添加一个图片下载任务
        //给imageView设置一个tag值  用于handler中通过tag值找到imageView
        imageView.setTag(imagePath);
        ImageLoadTask task = new ImageLoadTask();
        task.path = imagePath;
        tasks.add(task);
        //唤醒工作线程  赶紧起来干活
        synchronized (workThread) {
            workThread.notify();
        }
    }

    /**
     * 封装一个图片下载任务
     */
    class ImageLoadTask {
        String path;   //图片路径
        Bitmap bitmap;  //通过路径下载成功的bitmap
    }

    /**
     * 停止线程
     */
    public void stopThread() {
        isLoop = false;
        synchronized (workThread) {
            // 唤醒工作线程
            workThread.notify();
        }
    }

}








以上是关于图片处理的一些方法的主要内容,如果未能解决你的问题,请参考以下文章

是否有在单个活动中处理多个片段的 Android 设计模式?

处理屏幕旋转上的片段重复(带有示例代码)

在 Python 多处理进程中运行较慢的 OpenCV 代码片段

简单的方法来分享/讨论/协作的代码片段?

根据图片的url地址下载图片到本地保存代码片段

图片处理的一些方法