博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 图片相关整理
阅读量:6422 次
发布时间:2019-06-23

本文共 12169 字,大约阅读时间需要 40 分钟。

hot3.png

目录介绍

  • 0.思考问题及解决方案
  • 1.加载图片的压缩处理技术
  • 2.网络url图片转换Bitmap保存到本地
    • 2.1 直接通过http请求网络图片通过流转化成Bitmap
    • 2.2 使用第三方库glide将网络图片转化为Bitmap
  • 3.保存bitmap图片到本地文件夹
  • 4.实现带有圆角的图片
    • 4.1 使用glide处理图片圆角的逻辑
    • 4.2 自定义带有圆角的ImageView
  • 5.毫无满仓轮播图背景做高斯模糊
    • 5.1 高斯模糊实现原理
    • 5.2 高斯模糊实现的代码
    • 5.3 高斯模糊可能会造成的崩溃
    • 5.4 高斯模糊参考案例

关于链接

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 5.

0.思考问题及解决方案

  • 0.1.0 图片压缩的技术是什么,原理如何理解?
  • 0.1.1 为什么保存图片,切割图片圆角需要将图片转化成bitmap?
  • 0.1.2 对于从网络下载图片,可以采用什么方式?为什么glide相比从网络直接请求更加高效?
  • 0.1.3 图片背景滑动高斯模糊的原理是什么,是否影响性能?
  • 0.1.4 bitmap如何避免被回收?如果回收了,怎么避免出现使用bitmap崩溃
  • 0.1.5 为什么设置高斯模糊需要放在子线程中处理,不这样做会有什么影响?

1.加载图片的压缩处理技术

1.1 压缩技术步骤

  • 1.1.1 科学计算图片所需的采样比例
  • 1.1.2 设置图片加载的渲染模式为Config.RGB_565,能降低一半内存
  • 1.1.3 对bitmap进行质量压缩

1.2 代码如下所示

