Android中的图片裁剪(三)之自定义裁剪工具

在上一篇文章中Android中的图片裁剪(二)之开源项目介绍了一些优秀的图片裁剪开源项目,在我们实现自己的裁剪功能的时候,也可以看下这些开源项目的源码,看看大牛们都是怎么实现的。

createBitmap方法

首先要做图片裁剪的功能,要先认识Bitmap,在这个类里面,有几个方法可以帮助我们实现功能。就比如下面这一个方法

/**
 * Returns an immutable bitmap from the specified subset of the source
 * bitmap. The new bitmap may be the same object as source, or a copy may
 * have been made. It is initialized with the same density as the original
 * bitmap.
 *...
 */
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)

好吧,方法注解太长,被我省略掉一些了,但是用起来其实挺简单的,只要传入指定的范围,它就能生成一个新的位图给你。(这里先说一句,图片的裁剪功能其实做起来不难,要做好就挺麻烦的,在实际的工具开发中免不了要自定义View这样的工作),而这边的范围一般是一个可拖动的方框,点击裁剪按钮的时候生成我们需要的图片。当然createBitmap方法还有很多其他重载实现,这里就不一一贴出来了。在具体实现的时候我们可以自定义两个View

public class CropImageView extends ImageView {

    HighlightView hv;
    //...
 
}

class HighlightView {
    //...
}

这里只是简单的提供一下思路,HighlightView用来表示裁剪框对象,封装裁剪框的一些信息啊,比如宽高和触摸状态什么的。CropImageView继承ImageView用来显示图片和处理触摸事件,在触摸事件中改变HighlightView的状态:

public boolean onTouchEvent(@NonNull MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
            //对触摸点进行一些逻辑判断,比如摸到裁剪框的边还是其他什么的
            int edge = hv.getHit(event.getX(), event.getY());
            //...
            //然后根据逻辑判断结果设置裁剪框的状态
            hv.setMode((edge == HighlightView.MOVE)
                        ? HighlightView.ModifyMode.Move
                        : HighlightView.ModifyMode.Grow);
            //...
        break;
            //...

啦啦啦,是不是说了跟没说一样,主要是具体实现起来真的挺麻烦的,贴那么多代码出来也没啥用,我自己都要看晕了,总归自己造轮子还是挺辛苦的,而且刚造出来也肯定有一些问题的,所以才有那句名言么,不要重复造轮子,我觉得只要看懂源代码的思路,然后根据需求,在别人的轮子上进行改造,这样就快的多啦。

Matrix的基本使用

一般呢,在裁剪的工具中,在对图片裁剪前,多可以对图片进行一些缩放,平移,旋转之类的操作,这些效果都是可以通过Matrix来实现的,那这个类怎么用呢。我们先看一下[官方文档中Matrix](file:///D:/Android/sdk/docs/reference/android/graphics/Matrix.html)的介绍(自带梯子) ,首先看一下它的官方定义:

**The Matrix class holds a 3x3 matrix for transforming coordinates. **

直译过来呢,就是一个转换坐标的3x3矩阵,你妹啊,什么是3x3矩阵...我也不知道啊 ,高等数学这东西我早就扔了好么,不过不知道没关系,面向对象么,我先知道怎么用就可以了,有时间有闲情再去深究。我们先主要看一下Matrix类里面,我们要用到的一些方法(补充说一下,这Matrix类是在graphics包下的,不要导成opengl包下的):

/**
 * Postconcats the matrix with the specified translation.
 * M' = T(dx, dy) * M
 */
public boolean postTranslate(float dx, float dy)

/**
 * Postconcats the matrix with the specified rotation.
 * M' = R(degrees) * M
 */
public boolean postRotate(float degrees)

好啦,毕竟是文档找的到东西,我这里就只贴两个方法出来,看注解应该很容易理解方法的使用,第一个方法就是对矩阵进行左乘T(dx, dy),第二个方法就是对矩阵左乘R(degrees),通过源码我们可以看到,方法里面通过jni调用lib层用c,c++实现运算转换的。反正直白点讲,在对它进行图片变换的时候,第一个方法就是平移图片,第二个方法就是旋转图片,啦啦啦,其他方法大家可以自行查找文档,问题都不大。

图片的平移,缩放,旋转

通过重写View或者Activity的onTouch事件来进行图片的平移,缩放和旋转会比较方便,这里我们要先做一些初始化工作,比如获取图片之类的,一般我们将图片的大小控制在手机内存的1/8,防止OOM和卡顿,然后就是在onTouch事件里做具体实现:

public boolean onTouch(View v, MotionEvent event)
{

    switch (event.getAction() & MotionEvent.ACTION_MASK)
    {
        // 主点按下
        case MotionEvent.ACTION_DOWN:
            cachMatrix.set(matrix);//用来变化的矩阵
            prev.set(event.getX(), event.getY());
            mode = DRAG;
            break;
        //...
        case MotionEvent.ACTION_MOVE:
            if (mode == DRAG)//拖动
            {
                matrix.set(cachMatrix);
                matrix.postTranslate(event.getX() - prev.x, event.getY() - prev.y);
            }
            else if (mode == ZOOM)//缩放
            {
                float newDist = spacing(event);
                if (newDist > 10f)
                {
                    matrix.set(cachMatrix);
                    float tScale = newDist / dist;
                    matrix.postScale(tScale, tScale, mid.x, mid.y);
                }
            }
            break;
    }
    imgView.setImageMatrix(matrix);
    //...
    return true;
}

代码就放了部分上去,主要说明一下思路,当然在将这些功能和裁剪进行合并的时候,是要对裁剪框的位置再进行计算的,比如因为对图片缩放了,所以再返回剪裁框大小的时候是要乘上缩放值的。

public Rect getScaledCropRect(float scale) {
    return new Rect((int) (cropRect.left * scale), (int) (cropRect.top * scale),
            (int) (cropRect.right * scale), (int) (cropRect.bottom * scale));
}

总结

图片的裁剪就先写到这里,主要介绍了一些关键方法和整体的实现思路,后面有时间的话,我会把代码整理后发布到github上去的,到时候再来补链接。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容