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

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 debugMatrix bmpMatrix = new Matrix(); //没啥bug了bmpMatrix.setTranslate(-(rect.left - offsetX) / mScale, -(rect.top - offsetY) / mScale);canvas.drawBitmap(mBitmap, bmpMatrix, null);return bitmap;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/17683.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker 中的 .NET 异常了怎么抓 Dump (转载)

一、背景 1. 讲故事 有很多朋友跟我说&#xff0c;在 Windows 上看过你文章知道了怎么抓 Crash, CPU爆高&#xff0c;内存暴涨 等各种Dump&#xff0c;为什么你没有写在 Docker 中如何抓的相关文章呢&#xff1f;瞧不上吗&#xff1f; 哈哈&#xff0c;在DUMP的分析旅程中&a…

[MySQL]MySQL库的操作

[MySQL]MySQL库的操作 文章目录 [MySQL]MySQL库的操作1. 创建数据库2. 字符集和校验规则2.1. 基本概念2.2. 查看系统默认字符集以及校验规则2.3. 查看数据库支持的字符集2.4 查看数据库支持的校验规则2.5 指明字符集和校验规则创建数据库2.6 校验规则对数据库的影响 3. 删除数据…

我爱学QT-制作一个最简单的QT界面

1.qt基础 qt的移植性非常强&#xff0c;一套代码不用我们改太多&#xff0c;直接通用所有平台。不久的将来&#xff0c;qt会被用到MCU上&#xff0c;学习QT还是非常有意义的。 2.做一个简单的QT界面 首先新建工程 注意这个不一样 工程文件分析&#xff1a; #--------------…

【优选算法】—— 双指针问题

从今天开始&#xff0c;整个暑假期间。我将不定期给大家带来有关各种算法的题目&#xff0c;帮助大家攻克面试过程中可能会遇到的算法这一道难关。 目录 &#xff08;一&#xff09; 基本概念 &#xff08;二&#xff09;题目讲解 1、难度&#xff1a;easy 1️⃣移动零 2️…

nginx的优化

目录 一 隐藏版本号在网页上面有nginx的版本号会让别人攻击你的服务器 二 nginx的优化之日志分割 三 nginx的优化之页面压缩 四 连接超时 五 nginx的并发设置 七总结:nginx的优化 一 隐藏版本号在网页上面有nginx的版本号会让别人攻击你的服务器 如图所示 第一种方法是关…

数据结构与算法——数据结构有哪些,常用数据结构详解

数据结构是学习数据存储方式的一门学科&#xff0c;那么&#xff0c;数据存储方式有哪几种呢&#xff1f;下面将对数据结构的学习内容做一个简要的总结。 数据结构大致包含以下几种存储结构&#xff1a; 线性表&#xff0c;还可细分为顺序表、链表、栈和队列&#xff1b;树结…

C# 依赖倒置原则(DIP)

目录 一&#xff0c;引子 1.1 传统的程序架构 1.2 依赖倒置 1.3 依赖倒置的作用 二&#xff0c;依赖注入 一&#xff0c;引子 1.1 传统的程序架构 在程序执行过程中&#xff0c;传统的程序架构如图&#xff1a; 可以看到&#xff0c;在传统的三层架构中&#xff0c;层与…

CRC Principle and Implementation Method(Java C)

CRC原理和程序实现方法1_哔哩哔哩_bilibili 其实原理很简单 但是我想了两个小时。。 收获的是原来一些复杂的运算都可以通过位运算来实现。 实现思路 public class CRC16Calculator {public static String CRC16(byte[] bytes) {int CRC 0x0000ffff;int POLYNOMIAL 0x0000a…

sklearn.preprocessing模块介绍

数据预处理 Binarizer: 二值化 用于将数值特征二值化。它将特征值与给定的阈值进行比较&#xff0c;并将特征值转换为布尔值&#xff08;0 或 1&#xff09;&#xff0c;取决于特征值是否超过阈值 Binarizer(*, threshold0.0, copyTrue)参数&#xff1a; threshold&#xf…

day1-二分查找

二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值存在返回下标&#xff0c;否则返回 -1。 示例 1: 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 解…

Redis实战案例14-分布式锁的基本原理、不同实现方法对比以及基于Redis进行实现思路

1. 分布式锁基本原理 基于数据库的分布式锁&#xff1a;这种方式使用数据库的特性来实现分布式锁。具体流程如下&#xff1a; 获取锁&#xff1a;当一个节点需要获得锁时&#xff0c;它尝试在数据库中插入一个特定的唯一键值&#xff08;如唯一约束的主键&#xff09;&#xff…

优化chatGPT提示词的Prompts

你扮演一个专业的chatGPT提示词工程师&#xff0c;我将为您提供我的提示词&#xff0c;它用三个反引号分隔&#xff0c;请根据openai发布的提示词标准和优化技巧&#xff0c;改进和优化我的提示词&#xff0c;让chatGPT能够更好的理解。 我的第一个提示词是&#xff1a;“”“……