// pages/piano/cropper/cropper.js const { BtCmd } = require('../../../devices/bluetooth/bt_cmd'); import EventManager from '../../../utils/event_bus' import { EnumCmdEvent, CmdEvent } from '../../../devices/cmd_key_event'; import route_util from '../../../utils/route_util'; const { BtHelper } = require('../../../devices/bt_helper'); Page({ /** * 页面的初始数据 */ data: { src: "", width: 320,//宽度 height: 320,//高度 max_width: 320, max_height: 320, disable_rotate: true, //是否禁用旋转 disable_ratio: true, //锁定比例 limit_move: true, //是否限制移动 showProgress: false, _imageBuffer: null, progress: 0, }, cropper: null, // 图片转RGB565 convertToRGB565(imageData) { const { data, width, height } = imageData; // 原始像素数据 (RGBA 格式) const rgba = new Uint8Array(data); // 创建 RGB565 的 ArrayBuffer const pixelCount = width * height; const rgb565Buffer = new ArrayBuffer(pixelCount * 2); // 每像素 2 字节 const rgb565View = new Uint16Array(rgb565Buffer); // 转换每个像素 for (let i = 0; i < pixelCount; i++) { const r = rgba[i * 4]; // Red const g = rgba[i * 4 + 1]; // Green const b = rgba[i * 4 + 2]; // Blue // RGB565 的位运算 const r5 = (r >> 3) & 0x1F; // R 的高 5 位 const g6 = (g >> 2) & 0x3F; // G 的高 6 位 const b5 = (b >> 3) & 0x1F; // B 的高 5 位 // 组合成 RGB565 格式 const rgb565 = (r5 << 11) | (g6 << 5) | b5; // 写入到 RGB565 的 buffer 中 rgb565View[i] = rgb565; } return rgb565Buffer; }, cropperload(e) { console.log('cropper加载完成'); }, upload() { let that = this; wx.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album'], success(res) { wx.showLoading({ title: '加载中', }) const tempFilePaths = res.tempFilePaths[0]; //重置图片角度、缩放、位置 that.cropper.imgReset(); that.setData({ src: tempFilePaths }); } }) }, loadimage(e) { wx.hideLoading(); console.log('图片', e); this.cropper.imgReset(); }, clickcut(e) { console.log("clickcut:", e.detail); //图片预览 wx.previewImage({ current: e.detail.url, // 当前显示图片的http链接 urls: [e.detail.url] // 需要预览的图片http链接列表 }) }, cancel() { wx.navigateBack({ delta: -1 }) }, submit() { let _this = this wx.showLoading({ title: '图片裁剪中', }) const fs = wx.getFileSystemManager(); this.cropper.getImg((obj) => { // app.globalData.imgSrc = obj.url; console.log("裁剪图片:", obj); fs.readFile({ filePath: obj.url, encoding: '', // 不指定编码以获取原始二进制数据 success: (res) => { console.log("下载文件成功:", res) let rgbData = _this.convertToRGB565({ width: obj.width, height: obj.height, data: res.data }) _this.data._imageBuffer = rgbData; console.log("下载文件成功2:", _this.data._imageBuffer) wx.hideLoading(); wx.showLoading({ title: '开始传输图片', }) _this.startImage(); }, fail: (err) => { console.error('读取 .bin 文件失败:', err); }, }); }); // 651kb的 // _this.downloadAndSaveFile("https://music-play.oss-cn-shenzhen.aliyuncs.com/backOss/file/6a909799a6924e6f86a4683e6da4fad4.bin"); // 55kb的 // _this.downloadAndSaveFile("https://music-play.oss-cn-shenzhen.aliyuncs.com/backOss/file/55d2dd22bd554eb19b71536bec4ba42c.bin"); }, // 下载网络文件并保存到本地 downloadAndSaveFile(url) { // https://music-play.oss-cn-shenzhen.aliyuncs.com/backOss/file/6a909799a6924e6f86a4683e6da4fad4.bin const fs = wx.getFileSystemManager(); let _this = this; wx.downloadFile({ url: url, // 网络文件的 URL success: (res) => { if (res.statusCode === 200) { // 下载成功,res.tempFilePath 是临时文件路径 const tempFilePath = res.tempFilePath; console.log("下载文件:", res) fs.readFile({ filePath: tempFilePath, // encoding: '', // 不指定编码以获取原始二进制数据 success: (res) => { console.log("下载文件成功:", res.data) let rgbData = res.data _this.data._imageBuffer = rgbData; // console.log("下载文件成功2:", _this.data._imageBuffer) wx.hideLoading(); wx.showLoading({ title: '开始传输图片', }) _this.startImage(); }, fail: (err) => { console.error('读取 .bin 文件失败:', err); }, }); } else { console.error('下载文件失败:', res.statusCode); } }, fail: (err) => { console.error('下载文件失败:', err); }, }); }, checkAndRequestImagePermission: function () { const _this = this; // 检查用户是否已经授权访问相册 wx.getSetting({ success(res) { if (!res.authSetting['scope.writePhotosAlbum']) { // 用户未授权访问相册,请求用户授权 wx.authorize({ scope: 'scope.writePhotosAlbum', success() { // 用户同意授权 console.log('用户已授权访问相册'); // 可以在这里执行访问相册的操作 }, fail() { // 用户拒绝授权 console.log('用户拒绝授权访问相册'); wx.showModal({ title: '提示', content: '您拒绝了访问相册的权限,请在设置中手动开启', showCancel: false, success(res) { if (res.confirm) { // 跳转到设置页面 wx.openSetting({ success(settingRes) { if (settingRes.authSetting['scope.writePhotosAlbum']) { console.log('用户已在设置中开启访问相册的权限'); // 可以在这里执行访问相册的操作 } else { console.log('用户仍未授权访问相册'); } } }); } } }); } }); } else { // 用户已授权访问相册 console.log('用户已授权访问相册'); // 可以在这里执行访问相册的操作 } } }); }, async startImage() { BtHelper.sendCallBack(BtCmd.wallPaper(1), function (res) { if (!res) { wx.hideLoading() wx.showToast({ title: '发送失败', icon: 'none' }) } }); }, sliceDataIntoChunks(data, chunkSize) { console.log("发送图片数据:", data.byteLength) const chunks = []; // for (let i = 0; i < data.length; i += chunkSize) { for (let i = 0; i < data.byteLength; i += chunkSize) { const chunk = data.slice(i, i + chunkSize); chunks.push(chunk); } return chunks; }, async sendImage(imageBuffer, index) { let _this = this wx.hideLoading() console.log("发送图片数据0:", index, imageBuffer.byteLength) // console.log("发送图片数据0:", index, imageBuffer.length) let chunks = this.sliceDataIntoChunks(imageBuffer, 16); let next = 0; let total = imageBuffer.byteLength; // let total = imageBuffer.length; let btHelper = BtHelper.getInstance(); for (let i = 0; i < chunks.length; i++) { const chunk = chunks[i]; next += chunk.byteLength; // next += chunk.length; let uint8Array = new Uint8Array(chunk); let unit16 = uint8Array.map(item => { return item.toString(16) }); console.log("发送图片数据1:", i, next, total, unit16) _this.updateProgress(next, total); await _this.delay(20); let res = await btHelper.wallPaperSyncData(chunk); // btHelper.wallPaperData(chunk); let nowDate = Date.now() if (i === chunks.length - 1 && res) { wx.showModal({ title: '图片上传成功' + i + " / " + nowDate, showCancel: false }) _this.endImage(0) } else if (!res) { wx.showModal({ title: '图片上传失败', showCancel: false }) _this.endImage(2) } } }, async delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }, endImage(value) { BtHelper.getInstance().wallPaper(value); }, startProgress() { this.setData({ progress: 0, showProgress: true }) }, updateProgress(chunk, total) { let progress = chunk / total; let _this = this if (chunk >= total) { _this.setData({ progress: 0, showProgress: false, // showCropImg: false }); wx.showToast({ title: '图片上传成功', }) } else { _this.setData({ progress: progress, }); } }, /** * 生命周期函数--监听页面加载 */ onLoad(options) { this.checkAndRequestImagePermission() this.cropper = this.selectComponent("#image-cropper"); this.cropper.imgReset(); // this.setData({ // scr:json, // }) this.upload(); //上传图片 let _this = this; EventManager.addNotification(CmdEvent.eventName, function (event) { let name = event.cmdEvent; console.log("裁剪页:", EnumCmdEvent) switch (name) { case EnumCmdEvent.wallpaper: let otaCmd = event.wallpaper; let kind = event.heiJiaoKind; console.log("裁剪页:", otaCmd, kind) if (otaCmd === 1 && kind == 1) { // 开始发送 _this.sendImage(_this.data._imageBuffer, 0) _this.startProgress() } else if (otaCmd === 0 && kind == 1) { // 发送结束 // _this.endImage(0) } else if (kind == 0) { wx.hideLoading() wx.showModal({ title: '图片上传失败了', showCancel: false }) } break; default: break; } }, this) }, /** * 生命周期函数--监听页面初次渲染完成 */ onReady() { }, /** * 生命周期函数--监听页面显示 */ onShow() { }, /** * 生命周期函数--监听页面隐藏 */ onHide() { }, /** * 生命周期函数--监听页面卸载 */ onUnload() { EventManager.removeNotification(CmdEvent.eventName, this); }, /** * 页面相关事件处理函数--监听用户下拉动作 */ onPullDownRefresh() { }, /** * 页面上拉触底事件的处理函数 */ onReachBottom() { }, /** * 用户点击右上角分享 */ onShareAppMessage() { } })