【自用笔记】小程序 van-uploader 压缩图片

小程序van-uploader图片上传前压缩 在bind:after-read事件中进行图片压缩,当然在bind:before-read事件中操作也是可以的,我使用的是mpvue架构对应的事件为@afterRead @beforeRead,需要注意的是在使用@beforeRead时要开启useBeforeRead,bind:before-read对应的为use-before-read。同时我用的mpvue框架 afterRead(file) 文件流信息有所不同 为file.mp.detail 一般情况下为file.detail 具体情况还请自行测试。 阅读详情

主要是用到canvas进行压缩,参考地方找不到了,如果找到,会修改添加

下面直接上代码:

我使用的是van-uploader组件进行上传的,所以我们可以在before-read事件中进行处理,那么,我的 .wxml的代码如下(去除了不相关部分,仅余压缩相关内容)

<!-- 设置use-before-read为true,并控制before-read事件进行压缩 -->
<van-uploader file-list="{{ imgList }}" max-count="5" upload-icon="scan" bind:after-read="afterRead" bind:delete="imgDelete" use-before-read="{{ true }}" bind:before-read="beforeRead" />
<!-- 在压缩中需要用到,这里通过css控制在界面上不可见 -->
<canvas style="width:{{canvasWidth}}px;height:{{canvasHeight}}px;position:fixed;left:100%;" id="picCanvas" type="2d"></canvas>

.js中代码如下(仅余压缩相关内容,其他部分已去除)

page ({
  data:{
   canvasWidth: '',  //画布宽度
   canvasHeight: '', //画布高度
  }

 //before-read事件
 beforeRead(event) {
    const { file, callback } = event.detail;
    //进入压缩
    this.compressImg(file).then(res => {
        // res为暴露返回的图片地址,赋值给file后再在after中接收
        file.url = res;  
        file.path = res; //和url相同,但在这里不做处理
        callback(file);
    })
  },
   //图片压缩
    compressImg(file){
        let _this = this;
        return new Promise((resolve, reject) => {
        //获取原图片信息 canvas压缩实现
        wx.getImageInfo({
        src: file.url || file.path,
        success: function (res) {
        let canvasRatio = 1.1;
        let picWidth = res.width //图片原始宽高
        let picHeight = res.height
        while (picWidth > 600 || picHeight > 600) { // 保证宽高在600以内(这里可以自行配置)
            picWidth = Math.trunc(res.width / canvasRatio)
            picHeight = Math.trunc(res.height / canvasRatio)
            canvasRatio = canvasRatio + 0.1;
        }
        const query = wx.createSelectorQuery()
        query.select('#picCanvas').fields({
            node: true,
            size: true
        }).exec((res) => {
            try {
            const canvas = res[0].node
            const ctx = canvas.getContext('2d')
            let dpr = wx.getSystemInfoSync().pixelRatio
            //这里是设置css样式的宽高。
            //属性宽高是css样式宽高的dpr倍,兼容不同机型,避免绘制的内容模糊。
            _this.setData({
                canvasWidth: picWidth / dpr,
                canvasHeight: picHeight / dpr
            })
            canvas.width = picWidth
            canvas.height = picHeight

            const img = canvas.createImage()
            img.src = file.url || file.path
            console.log(img.src,'=> path')
            img.onload = () => {
                console.log('延迟1111600')
                ctx.drawImage(img, 0, 0, picWidth, picHeight); //先画出图片
                //延迟600ms,避免部分机型未绘制出图片内容就执行保存操作,导致最终的图片是块白色画板。
                setTimeout(() => {
                    console.log('延迟600')
                wx.canvasToTempFilePath({
                    fileType: "jpg",
                    canvas: canvas,
                    destWidth: picWidth,
                    destHeight: picHeight,
                    success: function (res) {
                    return resolve(res.tempFilePath) //将压缩后的图片地址暴露出去
                    }
                }, _this)
                }, 600)
            }
            } catch (e) {
                //异常后的操作
            }
        })
        }
    })
    })
    },
   //图片上传
  afterRead(e) {
    console.log(e,'=> after')
    let _this = this
    // 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
    const { file } = e.detail;

    // 接下下来就可以进行你的业务操作啦,这里file.url || file.path就已经是压缩后的图片啦
  }


})

延伸一个添加水印的,我在添加水印前,会先压缩一下图,不然太大的图添加水印过慢或者无法添加,这里的压缩是压缩图片质量,大概核心就是算出图片比,然后赋值给canvas宽高,逻辑你们自己想吧,我在这个过程中也是懵懵的,总之是实现效果了,wxml里面同样要加canvas标签,声明canvas宽高变量,然后直接在afterRead事件中获取图片大小(我这里同样封装了,只展示相关内容,其他无关已经剔除):

