微信小程序实现图片多点裁剪
话不多说,直接上代码
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的安装。…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
