微信小程序实现图片多点裁剪
话不多说,直接上代码
1、页面布局
<view class="buttons" style="height: 50px;"><view class="upload btn" style="background-color: #d18118;"bindtap="uploadImage"> 上传图片 </view><viewclass="getCropperImage btn"style="background-color: #04b00f;"bindtap="getCropperImage">生成图片</view>
</view>
<view class="canvas"><canvas style="width: {{canvasWidth}}px;height: {{canvasHeight}}px;"type="2d" id="canvas-1" canvas-id="canvas-1"disable-scroll="true"></canvas><canvas style="width: {{canvasWidth}}px;height: {{canvasHeight}}px;position: absolute;top: 0;z-index: 999;"type="2d" id="canvas-2" disable-scroll="true"bindtouchstart="touchStart"bindtouchmove="touchMove"bindtouchend="touchEnd"></canvas>
</view>
2、页面样式
page{padding: 0;-webkit-user-select: none;user-select: none;width: 100%;height: 100%;background-color: #c0c0c0;font-family: Arial, Helvetica, sans-serif;overflow-x: hidden;
}
.buttons{display: flex;flex-direction: row;justify-content: space-between;align-items: center;padding: 0 25rpx;border-bottom: 1rpx solid white;
}
.canvas{position: relative;
}
3、页面逻辑
let ctx = null;
let canvas = null;
Page({data: {canvasWidth:300,canvasHeight:500,pixelRatio:2,pointRadius:12,// 裁剪框边角原点半径point:[[48,48],[312, 48],[312, 224],[48, 224]],// 裁剪框边角原点位置moveIndex:-1//点击的剪切框原点小标},onLoad (options) {const that = this;wx.getSystemInfo({success (res) {that.setData({canvasWidth:res.windowWidth,canvasHeight:res.windowHeight -50,pixelRatio: res.pixelRatio,})}})},uploadImage(){const that = this;wx.chooseMedia({count: 1,mediaType: ['image','video'],sourceType: ['album', 'camera'],maxDuration: 30,camera: 'back',success(res) {that.drawImage(res.tempFiles[0].tempFilePath);}})},drawImage(src){const self = this;wx.getImageInfo({src: src,success (res) {const width = self.data.canvasWidth;const height = self.data.canvasHeight;var innerAspectRadio = res.width / res.height;//图片宽高比var customAspectRadio = width / height;//画布宽高比let x = 0;let y = 0;let baseWidth = 0;//图片在画布宽度let baseHeight = 0;//图片在画布高度if (innerAspectRadio > customAspectRadio) {baseWidth = width*0.8;baseHeight = (width / innerAspectRadio)*0.8;} else {baseWidth = height * innerAspectRadio;baseHeight = height;}x = (width-baseWidth)/2;y = (height-baseHeight)/2;// 绘制图片wx.createSelectorQuery().select('#canvas-1').fields({ node: true, size: true }).exec((res) => {// Canvas 对象const canvas = res[0].node// 渲染上下文const ctx = canvas.getContext('2d');// 初始化画布大小const dpr = self.data.pixelRatiocanvas.width = width * dprcanvas.height = height * dprctx.scale(dpr, dpr)// 开始绘制let image = canvas.createImage();//创建iamge实例image.src = src; //引入图片image.onload = function () {ctx.drawImage(image, x, y, baseWidth, baseHeight);self.setData({point:[[x-10,y-10],[x+baseWidth+10,y-10],[x+baseWidth+10,y+baseHeight+10],[x-10,y+baseHeight+10]]},()=>{self.pointInit()})}})}})},pointInit(){const that = this;const query = wx.createSelectorQuery()query.select('#canvas-2').fields({ node: true, size: true }).exec((res) => {// Canvas 对象const canvas = res[0].nodethat.canvas = canvas;// 渲染上下文const ctx = canvas.getContext('2d');that.ctx = ctx;// 初始化画布大小const dpr = that.data.pixelRatiocanvas.width = that.data.canvasWidth * dprcanvas.height = that.data.canvasHeight * dprctx.scale(dpr, dpr)// 开始绘制that.drawPoint(that.data.point)})},drawPoint(point){const ctx = this.ctx;const pointRadius = this.data.pointRadius;ctx.clearRect(0, 0, this.data.canvasWidth, this.data.canvasHeight)ctx.beginPath()ctx.fillStyle = 'rgb(0, 0, 200)';ctx.arc(point[0][0], point[0][1], pointRadius, 0, 2*Math.PI , true)ctx.arc(point[1][0], point[1][1], pointRadius, 0, 2*Math.PI , true)ctx.fill()ctx.beginPath()ctx.arc(point[2][0], point[2][1], pointRadius, 0, 2*Math.PI , true)ctx.arc(point[3][0], point[3][1], pointRadius, 0, 2*Math.PI , true)ctx.fill()ctx.beginPath()ctx.lineWidth = 4ctx.strokeStyle = 'rgba(255,255,255,0.6)';ctx.lineJoin = 'round'ctx.lineCap = 'round'ctx.lineTo(point[0][0], point[0][1])ctx.lineTo(point[1][0], point[1][1])ctx.lineTo(point[2][0], point[2][1])ctx.lineTo(point[3][0], point[3][1])ctx.lineTo(point[0][0], point[0][1])ctx.stroke()ctx.fillStyle = 'rgb(0, 0, 0, 0.5)';ctx.fill()},// 手势初始监测touchStart: function touchStart (e) {var that = this;var ref = e.touches[0];const point = this.data.point;const pointRadius = this.data.pointRadius;let moveIndex = -1;for(var i=0;i<4;i++){if(ref.x > (point[i][0]-pointRadius) && ref.x < (point[i][0]+pointRadius)){if(ref.y > (point[i][1]-pointRadius) && ref.y < (point[i][1]+pointRadius)){moveIndex = i;break;}}}if(moveIndex!=-1){that.setData({moveIndex:moveIndex})}},// 手势滑动touchMove: function touchMove (e) {var ref = e.touches[0];var x = ref.x;var y = ref.y;if(this.data.moveIndex!=-1){const point = this.data.point;const index = this.data.moveIndex;point[index][0] = x;point[index][1] = y;this.setData({point:point},()=>{this.drawPoint(point);})}},// 手势滑动结束touchEnd: function touchEnd (e) {var ref = e.changedTouches[0];var x = ref.x;var y = ref.y;if(this.data.moveIndex!=-1){const point = this.data.point;const index = this.data.moveIndex;point[index][0] = x;point[index][1] = y;this.setData({point:point,moveIndex:-1})}},getCropperImage(){const self = this;const point = this.data.point;wx.createSelectorQuery().select('#canvas-1').fields({ node: true, size: true }).exec((res) => {// Canvas 对象const canvas = res[0].node// 渲染上下文const ctx = canvas.getContext('2d');// 初始化画布大小// const dpr = self.data.pixelRatio// canvas.width = self.data.windowWidth * dpr// canvas.height = self.data.windowHeight * dpr// ctx.scale(dpr, dpr)// // 开始绘制// ctx.beginPath()// ctx.moveTo(point[0][0], point[0][1]);// ctx.lineTo(point[1][0], point[1][1]);// ctx.lineTo(point[2][0], point[2][1]);// ctx.lineTo(point[3][0], point[3][1]);// ctx.lineTo(point[0][0], point[0][1]);// //先关闭绘制路径。注意,此时将会使用直线连接当前端点和起始端点。// ctx.closePath();// ctx.fill()// ctx.clip()debuggerwx.canvasToTempFilePath({x: 0,y: 0,width: 200,height: 200,destWidth: 200,destHeight: 200,canvasId: 'canvas-1',success: function (res) {debuggerconsole.log(res.tempFilePath)},fail: function (res) {debuggerconsole.log(res)},},this)})}
})相关文章:
微信小程序实现图片多点裁剪
话不多说,直接上代码 1、页面布局 <view class"buttons" style"height: 50px;"><view class"upload btn" style"background-color: #d18118;"bindtap"uploadImage"> 上传图片 </view><vie…...
计算图片的均值和方差用图片的归一化取值
计算图片的均值和方差用图片的归一化取值 注意:使用这种方法的前提是进行了数据批量化操作,需要使用神经网络库,torch,DataLoader def getStat(data):print(len(data))loader torch.utils.data.DataLoader(data, batch_size1, …...
预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM
回归拟合: 分类 本文是作者的预测算法系列的第四篇,前面的文章中介绍了BP、SVM、RF及其优化,感兴趣的读者可以在作者往期文章中了解,这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&am…...
小黑子—JavaWeb:第六章 - Filter、Listener、AJAX与JSON
JavaWeb入门6.0 1. Filter1.1 Filter快速入门1.2 Filter执行流程1.3 Filter拦截路径配置1.4 Filter过滤器链1.5 案例登录验证 2. Listener2.1 ServletContextListener使用 3. AJAX3.1 AJAX 快速入门3.2 案例 验证用户名是否存在3.3 Axios 异步框架3.3.1 Axios 快速入门3.3.2 Ax…...
STM32 LL库开发
一、STM32开发方式 标准库开发:Standard Peripheral Libraries,STDHAL库开发:Hardware Abstraction Layer,硬件抽象层LL库开发:Low-layer,底层库 二、HAL库与LL库开发对比 ST在推行HAL库的时候,…...
标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法
🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏&…...
277/300 React+react-router-dom+Vite 二级页面刷新时,白屏问题解决
(一)方案 BrowserRouter 换为 HashRouter (二)代码 import routes from ./routes import {ReactElement, Suspense} from react import {createHashRouter, Navigate} from react-router-dom // 生成路由数据 const generateR…...
如何做线上监控
1、背景 软件的质量是需要全生命周期进行关注的,在生产环境下QA的活动就是测试右移,测试右移最关键的手段就是线上监控,也是至关重要的一个环节,可以通过技术的手段,提前感知到线上问题和风险,先于用户提前发现问题,提升服务可感知性,从而降低客户投诉。 2、通用原则…...
饥荒开服教程——游戏
饥荒开服教程——游戏 1. 开服环境2. 开服步骤2.1 创建集群2.2 安装服务端2.3 上传mod2.4 启动脚本2.5 上传地图2.6 设置访问令牌2.7 修改配置 3. 服务器命令3.1 关闭服务器3.2 回档 记录一些在饥荒联机版开服中遇到过的问题。 参考:3分钟创建你的饥荒联机专属服务…...
查询 npm/yarn 安装依赖的全局路径及路径修改
一、NPM 1.查询 npm 安装依赖的全局路径 npm prefix -g 2. 修改 npm 全局安装位置 npm config set prefix "D:\nodejs\node_modules\npm\node_modules" 3. 修改 npm 全局 cache 位置 npm config set cache "D:\nodejs\node_modules\npm\cache" 4. np…...
掌握Python的X篇_35_用Python为美女打码_图像库Pillow
本篇将会介绍python中的一个图像库Pillow。 文章目录 1. Pillow与PIL的关系2. 调整大小3. 加滤镜4. 剪裁5. 生成验证码 1. Pillow与PIL的关系 我们在网上搜python的图像库的话,可能搜到的时PIL。实际上之前python发展的时候就是PIL,这个库比较好用&…...
SpringBoot 异步、邮件任务
异步任务 创建一个Hello项目 创建一个类AsyncService 异步处理还是非常常用的,比如我们在网站上发送邮件,后台会去发送邮件,此时前台会造成响应不动,直到邮件发送完毕,响应才会成功,所以我们一般会采用多线…...
【LeetCode】45. 跳跃游戏 II - 贪婪算法
目录标题 2023-8-11 09:49:25 45. 跳跃游戏 II 2023-8-11 09:49:25 自己没做出来,废物Orz class Solution {public int jump(int[] nums) {int length nums.length;int end 0;int maxPosition 0;int steps 0;for (int i 0; i < length - 1; i) {maxPosit…...
[C初阶笔记]P1
什么是C语言 1、机器语言(二进制)>汇编语言(助记符)>高级语言(C、C等) 2、c语言擅长底层软件开发(操作系统、驱动程序),并不意味着不能开发其他。 C语言更贴近操作…...
外企面试题
Interview Prepare is there anyone we can talk to for a character reference? yes, I have some teammate can help to provide related working information. why did you leave/quit your last job? I got blocked on my last job. I found I cant learn new things fr…...
【目标检测系列】YOLOV1解读
前言 从R-CNN到Fast-RCNN,之前的目标检测工作都是分成两阶段,先提供位置信息在进行目标分类,精度很高但无法满足实时检测的要求。 而YoLo将目标检测看作回归问题,输入为一张图片,输出为S*S*(5*BC)的三维向量。该向量…...
Sentieon | 每周文献-Multi-omics(多组学)-第九期
多组学系列文章-1 标题(英文): Prediction of axillary lymph node metastasis in triple-negative breast cancer by multi-omics analysis and an integrated model标题(中文): 基于多组学分析和综合模型…...
CSDN竞赛70期
CSDN竞赛70期 CSDN竞赛70期1.小张的手速大比拼分析代码 2.坐公交分析代码 3.三而竭分析代码 4.争风吃醋的豚鼠分析代码 CSDN竞赛70期 1.小张的手速大比拼 在很久很久以前,小张找到了一颗有 N 个节点的有根树 T 。 树上的节点编号在 1 到 N 范围内。 他很快发现树上…...
mac安装vscode 配置git
1、安装vscode 官网地址 下载mac稳定版安装很慢的解决办法 (转自) mac电脑如何解决下载vscode慢的问题 选择谷歌浏览器右上角的3个点,选择下载内容,右键选择复制链接地址,在新窗口粘贴地址, 把地址中的一段替换成下面的vscode.cd…...
UI自动化环境的搭建(python+pycharm+selenium+chrome)
最近在做一些UI自动化的项目,为此从环境搭建来从0到1,希望能够帮助到你,同时也是自我的梳理。将按照如下进行开展: 1、python的下载、安装,python环境变量的配置。 2、pycharm开发工具的下载安装。 3、selenium的安装。…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
[拓扑优化] 1.概述
常见的拓扑优化方法有:均匀化法、变密度法、渐进结构优化法、水平集法、移动可变形组件法等。 常见的数值计算方法有:有限元法、有限差分法、边界元法、离散元法、无网格法、扩展有限元法、等几何分析等。 将上述数值计算方法与拓扑优化方法结合&#…...
