当前位置: 首页 > 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的安装。…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)

目录 &#x1f50d; 若用递归计算每一项&#xff0c;会发生什么&#xff1f; Horners Rule&#xff08;霍纳法则&#xff09; 第一步&#xff1a;我们从最原始的泰勒公式出发 第二步&#xff1a;从形式上重新观察展开式 &#x1f31f; 第三步&#xff1a;引出霍纳法则&…...

raid存储技术

1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划&#xff0c;涵盖存储系统的布局、数据存储策略等&#xff0c;它明确数据如何存储、管理与访问&#xff0c;为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...