创造一款安卓自定义控件_裁剪原理介绍

1、新增功能,旋转:

效果如图,点击旋转,可以将控件画面本身进行90度倍数的旋转,并进行宽高比例适配,旋转之后裁剪依然正常。

 

 

 

功能实现原理:

1、通过调用view的setRotation功能进行以View为中心的旋转

2、在旋转后,由于view的宽高反过来了,因此还需要根据当前宽高进行缩放。即如果旋转的角度为90度的倍数时,因为控件和图片的宽和高的对应关系相反,因此需要要么以(图片高/控件宽),要么以(图片宽/控件高)进行缩放,使得图片按比例缩放到和控件对齐。

具体实现代码:

/**设置旋转量**/
public void rotate(int rotate) throws Exception {
    if (rotate % 90 != 0) {
        throw new Exception("不允许使用非90度倍率的旋转角度");
    }
    setRotation(rotate); //整个控件进行旋转
    if (null == mBitmap) {
        return;
    }
    float ratioW = (float) mBitmap.getHeight() / mWidth;
    float ratioH = (float) mBitmap.getWidth() / mHeight;
    float scale = 1f;
    if (ratioW < ratioH) {
        scale = 1f / ratioW;
    } else {
        scale = 1f / ratioH;
    }
    if (getRotation() % 180 == 0) {
        setScaleX(1f);
        setScaleY(1f);
    } else {
        setScaleX(scale);
        setScaleY(scale);
    }
    invalidate();
}

2、裁剪功能:

之前由于裁剪功能没有实现完善,最近因为有需求,顺便实现好了。

1、获取选框的外接矩形区域,方法为统计4个点中x的最大最小值和y的最大最小值。最小的x,y为左上角,最大的x,y为右下角。

2、然后因为图像需要在控件canvas中居中,因此选择点的坐标其实包含了左右或者上下的黑边,因此需要先进行去除,即去除offsetX, offsetY部分。

3、反向使用当前的所放量获得缩放框实际在原图上应该有的大小,以该大小创建画布。

4、使用rect的left、top值反向移动裁剪框,使得图片在canvas上相对有left、top值的移动。

5、裁剪框去掉在view上才有意义的left和top值,因为新画布本身并没有黑边。

6、反向缩放裁剪框,理由和3一样。设置为画布裁剪区域

7、bmp反向移动去除黑边并按照实际原图大小的left和top值对齐画布,会进行绘制

public Bitmap cutPhoto() {
    if (null == mBitmap || mBitmap.isRecycled()) {
        Log.e(TAG, "当前没有图片");
        return null;
    }
    if (null == mVectorPoint) {
        Log.e(TAG, "当前没有初始化选择点");
        return null;
    }
    if (null == mCutterClipPath) {
        Log.e(TAG, "当前没有用户裁剪path");
        return null;
    }
    //算出裁剪框的裁剪范围的外接矩形:
    float offsetX = ((mWidth - mBitmap.getWidth() * mScale) / 2f); //去除计算中纳入的控件黑边,以防图像在控件缩放后两边有黑边时,导致裁剪时把偏移量多算了控件上的黑边范围导致严重误差
    float offsetY = ((mHeight - mBitmap.getHeight() * mScale) / 2f); //去除计算中纳入的控件黑边,以防图像在控件缩放后两边有黑边时,导致裁剪时把偏移量多算了控件上的黑边范围导致严重误差

    float left = Math.min(mVectorPoint[0].x, mVectorPoint[3].x);
    float top = Math.min(mVectorPoint[0].y, mVectorPoint[1].y);
    float right = Math.max(mVectorPoint[1].x, mVectorPoint[2].x);
    float bottom = Math.max(mVectorPoint[2].y, mVectorPoint[3].y);
    Rect rect = new Rect((int) left, (int) top, (int) right, (int) bottom);
    Bitmap bitmap = Bitmap.createBitmap((int) ((float) rect.width() * (1f / mScale)), (int) ((float) rect.height() * (1f / mScale)), Bitmap.Config.ARGB_8888);  //大小不定, 只看外接矩形的大小
    Canvas canvas = new Canvas(bitmap);
    canvas.drawColor(Color.TRANSPARENT);

    //将裁剪范围应用于画布
    Path cutterPathClone = new Path(mCutterClipPath);
    Matrix pathMatrix = new Matrix();
    pathMatrix.postTranslate(-rect.left, -rect.top); //因为left和top是应用于view的canvas之上的,还要转换为当前bmp画布的坐标,抹去view的canvas留下的间隙偏移量
    pathMatrix.postScale(1f / mScale, 1f / mScale);
    cutterPathClone.transform(pathMatrix);
    canvas.clipPath(cutterPathClone);
    //canvas.drawColor(Color.RED); //for debug

    Matrix bmpMatrix = new Matrix(); //没啥bug了
    bmpMatrix.setTranslate(-(rect.left - offsetX) / mScale, -(rect.top - offsetY) / mScale);
    canvas.drawBitmap(mBitmap, bmpMatrix, null);

    return bitmap;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android自定义相机是一种使用相机API来定制自己的相机界面或开发特殊相机功能的方法。它适用于需要对照片进行裁剪、滤镜处理、添加贴纸、表情、地点标签等操作的场景。相比直接通过Intent调用系统相机组件,自定义相机能够提供更多的灵活性和可定制性。在使用自定义相机之前,需要进行系统权限配置,包括相机权限、文件读写权限以及相机自动对焦配置。同时,应该检查设备是否具备相机功能,以避免在没有相机的设备上使用相关功能。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Androd自定义控件(五)打造自己的Camera](https://blog.csdn.net/sdkfjksf/article/details/51137408)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Android自定义相机—Camera篇](https://blog.csdn.net/m0_56146626/article/details/128595800)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值