• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >Android > Android开发技巧——大图裁剪

Android开发技巧——大图裁剪

作者:网友 字体:[增加 减小] 来源:互联网 时间:2017-05-26

网友通过本文主要向大家介绍了android开发技巧,android开发小技巧,android开发,android开发环境搭建,android开发工具等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Android开发技巧——大图裁剪


本篇内容是接上篇《Android开发技巧——定制仿微信图片裁剪控件》 的,先简单介绍对上篇所封装的裁剪控件的使用,再详细说明如何使用它进行大图裁剪,包括对旋转图片的裁剪。

裁剪控件的简单使用

XML代码

使用如普通控件一样,首先在布局文件里包含该控件:

 

支持的属性如下:

civHeight 高度比例,默认为1 civWidth 宽度比例,默认为1 civTipText 裁剪的提示文字 civTipTextSize 裁剪的提示文字的大小 civMaskColor 遮罩层颜色 civClipPadding 裁剪框边距

Java代码

如果裁剪的图片不大,可以直接设置,就像使用ImageView一样,通过如下四种方法设置图片:

mClipImageView.setImageURI(Uri.fromFile(new File(mInput)));
mClipImageView.setImageBitmap(bitmap);
mClipImageView.setImageResource(R.drawable.xxxx);
mClipImageView.setImageDrawable(drawable);

裁剪的时候调用mClipImageView.clip();就可以返回裁剪之后的Bitmap对象。

大图裁剪

这里会把大图裁剪及图片文件可能旋转的情况一起处理。
注意:由于裁剪图片最终还是需要把裁剪结果以Bitmap对象加载到内存中,所以裁剪之后的图片也是会有大小限制的,否则会有OOM的情况。所以,下面会设一个裁剪后的最大宽度的值。

读取图片旋转角度

在第一篇《 Android开发技巧——Camera拍照功能 》的时候,有提到过像三星的手机,竖屏拍出来的照片还是横的,但是有Exif信息记录了它的旋转方向。考虑到我们进行裁剪的时候,也会遇到类似这样的照片,所以对于这种照片需要旋转的情况,我选择了在裁剪的时候才进行处理。所以首先,我们需要读到图片的旋转角度:

    /**
     * 读取图片属性:旋转的角度
     *
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

如果你能确保要裁剪的图片不大不会导致OOM的情况发生的话,是可以直接通过这个角度,创建一个Matrix对象,进行postRotate,然后由原图创建一个新的Bitmap来得到一个正确朝向的图片的。但是这里考虑到我们要裁剪的图片是从手机里读取的,有可能有大图,而我们的裁剪控件本身只实现了简单的手势缩放和裁剪功能,并没有实现大图加载的功能,所以需要在设置图片进行之前进行一些预处理。

采样缩放

由于图片较大,而我们又需要把整张图都加载进来而不是只加载局部,所以就需要在加载的时候进行采样,来加载缩小之后的图片,这样加载到的图片较小,就能有效避免OOM了。
以前文提到的裁剪证件照为例,这里仍以宽度为参考值来计算采样值,具体是用宽还是高或者是综合宽高(这种情况较多,考虑到可能会有很长的图)来计算采样值,还得看你具体情况。在计算采样的时候,我们还需要用到上面读到的旋转值,在图片被旋转90度或180度时,进行宽和高的置换。所以,除了相关的控件,我们需要定义如下相关的变量:

    private String mOutput;
    private String mInput;
    private int mMaxWidth;

    // 图片被旋转的角度
    private int mDegree;
    // 大图被设置之前的采样比例
    private int mSampleSize;
    private int mSourceWidth;
    private int mSourceHeight;

计算采样代码如下:

mClipImageView.post(new Runnable() {
    @Override
    public void run() {
        mClipImageView.setMaxOutputWidth(mMaxWidth);

        mDegree = readPictureDegree(mInput);

        final boolean isRotate = (mDegree == 90 || mDegree == 270);

        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mInput, options);

        mSourceWidth = options.outWidth;
        mSourceHeight = options.outHeight;

        // 如果图片被旋转,则宽高度置换
        int w = isRotate ? options.outHeight : options.outWidth;

        // 裁剪是宽高比例3:2,只考虑宽度情况,这里按border宽度的两倍来计算缩放。
        mSampleSize = findBestSample(w, mClipImageView.getClipBorder().width());
        //代码未完,将下面的[缩放及设置]里分段讲到。
    }
});

由于我们是需要裁剪控件的裁剪框来计算采样,所以需要获取裁剪框,因此我们把上面的代码通过控件的post方法来调用。
inJustDecodeBounds在许多讲大图缩放的博客都有讲到,相信很多朋友都清楚,本文就不赘述了。
注意:采样的值是2的幂次方的,如果你传的值不是2的幂次方,它在计算的时候最终会往下找到最近的2的幂次方的值。所以,如果你后面还需要用这个值来进行计算,就不要使用网上的一些直接用两个值相除进行计算sampleSize的方法。精确的计算方式应该是直接计算时这个2的幂次方的值,例如下面代码:

    /**
     * 计算最好的采样大小。
     * @param origin 当前宽度
     * @param target 限定宽度
     * @return sampleSize
     */
    private static int findBestSample(int origin, int target) {
        int sample = 1;
        for (int out = origin / 2; out > target; out /= 2) {
            sample *= 2;
        }
        return sample;
    }

