index.vue 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. <template name="xy-imgResiz">
  2. <view>
  3. <canvas canvas-id="avatar-canvas" id="avatar-canvas" class="my-canvas" :style="{top: sT, height: csH}"
  4. disable-scroll="false"></canvas>
  5. <canvas canvas-id="oper-canvas" id="oper-canvas" class="oper-canvas" :style="{top: sT, height: csH}"
  6. disable-scroll="false" @touchstart="fStart" @touchmove="fMove" @touchend="fEnd"></canvas>
  7. <canvas canvas-id="prv-canvas" id="prv-canvas" class="prv-canvas" disable-scroll="false" @touchstart="fHideImg"
  8. :style="{ height: csH, top: pT }"></canvas>
  9. <view class="oper-wrapper" :style="{display: sD, top:tp}">
  10. <view class="oper">
  11. <view class="btn-wrapper" v-if="sO">
  12. <view @click="fSelect" hover-class="hover" :style="{width: bW}"><text>重选</text></view>
  13. <view @click="fClose" hover-class="hover" :style="{width: bW}"><text>关闭</text></view>
  14. <view @click="fRotate" hover-class="hover" :style="{width: bW, display: bD}"><text>旋转</text></view>
  15. <view @click="fPreview" hover-class="hover" :style="{width: bW}"><text>预览</text></view>
  16. <view @click="fUpload" hover-class="hover" :style="{width: bW}"><text>上传</text></view>
  17. </view>
  18. <view class="clr-wrapper" v-else>
  19. <slider class="my-slider" @change="fColorChange" block-size="25" value="0" min="-100" max="100"
  20. activeColor="red" backgroundColor="green" block-color="grey" show-value></slider>
  21. <view @click="fPrvUpload" hover-class="hover" :style="{width: bW}"><text>上传</text></view>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </template>
  27. <script>
  28. "use strict";
  29. const tH = 50;
  30. export default {
  31. name: "xy-imgResiz",
  32. data() {
  33. return {
  34. csH: '0px',
  35. sD: 'none',
  36. sT: '-10000px',
  37. pT: '-10000px',
  38. iS: {},
  39. sS: {},
  40. sO: true,
  41. bW: '19%',
  42. bD: 'flex',
  43. tp: 0,
  44. imgSrc: {
  45. imgSrc: ''
  46. },
  47. };
  48. },
  49. watch: {
  50. avatarSrc() {
  51. this.imgSrc.imgSrc = this.avatarSrc;
  52. }
  53. },
  54. props: {
  55. avatarSrc: '',
  56. avatarStyle: '',
  57. selWidth: '',
  58. selHeight: '',
  59. expWidth: '',
  60. expHeight: '',
  61. minScale: '',
  62. maxScale: '',
  63. canScale: '',
  64. canRotate: '',
  65. lockWidth: '',
  66. lockHeight: '',
  67. stretch: '',
  68. lock: '',
  69. fileType: '',
  70. noTab: '',
  71. inner: '',
  72. quality: '',
  73. index: '',
  74. bgImage: '',
  75. },
  76. created() {
  77. this.cc = uni.createCanvasContext('avatar-canvas', this);
  78. this.cco = uni.createCanvasContext('oper-canvas', this);
  79. this.ccp = uni.createCanvasContext('prv-canvas', this);
  80. this.qlty = parseFloat(this.quality) || 1;
  81. this.imgSrc.imgSrc = this.avatarSrc;
  82. this.letRotate = (this.canRotate === false || this.inner === true || this.inner === 'true' || this
  83. .canRotate === 'false') ? 0 : 1;
  84. this.letScale = (this.canScale === false || this.canScale === 'false') ? 0 : 1;
  85. this.isin = (this.inner === true || this.inner === 'true') ? 1 : 0;
  86. this.indx = this.index || undefined;
  87. this.mnScale = parseFloat(this.minScale) || 0.3;
  88. this.mxScale = parseFloat(this.maxScale) || 4;
  89. this.noBar = (this.noTab === true || this.noTab === 'true') ? 1 : 0;
  90. this.stc = this.stretch;
  91. this.lck = this.lock;
  92. this.fType = this.fileType === 'jpg' ? 'jpg' : 'png';
  93. if (this.isin || !this.letRotate) {
  94. this.bW = '24%';
  95. this.bD = 'none';
  96. } else {
  97. this.bW = '19%';
  98. this.bD = 'flex';
  99. }
  100. if (this.noBar) {
  101. this.fWindowResize();
  102. } else {
  103. uni.showTabBar({
  104. fail: () => {
  105. this.noBar = 1;
  106. },
  107. success: () => {
  108. this.noBar = 0;
  109. },
  110. complete: (res) => {
  111. this.fWindowResize();
  112. }
  113. });
  114. }
  115. },
  116. methods: {
  117. fWindowResize() {
  118. let sysInfo = uni.getSystemInfoSync();
  119. this.platform = sysInfo.platform;
  120. this.wW = sysInfo.windowWidth;
  121. // #ifdef H5
  122. this.drawTop = sysInfo.windowTop;
  123. // #endif
  124. // #ifndef H5
  125. this.drawTop = 0;
  126. // #endif
  127. // #ifdef MP-ALIPAY
  128. this.wH = sysInfo.screenHeight - sysInfo.statusBarHeight - sysInfo.titleBarHeight;
  129. this.csH = this.wH - tH + 'px';
  130. // #endif
  131. // #ifndef MP-ALIPAY
  132. this.wH = sysInfo.windowHeight;
  133. if (!this.noBar) this.wH += tH;
  134. this.csH = this.wH - tH + 'px';
  135. // #endif
  136. this.tp = this.csH;
  137. // #ifdef H5
  138. this.tp = sysInfo.windowTop + parseInt(this.csH) + 'px';
  139. // #endif
  140. this.pxRatio = this.wW / 750;
  141. let style = this.avatarStyle;
  142. if (style && style !== true && (style = style.trim())) {
  143. style = style.split(';');
  144. let obj = {};
  145. for (let v of style) {
  146. if (!v) continue;
  147. v = v.trim().split(':');
  148. if (v[1].toString().indexOf('upx') >= 0) {
  149. let arr = v[1].trim().split(' ');
  150. for (let k in arr) {
  151. if (!arr[k]) continue;
  152. if (arr[k].toString().indexOf('upx') >= 0) {
  153. arr[k] = parseFloat(arr[k]) * this.pxRatio + 'px';
  154. }
  155. }
  156. v[1] = arr.join(' ');
  157. }
  158. obj[v[0].trim()] = v[1].trim();
  159. }
  160. this.iS = obj;
  161. }
  162. this.expWidth && (this.eW = this.expWidth.toString().indexOf('upx') >= 0 ? parseInt(this.expWidth) * this
  163. .pxRatio :
  164. parseInt(this.expWidth));
  165. this.expHeight && (this.eH = this.expHeight.toString().indexOf('upx') >= 0 ? parseInt(this.expHeight) *
  166. this.pxRatio :
  167. parseInt(this.expHeight));
  168. if (this.sD === 'flex') {
  169. this.fDrawInit(true);
  170. }
  171. this.fHideImg();
  172. },
  173. fSelect() {
  174. if (this.fSelecting) return;
  175. this.fSelecting = true;
  176. setTimeout(() => {
  177. this.fSelecting = false;
  178. }, 500);
  179. uni.chooseImage({
  180. count: 1,
  181. sizeType: ['original', 'compressed'],
  182. sourceType: ['album', 'camera'],
  183. success: (r) => {
  184. // #ifdef MP-ALIPAY
  185. uni.showLoading();
  186. // #endif
  187. // #ifndef MP-ALIPAY
  188. uni.showLoading({
  189. title: '加载中...',
  190. mask: true
  191. });
  192. // #endif
  193. let path = this.imgPath = r.tempFilePaths[0];
  194. uni.getImageInfo({
  195. src: path,
  196. success: r => {
  197. this.imgWidth = r.width;
  198. this.imgHeight = r.height;
  199. this.path = path;
  200. if (!this.hasSel) {
  201. let style = this.sS || {};
  202. if (this.selWidth && this.selHeight) {
  203. let sW = this.selWidth.toString().indexOf('upx') >= 0 ?
  204. parseInt(this.selWidth) * this.pxRatio : parseInt(
  205. this.selWidth),
  206. sH = this.selHeight.toString().indexOf('upx') >= 0 ?
  207. parseInt(this.selHeight) * this.pxRatio : parseInt(
  208. this.selHeight);
  209. style.width = sW + 'px';
  210. style.height = sH + 'px';
  211. style.top = ((this.wH - sH - tH) | 0) / 2 + 'px';
  212. style.left = ((this.wW - sW) | 0) / 2 + 'px';
  213. } else {
  214. uni.showModal({
  215. title: '裁剪框的宽或高没有设置',
  216. showCancel: false
  217. })
  218. return;
  219. }
  220. this.sS = style;
  221. }
  222. if (this.noBar) {
  223. this.fDrawInit(true);
  224. } else {
  225. uni.hideTabBar({
  226. complete: () => {
  227. this.fDrawInit(true);
  228. }
  229. });
  230. }
  231. },
  232. fail: () => {
  233. uni.showToast({
  234. title: "请选择正确图片",
  235. duration: 2000,
  236. })
  237. },
  238. complete() {
  239. uni.hideLoading();
  240. }
  241. });
  242. }
  243. })
  244. },
  245. fUpload() {
  246. if (this.fUploading) return;
  247. this.fUploading = true;
  248. setTimeout(() => {
  249. this.fUploading = false;
  250. }, 1000)
  251. let style = this.sS,
  252. x = parseInt(style.left),
  253. y = parseInt(style.top),
  254. width = parseInt(style.width),
  255. height = parseInt(style.height),
  256. expWidth = this.eW || (width * this.pixelRatio),
  257. expHeight = this.eH || (height * this.pixelRatio);
  258. // #ifdef MP-ALIPAY
  259. uni.showLoading();
  260. // #endif
  261. // #ifndef MP-ALIPAY
  262. uni.showLoading({
  263. title: '加载中...',
  264. mask: true
  265. });
  266. // #endif
  267. this.sD = 'none';
  268. this.sT = '-10000px';
  269. this.hasSel = false;
  270. this.fHideImg();
  271. // #ifdef MP-ALIPAY
  272. this.cc.toTempFilePath({
  273. x: x,
  274. y: y,
  275. width: width,
  276. height: height,
  277. destWidth: expWidth,
  278. destHeight: expHeight,
  279. fileType: this.fType,
  280. quality: this.qlty,
  281. success: (r) => {
  282. r = r.apFilePath;
  283. this.$emit("upload", {
  284. avatar: this.imgSrc,
  285. path: r,
  286. index: this.indx,
  287. data: this.rtn,
  288. base64: this.base64 || null
  289. });
  290. },
  291. fail: (res) => {
  292. uni.showToast({
  293. title: "error1",
  294. duration: 2000,
  295. })
  296. },
  297. complete: () => {
  298. uni.hideLoading();
  299. this.noBar || uni.showTabBar();
  300. this.$emit("end");
  301. }
  302. });
  303. // #endif
  304. // #ifndef MP-ALIPAY
  305. uni.canvasToTempFilePath({
  306. x: x,
  307. y: y,
  308. width: width,
  309. height: height,
  310. destWidth: expWidth,
  311. destHeight: expHeight,
  312. canvasId: 'avatar-canvas',
  313. fileType: this.fType,
  314. quality: this.qlty,
  315. success: (r) => {
  316. r = r.tempFilePath;
  317. // #ifdef H5
  318. this.btop(r).then((r) => {
  319. this.$emit("upload", {
  320. avatar: this.imgSrc,
  321. path: r,
  322. index: this.indx,
  323. data: this.rtn,
  324. base64: this.base64 || null
  325. });
  326. return;
  327. })
  328. // #endif
  329. // #ifndef H5
  330. this.$emit("upload", {
  331. avatar: this.imgSrc,
  332. path: r,
  333. index: this.indx,
  334. data: this.rtn,
  335. base64: this.base64 || null
  336. });
  337. // #endif
  338. },
  339. fail: (res) => {
  340. uni.showToast({
  341. title: "error1",
  342. duration: 2000,
  343. })
  344. },
  345. complete: () => {
  346. uni.hideLoading();
  347. this.noBar || uni.showTabBar();
  348. this.$emit("end");
  349. }
  350. }, this);
  351. // #endif
  352. },
  353. fPrvUpload() {
  354. if (this.fPrvUploading) return;
  355. this.fPrvUploading = true;
  356. setTimeout(() => {
  357. this.fPrvUploading = false;
  358. }, 1000)
  359. let style = this.sS,
  360. destWidth = parseInt(style.width),
  361. destHeight = parseInt(style.height),
  362. prvX = this.prvX,
  363. prvY = this.prvY,
  364. prvWidth = this.prvWidth,
  365. prvHeight = this.prvHeight,
  366. expWidth = this.eW || (parseInt(style.width) * this.pixelRatio),
  367. expHeight = this.eH || (parseInt(style.height) * this.pixelRatio);
  368. // #ifdef MP-ALIPAY
  369. uni.showLoading();
  370. // #endif
  371. // #ifndef MP-ALIPAY
  372. uni.showLoading({
  373. title: '加载中...',
  374. mask: true
  375. });
  376. // #endif
  377. this.sD = 'none';
  378. this.sT = '-10000px';
  379. this.hasSel = false;
  380. this.fHideImg();
  381. // #ifdef MP-ALIPAY
  382. this.ccp.toTempFilePath({
  383. x: prvX,
  384. y: prvY,
  385. width: prvWidth,
  386. height: prvHeight,
  387. destWidth: expWidth,
  388. destHeight: expHeight,
  389. fileType: this.fType,
  390. quality: this.qlty,
  391. success: (r) => {
  392. r = r.apFilePath;
  393. this.$emit("upload", {
  394. avatar: this.imgSrc,
  395. path: r,
  396. index: this.indx,
  397. data: this.rtn,
  398. base64: this.base64 || null
  399. });
  400. },
  401. fail: () => {
  402. uni.showToast({
  403. title: "error_prv",
  404. duration: 2000,
  405. })
  406. },
  407. complete: () => {
  408. uni.hideLoading();
  409. this.noBar || uni.showTabBar();
  410. this.$emit("end");
  411. }
  412. });
  413. // #endif
  414. // #ifndef MP-ALIPAY
  415. uni.canvasToTempFilePath({
  416. x: prvX,
  417. y: prvY,
  418. width: prvWidth,
  419. height: prvHeight,
  420. destWidth: expWidth,
  421. destHeight: expHeight,
  422. canvasId: 'prv-canvas',
  423. fileType: this.fType,
  424. quality: this.qlty,
  425. success: (r) => {
  426. r = r.tempFilePath;
  427. // #ifdef H5
  428. this.btop(r).then((r) => {
  429. this.$emit("upload", {
  430. avatar: this.imgSrc,
  431. path: r,
  432. index: this.indx,
  433. data: this.rtn,
  434. base64: this.base64 || null
  435. });
  436. })
  437. // #endif
  438. // #ifndef H5
  439. this.$emit("upload", {
  440. avatar: this.imgSrc,
  441. path: r,
  442. index: this.indx,
  443. data: this.rtn,
  444. base64: this.base64 || null
  445. });
  446. // #endif
  447. },
  448. fail: () => {
  449. uni.showToast({
  450. title: "error_prv",
  451. duration: 2000,
  452. })
  453. },
  454. complete: () => {
  455. uni.hideLoading();
  456. this.noBar || uni.showTabBar();
  457. this.$emit("end");
  458. }
  459. }, this);
  460. // #endif
  461. },
  462. fDrawInit(ini = false) {
  463. let allWidth = this.wW,
  464. allHeight = this.wH,
  465. imgWidth = this.imgWidth,
  466. imgHeight = this.imgHeight,
  467. imgRadio = imgWidth / imgHeight,
  468. useWidth = allWidth - 40,
  469. useHeight = allHeight - tH - 80,
  470. useRadio = useWidth / useHeight,
  471. sW = parseInt(this.sS.width),
  472. sH = parseInt(this.sS.height);
  473. this.fixWidth = 0;
  474. this.fixHeight = 0;
  475. this.lckWidth = 0;
  476. this.lckHeight = 0;
  477. switch (this.stc) {
  478. case 'x':
  479. this.fixWidth = 1;
  480. break;
  481. case 'y':
  482. this.fixHeight = 1;
  483. break;
  484. case 'long':
  485. if (imgRadio > 1) this.fixWidth = 1;
  486. else this.fixHeight = 1;
  487. break;
  488. case 'short':
  489. if (imgRadio > 1) this.fixHeight = 1;
  490. else this.fixWidth = 1;
  491. break;
  492. case 'longSel':
  493. if (sW > sH) this.fixWidth = 1;
  494. else this.fixHeight = 1;
  495. break;
  496. case 'shortSel':
  497. if (sW > sH) this.fixHeight = 1;
  498. else this.fixWidth = 1;
  499. break;
  500. }
  501. switch (this.lck) {
  502. case 'x':
  503. this.lckWidth = 1;
  504. break;
  505. case 'y':
  506. this.lckHeight = 1;
  507. break;
  508. case 'long':
  509. if (imgRadio > 1) this.lckWidth = 1;
  510. else this.lckHeight = 1;
  511. break;
  512. case 'short':
  513. if (imgRadio > 1) this.lckHeight = 1;
  514. else this.lckWidth = 1;
  515. break;
  516. case 'longSel':
  517. if (sW > sH) this.lckWidth = 1;
  518. else this.lckHeight = 1;
  519. break;
  520. case 'shortSel':
  521. if (sW > sH) this.lckHeight = 1;
  522. else this.lckWidth = 1;
  523. break;
  524. }
  525. if (this.fixWidth) {
  526. useWidth = sW;
  527. useHeight = useWidth / imgRadio;
  528. } else if (this.fixHeight) {
  529. useHeight = sH;
  530. useWidth = useHeight * imgRadio;
  531. } else if (imgRadio < useRadio) {
  532. if (imgHeight < useHeight) {
  533. useWidth = imgWidth;
  534. useHeight = imgHeight;
  535. } else {
  536. useWidth = useHeight * imgRadio;
  537. }
  538. } else {
  539. if (imgWidth < useWidth) {
  540. useWidth = imgWidth;
  541. useHeight = imgHeight;
  542. } else {
  543. useHeight = useWidth / imgRadio;
  544. }
  545. }
  546. if (this.isin) {
  547. if (useWidth < sW) {
  548. useWidth = sW;
  549. useHeight = useWidth / imgRadio;
  550. this.lckHeight = 0;
  551. }
  552. if (useHeight < sH) {
  553. useHeight = sH;
  554. useWidth = useHeight * imgRadio;
  555. this.lckWidth = 0;
  556. }
  557. }
  558. this.scaleSize = 1;
  559. this.rotateDeg = 0;
  560. this.posWidth = (allWidth - useWidth) / 2 | 0;
  561. this.posHeight = (allHeight - useHeight - tH) / 2 | 0;
  562. this.useWidth = useWidth | 0;
  563. this.useHeight = useHeight | 0;
  564. this.centerX = this.posWidth + useWidth / 2;
  565. this.centerY = this.posHeight + useHeight / 2;
  566. this.focusX = 0;
  567. this.focusY = 0;
  568. let style = this.sS,
  569. left = parseInt(style.left),
  570. top = parseInt(style.top),
  571. width = parseInt(style.width),
  572. height = parseInt(style.height),
  573. canvas = this.canvas,
  574. canvasOper = this.canvasOper,
  575. cc = this.cc,
  576. cco = this.cco;
  577. cco.beginPath();
  578. cco.setLineWidth(3);
  579. cco.setGlobalAlpha(1);
  580. cco.setStrokeStyle('white');
  581. cco.strokeRect(left, top, width, height);
  582. cco.setFillStyle('black');
  583. cco.setGlobalAlpha(0.5);
  584. cco.fillRect(0, 0, this.wW, top);
  585. cco.fillRect(0, top, left, height);
  586. cco.fillRect(0, top + height, this.wW, this.wH - height - top - tH);
  587. cco.fillRect(left + width, top, this.wW - width - left, height);
  588. cco.setGlobalAlpha(1);
  589. cco.setStrokeStyle('red');
  590. cco.moveTo(left + 15, top);
  591. cco.lineTo(left, top);
  592. cco.lineTo(left, top + 15);
  593. cco.moveTo(left + width - 15, top);
  594. cco.lineTo(left + width, top);
  595. cco.lineTo(left + width, top + 15);
  596. cco.moveTo(left + 15, top + height);
  597. cco.lineTo(left, top + height);
  598. cco.lineTo(left, top + height - 15);
  599. cco.moveTo(left + width - 15, top + height);
  600. cco.lineTo(left + width, top + height);
  601. cco.lineTo(left + width, top + height - 15);
  602. cco.stroke();
  603. cco.draw(false, () => {
  604. if (ini) {
  605. this.sD = 'flex';
  606. this.sT = this.drawTop + 'px';
  607. this.fDrawImage(true);
  608. }
  609. });
  610. this.$emit("init");
  611. },
  612. fDrawImage(ini = false) {
  613. let tm_now = Date.now();
  614. if (tm_now - this.drawTm < 20) return;
  615. this.drawTm = tm_now;
  616. let cc = this.cc,
  617. imgWidth = this.useWidth * this.scaleSize,
  618. imgHeight = this.useHeight * this.scaleSize;
  619. // #ifdef MP-ALIPAY
  620. cc.save();
  621. // #endif
  622. if (this.bgImage) {
  623. // #ifdef MP-ALIPAY
  624. cc.clearRect(0, 0, this.wW, this.wH - tH);
  625. // #endif
  626. // #ifndef MP-ALIPAY
  627. cc.drawImage(this.bgImage, 0, 0, this.wW, this.wH - tH);
  628. // #endif
  629. } else {
  630. cc.fillRect(0, 0, this.wW, this.wH - tH);
  631. }
  632. if (this.isin) {
  633. let cx = this.focusX * (this.scaleSize - 1),
  634. cy = this.focusY * (this.scaleSize - 1);
  635. cc.translate(this.centerX, this.centerY);
  636. cc.rotate(this.rotateDeg * Math.PI / 180);
  637. cc.drawImage(this.imgPath, this.posWidth - this.centerX - cx, this.posHeight - this.centerY - cy,
  638. imgWidth, imgHeight);
  639. } else {
  640. cc.translate(this.posWidth + imgWidth / 2, this.posHeight + imgHeight / 2);
  641. cc.rotate(this.rotateDeg * Math.PI / 180);
  642. cc.drawImage(this.imgPath, -imgWidth / 2, -imgHeight / 2, imgWidth, imgHeight);
  643. }
  644. cc.draw(false);
  645. // #ifdef MP-ALIPAY
  646. cc.restore();
  647. // #endif
  648. },
  649. fPreview() {
  650. if (this.fPreviewing) return;
  651. this.fPreviewing = true;
  652. setTimeout(() => {
  653. this.fPreviewing = false;
  654. }, 1000);
  655. let style = this.sS,
  656. x = parseInt(style.left),
  657. y = parseInt(style.top),
  658. width = parseInt(style.width),
  659. height = parseInt(style.height);
  660. // #ifdef MP-ALIPAY
  661. uni.showLoading();
  662. // #endif
  663. // #ifndef MP-ALIPAY
  664. uni.showLoading({
  665. title: '加载中...',
  666. mask: true
  667. });
  668. // #endif
  669. // #ifdef MP-ALIPAY
  670. this.cc.toTempFilePath({
  671. x: x,
  672. y: y,
  673. width: width,
  674. height: height,
  675. expWidth: width * this.pixelRatio,
  676. expHeight: height * this.pixelRatio,
  677. fileType: this.fType,
  678. quality: this.qlty,
  679. success: (r) => {
  680. this.prvImgTmp = r = r.apFilePath;
  681. let ccp = this.ccp,
  682. prvX = this.wW,
  683. prvY = parseInt(this.csH),
  684. prvWidth = parseInt(this.sS.width),
  685. prvHeight = parseInt(this.sS.height),
  686. useWidth = prvX - 40,
  687. useHeight = prvY - 80,
  688. radio = useWidth / prvWidth,
  689. rHeight = prvHeight * radio;
  690. if (rHeight < useHeight) {
  691. prvWidth = useWidth;
  692. prvHeight = rHeight;
  693. } else {
  694. radio = useHeight / prvHeight;
  695. prvWidth *= radio;
  696. prvHeight = useHeight;
  697. }
  698. ccp.fillRect(0, 0, prvX, prvY);
  699. this.prvX = prvX = ((prvX - prvWidth) / 2) | 0;
  700. this.prvY = prvY = ((prvY - prvHeight) / 2) | 0;
  701. this.prvWidth = prvWidth = prvWidth | 0;
  702. this.prvHeight = prvHeight = prvHeight | 0;
  703. ccp.drawImage(r, prvX, prvY, prvWidth, prvHeight);
  704. ccp.draw(false);
  705. this.sO = false;
  706. this.pT = '0';
  707. },
  708. fail: () => {
  709. uni.showToast({
  710. title: "error2",
  711. duration: 2000,
  712. })
  713. },
  714. complete: () => {
  715. uni.hideLoading();
  716. }
  717. });
  718. // #endif
  719. // #ifndef MP-ALIPAY
  720. uni.canvasToTempFilePath({
  721. x: x,
  722. y: y,
  723. width: width,
  724. height: height,
  725. expWidth: width * this.pixelRatio,
  726. expHeight: height * this.pixelRatio,
  727. canvasId: 'avatar-canvas',
  728. fileType: this.fType,
  729. quality: this.qlty,
  730. success: (r) => {
  731. this.prvImgTmp = r = r.tempFilePath;
  732. let ccp = this.ccp,
  733. prvX = this.wW,
  734. prvY = parseInt(this.csH);
  735. // #ifndef H5||MP-WEIXIN||APP-PLUS
  736. prvY += tH;
  737. // #endif
  738. // #ifdef APP-PLUS
  739. if (this.platform === 'android') {
  740. prvY += tH;
  741. }
  742. // #endif
  743. let prvWidth = parseInt(this.sS.width),
  744. prvHeight = parseInt(this.sS.height),
  745. useWidth = prvX - 40,
  746. useHeight = prvY - 80,
  747. radio = useWidth / prvWidth,
  748. rHeight = prvHeight * radio;
  749. if (rHeight < useHeight) {
  750. prvWidth = useWidth;
  751. prvHeight = rHeight;
  752. } else {
  753. radio = useHeight / prvHeight;
  754. prvWidth *= radio;
  755. prvHeight = useHeight;
  756. }
  757. ccp.fillRect(0, 0, prvX, prvY);
  758. this.prvX = prvX = ((prvX - prvWidth) / 2) | 0;
  759. this.prvY = prvY = ((prvY - prvHeight) / 2) | 0;
  760. this.prvWidth = prvWidth = prvWidth | 0;
  761. this.prvHeight = prvHeight = prvHeight | 0;
  762. ccp.drawImage(r, prvX, prvY, prvWidth, prvHeight);
  763. ccp.draw(false);
  764. // #ifdef H5
  765. this.btop(r).then((r) => {
  766. this.sO = false;
  767. this.pT = this.drawTop + 'px';
  768. })
  769. // #endif
  770. this.sO = false;
  771. // if (this.platform === 'android') this.sO = false;
  772. this.pT = this.drawTop + 'px';
  773. },
  774. fail: () => {
  775. uni.showToast({
  776. title: "error2",
  777. duration: 2000,
  778. })
  779. },
  780. complete: () => {
  781. uni.hideLoading();
  782. }
  783. }, this);
  784. // #endif
  785. },
  786. fChooseImg(params = undefined, data = undefined, index = undefined, ) {
  787. if (params) {
  788. let sW = params.selWidth,
  789. sH = params.selHeight,
  790. expWidth = params.expWidth,
  791. expHeight = params.expHeight,
  792. quality = params.quality,
  793. canRotate = params.canRotate,
  794. canScale = params.canScale,
  795. minScale = params.minScale,
  796. maxScale = params.maxScale,
  797. stretch = params.stretch,
  798. fileType = params.fileType,
  799. inner = params.inner,
  800. lock = params.lock;
  801. expWidth && (this.eW = expWidth.toString().indexOf('upx') >= 0 ? parseInt(expWidth) * this.pxRatio :
  802. parseInt(
  803. expWidth));
  804. expHeight && (this.eH = expHeight.toString().indexOf('upx') >= 0 ? parseInt(expHeight) * this.pxRatio :
  805. parseInt(
  806. expHeight));
  807. this.letRotate = (canRotate === false || inner === true || inner === 'true' || canRotate === 'false') ?
  808. 0 : 1;
  809. this.letScale = (canScale === false || canScale === 'false') ? 0 : 1;
  810. this.qlty = parseFloat(quality) || 1;
  811. this.mnScale = parseFloat(minScale) || 0.3;
  812. this.mxScale = parseFloat(maxScale) || 4;
  813. this.stc = stretch;
  814. this.isin = (inner === true || inner === 'true') ? 1 : 0;
  815. this.fType = fileType === 'jpg' ? 'jpg' : 'png';
  816. this.lck = lock;
  817. if (this.isin || !this.letRotate) {
  818. this.bW = '24%';
  819. this.bD = 'none';
  820. } else {
  821. this.bW = '19%';
  822. this.bD = 'flex';
  823. }
  824. if (sW && sH) {
  825. sW = sW.toString().indexOf('upx') >= 0 ? parseInt(sW) * this.pxRatio : parseInt(sW);
  826. sH = sH.toString().indexOf('upx') >= 0 ? parseInt(sH) * this.pxRatio : parseInt(sH);
  827. this.sS.width = sW + 'px';
  828. this.sS.height = sH + 'px';
  829. this.sS.top = ((this.wH - sH - tH) | 0) / 2 + 'px';
  830. this.sS.left = ((this.wW - sW) | 0) / 2 + 'px';
  831. this.hasSel = true;
  832. }
  833. }
  834. this.rtn = data;
  835. this.indx = index;
  836. this.fSelect();
  837. },
  838. fRotate() {
  839. this.rotateDeg += 90 - this.rotateDeg % 90;
  840. this.fDrawImage();
  841. },
  842. fStart(e) {
  843. let touches = e.touches,
  844. touch0 = touches[0],
  845. touch1 = touches[1];
  846. this.touch0 = touch0;
  847. this.touch1 = touch1;
  848. if (touch1) {
  849. let x = touch1.x - touch0.x,
  850. y = touch1.y - touch0.y;
  851. this.fgDistance = Math.sqrt(x * x + y * y);
  852. }
  853. },
  854. fMove(e) {
  855. let touches = e.touches,
  856. touch0 = touches[0],
  857. touch1 = touches[1];
  858. if (touch1) {
  859. let x = touch1.x - touch0.x,
  860. y = touch1.y - touch0.y,
  861. fgDistance = Math.sqrt(x * x + y * y),
  862. scaleSize = 0.005 * (fgDistance - this.fgDistance),
  863. beScaleSize = this.scaleSize + scaleSize;
  864. do {
  865. if (!this.letScale) break;
  866. if (beScaleSize < this.mnScale) break;
  867. if (beScaleSize > this.mxScale) break;
  868. let growX = this.useWidth * scaleSize / 2,
  869. growY = this.useHeight * scaleSize / 2;
  870. if (this.isin) {
  871. let imgWidth = this.useWidth * beScaleSize,
  872. imgHeight = this.useHeight * beScaleSize,
  873. l = this.posWidth - growX,
  874. t = this.posHeight - growY,
  875. r = l + imgWidth,
  876. b = t + imgHeight,
  877. left = parseInt(this.sS.left),
  878. top = parseInt(this.sS.top),
  879. width = parseInt(this.sS.width),
  880. height = parseInt(this.sS.height),
  881. right = left + width,
  882. bottom = top + height,
  883. cx, cy;
  884. if (imgWidth <= width || imgHeight <= height) break;
  885. this.cx = cx = this.focusX * beScaleSize - this.focusX,
  886. this.cy = cy = this.focusY * beScaleSize - this.focusY;
  887. this.posWidth -= growX;
  888. this.posHeight -= growY;
  889. if (this.posWidth - cx > left) {
  890. this.posWidth = left + cx;
  891. }
  892. if (this.posWidth + imgWidth - cx < right) {
  893. this.posWidth = right - imgWidth + cx;
  894. }
  895. if (this.posHeight - cy > top) {
  896. this.posHeight = top + cy;
  897. }
  898. if (this.posHeight + imgHeight - cy < bottom) {
  899. this.posHeight = bottom - imgHeight + cy;
  900. }
  901. } else {
  902. this.posWidth -= growX;
  903. this.posHeight -= growY;
  904. }
  905. this.scaleSize = beScaleSize;
  906. } while (0);
  907. this.fgDistance = fgDistance;
  908. if (touch1.x !== touch0.x && this.letRotate) {
  909. x = (this.touch1.y - this.touch0.y) / (this.touch1.x - this.touch0.x);
  910. y = (touch1.y - touch0.y) / (touch1.x - touch0.x);
  911. this.rotateDeg += Math.atan((y - x) / (1 + x * y)) * 180 / Math.PI;
  912. this.touch0 = touch0;
  913. this.touch1 = touch1;
  914. }
  915. this.fDrawImage();
  916. } else if (this.touch0) {
  917. let x = touch0.x - this.touch0.x,
  918. y = touch0.y - this.touch0.y,
  919. beX = this.posWidth + x,
  920. beY = this.posHeight + y;
  921. if (this.isin) {
  922. let imgWidth = this.useWidth * this.scaleSize,
  923. imgHeight = this.useHeight * this.scaleSize,
  924. l = beX,
  925. t = beY,
  926. r = l + imgWidth,
  927. b = t + imgHeight,
  928. left = parseInt(this.sS.left),
  929. top = parseInt(this.sS.top),
  930. right = left + parseInt(this.sS.width),
  931. bottom = top + parseInt(this.sS.height),
  932. cx, cy;
  933. this.cx = cx = this.focusX * this.scaleSize - this.focusX;
  934. this.cy = cy = this.focusY * this.scaleSize - this.focusY;
  935. if (!this.lckWidth && Math.abs(x) < 100) {
  936. if (left < l - cx) {
  937. this.posWidth = left + cx;
  938. } else if (right > r - cx) {
  939. this.posWidth = right - imgWidth + cx;
  940. } else {
  941. this.posWidth = beX;
  942. this.focusX -= x;
  943. }
  944. }
  945. if (!this.lckHeight && Math.abs(y) < 100) {
  946. if (top < t - cy) {
  947. this.focusY -= (top + cy - this.posHeight);
  948. this.posHeight = top + cy;
  949. } else if (bottom > b - cy) {
  950. this.focusY -= (bottom + cy - (this.posHeight + imgHeight));
  951. this.posHeight = bottom - imgHeight + cy;
  952. } else {
  953. this.posHeight = beY;
  954. this.focusY -= y;
  955. }
  956. }
  957. } else {
  958. if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX;
  959. if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY;
  960. this.focusX -= x;
  961. this.focusY -= y;
  962. }
  963. this.touch0 = touch0;
  964. this.fDrawImage();
  965. }
  966. },
  967. fEnd(e) {
  968. let touches = e.touches,
  969. touch0 = touches && touches[0],
  970. touch1 = touches && touches[1];
  971. if (touch0) {
  972. this.touch0 = touch0;
  973. } else {
  974. this.touch0 = null;
  975. this.touch1 = null;
  976. }
  977. },
  978. fHideImg() {
  979. this.prvImg = '';
  980. this.pT = '-10000px';
  981. this.sO = true;
  982. this.prvImgData = null;
  983. this.target = null;
  984. },
  985. fClose() {
  986. this.sD = 'none';
  987. this.sT = '-10000px';
  988. this.hasSel = false;
  989. this.fHideImg();
  990. this.noBar || uni.showTabBar();
  991. this.$emit("end");
  992. },
  993. fGetImgData() {
  994. return new Promise((resolve, reject) => {
  995. let prvX = this.prvX,
  996. prvY = this.prvY,
  997. prvWidth = this.prvWidth,
  998. prvHeight = this.prvHeight;
  999. // #ifdef MP-ALIPAY
  1000. this.ccp.getImageData({
  1001. x: prvX,
  1002. y: prvY,
  1003. width: prvWidth,
  1004. height: prvHeight,
  1005. success(res) {
  1006. resolve(res.data);
  1007. },
  1008. fail(err) {
  1009. reject(err);
  1010. }
  1011. }, this);
  1012. // #endif
  1013. // #ifndef MP-ALIPAY
  1014. uni.canvasGetImageData({
  1015. canvasId: 'prv-canvas',
  1016. x: prvX,
  1017. y: prvY,
  1018. width: prvWidth,
  1019. height: prvHeight,
  1020. success(res) {
  1021. resolve(res.data);
  1022. },
  1023. fail(err) {
  1024. reject(err);
  1025. }
  1026. }, this);
  1027. // #endif
  1028. });
  1029. },
  1030. async fColorChange(e) {
  1031. let tm_now = Date.now();
  1032. if (tm_now - this.prvTm < 100) return;
  1033. this.prvTm = tm_now;
  1034. // #ifdef MP-ALIPAY
  1035. uni.showLoading();
  1036. // #endif
  1037. // #ifndef MP-ALIPAY
  1038. uni.showLoading({
  1039. title: '加载中...',
  1040. mask: true
  1041. });
  1042. // #endif
  1043. if (!this.prvImgData) {
  1044. if (!(this.prvImgData = await this.fGetImgData().catch(() => {
  1045. uni.showToast({
  1046. title: "error_read",
  1047. duration: 2000,
  1048. })
  1049. }))) return;
  1050. this.target = new Uint8ClampedArray(this.prvImgData.length);
  1051. }
  1052. let data = this.prvImgData,
  1053. target = this.target,
  1054. i = e.detail.value,
  1055. r, g, b, a, h, s, l, d, p, q, t, min, max, hK, tR, tG, tB;
  1056. if (i === 0) {
  1057. target = data;
  1058. } else {
  1059. i = (i + 100) / 200;
  1060. if (i < 0.005) i = 0;
  1061. if (i > 0.995) i = 1;
  1062. for (let n = data.length - 1; n >= 0; n -= 4) {
  1063. r = data[n - 3] / 255;
  1064. g = data[n - 2] / 255;
  1065. b = data[n - 1] / 255;
  1066. max = Math.max(r, g, b);
  1067. min = Math.min(r, g, b);
  1068. d = max - min;
  1069. if (max === min) {
  1070. h = 0;
  1071. } else if (max === r && g >= b) {
  1072. h = 60 * ((g - b) / d);
  1073. } else if (max === r && g < b) {
  1074. h = 60 * ((g - b) / d) + 360;
  1075. } else if (max === g) {
  1076. h = 60 * ((b - r) / d) + 120;
  1077. } else if (max === b) {
  1078. h = 60 * ((r - g) / d) + 240;
  1079. }
  1080. l = (max + min) / 2;
  1081. if (l === 0 || max === min) {
  1082. s = 0;
  1083. } else if (0 < l && l <= 0.5) {
  1084. s = d / (2 * l);
  1085. } else if (l > 0.5) {
  1086. s = d / (2 - 2 * l);
  1087. }
  1088. data[n] && (a = data[n]);
  1089. if (i < 0.5) {
  1090. s = s * i / 0.5;
  1091. } else if (i > 0.5) {
  1092. s = 2 * s + 2 * i - (s * i / 0.5) - 1;
  1093. }
  1094. if (s === 0) {
  1095. r = g = b = Math.round(l * 255);
  1096. } else {
  1097. if (l < 0.5) {
  1098. q = l * (1 + s);
  1099. } else if (l >= 0.5) {
  1100. q = l + s - (l * s);
  1101. }
  1102. p = 2 * l - q;
  1103. hK = h / 360;
  1104. tR = hK + 1 / 3;
  1105. tG = hK;
  1106. tB = hK - 1 / 3;
  1107. let correctRGB = (t) => {
  1108. if (t < 0) {
  1109. return t + 1.0;
  1110. }
  1111. if (t > 1) {
  1112. return t - 1.0;
  1113. }
  1114. return t;
  1115. };
  1116. let createRGB = (t) => {
  1117. if (t < (1 / 6)) {
  1118. return p + ((q - p) * 6 * t);
  1119. } else if (t >= (1 / 6) && t < (1 / 2)) {
  1120. return q;
  1121. } else if (t >= (1 / 2) && t < (2 / 3)) {
  1122. return p + ((q - p) * 6 * ((2 / 3) - t));
  1123. }
  1124. return p;
  1125. };
  1126. r = tR = Math.round(createRGB(correctRGB(tR)) * 255);
  1127. g = tG = Math.round(createRGB(correctRGB(tG)) * 255);
  1128. b = tB = Math.round(createRGB(correctRGB(tB)) * 255);
  1129. }
  1130. a && (target[n] = a);
  1131. target[n - 3] = r;
  1132. target[n - 2] = g;
  1133. target[n - 1] = b;
  1134. }
  1135. }
  1136. let prvX = this.prvX,
  1137. prvY = this.prvY,
  1138. prvWidth = this.prvWidth,
  1139. prvHeight = this.prvHeight;
  1140. // #ifdef MP-ALIPAY
  1141. this.ccp.putImageData({
  1142. x: prvX,
  1143. y: prvY,
  1144. width: prvWidth,
  1145. height: prvHeight,
  1146. data: target,
  1147. fail() {
  1148. uni.showToast({
  1149. title: 'error_put',
  1150. duration: 2000
  1151. })
  1152. },
  1153. complete() {
  1154. uni.hideLoading();
  1155. }
  1156. }, this);
  1157. // #endif
  1158. // #ifndef MP-ALIPAY
  1159. uni.canvasPutImageData({
  1160. canvasId: 'prv-canvas',
  1161. x: prvX,
  1162. y: prvY,
  1163. width: prvWidth,
  1164. height: prvHeight,
  1165. data: target,
  1166. fail() {
  1167. uni.showToast({
  1168. title: 'error_put',
  1169. duration: 2000
  1170. })
  1171. },
  1172. complete() {
  1173. uni.hideLoading();
  1174. }
  1175. }, this);
  1176. // #endif
  1177. },
  1178. btop(base64) {
  1179. this.base64 = base64;
  1180. return new Promise(function(resolve, reject) {
  1181. var arr = base64.split(','),
  1182. mime = arr[0].match(/:(.*?);/)[1],
  1183. bstr = atob(arr[1]),
  1184. n = bstr.length,
  1185. u8arr = new Uint8Array(n);
  1186. while (n--) {
  1187. u8arr[n] = bstr.charCodeAt(n);
  1188. }
  1189. return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([u8arr], {
  1190. type: mime
  1191. })));
  1192. });
  1193. },
  1194. }
  1195. }
  1196. </script>
  1197. <style>
  1198. .my-canvas {
  1199. display: flex;
  1200. position: fixed !important;
  1201. background: #000000;
  1202. left: 0;
  1203. z-index: 100000;
  1204. width: 100%;
  1205. }
  1206. .my-avatar {
  1207. width: 160rpx;
  1208. height: 160rpx;
  1209. }
  1210. .oper-canvas {
  1211. display: flex;
  1212. position: fixed !important;
  1213. left: 0;
  1214. z-index: 100001;
  1215. width: 100%;
  1216. }
  1217. .prv-canvas {
  1218. display: flex;
  1219. position: fixed !important;
  1220. background: #000000;
  1221. left: 0;
  1222. z-index: 200000;
  1223. width: 100%;
  1224. }
  1225. .oper-wrapper {
  1226. height: 50px;
  1227. position: fixed !important;
  1228. box-sizing: border-box;
  1229. border: 1px solid #F1F1F1;
  1230. background: #ffffff;
  1231. width: 100%;
  1232. left: 0;
  1233. bottom: 0;
  1234. z-index: 100009;
  1235. flex-direction: row;
  1236. }
  1237. .oper {
  1238. display: flex;
  1239. flex-direction: column;
  1240. justify-content: center;
  1241. padding: 10upx 20upx;
  1242. width: 100%;
  1243. height: 100%;
  1244. box-sizing: border-box;
  1245. align-self: center;
  1246. }
  1247. .btn-wrapper {
  1248. display: flex;
  1249. flex-direction: row;
  1250. /* #ifndef H5 */
  1251. flex-grow: 1;
  1252. /* #endif */
  1253. /* #ifdef H5 */
  1254. height: 50px;
  1255. /* #endif */
  1256. justify-content: space-between;
  1257. }
  1258. .btn-wrapper view {
  1259. display: flex;
  1260. align-items: center;
  1261. justify-content: center;
  1262. font-size: 16px;
  1263. color: #333;
  1264. border: 1px solid #f1f1f1;
  1265. border-radius: 6%;
  1266. }
  1267. .hover {
  1268. background: #f1f1f1;
  1269. border-radius: 6%;
  1270. }
  1271. .clr-wrapper {
  1272. display: flex;
  1273. flex-direction: row;
  1274. flex-grow: 1;
  1275. }
  1276. .clr-wrapper view {
  1277. display: flex;
  1278. align-items: center;
  1279. justify-content: center;
  1280. font-size: 16px;
  1281. color: #333;
  1282. border: 1px solid #f1f1f1;
  1283. border-radius: 6%;
  1284. }
  1285. .my-slider {
  1286. flex-grow: 1;
  1287. }
  1288. </style>