当前位置: 首页 > news >正文

微信小程序实现图片多点裁剪

话不多说,直接上代码

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)})}
})

相关文章:

微信小程序实现图片多点裁剪

话不多说&#xff0c;直接上代码 1、页面布局 <view class"buttons" style"height: 50px;"><view class"upload btn" style"background-color: #d18118;"bindtap"uploadImage"> 上传图片 </view><vie…...

计算图片的均值和方差用图片的归一化取值

计算图片的均值和方差用图片的归一化取值 注意&#xff1a;使用这种方法的前提是进行了数据批量化操作&#xff0c;需要使用神经网络库&#xff0c;torch&#xff0c;DataLoader def getStat(data):print(len(data))loader torch.utils.data.DataLoader(data, batch_size1, …...

预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM

回归拟合&#xff1a; 分类 本文是作者的预测算法系列的第四篇&#xff0c;前面的文章中介绍了BP、SVM、RF及其优化&#xff0c;感兴趣的读者可以在作者往期文章中了解&#xff0c;这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&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开发方式 标准库开发&#xff1a;Standard Peripheral Libraries&#xff0c;STDHAL库开发&#xff1a;Hardware Abstraction Layer&#xff0c;硬件抽象层LL库开发&#xff1a;Low-layer&#xff0c;底层库 二、HAL库与LL库开发对比 ST在推行HAL库的时候&#xff0c;…...

标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法

&#x1f52d; 嗨&#xff0c;您好 &#x1f44b; 我是 vnjohn&#xff0c;在互联网企业担任 Java 开发&#xff0c;CSDN 优质创作者 &#x1f4d6; 推荐专栏&#xff1a;Spring、MySQL、Nacos、Java&#xff0c;后续其他专栏会持续优化更新迭代 &#x1f332;文章所在专栏&…...

277/300 React+react-router-dom+Vite 二级页面刷新时,白屏问题解决

&#xff08;一&#xff09;方案 BrowserRouter 换为 HashRouter &#xff08;二&#xff09;代码 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 回档 记录一些在饥荒联机版开服中遇到过的问题。 参考&#xff1a;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的图像库的话&#xff0c;可能搜到的时PIL。实际上之前python发展的时候就是PIL&#xff0c;这个库比较好用&…...

SpringBoot 异步、邮件任务

异步任务 创建一个Hello项目 创建一个类AsyncService 异步处理还是非常常用的&#xff0c;比如我们在网站上发送邮件&#xff0c;后台会去发送邮件&#xff0c;此时前台会造成响应不动&#xff0c;直到邮件发送完毕&#xff0c;响应才会成功&#xff0c;所以我们一般会采用多线…...

【LeetCode】45. 跳跃游戏 II - 贪婪算法

目录标题 2023-8-11 09:49:25 45. 跳跃游戏 II 2023-8-11 09:49:25 自己没做出来&#xff0c;废物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、机器语言&#xff08;二进制&#xff09;>汇编语言&#xff08;助记符&#xff09;>高级语言&#xff08;C、C等&#xff09; 2、c语言擅长底层软件开发&#xff08;操作系统、驱动程序&#xff09;&#xff0c;并不意味着不能开发其他。 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&#xff0c;之前的目标检测工作都是分成两阶段&#xff0c;先提供位置信息在进行目标分类&#xff0c;精度很高但无法满足实时检测的要求。 而YoLo将目标检测看作回归问题&#xff0c;输入为一张图片&#xff0c;输出为S*S*(5*BC)的三维向量。该向量…...

Sentieon | 每周文献-Multi-omics(多组学)-第九期

多组学系列文章-1 标题&#xff08;英文&#xff09;&#xff1a; Prediction of axillary lymph node metastasis in triple-negative breast cancer by multi-omics analysis and an integrated model标题&#xff08;中文&#xff09;&#xff1a; 基于多组学分析和综合模型…...

CSDN竞赛70期

CSDN竞赛70期 CSDN竞赛70期1.小张的手速大比拼分析代码 2.坐公交分析代码 3.三而竭分析代码 4.争风吃醋的豚鼠分析代码 CSDN竞赛70期 1.小张的手速大比拼 在很久很久以前&#xff0c;小张找到了一颗有 N 个节点的有根树 T 。 树上的节点编号在 1 到 N 范围内。 他很快发现树上…...

mac安装vscode 配置git

1、安装vscode 官网地址 下载mac稳定版安装很慢的解决办法 (转自) mac电脑如何解决下载vscode慢的问题 选择谷歌浏览器右上角的3个点&#xff0c;选择下载内容&#xff0c;右键选择复制链接地址&#xff0c;在新窗口粘贴地址&#xff0c; 把地址中的一段替换成下面的vscode.cd…...

UI自动化环境的搭建(python+pycharm+selenium+chrome)

最近在做一些UI自动化的项目&#xff0c;为此从环境搭建来从0到1&#xff0c;希望能够帮助到你&#xff0c;同时也是自我的梳理。将按照如下进行开展&#xff1a; 1、python的下载、安装&#xff0c;python环境变量的配置。 2、pycharm开发工具的下载安装。 3、selenium的安装。…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手&#xff0c;它却总在Library里给你写"回忆录"&#xff1f;卸载的Final Cut Pro像电子幽灵般阴魂不散&#xff1f;总是会有残留文件&#xff0c;别慌&#xff01;这份Mac软件卸载指南&#xff0c;将用最硬核的方式教你"数字分手术"&#xff0…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

return this;返回的是谁

一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请&#xff0c;不同级别的经理有不同的审批权限&#xff1a; // 抽象处理者&#xff1a;审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...