import { compressImg } from "../../utils/compressImg.js" // 我放在了utils里面,这里的路径要根据你自己的去修改哦

data(){
    canvasWidth: 0, //画布宽
    canvasHeight: 0, //画布高度
}
 
//图片上传
  afterRead(e) {
    let _this = this
    const { file } = e.detail;
    wx.getImageInfo({
      src: file.url || file.path,
      success: function (res) {
        let oWidth = res.width;
        let oHeight = res.height;
        let maxWidth = 1200;
        let maxHeight = 1600;
        let tWidth = oWidth;
        let tHeight = oHeight;
        if (oWidth > maxWidth || oHeight > maxHeight) {
            if (oWidth/oHeight > maxWidth/maxHeight) {
                tWidth = maxWidth;
                tHeight = Math.round(maxWidth * (oHeight/oWidth));
            } else {
                tHeight = maxHeight;
                tWidth = Math.round(maxHeight * (oWidth/oHeight));
            }
        } 
        _this.setData({
          canvasWidth:  tWidth,
          canvasHeight: tHeight
        })
        console.log(_this.data.canvasWidth,_this.data.canvasHeight)
        // _this.addWatermark(file.url || file.path,e.target.dataset.type,e.target.dataset.index);
        let address = _this.data.locationAdds || '';
        let img = file.url || file.path;
        _this.compressUploadImg(img,true,address)
      },
      fail(err) {
          let address = _this.data.locationAdds || '';
          _this.compressUploadImg(file.url || file.path,false,address)
      }
    })
  },
  //压缩添加水印
  compressUploadImg(imgUrl,isMark,adress){
    wx.showLoading({
        title: '图片上传中...',
      })
    let _this = this;
    compressImg(imgUrl,isMark,adress,isUpload).then(res => {
        wx.hideLoading();
        //这里是你获取到的图片回调,进行业务操作
    })
  },

utils - compressImg.js : 

const { timeNow } = require("./util.js")

/**
 * base6转为图片地址
 * @param {*} base64 图片base64
 * @param {*} cb callback回调
 */