缩放及设置

接下来就是设置inJustDecodeBounds,inSampleSize,以及把inPreferredConfig设置为RGB_565,然后把图片给加载进来,如下:

        options.inJustDecodeBounds = false;
        options.inSampleSize = mSampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        final Bitmap source = BitmapFactory.decodeFile(mInput, options);

这里加载的图片还是没有旋转到正确朝向的,所以我们要根据上面所计算的角度,对图片进行旋转。我们竖屏拍的图,在一些手机上是横着保存的,但是它会记录一个旋转90度的值在Exif中。如下图中,左边是保存的图,它依然是横着的,右边是我们显示时的图。所以我们读取到这个值后,需要对它进行顺时针的旋转。
这里写图片描述
代码如下:

        // 解决图片被旋转的问题
        Bitmap target;
        if (mDegree == 0) {
            target = source;
        } else {
            final Matrix matrix = new Matrix();
            matrix.postRotate(mDegree);
            target = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, false);
            if (target != source && !source.isRecycled()) {
                source.recycle();
            }
        }
        mClipImageView.setImageBitmap(target);

这里需要补充的一个注意点是:Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, false);这个方法返回的Bitmap不一定是重新创建的,如果matrix相同并且宽高相同,而且你没有对Bitmap进行其他设置的话,它可能会返回原来的对象。所以在创建新的Bitmap之后,

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • android 编程小技巧(持续中)
  • Android开发技巧——大图裁剪
  • Android开发技巧——定制仿微信图片裁剪控件
  • Android开发技巧之Camera拍照功能

相关文章

  • 2017-05-26Android Studio 1.5.1 JNI 编程
  • 2017-05-26从源码的角度理解四大组件的工作过程——Android开发艺术探索笔记
  • 2017-05-26android基础部分再学习---再谈Service进程服务通信
  • 2017-05-26通知 listview刷新!一天没搞出来的血泪史,listview血泪史
  • 2017-05-26Androidstudio中导入内部依赖模块总结,androidstudio模块
  • 2017-05-26Android Studio上面使用Ndk JNI 开发工程
  • 2017-05-26MVP解析,mvp模式解析实践
  • 2017-05-26android 动画详解(二)
  • 2017-05-26Android之HTTP网络通信--GET传递,android--get
  • 2017-05-26Linux内核系列—12.b.操作系统开发之从Loader跳入保护模式,12.bloader

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • Android最佳实践之SystemBar状态栏全版本适配方案
    • Android安全专项-Apk加固浅析
    • 编译android源码4---ubuntu下载Android源代码
    • Android Gson使用入门及GsonFormat插件的使用
    • Android之ViewPager 第一课,androidviewpager
    • 订单流程view,订单view
    • 如何编写高效的android代码
    • .5.9 AlertDialog(对话框)详解
    • ActionBar设置自定义setCustomView()留有空白的问题,setcustomview空白
    • Linux内核系列—操作系统开发之进入32位保护模式,linux保护模式

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有