cropper.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. const { BtCmd } = require('../../../devices/bluetooth/bt_cmd');
  2. import eventBus from '../../../utils/eventBus'
  3. import { EnumCmdEvent, CmdEvent } from '../../../devices/cmd_key_event';
  4. import routeUtil from '../../../utils/routeUtil';
  5. const { BtHelper } = require('../../../devices/bt_helper');
  6. const { uploadImage } = require('../../../request/imageRequest');
  7. Page({
  8. /**
  9. * 页面的初始数据
  10. */
  11. data: {
  12. navbarData: {
  13. showCapsule: 1, //是否显示左上角图标 1表示显示 0表示不显示
  14. title: '壁纸设置', //导航栏 中间的标题
  15. callback: true,
  16. },
  17. src: "",
  18. width: 320,//宽度
  19. height: 320,//高度
  20. showProgress: false,
  21. _chunks: [],
  22. progress: 0,
  23. _timer: null,
  24. // 裁剪后的图片地址
  25. _imgUrl: null,
  26. _imgMD5: null,
  27. _imgIndex: null,
  28. // 从上级界面过来的图片地址,也是要返回去的地址
  29. _imgTopPic: null,
  30. _imgNext: 0,
  31. max_scale: 2,
  32. _hasPermission: false,
  33. _hasShowModal: false,
  34. _deviceId: null,
  35. wallpaper: {},
  36. },
  37. cropper: null,
  38. callback() {
  39. let that = this
  40. if (this.data._chunks.length > 0) {
  41. wx.showModal({
  42. title: '保存壁纸中,确定要中断退出吗?',
  43. content: '',
  44. complete: (res) => {
  45. if (res.confirm) {
  46. that.endImage(2)
  47. wx.navigateBack({
  48. delta: 1,
  49. })
  50. }
  51. }
  52. })
  53. } else {
  54. wx.navigateBack({
  55. delta: 1,
  56. })
  57. }
  58. },
  59. cropperload(e) {
  60. console.log('cropper加载完成');
  61. },
  62. upload() {
  63. let that = this;
  64. wx.chooseMedia({
  65. count: 1,
  66. mediaType: ['image'],
  67. sourceType: ['album'],
  68. success(res) {
  69. wx.showLoading({
  70. title: '加载中',
  71. })
  72. const tempFilePaths = res.tempFiles[0].tempFilePath;
  73. that.cropper.imgReset();
  74. that.setData({
  75. src: tempFilePaths
  76. });
  77. // todo 测试用
  78. // that.testUpload(tempFilePaths)
  79. }, fail(err2) {
  80. console.log(err2)
  81. }
  82. })
  83. },
  84. testUpload(url) {
  85. let _this = this
  86. // 读取裁剪的jpg图片
  87. const fs = wx.getFileSystemManager();
  88. fs.readFile({
  89. filePath: url,
  90. encoding: '', // 不指定编码以获取原始二进制数据
  91. success: (obj) => {
  92. console.log("加载文件成功:", obj.data.byteLength, obj.data.length)
  93. fs.getFileInfo({
  94. "filePath": url, "digestAlgorithm": "md5", success: (res) => {
  95. console.log("md5:", res)
  96. _this.data._imgMD5 = res.digest
  97. _this.data._imgIndex = 0
  98. console.log("加载文件成功:", obj.data.byteLength, obj.data.length, obj.getFileInfo)
  99. let binData = obj.data;
  100. // let myMd5 = _this.getImgMd5(binData)
  101. // let my2Md5 = _this.getImg2Md5(binData)
  102. // let my3Md5 = _this.getImg3Md5(binData)
  103. wx.setClipboardData({
  104. data: res.digest,
  105. fail: (err) => {
  106. console.error('setClipboardData失败:', err);
  107. },
  108. success: (res) => {
  109. console.log('setClipboardData成功:', res);
  110. },
  111. })
  112. _this.sliceDataIntoChunks(binData, 64);
  113. console.log("加载文件成功2:", binData.byteLength, binData.length)
  114. _this.data._imageBufferLength = binData.byteLength ?? binData.length
  115. wx.hideLoading();
  116. wx.showLoading({
  117. title: '开始传输壁纸',
  118. })
  119. console.log("md5 2:", _this.data._imgMD5)
  120. _this.startImage()
  121. }, fail: (err) => {
  122. console.error('getFileInfo失败:', err);
  123. },
  124. })
  125. },
  126. fail: (err) => {
  127. console.error('读取 .bin 文件失败2:', err);
  128. },
  129. });
  130. // 651kb的
  131. // _this.downloadAndSaveFile("https://music-play.oss-cn-shenzhen.aliyuncs.com/backOss/file/8770a6097d9940b59032d099b2fdde3b.bin");
  132. },
  133. loadimage(e) {
  134. wx.hideLoading();
  135. console.log('加载壁纸', e.detail.path);
  136. this.data._imgTopPic = e.detail.path
  137. // this.cropper.imgReset();
  138. },
  139. clickcut(e) {
  140. console.log("clickcut:", e.detail);
  141. //壁纸预览
  142. wx.previewImage({
  143. current: e.detail.url,
  144. urls: [e.detail.url]
  145. })
  146. },
  147. cancel() {
  148. wx.navigateBack({
  149. delta: -1
  150. })
  151. },
  152. async _uploadImgIOS(url) {
  153. let _this = this;
  154. let res = await uploadImage(url);
  155. // 服务器的走下载图片
  156. _this.data._imgTopPic = res.data;
  157. console.log("添加图片2,", _this.data._imgTopPic.length)
  158. console.log("IOS的走下载图片", res)
  159. _this._downloadAndSaveFile(_this.data._imgTopPic)
  160. },
  161. _uploadImage(url) {
  162. const fs = wx.getFileSystemManager();
  163. let _this = this;
  164. // app.globalData.imgSrc = obj.url;
  165. console.log("裁剪壁纸:", url);
  166. _this.data._imgUrl = url
  167. fs.readFile({
  168. filePath: _this.data._imgUrl,
  169. encoding: '', // 不指定编码以获取原始二进制数据
  170. success: (obj) => {
  171. console.log("加载文件成功:", obj.data.byteLength, obj.data.length)
  172. fs.getFileInfo({
  173. "filePath": _this.data._imgUrl, "digestAlgorithm": "md5", success: (res2) => {
  174. console.log("md5:", res2)
  175. _this.data._imgMD5 = res2.digest
  176. _this.data._imgIndex = 0
  177. console.log("加载文件成功:", obj.data.byteLength, obj.data.length, obj.getFileInfo)
  178. let binData = obj.data;
  179. // let myMd5 = _this.getImgMd5(binData)
  180. // let my2Md5 = _this.getImg2Md5(binData)
  181. // let my3Md5 = _this.getImg3Md5(binData)
  182. // todo 测试用
  183. // wx.setClipboardData({
  184. // data: res2.digest,
  185. // })
  186. _this.sliceDataIntoChunks(binData, 64);
  187. console.log("加载文件成功2:", binData.byteLength, binData.length)
  188. _this.data._imageBufferLength = binData.byteLength ?? binData.length
  189. wx.hideLoading();
  190. wx.showLoading({
  191. title: '开始传输壁纸',
  192. })
  193. console.log("md5 2:", _this.data._imgMD5)
  194. _this.startImage()
  195. }, fail: (err) => {
  196. console.error('getFileInfo失败:', err);
  197. },
  198. })
  199. },
  200. fail: (err) => {
  201. wx.hideLoading()
  202. wx.showToast({
  203. title: '读取该图片失败',
  204. })
  205. console.error('读取 .bin 文件失败:', err);
  206. },
  207. });
  208. },
  209. submit() {
  210. let _this = this
  211. // if (_this.data._chunks.length > 0) {
  212. // return;
  213. // }
  214. let _imgTopPic = _this.data._imgTopPic ?? ""
  215. console.log("长度:", _imgTopPic, _imgTopPic.length)
  216. if (_imgTopPic.length == 0) {
  217. wx.showToast({
  218. title: '壁纸不能为空',
  219. icon: "none"
  220. })
  221. return
  222. }
  223. if (_imgTopPic.startsWith("http")) {
  224. // 服务器的走下载图片
  225. console.log("服务器的走下载图片", _this.data._imgTopPic)
  226. _this._downloadAndSaveFile(_this.data._imgTopPic)
  227. return;
  228. }
  229. const res = wx.getSystemInfoSync(); // 获取系统信息
  230. /// android ios
  231. const platform = res.platform; // 获取平台类型
  232. wx.showLoading({
  233. title: '壁纸裁剪中',
  234. })
  235. // 读取裁剪的jpg图片
  236. this.cropper.getImg((res) => {
  237. if (platform === 'ios') {
  238. _this._uploadImgIOS(res.url)
  239. } else {
  240. _this.data._imgTopPic = res.url
  241. _this._uploadImage(res.url)
  242. }
  243. });
  244. },
  245. _downloadAndSaveFile(url) {
  246. let _this = this
  247. // 下载文件
  248. wx.downloadFile({
  249. url: url,
  250. success: function (res) {
  251. if (res.statusCode === 200) {
  252. const tempFilePath = res.tempFilePath;
  253. _this.data._imgTopPic = url
  254. _this._uploadImage(tempFilePath)
  255. } else {
  256. wx.showToast({
  257. title: '下载图片失败',
  258. icon: 'error'
  259. });
  260. }
  261. },
  262. fail: function (err) {
  263. console.error('下载文件失败', err);
  264. wx.showToast({
  265. title: '下载失败',
  266. icon: 'error'
  267. });
  268. }
  269. });
  270. },
  271. checkAndRequestImagePermission: function () {
  272. const _this = this;
  273. // 检查用户是否已经授权访问相册
  274. wx.getSetting({
  275. success(res) {
  276. if (!res.authSetting['scope.writePhotosAlbum']) {
  277. // 用户未授权访问相册,请求用户授权
  278. wx.authorize({
  279. scope: 'scope.writePhotosAlbum',
  280. success() {
  281. // 用户同意授权
  282. console.log('用户已授权访问相册1');
  283. _this.upload()
  284. // 可以在这里执行访问相册的操作
  285. },
  286. fail() {
  287. // 用户拒绝授权
  288. console.log('用户拒绝授权访问相册');
  289. wx.showModal({
  290. title: '提示',
  291. content: '您拒绝了访问相册的权限,无法上传壁纸',
  292. showCancel: false,
  293. success(res) {
  294. if (res.confirm) {
  295. // 跳转到设置页面
  296. wx.openSetting({
  297. success(settingRes) {
  298. if (settingRes.authSetting['scope.writePhotosAlbum']) {
  299. console.log('用户已在设置中开启访问相册的权限');
  300. // 可以在这里执行访问相册的操作
  301. _this.upload(); //上传壁纸
  302. } else {
  303. console.log('用户仍未授权访问相册');
  304. }
  305. }
  306. });
  307. }
  308. }
  309. });
  310. }
  311. });
  312. } else {
  313. // 用户已授权访问相册
  314. console.log('用户已授权访问相册2');
  315. // 可以在这里执行访问相册的操作
  316. _this.upload()
  317. }
  318. }
  319. });
  320. },
  321. async startImage() {
  322. console.log("开始发送壁纸数据: 0x78",)
  323. BtHelper.sendCallBack(BtCmd.wallPaper(1), function (res) {
  324. if (!res) {
  325. wx.hideLoading()
  326. wx.setTimeout(function () {
  327. wx.showToast({
  328. title: '发送失败',
  329. icon: 'error',
  330. duration: 2000
  331. })
  332. }, 100)
  333. }
  334. });
  335. },
  336. sliceDataIntoChunks(data, chunkSize) {
  337. let buffer = data;
  338. console.log("发送壁纸数据:", buffer.byteLength, buffer.length)
  339. let total = buffer.byteLength || buffer.length
  340. const chunks = [];
  341. // for (let i = 0; i < data.length; i += chunkSize) {
  342. for (let i = 0; i < total; i += chunkSize) {
  343. const chunk = buffer.slice(i, i + chunkSize);
  344. chunks.push(chunk);
  345. }
  346. // const sliceSize = chunkSize / 2; // 每个 RGB565 占 2 字节
  347. // const chunks = [];
  348. // for (let i = 0; i < total; i += sliceSize) {
  349. // chunks.push(buffer.slice(i, i + sliceSize));
  350. // }
  351. this.data._chunks = chunks;
  352. },
  353. // getImgMd5(buffer) {
  354. // let md5ctx = js_md5.md5_init();
  355. // js_md5.md5_update(md5ctx, buffer, buffer.byteLength ?? buffer.length);
  356. // let result = js_md5.md5_final(md5ctx);
  357. // let md5 = js_md5.md5_encode_hex(result, 16);
  358. // console.log("result:", md5, result);
  359. // return md5
  360. // },
  361. sendImageMD5() {
  362. // let lengthCode = this.data._chunks.length
  363. // console.log("发送壁纸MD5 1:", lengthCode, this.data._imgMD5)
  364. let value = BtCmd.sendWiFiInfo("99", this.data._imgMD5)
  365. // console.log("发送壁纸MD5 2:", value)
  366. BtHelper.sendCallBack(BtCmd.wallPaperMD5(value), function (res) {
  367. if (!res) {
  368. wx.hideLoading()
  369. wx.showToast({
  370. title: '发送图片失败',
  371. icon: 'error'
  372. })
  373. }
  374. });
  375. },
  376. // 切分高位和低位
  377. splitHighLowBytes(value) {
  378. let highByte = (value >> 8) & 0xFF;
  379. let lowByte = value & 0xFF;
  380. return { highByte, lowByte };
  381. },
  382. async sendImage() {
  383. let _this = this
  384. let index = _this.data._imgIndex
  385. wx.hideLoading()
  386. let chunks = _this.data._chunks
  387. let total = _this.data._imageBufferLength;
  388. let btHelper = BtHelper.getInstance();
  389. // let i = 0;
  390. // _this.data._timer = setInterval(async () => {
  391. if (index > chunks.length - 1) {
  392. // wx.showModal({
  393. // title: '壁纸上传完成md5:' + _this.data._imgMD5,
  394. // content: '最终发送数据大小:' + _this.data._imgNext + ',总大小:' + total + '',
  395. // showCancel: false,
  396. // success(res) {
  397. // }
  398. // })
  399. _this.endImage(0)
  400. return;
  401. }
  402. const chunk = chunks[index];
  403. _this.data._imgNext += (chunk.byteLength ?? chunk.length);
  404. // console.log("发送壁纸数据1:", index, ":", _this.data._imgNext, ":", chunk.length, ":", chunk.byteLength, ":", total, chunks.length)
  405. _this.data._imgIndex += 1;
  406. let res = await btHelper.wallPaperSyncData(chunk);
  407. // let res = true;
  408. // btHelper.wallPaperData(chunk);
  409. if (!res) {
  410. wx.showModal({
  411. title: '壁纸上传失败',
  412. showCancel: false
  413. })
  414. _this.endImage(2)
  415. return
  416. }
  417. _this.updateProgress(_this.data._imgNext, total);
  418. // }, 30);
  419. },
  420. async delay(ms) {
  421. return new Promise(resolve => setTimeout(resolve, ms));
  422. },
  423. endImage(value) {
  424. let _this = this
  425. console.log("结束壁纸上传:", value)
  426. if (_this.data._timer) {
  427. clearInterval(_this.data._timer)
  428. _this.data._timer = null
  429. }
  430. _this.setData({
  431. progress: 0,
  432. showProgress: false
  433. })
  434. _this.data._chunks = []
  435. _this.data._imgNext = 0
  436. _this.data._imgMD5 = null
  437. _this.data._imgIndex = 0
  438. BtHelper.getInstance().wallPaper(value);
  439. },
  440. startProgress() {
  441. this.setData({
  442. progress: 0,
  443. showProgress: true
  444. })
  445. },
  446. updateProgress(chunk, total) {
  447. let progress = parseFloat((chunk / total * 100).toFixed(2));
  448. let _this = this
  449. if (chunk >= total) {
  450. _this.setData({
  451. progress: 100,
  452. showCropImg: false
  453. });
  454. } else {
  455. _this.setData({
  456. progress: progress,
  457. });
  458. }
  459. },
  460. successSend() {
  461. let _this = this
  462. wx.showModal({
  463. title: '保存壁纸成功',
  464. showCancel: false,
  465. success(res) {
  466. if (res.confirm) {
  467. const pages = getCurrentPages();
  468. // 获取上一级页面实例
  469. const prevPage = pages[pages.length - 2];
  470. // 传递参数
  471. prevPage.updateTopImg(_this.data._imgTopPic)
  472. wx.navigateBack({
  473. delta: 1,
  474. })
  475. }
  476. }
  477. })
  478. },
  479. failSend(showToast) {
  480. console.log('failSend')
  481. let _this = this
  482. _this.data._chunks = []
  483. _this.data._imgMD5 = null
  484. _this.data._imgIndex = 0
  485. _this.data._imgNext = 0
  486. wx.hideLoading()
  487. if (showToast) {
  488. wx.showToast({
  489. title: '发送图片失败',
  490. icon: 'error'
  491. })
  492. }
  493. _this.setData({
  494. progress: 0,
  495. showProgress: false,
  496. showCropImg: false
  497. });
  498. },
  499. hasImage(image) {
  500. let that = this;
  501. that.cropper.imgReset();
  502. // 有图片的进制缩放
  503. that.setData({
  504. src: image.pic,
  505. max_scale: 1,
  506. });
  507. that.data._imgTopPic = image.pic
  508. console.log("有图片", image.pic, that.data._imgTopPic.length)
  509. },
  510. disconnectDevCallback() {
  511. routeUtil.goBackHomePage()
  512. // 设备断开连接回调,请重新连接设备
  513. },
  514. /**
  515. * 生命周期函数--监听页面加载
  516. */
  517. onLoad(options) {
  518. let _this = this;
  519. this.cropper = this.selectComponent("#image-cropper");
  520. this.cropper.imgReset();
  521. let image = options.param
  522. let json = JSON.parse(image)
  523. console.log("裁剪页:", json)
  524. let topImg = json.topImg ?? {}
  525. let deviceId = json.deviceId ?? "";
  526. _this.data._deviceId = deviceId
  527. if (topImg.pic) {
  528. this.hasImage(topImg)
  529. } else {
  530. console.log("没有图片")
  531. this.checkAndRequestImagePermission()
  532. }
  533. // this.setData({
  534. // scr:json,
  535. // })
  536. eventBus.addNotification(CmdEvent.eventName, function (event) {
  537. let name = event.cmdEvent;
  538. let value = event.wallpaper;
  539. let kind = event.heiJiaoKind;
  540. // console.log("裁剪页:", name, value, kind)
  541. switch (name) {
  542. case EnumCmdEvent.onoffline:
  543. wx.hideLoading();
  544. break;
  545. case EnumCmdEvent.wallpaper:
  546. //0x78
  547. // 小程序:0x78, 1。 开启壁纸
  548. // 黑胶回:0x78, 2, 1 ,1。 0x78, 2, 0, 2 。 1成功,2失败
  549. // 小程序:0x80, [参考wifi指令], [0x22,总长度,0x33,包长,包数,0x44,md5长,md5]
  550. // 黑胶回:0x80, 1, 1。 0x80, 0, 2。 1成功,2失败
  551. // 小程序:0x79, 数据长度,数据
  552. // 黑胶回:0x79, 1, 1 。0x79, 0, 2 。 1成功,2失败
  553. // 小程序:0x78, 0。结束了
  554. // 黑胶回:0x78, 2, 0, 1 。 0x78, 2, 0, 3 。 0流程成功,3流程失败
  555. // 小程序: 0x78, 2。异常结束
  556. if (value === 1 && kind == 1) {
  557. // 开始校验md5
  558. _this.sendImageMD5()
  559. // _this.sendImage()
  560. _this.startProgress()
  561. } else if (value === 0 && (kind == 2 || kind == 3)) {
  562. // 发送失败
  563. _this.failSend(true)
  564. } else if (value === 0 && kind == 1) {
  565. // 发送完成
  566. _this.successSend()
  567. } else {
  568. // 发送失败
  569. _this.failSend(true)
  570. }
  571. break;
  572. case EnumCmdEvent.wallPaperMD5:
  573. // 0x80
  574. console.log("开始发送MD5回复", kind, value)
  575. // 收到回复md5,开始发送图片的第一片
  576. if (kind == 1 && value === 1) {
  577. _this.data._imgIndex = 0
  578. _this.sendImage(_this.data._imgIndex)
  579. } else if (kind == 0 && value === 3) {
  580. _this.failSend(false)
  581. wx.showModal({
  582. title: '发送图片失败,请重启设备再试试吧',
  583. showCancel: false,
  584. success: function (res) {
  585. if (res.confirm) {
  586. console.log('用户点击确定')
  587. }
  588. }
  589. })
  590. } else {
  591. _this.failSend(true)
  592. }
  593. break;
  594. case EnumCmdEvent.wallPaperData:
  595. // 0x79
  596. // 收到回复md5,开始发送图片后面N片
  597. if (kind == 1 && value === 1) {
  598. _this.sendImage(_this.data._imgIndex)
  599. } else {
  600. _this.failSend(true)
  601. }
  602. break;
  603. default:
  604. break;
  605. }
  606. }, this)
  607. },
  608. /**
  609. * 生命周期函数--监听页面初次渲染完成
  610. */
  611. onReady() {
  612. },
  613. /**
  614. * 生命周期函数--监听页面显示
  615. */
  616. onShow() {
  617. },
  618. /**
  619. * 生命周期函数--监听页面隐藏
  620. */
  621. onHide() {
  622. },
  623. /**
  624. * 生命周期函数--监听页面卸载
  625. */
  626. onUnload() {
  627. eventBus.removeNotification(CmdEvent.eventName, this);
  628. },
  629. /**
  630. * 页面相关事件处理函数--监听用户下拉动作
  631. */
  632. onPullDownRefresh() {
  633. },
  634. /**
  635. * 页面上拉触底事件的处理函数
  636. */
  637. onReachBottom() {
  638. },
  639. /**
  640. * 用户点击右上角分享
  641. */
  642. onShareAppMessage() {
  643. }
  644. })