const base64ImgtoFile = (base64, cb) => {
    const fsm = wx.getFileSystemManager();
    const FILE_BASE_NAME = new Date().getTime(); //自定义文件名(这里以时间戳为文件名)
    const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
    if (!format) {
        return (new Error('ERROR_BASE64SRC_PARSE'));
    }
    const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.png`;
    const buffer = wx.base64ToArrayBuffer(bodyData);
    fsm.writeFile({
        filePath,
        data: buffer,
        encoding: 'binary',
        success() {
          cb(filePath);
        },
        fail() {
          return (new Error('ERROR_BASE64SRC_WRITE'));
        },
    });
}

/**
 * 给图片添加水印
 * @param {String} imageUrl  图片链接
 * @param {*} canvasWidth    图片宽度
 * @param {*} canvasHeight   图片高度
 * @param {String} address  水印地址
 */
  const addWatermark = (imageUrl,canvasWidth,canvasHeight,address) => {
    return new Promise((resolve, reject)=> {
        wx.showLoading({
            title: '图片生成中...',
        })
        const query = wx.createSelectorQuery();
        query.select('#canvas').fields({
          node: true,
          size: true
        }).exec((res) => {
            const canvas = res[0].node;
            const ctx = canvas.getContext('2d');
            canvas.width = canvasWidth
            canvas.height = canvasHeight
             // 绘制背景图片
            const image = canvas.createImage();
            image.src = imageUrl;
            image.onload = () => {
                ctx.drawImage(image, 0, 0, canvasWidth, canvasHeight);   // 绘制图片到画布上
                let fontSi = canvasWidth / 780 * 18
                ctx.font = `normal ${fontSi}px null`;
                ctx.fillStyle = '#fff';
                ctx.textBaseline = 'bottom';
                ctx.shadowColor = "black"; // 阴影颜色
                ctx.shadowOffsetX = 0 // 水平偏移量
                ctx.shadowOffsetY = 0  // 垂直偏移量
                ctx.shadowBlur = 10  // 模糊度

                // 绘制经纬度
                ctx.fillText(address || '', 10, canvasHeight - 5);

                // 绘制时间
                ctx.fillText(timeNow(), 10, canvasHeight - fontSi - 5);

                // 绘制星期
                // ctx.fillText(this.data.week, 20, canvasHeight - 115);

                wx.canvasToTempFilePath({
                    canvas,
                    success: (res) => { 
                        resolve(res.tempFilePath)
                    },
                    fail: () => {
                        imgurl = imageUrl
                        reject(new Error('转换为图片失败'));
                    }
                })
            }
        })
    })
  }


/**
 * 压缩图片\添加水印
 * @param {*} imageUrl         图片地址 
 * @param {Boolean} isMark     是否要添加水印 
 * @param {String} address     水印地址 
 */
const compressImg = (imageUrl,isMark,address) => {
    var imageUrl = imageUrl;
    var isMark = isMark || false;
    let _this = this;
    return new Promise((resolve, reject) => {
      //获取原图片信息 canvas压缩实现
      wx.getImageInfo({
        src: imageUrl,
        success: async function (res) {
             if(isMark) {
                await addWatermark(imageUrl,res.width,res.height,address).then(res => {
                    imageUrl = res
                }) 
            }
            wx.showLoading({
                title: '图片压缩中...',
            })
            //  我怕之前的压缩无效,这里会再次进行压缩(你们可以自行删减)
            var quality = 0.9;   //压缩系数0-1之间,越小越模糊
            let picWidth = res.width  //图片原始宽高
            let picHeight = res.height
            let maxWidth = 1200;  //最大宽幅
            let maxHeight = 1600; //最大高度
            let tWidth = picWidth;
            let tHeight = picHeight;
            if (picWidth > maxWidth || picHeight > maxHeight) {
                if (picWidth/picHeight > maxWidth/maxHeight) {
                    tWidth = maxWidth;
                    tHeight = Math.round(maxWidth * (picHeight/picWidth));
                } else {
                    tHeight = maxHeight;
                    tWidth = Math.round(maxHeight * (picWidth/picHeight));
                }
            }
            const query = wx.createSelectorQuery()
            query.select('#picCanvas').fields({
                node: true,
                size: true
            }).exec((res) => {
                try {
                const canvas = res[0].node
                const ctx = canvas.getContext('2d')
                canvas.width = tWidth
                canvas.height = tHeight
                const img = canvas.createImage()
                img.src = imageUrl
                img.onload = () => {
                    ctx.drawImage(img, 0, 0, tWidth, tHeight); //先画出图片
                    var base64 = canvas.toDataURL("image/jpeg",quality ); //压缩语句(压缩体积,不改变宽高大小,quality可以动态改变)
                    base64ImgtoFile(base64, resCurrent => {
                         let objInfo = {};
                            objInfo.imageUrl = resCurrent;
                            return resolve(objInfo)
                    })
                }
                } catch (e) {
                    //异常后的操作
                }
            })
        }
      })
    })
}


module.exports = {
    compressImg
}

目前这样的操作,在添加完水印的情况下,可以让一个11M的图片压缩到576KB,还是可以满足我的需求的,如果你们有更好的,希望可以留言

van-uploader 二次封装,多图片上传到服务器,从服务器进行删除图片 最近写的一个h5项目,我采用的是vant-ui ,图片上传算是无可避免的,所以根据需求进行二次封装van-uploader。 阅读详情

相关推荐

解决uniapp中van-uploader组件‘Invalid handler for event load‘警告

在前端开发中,组件化开发和跨平台框架是提升效率的关键技术。van-uploader作为vant-weapp组件库的核心上传组件,在uniapp跨平台编译时可能出现'Invalid handler for event load'警告。这源于uniapp的事件封装机制与原生小程序事件处理的差异,特别是在处理图片加载等异步操作时。理解组件通信原理和事件处理机制,可以帮助开发者更好地解决这类兼容性问题。通过自定义组件封装、条件编译或错误监控等工程实践,不仅能解决当前警告,还能提升上传功能的健壮性。对于H5和小程序等

weixin_33861800的博客 550

【vue】van-uploader图片上传压缩处理

二、van-uploader组件。一、安装,在组件中引入。

weixin_42269728的博客 4220

告别微信H5拍照闪退:从van-uploader源码角度,聊聊低端安卓机的内存优化实战

本文深入分析了低端安卓机在微信H5拍照上传时频繁闪退的问题,从van-uploader源码角度出发,探讨了内存优化的实战策略。通过对比微信JSSDK与原生方案的性能差异,提出了智能压缩、内存管理及架构级优化等多层次解决方案,有效提升了低端机的使用体验。

weixin_27960253的博客 238

关于vant组件库中uploader组件使用心得

vue3 vant组件库

qq_44307861的博客 5013

微信小程序 wx.uploadFile 封装实战:3步构建通用上传服务,支持多表单复用

本文详细介绍了微信小程序中wx.uploadFile的工程化封装实践,通过3步构建通用上传服务,支持多表单复用和Promise化调用。文章涵盖基础封装、多表单动态配置、UI组件协同等核心内容,帮助开发者解决代码重复、维护困难等实际问题,提升小程序文件上传功能的开发效率和可维护性。

weixin_29015899的博客 285

移动端 Vue+Vant 的Uploader 实现上传、压缩、旋转图片功能

主要介绍了移动端 Vue+Vant 的Uploader 实现 上传、压缩、旋转图片功能,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值 ,需要的朋友可以参考下

微信小程序(wepy + vant = 文件上传 van-uploader)

场景说明 微信小程序 - 进行图片上传(图片多选、图片放大预览) 官网详解:https://vant-contrib.gitee.io/vant-weapp/#/uploader 1.组件引入 <config> { navigationBarTitleText: 'xxxx', usingComponents: { "van-uploader": "module:@vant/weapp/dist/uploader", } } </config> 2.代码模块

weixin_45189855的博客 2884

eNSP安装教程

eNSP安装教程一、安装eNSP1、先安装依赖组件2、安装eNSP主程序eNSP+V100R003C00SPC100+Setup ---不要安装在中文路径下3、安装完成后注册设备 一、安装eNSP 程序包位置:https://drive.weixin.qq.com/s?k=AOgAQQfOAAsw1wAKEgAAcAbgbSAKQ 1、先安装依赖组件 依赖组件: WinPcap_4_1_3 —直接下一步,但不要安装在中文路径下 Wireshark_v3.4.6 或者wireshark-win3

qimowei的博客 8669

小程序van-uploader 上传图片并压缩图片

<view class="upload"> <van-uploader file-list="{{ file }}" bind:after-read="afterRead" deletable="{{ true }}" data-id="business_license" preview-image="{{true}}" bind:delete="delete_img" /> <canvas canv...

4278

Python-网络爬虫

网络爬虫(Web Spider)又称网络蜘蛛或网络机器人,是一段用来实现自动采集网站数据的程序。网络爬虫不仅能够为搜索引擎采集网络信息,而且还可以作为定向信息采集器,定向采集某些网站中的特定信息。对于定向信息的爬取,网络爬虫主要采取数据抓取、数据解析、数据入库的操作流程。(1)数据抓取:发送构造的HTTP请求,获得包含所需数据的HTTP响应;(2)数据解析:对HTTP响应的原始数据进行分析、清洗,以提取出所需要的数据;(3)数据入库:将数据进一步保存到数据库(或文本文件)中,用于构建知识库。

qq_42759120的博客 1761

OAI骨关节炎数据集申请与DICOM下载全流程避坑指南

医学影像分析中,DICOM格式是存储与交换CT、MRI等数据的通用标准,其元数据Tag承载着像素间距、层厚等关键物理信息,直接影响定量分析的准确性。在骨关节炎研究领域,OAI数据集因样本量大、随访时间长而成为高价值资源,但获取需通过NDA协议申请,并借助nda-tools命令行工具完成TB级影像的批量下载与断点续传。这一流程涉及浏览器环境配置、DICOM格式转换及Python预处理等工程环节,任一细节疏漏都可能导致数据读取异常或分析偏差。掌握从申请到落地的完整链路,能显著提升医学影像AI研究的效率与可复现性

weixin_30843121的博客 278

【自用笔记】小程序 图片url和base64互转,延伸canvas压缩

小程序 使用canvas压缩,并通过base64 转 图片url

Lin_javascript的博客 631

【低空经济】无人机充电站设计方案

随着无人机技术的快速发展和广泛应用,其在物流、农业、巡检、救援等领域的应用日益普及。然而,无人机的续航能力一直是限制其大规模应用的关键因素之一。为了解决这一问题,无人机充电站的设计与建设显得尤为重要。本项目旨在设计一套高效、智能、可扩展的无人机充电站系统,以满足不同场景下无人机的充电需求,提升其作业效率和应用范围。无人机充电站的设计将围绕以下几个核心目标展开:首先,充电站应具备快速充电能力,以减少无人机的停机时间,提高作业效率;

2960

小程序图片上传压缩

小程序图片压缩上传

weixin_43385164的博客 249

GitHub 新手使用手册

理论说太多容易忘,来实践实践吧。

2501_90226046的博客 1054

打造AI智能体员工,我用扣子复刻了华与华、奥美和金枪大叔

这事说穿了,就是你用多个AI智能体,分别扮演专业角色,构成一支能力互补、各司其职的“数字团队”。每个智能体,都有明确的角色设定、任务边界和接口形式。它不再是一个泛泛的ChatGPT,而是你手下的“品牌顾问”、“策略专家”、“文案大神”、“短视频导演”、“运营总监”。简单来说,你不再是雇一个人,而是养一群机器人打工——24小时不摸鱼,不请假,不离职。如果你是个人创业者、内容创作者、培训机构、中小企业主,其实都可以尝试构建属于你自己的“AI虚拟员工矩阵”。

互联网架构师笔记 1499

小程序上传图片之压缩图片并转base64

效果图: 说明:当上传图片内存大于100kb时对图片进行压缩处理; html: <canvas canvas-id='attendCanvasId' class='myCanvas' style="width:{{imageWidth}}px; height:{{imageHeight}}px"></canvas> <view class="upLoadPicBox"> <view class="upLoadPicIconBox" wx:for="{{tem

nononoCoder的博客 831

AutoSAR系列讲解(深入篇)14.7-Mcal Adc配置(上)

详细讲解了ADC的各个配置项的作用

雪云飞星的博客 1万+

Vant Uploader 上传多张图片设置status

Vant Uploader 上传多张图片设置status,beforRead和afterRead 不能同时执行

codingLeader的博客 4018

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

微信小程序 webview 中的h5 页面 van-uploader 部分机型无法上传 解决方案

微信小程序 webview 中的h5 页面 van-uploader 部分机型无法上传 解决方案

射手男很懒的博客 9335

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

Vant Weapp Uploader 文件上传组件完全指南:从基础用法到源码级原理

本文围绕 Vant Weapp 组件库中的 Uploader 文件上传组件展开,系统讲解其引入方式、基础用法、图片预览、上传状态管理、数量限制、自定义样式、上传前校验以及小程序云开发集成等完整实践,并结合仓库源码剖析其文件选择、类型识别、事件流转与尺寸控制等底层实现。读完本文,你将掌握在微信小程序中基于 `van-uploader` 构建完整文件上传交互的实战能力,同时理解该组件"选择与预览由组件

gitblog_00749的博客 401

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

uniapp+vant-weapp上传组件事件处理错误解决方案

在跨平台开发中,事件处理机制是连接视图层与逻辑层的核心桥梁。Vue框架通过@event语法实现声明式事件绑定,而微信小程序则采用原生bind/catch事件系统。当使用uniapp编译vant-weapp等小程序组件时,这种机制差异可能导致'Invalid handler for event'等典型错误。本文以van-uploader组件的load事件处理为例,深入解析uniapp编译原理与小程序原生组件的事件交互机制,提供包括基础修复、组件封装、生命周期管理在内的多维度解决方案。针对文件上传这一常见场景,

weixin_30315723的博客 342

小程序上传多张图片转base64

小程序上传多张图片转base64 XML代码: <view style='background-color: #F1F1F1; width:100%rpx;height:3rpx;'></view> <view class='flex-item'> <text decode="{{true}}" style="font-size: ...

吕海安·HAIANLV 764

微信小程序选择图片和预览图片

作者>:燕潇洒 视频中,老师也是看着官方文档,为学生们讲解,微信提供了系统的方法来选择图片.wx.chooseImage此方法是用来选择图片的方法,具体使用如下: data: { avatarUrl:null },首先在数据中定义接收数据的变量,然后调用方法选择图片,将图片显示出来。bindViewTap:function(){ var that = this; wx.c

yanxiaosa的博客 2万+

微信小程序图片裁剪实战:从Canvas原理到WeCropper组件集成

在移动应用开发中,图片处理是常见的功能需求,尤其在用户头像上传、商品展示等场景。其核心原理是通过Canvas API对图像像素进行操作,实现裁剪、缩放等变换。这项技术能有效统一图片尺寸、优化加载性能并提升用户体验。在微信小程序生态中,开发者通常面临两种实现路径:基于原生Canvas API自研,或集成第三方组件库。原生方案虽然灵活可控,但开发成本高、兼容性挑战大;而采用WeCropper等成熟组件库,则能快速实现开箱即用的裁剪功能,大幅提升开发效率。本文将以WeCropper为例,详细解析如何在小程序中集成

weixin_34009794的博客 448
上一篇: 【自用笔记】小程序 图片url和base64互转,延伸canvas压缩
下一篇: 【自用笔记】微信小程序 使用van-tab时的问题处理
林希雨
博客等级 码龄4年 84粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值