/** * 根据路径获得突破并压缩返回bitmap用于显示 * @return          Bitmap */public static Bitmap getSmallBitmap(String filePath, int newWidth, int newHeight) {    final BitmapFactory.Options options = new BitmapFactory.Options();    //设置只解析图片的边界参数,即宽高    options.inJustDecodeBounds = true;    //options.inSampleSize = 2;    BitmapFactory.decodeFile(filePath, options);    // Calculate inSampleSize    //科学计算图片所需的采样比例    options.inSampleSize = calculateInSampleSize(options, newWidth, newHeight);    //设置图片加载的渲染模式为Config.RGB_565,能降低一半内存,但是会影响图片质量    options.inPreferredConfig = Bitmap.Config.RGB_565;    // Decode bitmap with inSampleSize set    //关闭标记,解析真实的图片    options.inJustDecodeBounds = false;    Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);    //质量压缩    Bitmap newBitmap = compressImage(bitmap, 500);    if (bitmap != null){        bitmap.recycle();    }    return newBitmap;}/** * 计算图片的缩放值 */private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {    // Raw height and width of image    final int height = options.outHeight;    final int width = options.outWidth;    int inSampleSize = 1;    if (height > reqHeight || width > reqWidth) {        // Calculate ratios of height and width to requested height and        // width        final int heightRatio = Math.round((float) height / (float) reqHeight);        final int widthRatio = Math.round((float) width / (float) reqWidth);        // Choose the smallest ratio as inSampleSize value, this will        // guarantee        // a final image with both dimensions larger than or equal to the        // requested height and width.        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;    }    return inSampleSize;}/** * 质量压缩 * @param image * @param maxSize */private static Bitmap compressImage(Bitmap image, int maxSize){    ByteArrayOutputStream os = new ByteArrayOutputStream();    // scale    int options = 80;    // Store the bitmap into output stream(no compress)    image.compress(Bitmap.CompressFormat.JPEG, options, os);    // Compress by loop    while ( os.toByteArray().length / 1024 > maxSize) {        // Clean up os        os.reset();        // interval 10        options -= 10;        image.compress(Bitmap.CompressFormat.JPEG, options, os);    }    Bitmap bitmap = null;    byte[] b = os.toByteArray();    if (b.length != 0) {        bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);    }    return bitmap;}

2.网络url图片转换Bitmap保存到本地

2.1 直接通过http请求网络图片通过流转化成Bitmap

  • 2.1.1 直接通过网络请求将网络图片转化成bitmap
    • 经过测试,请求8张图片,耗时毫秒值174
    • 如果是服务器响应速度一般,耗时需要2秒【正式接口】
/** * 请求网络图片转化成bitmap * @param url                       url * @return                          将url图片转化成bitmap对象 */private static long time = 0;public static Bitmap returnBitMap(String url) {    long l1 = System.currentTimeMillis();    URL myFileUrl = null;    Bitmap bitmap = null;    HttpURLConnection conn = null;    InputStream is = null;    try {        myFileUrl = new URL(url);    } catch (MalformedURLException e) {        e.printStackTrace();    }    try {        conn = (HttpURLConnection) myFileUrl.openConnection();        conn.setConnectTimeout(10000);        conn.setReadTimeout(5000);        conn.setDoInput(true);        conn.connect();        is = conn.getInputStream();        bitmap = BitmapFactory.decodeStream(is);    } catch (IOException e) {        e.printStackTrace();    } finally {        try {            if (is != null) {                is.close();                conn.disconnect();            }        } catch (IOException e) {            e.printStackTrace();        }        long l2 = System.currentTimeMillis();        time = (l2-l1) + time;        LogUtils.e("毫秒值"+time);        //保存    }    return bitmap;}

2.2 使用第三方库glide将网络图片转化为Bitmap

/** * 请求网络图片转化成bitmap */private static long times = 0;public static void glideBitmap(Context context,String url){    final long l1 = System.currentTimeMillis();    Glide.with(context)            .load(url)            .asBitmap()            //设置缓存            .diskCacheStrategy(DiskCacheStrategy.ALL)            .into(new SimpleTarget
() { @Override public void onResourceReady(Bitmap resource, GlideAnimation
glideAnimation) { long l2 = System.currentTimeMillis(); times = (l2-l1) + times; LogUtils.e("毫秒值"+times); //请求8张图片,耗时毫秒值98 } });}

3.保存bitmap图片到本地文件夹

/** * 保存图片至自定义路径,刷新相册 */public static void saveImageToFile(Context context, Bitmap bmp) {    // 首先保存图片,这个路径可以自定义    File appDir = new File(Environment.getExternalStorageDirectory(), "yc");    // 测试由此抽象路径名表示的文件或目录是否存在    if (!appDir.exists()) {        //如果不存在,则创建由此抽象路径名命名的目录        //noinspection ResultOfMethodCallIgnored        appDir.mkdir();    }    // 然后自定义图片的文件名称    String fileName = System.currentTimeMillis() + ".jpg";    // 创建file对象    File file = new File(appDir, fileName);    try {        FileOutputStream fos = new FileOutputStream(file);        bmp.compress(Bitmap.CompressFormat.JPEG, 100, fos);        fos.flush();        fos.close();    } catch (IOException e) {        e.printStackTrace();    }    // 其次把文件插入到系统图库    try {        MediaStore.Images.Media.insertImage(context.getContentResolver(),                file.getAbsolutePath(), fileName, null);    } catch (FileNotFoundException e) {        e.printStackTrace();    }    // 最后通知图库更新    Intent intent = new Intent();    intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);    intent.setData(Uri.parse("file://" + file.getAbsoluteFile()));    context.sendBroadcast(intent);}

4.实现带有圆角的图片

4.1 使用glide处理图片圆角的逻辑

/** * 加载带有圆角的矩形图片  用glide处理 * * @param path   路径 * @param round  圆角半径 * @param resId  加载失败时的图片 * @param target 控件 */public static void loadImgByPicassoWithRound(final Context activity, String path,                                             final int round, int resId, final ImageView target) {    if (path != null && path.length() > 0) {        Glide.with(activity)                .load(path)                .asBitmap()                .placeholder(resId)                .error(resId)                //设置缓存                .diskCacheStrategy(DiskCacheStrategy.ALL)                .into(new BitmapImageViewTarget(target) {                    @Override                    protected void setResource(Bitmap resource) {                        super.setResource(resource);                        RoundedBitmapDrawable circularBitmapDrawable = RoundedBitmapDrawableFactory                                .create(activity.getResources(), resource);                        //设置绘制位图时要应用的角半径                        circularBitmapDrawable.setCornerRadius(round);                        target.setImageDrawable(circularBitmapDrawable);                    }                });    }}

4.2 自定义带有圆角的ImageView

  • 使用BitmapShader实现圆形、圆角图片
  • 具体看: 中的lib\image自定义imageView

5.毫无满仓轮播图背景做高斯模糊

5.1 高斯模糊实现原理

  • 前沿【摘自网络】:在Android平台上进行模糊渲染是一个相当耗CPU也相当耗时的操作,一旦处理不好,卡顿是在所难免的。考虑到效率,渲染一张图片最好的方法是使用OpenGL,其次是使用C++/C,使用Java代码是最慢的。但是Android推出RenderScript之后,我们就有了新的选择,测试表明,使用RenderScript的渲染效率和使用C/C++不相上下,但是使用RenderScript却比使用JNI简单地多!
  • 原理步骤如下所示:
    • a.压缩图片,可以质量压缩,也可以宽高压缩
    • b.创建RenderScript内核对象
    • c.创建一个模糊效果的RenderScript的工具对象
    • d.设置相关参数,具体看代码……
  • 实现思路:先将图片进行最大程度的模糊处理,再将原图放置在模糊后的图片上面,通过不断改变原图的透明度(Alpha值)来实现动态模糊效果。

5.2 高斯模糊实现的代码

  • 5.2.1 设置高斯模糊代码
/** * 设置模糊背景 */private void setBlurBackground(int pos) {    //获取轮播图索引pos处的图片    Integer integer = pagerAdapter.getBitmapHashMap().get(pos);    Resources res = this.getResources();    Bitmap bitmap= BitmapFactory.decodeResource(res, integer);    //压缩图片    final Bitmap image = BitmapUtils.compressImage(bitmap);    if (bitmap != null) {        if (mBlurRunnable != null) {            mIvBlurBackground.removeCallbacks(mBlurRunnable);        }        mBlurRunnable = new Runnable() {            @Override            public void run() {                //压缩图片,宽高缩放                Bitmap blurBitmap = BlurBitmapUtils.getBlurBitmap(                        mIvBlurBackground.getContext(), image, 15);                ViewSwitchUtils.startSwitchBackgroundAnim(mIvBlurBackground, blurBitmap);            }        };        mIvBlurBackground.postDelayed(mBlurRunnable, 100);    }}
  • 5.2.2 RenderScript图片高斯模糊
/** * RenderScript图片高斯模糊 */public class BlurBitmapUtils {    /**     * 建议模糊度(在0.0到25.0之间)     */    private static final int SCALED_WIDTH = 100;    private static final int SCALED_HEIGHT = 100;    /**     * 得到模糊后的bitmap     * @param context                   上下文     * @param bitmap                    bitmap     * @param radius                    半径     * @return     */    public static Bitmap getBlurBitmap(Context context, Bitmap bitmap, int radius) {        // 将缩小后的图片做为预渲染的图片。        Bitmap inputBitmap = Bitmap.createScaledBitmap(bitmap, SCALED_WIDTH, SCALED_HEIGHT, false);        // 创建一张渲染后的输出图片。        Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap);        // 创建RenderScript内核对象        RenderScript rs = RenderScript.create(context);        // 创建一个模糊效果的RenderScript的工具对象        ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));        // 由于RenderScript并没有使用VM来分配内存,所以需要使用Allocation类来创建和分配内存空间。        // 创建Allocation对象的时候其实内存是空的,需要使用copyTo()将数据填充进去。        Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);        Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);        // 设置渲染的模糊程度, 25f是最大模糊度        blurScript.setRadius(radius);        // 设置blurScript对象的输入内存        blurScript.setInput(tmpIn);        // 将输出数据保存到输出内存中        blurScript.forEach(tmpOut);        // 将数据填充到Allocation中        tmpOut.copyTo(outputBitmap);        return outputBitmap;    }}
  • 5.2.3 设置高斯模糊背景View动画过渡效果
/** * 图片背景切换动画帮助类,设置View动画 */public class ViewSwitchUtils {    static void startSwitchBackgroundAnim(ImageView view, Bitmap bitmap) {        Drawable oldDrawable = view.getDrawable();        Drawable oldBitmapDrawable ;        TransitionDrawable oldTransitionDrawable = null;        if (oldDrawable instanceof TransitionDrawable) {            oldTransitionDrawable = (TransitionDrawable) oldDrawable;            oldBitmapDrawable = oldTransitionDrawable.findDrawableByLayerId(oldTransitionDrawable.getId(1));        } else if (oldDrawable instanceof BitmapDrawable) {            oldBitmapDrawable = oldDrawable;        } else {            oldBitmapDrawable = new ColorDrawable(0xffc2c2c2);        }        if (oldTransitionDrawable == null) {            oldTransitionDrawable = new TransitionDrawable(new Drawable[]{oldBitmapDrawable, new BitmapDrawable(bitmap)});            oldTransitionDrawable.setId(0, 0);            oldTransitionDrawable.setId(1, 1);            oldTransitionDrawable.setCrossFadeEnabled(true);            view.setImageDrawable(oldTransitionDrawable);        } else {            oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(0), oldBitmapDrawable);            oldTransitionDrawable.setDrawableByLayerId(oldTransitionDrawable.getId(1), new BitmapDrawable(bitmap));        }        oldTransitionDrawable.startTransition(1000);    }}

5.3 高斯模糊可能会造成的崩溃

  • 5.3.1 崩溃日志
    • 开发回收bitmap引发Canvas: trying to use a recycled bitmap错误处理
  • 5.3.2 抛该异常的原因分析
    • 如果代码已经不再需要使用Bitmap对象了,就可以释放了。释放内存以后,就不能再使用该Bitmap对象了,如果再次使用,就会抛出异常。所以一定要保证不再使用的时候释放。
  • 5.3.3 解决该问题的办法
    • 使用缓存

5.4 高斯模糊参考案例

  • Android 图片高斯模糊解决方案:
关于我的博客
  • 我的个人站点:www.yczbj.org,www.ycbjie.cn
  • github:
  • 知乎:
  • 简书:
  • csdn:
  • 喜马拉雅听书:
  • 开源中国:
  • 泡在网上的日子:
  • 阿里云博客: 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:

转载于:https://my.oschina.net/zbj1618/blog/1841004

你可能感兴趣的文章
Linux Centos 查询信息
查看>>
android adb命令
查看>>
python “双”稀疏矩阵转换为最小联通量“单”矩阵
查看>>
揭秘天猫双11背后:20万商家600万张海报,背后只有一个鹿班
查看>>
重置mysq root密码脚本
查看>>
我的友情链接
查看>>
MHA配置参数
查看>>
深入理解Lock
查看>>
vim的块选择
查看>>
HTML --块
查看>>
在DLL中获取主进程窗口句柄
查看>>
基于消息队列的双向通信
查看>>
一个不错的loading效果
查看>>
Debian允许root用户登录
查看>>
linux的文件系统
查看>>
上云利器,K8S应用编排设计器之快到极致
查看>>
袋鼠云服务案例系列 | 从DB2到MySQL,某传统金融平台的互联网转型之路
查看>>
RealServer配置脚本
查看>>
九月份技术指标 华为交换机的简单配置
查看>>
python 写json格式字符串到文件
查看>>