You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1188 lines
31 KiB

  1. /**
  2. * we-cropper v1.3.9
  3. * (c) 2020 dlhandsome
  4. * @license MIT
  5. */
  6. (function (global, factory) {
  7. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  8. typeof define === 'function' && define.amd ? define(factory) :
  9. (global.WeCropper = factory());
  10. }(this, (function () { 'use strict';
  11. var device = void 0;
  12. var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended'];
  13. function firstLetterUpper (str) {
  14. return str.charAt(0).toUpperCase() + str.slice(1)
  15. }
  16. function setTouchState (instance) {
  17. var arg = [], len = arguments.length - 1;
  18. while ( len-- > 0 ) arg[ len ] = arguments[ len + 1 ];
  19. TOUCH_STATE.forEach(function (key, i) {
  20. if (arg[i] !== undefined) {
  21. instance[key] = arg[i];
  22. }
  23. });
  24. }
  25. function validator (instance, o) {
  26. Object.defineProperties(instance, o);
  27. }
  28. function getDevice () {
  29. if (!device) {
  30. device = wx.getSystemInfoSync();
  31. }
  32. return device
  33. }
  34. var tmp = {};
  35. var ref = getDevice();
  36. var pixelRatio = ref.pixelRatio;
  37. var DEFAULT = {
  38. id: {
  39. default: 'cropper',
  40. get: function get () {
  41. return tmp.id
  42. },
  43. set: function set (value) {
  44. if (typeof (value) !== 'string') {
  45. console.error(("id:" + value + " is invalid"));
  46. }
  47. tmp.id = value;
  48. }
  49. },
  50. width: {
  51. default: 750,
  52. get: function get () {
  53. return tmp.width
  54. },
  55. set: function set (value) {
  56. if (typeof (value) !== 'number') {
  57. console.error(("width:" + value + " is invalid"));
  58. }
  59. tmp.width = value;
  60. }
  61. },
  62. height: {
  63. default: 750,
  64. get: function get () {
  65. return tmp.height
  66. },
  67. set: function set (value) {
  68. if (typeof (value) !== 'number') {
  69. console.error(("height:" + value + " is invalid"));
  70. }
  71. tmp.height = value;
  72. }
  73. },
  74. pixelRatio: {
  75. default: pixelRatio,
  76. get: function get () {
  77. return tmp.pixelRatio
  78. },
  79. set: function set (value) {
  80. if (typeof (value) !== 'number') {
  81. console.error(("pixelRatio:" + value + " is invalid"));
  82. }
  83. tmp.pixelRatio = value;
  84. }
  85. },
  86. scale: {
  87. default: 2.5,
  88. get: function get () {
  89. return tmp.scale
  90. },
  91. set: function set (value) {
  92. if (typeof (value) !== 'number') {
  93. console.error(("scale:" + value + " is invalid"));
  94. }
  95. tmp.scale = value;
  96. }
  97. },
  98. zoom: {
  99. default: 5,
  100. get: function get () {
  101. return tmp.zoom
  102. },
  103. set: function set (value) {
  104. if (typeof (value) !== 'number') {
  105. console.error(("zoom:" + value + " is invalid"));
  106. } else if (value < 0 || value > 10) {
  107. console.error("zoom should be ranged in 0 ~ 10");
  108. }
  109. tmp.zoom = value;
  110. }
  111. },
  112. src: {
  113. default: '',
  114. get: function get () {
  115. return tmp.src
  116. },
  117. set: function set (value) {
  118. if (typeof (value) !== 'string') {
  119. console.error(("src:" + value + " is invalid"));
  120. }
  121. tmp.src = value;
  122. }
  123. },
  124. cut: {
  125. default: {},
  126. get: function get () {
  127. return tmp.cut
  128. },
  129. set: function set (value) {
  130. if (typeof (value) !== 'object') {
  131. console.error(("cut:" + value + " is invalid"));
  132. }
  133. tmp.cut = value;
  134. }
  135. },
  136. boundStyle: {
  137. default: {},
  138. get: function get () {
  139. return tmp.boundStyle
  140. },
  141. set: function set (value) {
  142. if (typeof (value) !== 'object') {
  143. console.error(("boundStyle:" + value + " is invalid"));
  144. }
  145. tmp.boundStyle = value;
  146. }
  147. },
  148. onReady: {
  149. default: null,
  150. get: function get () {
  151. return tmp.ready
  152. },
  153. set: function set (value) {
  154. tmp.ready = value;
  155. }
  156. },
  157. onBeforeImageLoad: {
  158. default: null,
  159. get: function get () {
  160. return tmp.beforeImageLoad
  161. },
  162. set: function set (value) {
  163. tmp.beforeImageLoad = value;
  164. }
  165. },
  166. onImageLoad: {
  167. default: null,
  168. get: function get () {
  169. return tmp.imageLoad
  170. },
  171. set: function set (value) {
  172. tmp.imageLoad = value;
  173. }
  174. },
  175. onBeforeDraw: {
  176. default: null,
  177. get: function get () {
  178. return tmp.beforeDraw
  179. },
  180. set: function set (value) {
  181. tmp.beforeDraw = value;
  182. }
  183. }
  184. };
  185. var ref$1 = getDevice();
  186. var windowWidth = ref$1.windowWidth;
  187. function prepare () {
  188. var self = this;
  189. // v1.4.0 版本中将不再自动绑定we-cropper实例
  190. self.attachPage = function () {
  191. var pages = getCurrentPages();
  192. // 获取到当前page上下文
  193. var pageContext = pages[pages.length - 1];
  194. // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问
  195. Object.defineProperty(pageContext, 'wecropper', {
  196. get: function get () {
  197. console.warn(
  198. 'Instance will not be automatically bound to the page after v1.4.0\n\n' +
  199. 'Please use a custom instance name instead\n\n' +
  200. 'Example: \n' +
  201. 'this.mycropper = new WeCropper(options)\n\n' +
  202. '// ...\n' +
  203. 'this.mycropper.getCropperImage()'
  204. );
  205. return self
  206. },
  207. configurable: true
  208. });
  209. };
  210. self.createCtx = function () {
  211. var id = self.id;
  212. var targetId = self.targetId;
  213. if (id) {
  214. self.ctx = self.ctx || wx.createCanvasContext(id);
  215. self.targetCtx = self.targetCtx || wx.createCanvasContext(targetId);
  216. } else {
  217. console.error("constructor: create canvas context failed, 'id' must be valuable");
  218. }
  219. };
  220. self.deviceRadio = windowWidth / 750;
  221. }
  222. var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  223. function createCommonjsModule(fn, module) {
  224. return module = { exports: {} }, fn(module, module.exports), module.exports;
  225. }
  226. var tools = createCommonjsModule(function (module, exports) {
  227. /**
  228. * String type check
  229. */
  230. exports.isStr = function (v) { return typeof v === 'string'; };
  231. /**
  232. * Number type check
  233. */
  234. exports.isNum = function (v) { return typeof v === 'number'; };
  235. /**
  236. * Array type check
  237. */
  238. exports.isArr = Array.isArray;
  239. /**
  240. * undefined type check
  241. */
  242. exports.isUndef = function (v) { return v === undefined; };
  243. exports.isTrue = function (v) { return v === true; };
  244. exports.isFalse = function (v) { return v === false; };
  245. /**
  246. * Function type check
  247. */
  248. exports.isFunc = function (v) { return typeof v === 'function'; };
  249. /**
  250. * Quick object check - this is primarily used to tell
  251. * Objects from primitive values when we know the value
  252. * is a JSON-compliant type.
  253. */
  254. exports.isObj = exports.isObject = function (obj) {
  255. return obj !== null && typeof obj === 'object'
  256. };
  257. /**
  258. * Strict object type check. Only returns true
  259. * for plain JavaScript objects.
  260. */
  261. var _toString = Object.prototype.toString;
  262. exports.isPlainObject = function (obj) {
  263. return _toString.call(obj) === '[object Object]'
  264. };
  265. /**
  266. * Check whether the object has the property.
  267. */
  268. var hasOwnProperty = Object.prototype.hasOwnProperty;
  269. exports.hasOwn = function (obj, key) {
  270. return hasOwnProperty.call(obj, key)
  271. };
  272. /**
  273. * Perform no operation.
  274. * Stubbing args to make Flow happy without leaving useless transpiled code
  275. * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)
  276. */
  277. exports.noop = function (a, b, c) {};
  278. /**
  279. * Check if val is a valid array index.
  280. */
  281. exports.isValidArrayIndex = function (val) {
  282. var n = parseFloat(String(val));
  283. return n >= 0 && Math.floor(n) === n && isFinite(val)
  284. };
  285. });
  286. var tools_7 = tools.isFunc;
  287. var tools_10 = tools.isPlainObject;
  288. var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad'];
  289. function observer () {
  290. var self = this;
  291. self.on = function (event, fn) {
  292. if (EVENT_TYPE.indexOf(event) > -1) {
  293. if (tools_7(fn)) {
  294. event === 'ready'
  295. ? fn(self)
  296. : self[("on" + (firstLetterUpper(event)))] = fn;
  297. }
  298. } else {
  299. console.error(("event: " + event + " is invalid"));
  300. }
  301. return self
  302. };
  303. }
  304. function wxPromise (fn) {
  305. return function (obj) {
  306. var args = [], len = arguments.length - 1;
  307. while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
  308. if ( obj === void 0 ) obj = {};
  309. return new Promise(function (resolve, reject) {
  310. obj.success = function (res) {
  311. resolve(res);
  312. };
  313. obj.fail = function (err) {
  314. reject(err);
  315. };
  316. fn.apply(void 0, [ obj ].concat( args ));
  317. })
  318. }
  319. }
  320. function draw (ctx, reserve) {
  321. if ( reserve === void 0 ) reserve = false;
  322. return new Promise(function (resolve) {
  323. ctx.draw(reserve, resolve);
  324. })
  325. }
  326. var getImageInfo = wxPromise(wx.getImageInfo);
  327. var canvasToTempFilePath = wxPromise(wx.canvasToTempFilePath);
  328. var base64 = createCommonjsModule(function (module, exports) {
  329. /*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */
  330. (function(root) {
  331. // Detect free variables `exports`.
  332. var freeExports = 'object' == 'object' && exports;
  333. // Detect free variable `module`.
  334. var freeModule = 'object' == 'object' && module &&
  335. module.exports == freeExports && module;
  336. // Detect free variable `global`, from Node.js or Browserified code, and use
  337. // it as `root`.
  338. var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal;
  339. if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
  340. root = freeGlobal;
  341. }
  342. /*--------------------------------------------------------------------------*/
  343. var InvalidCharacterError = function(message) {
  344. this.message = message;
  345. };
  346. InvalidCharacterError.prototype = new Error;
  347. InvalidCharacterError.prototype.name = 'InvalidCharacterError';
  348. var error = function(message) {
  349. // Note: the error messages used throughout this file match those used by
  350. // the native `atob`/`btoa` implementation in Chromium.
  351. throw new InvalidCharacterError(message);
  352. };
  353. var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  354. // http://whatwg.org/html/common-microsyntaxes.html#space-character
  355. var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g;
  356. // `decode` is designed to be fully compatible with `atob` as described in the
  357. // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob
  358. // The optimized base64-decoding algorithm used is based on @atk’s excellent
  359. // implementation. https://gist.github.com/atk/1020396
  360. var decode = function(input) {
  361. input = String(input)
  362. .replace(REGEX_SPACE_CHARACTERS, '');
  363. var length = input.length;
  364. if (length % 4 == 0) {
  365. input = input.replace(/==?$/, '');
  366. length = input.length;
  367. }
  368. if (
  369. length % 4 == 1 ||
  370. // http://whatwg.org/C#alphanumeric-ascii-characters
  371. /[^+a-zA-Z0-9/]/.test(input)
  372. ) {
  373. error(
  374. 'Invalid character: the string to be decoded is not correctly encoded.'
  375. );
  376. }
  377. var bitCounter = 0;
  378. var bitStorage;
  379. var buffer;
  380. var output = '';
  381. var position = -1;
  382. while (++position < length) {
  383. buffer = TABLE.indexOf(input.charAt(position));
  384. bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
  385. // Unless this is the first of a group of 4 characters…
  386. if (bitCounter++ % 4) {
  387. // …convert the first 8 bits to a single ASCII character.
  388. output += String.fromCharCode(
  389. 0xFF & bitStorage >> (-2 * bitCounter & 6)
  390. );
  391. }
  392. }
  393. return output;
  394. };
  395. // `encode` is designed to be fully compatible with `btoa` as described in the
  396. // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa
  397. var encode = function(input) {
  398. input = String(input);
  399. if (/[^\0-\xFF]/.test(input)) {
  400. // Note: no need to special-case astral symbols here, as surrogates are
  401. // matched, and the input is supposed to only contain ASCII anyway.
  402. error(
  403. 'The string to be encoded contains characters outside of the ' +
  404. 'Latin1 range.'
  405. );
  406. }
  407. var padding = input.length % 3;
  408. var output = '';
  409. var position = -1;
  410. var a;
  411. var b;
  412. var c;
  413. var buffer;
  414. // Make sure any padding is handled outside of the loop.
  415. var length = input.length - padding;
  416. while (++position < length) {
  417. // Read three bytes, i.e. 24 bits.
  418. a = input.charCodeAt(position) << 16;
  419. b = input.charCodeAt(++position) << 8;
  420. c = input.charCodeAt(++position);
  421. buffer = a + b + c;
  422. // Turn the 24 bits into four chunks of 6 bits each, and append the
  423. // matching character for each of them to the output.
  424. output += (
  425. TABLE.charAt(buffer >> 18 & 0x3F) +
  426. TABLE.charAt(buffer >> 12 & 0x3F) +
  427. TABLE.charAt(buffer >> 6 & 0x3F) +
  428. TABLE.charAt(buffer & 0x3F)
  429. );
  430. }
  431. if (padding == 2) {
  432. a = input.charCodeAt(position) << 8;
  433. b = input.charCodeAt(++position);
  434. buffer = a + b;
  435. output += (
  436. TABLE.charAt(buffer >> 10) +
  437. TABLE.charAt((buffer >> 4) & 0x3F) +
  438. TABLE.charAt((buffer << 2) & 0x3F) +
  439. '='
  440. );
  441. } else if (padding == 1) {
  442. buffer = input.charCodeAt(position);
  443. output += (
  444. TABLE.charAt(buffer >> 2) +
  445. TABLE.charAt((buffer << 4) & 0x3F) +
  446. '=='
  447. );
  448. }
  449. return output;
  450. };
  451. var base64 = {
  452. 'encode': encode,
  453. 'decode': decode,
  454. 'version': '0.1.0'
  455. };
  456. // Some AMD build optimizers, like r.js, check for specific condition patterns
  457. // like the following:
  458. if (
  459. typeof undefined == 'function' &&
  460. typeof undefined.amd == 'object' &&
  461. undefined.amd
  462. ) {
  463. undefined(function() {
  464. return base64;
  465. });
  466. } else if (freeExports && !freeExports.nodeType) {
  467. if (freeModule) { // in Node.js or RingoJS v0.8.0+
  468. freeModule.exports = base64;
  469. } else { // in Narwhal or RingoJS v0.7.0-
  470. for (var key in base64) {
  471. base64.hasOwnProperty(key) && (freeExports[key] = base64[key]);
  472. }
  473. }
  474. } else { // in Rhino or a web browser
  475. root.base64 = base64;
  476. }
  477. }(commonjsGlobal));
  478. });
  479. function makeURI (strData, type) {
  480. return 'data:' + type + ';base64,' + strData
  481. }
  482. function fixType (type) {
  483. type = type.toLowerCase().replace(/jpg/i, 'jpeg');
  484. var r = type.match(/png|jpeg|bmp|gif/)[0];
  485. return 'image/' + r
  486. }
  487. function encodeData (data) {
  488. var str = '';
  489. if (typeof data === 'string') {
  490. str = data;
  491. } else {
  492. for (var i = 0; i < data.length; i++) {
  493. str += String.fromCharCode(data[i]);
  494. }
  495. }
  496. return base64.encode(str)
  497. }
  498. /**
  499. * 获取图像区域隐含的像素数据
  500. * @param canvasId canvas标识
  501. * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
  502. * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
  503. * @param width 将要被提取的图像数据矩形区域的宽度
  504. * @param height 将要被提取的图像数据矩形区域的高度
  505. * @param done 完成回调
  506. */
  507. function getImageData (canvasId, x, y, width, height, done) {
  508. wx.canvasGetImageData({
  509. canvasId: canvasId,
  510. x: x,
  511. y: y,
  512. width: width,
  513. height: height,
  514. success: function success (res) {
  515. done(res, null);
  516. },
  517. fail: function fail (res) {
  518. done(null, res);
  519. }
  520. });
  521. }
  522. /**
  523. * 生成bmp格式图片
  524. * 按照规则生成图片响应头和响应体
  525. * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData
  526. * @returns {*} base64字符串
  527. */
  528. function genBitmapImage (oData) {
  529. //
  530. // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
  531. // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
  532. //
  533. var biWidth = oData.width;
  534. var biHeight = oData.height;
  535. var biSizeImage = biWidth * biHeight * 3;
  536. var bfSize = biSizeImage + 54; // total header size = 54 bytes
  537. //
  538. // typedef struct tagBITMAPFILEHEADER {
  539. // WORD bfType;
  540. // DWORD bfSize;
  541. // WORD bfReserved1;
  542. // WORD bfReserved2;
  543. // DWORD bfOffBits;
  544. // } BITMAPFILEHEADER;
  545. //
  546. var BITMAPFILEHEADER = [
  547. // WORD bfType -- The file type signature; must be "BM"
  548. 0x42, 0x4D,
  549. // DWORD bfSize -- The size, in bytes, of the bitmap file
  550. bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
  551. // WORD bfReserved1 -- Reserved; must be zero
  552. 0, 0,
  553. // WORD bfReserved2 -- Reserved; must be zero
  554. 0, 0,
  555. // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
  556. 54, 0, 0, 0
  557. ];
  558. //
  559. // typedef struct tagBITMAPINFOHEADER {
  560. // DWORD biSize;
  561. // LONG biWidth;
  562. // LONG biHeight;
  563. // WORD biPlanes;
  564. // WORD biBitCount;
  565. // DWORD biCompression;
  566. // DWORD biSizeImage;
  567. // LONG biXPelsPerMeter;
  568. // LONG biYPelsPerMeter;
  569. // DWORD biClrUsed;
  570. // DWORD biClrImportant;
  571. // } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
  572. //
  573. var BITMAPINFOHEADER = [
  574. // DWORD biSize -- The number of bytes required by the structure
  575. 40, 0, 0, 0,
  576. // LONG biWidth -- The width of the bitmap, in pixels
  577. biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
  578. // LONG biHeight -- The height of the bitmap, in pixels
  579. biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
  580. // WORD biPlanes -- The number of planes for the target device. This value must be set to 1
  581. 1, 0,
  582. // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
  583. // has a maximum of 2^24 colors (16777216, Truecolor)
  584. 24, 0,
  585. // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
  586. 0, 0, 0, 0,
  587. // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
  588. biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
  589. // LONG biXPelsPerMeter, unused
  590. 0, 0, 0, 0,
  591. // LONG biYPelsPerMeter, unused
  592. 0, 0, 0, 0,
  593. // DWORD biClrUsed, the number of color indexes of palette, unused
  594. 0, 0, 0, 0,
  595. // DWORD biClrImportant, unused
  596. 0, 0, 0, 0
  597. ];
  598. var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
  599. var aImgData = oData.data;
  600. var strPixelData = '';
  601. var biWidth4 = biWidth << 2;
  602. var y = biHeight;
  603. var fromCharCode = String.fromCharCode;
  604. do {
  605. var iOffsetY = biWidth4 * (y - 1);
  606. var strPixelRow = '';
  607. for (var x = 0; x < biWidth; x++) {
  608. var iOffsetX = x << 2;
  609. strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
  610. fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
  611. fromCharCode(aImgData[iOffsetY + iOffsetX]);
  612. }
  613. for (var c = 0; c < iPadding; c++) {
  614. strPixelRow += String.fromCharCode(0);
  615. }
  616. strPixelData += strPixelRow;
  617. } while (--y)
  618. var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
  619. return strEncoded
  620. }
  621. /**
  622. * 转换为图片base64
  623. * @param canvasId canvas标识
  624. * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
  625. * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
  626. * @param width 将要被提取的图像数据矩形区域的宽度
  627. * @param height 将要被提取的图像数据矩形区域的高度
  628. * @param type 转换图片类型
  629. * @param done 完成回调
  630. */
  631. function convertToImage (canvasId, x, y, width, height, type, done) {
  632. if ( done === void 0 ) done = function () {};
  633. if (type === undefined) { type = 'png'; }
  634. type = fixType(type);
  635. if (/bmp/.test(type)) {
  636. getImageData(canvasId, x, y, width, height, function (data, err) {
  637. var strData = genBitmapImage(data);
  638. tools_7(done) && done(makeURI(strData, 'image/' + type), err);
  639. });
  640. } else {
  641. console.error('暂不支持生成\'' + type + '\'类型的base64图片');
  642. }
  643. }
  644. var CanvasToBase64 = {
  645. convertToImage: convertToImage,
  646. // convertToPNG: function (width, height, done) {
  647. // return convertToImage(width, height, 'png', done)
  648. // },
  649. // convertToJPEG: function (width, height, done) {
  650. // return convertToImage(width, height, 'jpeg', done)
  651. // },
  652. // convertToGIF: function (width, height, done) {
  653. // return convertToImage(width, height, 'gif', done)
  654. // },
  655. convertToBMP: function (ref, done) {
  656. if ( ref === void 0 ) ref = {};
  657. var canvasId = ref.canvasId;
  658. var x = ref.x;
  659. var y = ref.y;
  660. var width = ref.width;
  661. var height = ref.height;
  662. if ( done === void 0 ) done = function () {};
  663. return convertToImage(canvasId, x, y, width, height, 'bmp', done)
  664. }
  665. };
  666. function methods () {
  667. var self = this;
  668. var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
  669. var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度
  670. var id = self.id;
  671. var targetId = self.targetId;
  672. var pixelRatio = self.pixelRatio;
  673. var ref = self.cut;
  674. var x = ref.x; if ( x === void 0 ) x = 0;
  675. var y = ref.y; if ( y === void 0 ) y = 0;
  676. var width = ref.width; if ( width === void 0 ) width = boundWidth;
  677. var height = ref.height; if ( height === void 0 ) height = boundHeight;
  678. self.updateCanvas = function (done) {
  679. if (self.croperTarget) {
  680. // 画布绘制图片
  681. self.ctx.drawImage(
  682. self.croperTarget,
  683. self.imgLeft,
  684. self.imgTop,
  685. self.scaleWidth,
  686. self.scaleHeight
  687. );
  688. }
  689. tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self);
  690. self.setBoundStyle(self.boundStyle); // 设置边界样式
  691. self.ctx.draw(false, done);
  692. return self
  693. };
  694. self.pushOrigin = self.pushOrign = function (src) {
  695. self.src = src;
  696. tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self);
  697. return getImageInfo({ src: src })
  698. .then(function (res) {
  699. var innerAspectRadio = res.width / res.height;
  700. var customAspectRadio = width / height;
  701. self.croperTarget = res.path;
  702. if (innerAspectRadio < customAspectRadio) {
  703. self.rectX = x;
  704. self.baseWidth = width;
  705. self.baseHeight = width / innerAspectRadio;
  706. self.rectY = y - Math.abs((height - self.baseHeight) / 2);
  707. } else {
  708. self.rectY = y;
  709. self.baseWidth = height * innerAspectRadio;
  710. self.baseHeight = height;
  711. self.rectX = x - Math.abs((width - self.baseWidth) / 2);
  712. }
  713. self.imgLeft = self.rectX;
  714. self.imgTop = self.rectY;
  715. self.scaleWidth = self.baseWidth;
  716. self.scaleHeight = self.baseHeight;
  717. self.update();
  718. return new Promise(function (resolve) {
  719. self.updateCanvas(resolve);
  720. })
  721. })
  722. .then(function () {
  723. tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self);
  724. })
  725. };
  726. self.removeImage = function () {
  727. self.src = '';
  728. self.croperTarget = '';
  729. return draw(self.ctx)
  730. };
  731. self.getCropperBase64 = function (done) {
  732. if ( done === void 0 ) done = function () {};
  733. CanvasToBase64.convertToBMP({
  734. canvasId: id,
  735. x: x,
  736. y: y,
  737. width: width,
  738. height: height
  739. }, done);
  740. };
  741. self.getCropperImage = function (opt, fn) {
  742. var customOptions = opt;
  743. var canvasOptions = {
  744. canvasId: id,
  745. x: x,
  746. y: y,
  747. width: width,
  748. height: height
  749. };
  750. var task = function () { return Promise.resolve(); };
  751. if (
  752. tools_10(customOptions) &&
  753. customOptions.original
  754. ) {
  755. // original mode
  756. task = function () {
  757. self.targetCtx.drawImage(
  758. self.croperTarget,
  759. self.imgLeft * pixelRatio,
  760. self.imgTop * pixelRatio,
  761. self.scaleWidth * pixelRatio,
  762. self.scaleHeight * pixelRatio
  763. );
  764. canvasOptions = {
  765. canvasId: targetId,
  766. x: x * pixelRatio,
  767. y: y * pixelRatio,
  768. width: width * pixelRatio,
  769. height: height * pixelRatio
  770. };
  771. return draw(self.targetCtx)
  772. };
  773. }
  774. return task()
  775. .then(function () {
  776. if (tools_10(customOptions)) {
  777. canvasOptions = Object.assign({}, canvasOptions, customOptions);
  778. }
  779. if (tools_7(customOptions)) {
  780. fn = customOptions;
  781. }
  782. var arg = canvasOptions.componentContext
  783. ? [canvasOptions, canvasOptions.componentContext]
  784. : [canvasOptions];
  785. return canvasToTempFilePath.apply(null, arg)
  786. })
  787. .then(function (res) {
  788. var tempFilePath = res.tempFilePath;
  789. return tools_7(fn)
  790. ? fn.call(self, tempFilePath, null)
  791. : tempFilePath
  792. })
  793. .catch(function (err) {
  794. if (tools_7(fn)) {
  795. fn.call(self, null, err);
  796. } else {
  797. throw err
  798. }
  799. })
  800. };
  801. }
  802. /**
  803. * 获取最新缩放值
  804. * @param oldScale 上一次触摸结束后的缩放值
  805. * @param oldDistance 上一次触摸结束后的双指距离
  806. * @param zoom 缩放系数
  807. * @param touch0 第一指touch对象
  808. * @param touch1 第二指touch对象
  809. * @returns {*}
  810. */
  811. var getNewScale = function (oldScale, oldDistance, zoom, touch0, touch1) {
  812. var xMove, yMove, newDistance;
  813. // 计算二指最新距离
  814. xMove = Math.round(touch1.x - touch0.x);
  815. yMove = Math.round(touch1.y - touch0.y);
  816. newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
  817. return oldScale + 0.001 * zoom * (newDistance - oldDistance)
  818. };
  819. function update () {
  820. var self = this;
  821. if (!self.src) { return }
  822. self.__oneTouchStart = function (touch) {
  823. self.touchX0 = Math.round(touch.x);
  824. self.touchY0 = Math.round(touch.y);
  825. };
  826. self.__oneTouchMove = function (touch) {
  827. var xMove, yMove;
  828. // 计算单指移动的距离
  829. if (self.touchended) {
  830. return self.updateCanvas()
  831. }
  832. xMove = Math.round(touch.x - self.touchX0);
  833. yMove = Math.round(touch.y - self.touchY0);
  834. var imgLeft = Math.round(self.rectX + xMove);
  835. var imgTop = Math.round(self.rectY + yMove);
  836. self.outsideBound(imgLeft, imgTop);
  837. self.updateCanvas();
  838. };
  839. self.__twoTouchStart = function (touch0, touch1) {
  840. var xMove, yMove, oldDistance;
  841. self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2);
  842. self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2);
  843. // 计算两指距离
  844. xMove = Math.round(touch1.x - touch0.x);
  845. yMove = Math.round(touch1.y - touch0.y);
  846. oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
  847. self.oldDistance = oldDistance;
  848. };
  849. self.__twoTouchMove = function (touch0, touch1) {
  850. var oldScale = self.oldScale;
  851. var oldDistance = self.oldDistance;
  852. var scale = self.scale;
  853. var zoom = self.zoom;
  854. self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1);
  855. // 设定缩放范围
  856. self.newScale <= 1 && (self.newScale = 1);
  857. self.newScale >= scale && (self.newScale = scale);
  858. self.scaleWidth = Math.round(self.newScale * self.baseWidth);
  859. self.scaleHeight = Math.round(self.newScale * self.baseHeight);
  860. var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2);
  861. var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2);
  862. self.outsideBound(imgLeft, imgTop);
  863. self.updateCanvas();
  864. };
  865. self.__xtouchEnd = function () {
  866. self.oldScale = self.newScale;
  867. self.rectX = self.imgLeft;
  868. self.rectY = self.imgTop;
  869. };
  870. }
  871. var handle = {
  872. // 图片手势初始监测
  873. touchStart: function touchStart (e) {
  874. var self = this;
  875. var ref = e.touches;
  876. var touch0 = ref[0];
  877. var touch1 = ref[1];
  878. if (!self.src) { return }
  879. setTouchState(self, true, null, null);
  880. // 计算第一个触摸点的位置,并参照改点进行缩放
  881. self.__oneTouchStart(touch0);
  882. // 两指手势触发
  883. if (e.touches.length >= 2) {
  884. self.__twoTouchStart(touch0, touch1);
  885. }
  886. },
  887. // 图片手势动态缩放
  888. touchMove: function touchMove (e) {
  889. var self = this;
  890. var ref = e.touches;
  891. var touch0 = ref[0];
  892. var touch1 = ref[1];
  893. if (!self.src) { return }
  894. setTouchState(self, null, true);
  895. // 单指手势时触发
  896. if (e.touches.length === 1) {
  897. self.__oneTouchMove(touch0);
  898. }
  899. // 两指手势触发
  900. if (e.touches.length >= 2) {
  901. self.__twoTouchMove(touch0, touch1);
  902. }
  903. },
  904. touchEnd: function touchEnd (e) {
  905. var self = this;
  906. if (!self.src) { return }
  907. setTouchState(self, false, false, true);
  908. self.__xtouchEnd();
  909. }
  910. };
  911. function cut () {
  912. var self = this;
  913. var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
  914. var boundHeight = self.height;
  915. // 裁剪框默认高度,即整个画布高度
  916. var ref = self.cut;
  917. var x = ref.x; if ( x === void 0 ) x = 0;
  918. var y = ref.y; if ( y === void 0 ) y = 0;
  919. var width = ref.width; if ( width === void 0 ) width = boundWidth;
  920. var height = ref.height; if ( height === void 0 ) height = boundHeight;
  921. /**
  922. * 设置边界
  923. * @param imgLeft 图片左上角横坐标值
  924. * @param imgTop 图片左上角纵坐标值
  925. */
  926. self.outsideBound = function (imgLeft, imgTop) {
  927. self.imgLeft = imgLeft >= x
  928. ? x
  929. : self.scaleWidth + imgLeft - x <= width
  930. ? x + width - self.scaleWidth
  931. : imgLeft;
  932. self.imgTop = imgTop >= y
  933. ? y
  934. : self.scaleHeight + imgTop - y <= height
  935. ? y + height - self.scaleHeight
  936. : imgTop;
  937. };
  938. /**
  939. * 设置边界样式
  940. * @param color 边界颜色
  941. */
  942. self.setBoundStyle = function (ref) {
  943. if ( ref === void 0 ) ref = {};
  944. var color = ref.color; if ( color === void 0 ) color = '#04b00f';
  945. var mask = ref.mask; if ( mask === void 0 ) mask = 'rgba(0, 0, 0, 0.3)';
  946. var lineWidth = ref.lineWidth; if ( lineWidth === void 0 ) lineWidth = 1;
  947. var half = lineWidth / 2;
  948. var boundOption = [
  949. {
  950. start: { x: x - half, y: y + 10 - half },
  951. step1: { x: x - half, y: y - half },
  952. step2: { x: x + 10 - half, y: y - half }
  953. },
  954. {
  955. start: { x: x - half, y: y + height - 10 + half },
  956. step1: { x: x - half, y: y + height + half },
  957. step2: { x: x + 10 - half, y: y + height + half }
  958. },
  959. {
  960. start: { x: x + width - 10 + half, y: y - half },
  961. step1: { x: x + width + half, y: y - half },
  962. step2: { x: x + width + half, y: y + 10 - half }
  963. },
  964. {
  965. start: { x: x + width + half, y: y + height - 10 + half },
  966. step1: { x: x + width + half, y: y + height + half },
  967. step2: { x: x + width - 10 + half, y: y + height + half }
  968. }
  969. ];
  970. // 绘制半透明层
  971. self.ctx.beginPath();
  972. self.ctx.setFillStyle(mask);
  973. self.ctx.fillRect(0, 0, x, boundHeight);
  974. self.ctx.fillRect(x, 0, width, y);
  975. self.ctx.fillRect(x, y + height, width, boundHeight - y - height);
  976. self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight);
  977. self.ctx.fill();
  978. boundOption.forEach(function (op) {
  979. self.ctx.beginPath();
  980. self.ctx.setStrokeStyle(color);
  981. self.ctx.setLineWidth(lineWidth);
  982. self.ctx.moveTo(op.start.x, op.start.y);
  983. self.ctx.lineTo(op.step1.x, op.step1.y);
  984. self.ctx.lineTo(op.step2.x, op.step2.y);
  985. self.ctx.stroke();
  986. });
  987. };
  988. }
  989. var version = "1.3.9";
  990. var WeCropper = function WeCropper (params) {
  991. var self = this;
  992. var _default = {};
  993. validator(self, DEFAULT);
  994. Object.keys(DEFAULT).forEach(function (key) {
  995. _default[key] = DEFAULT[key].default;
  996. });
  997. Object.assign(self, _default, params);
  998. self.prepare();
  999. self.attachPage();
  1000. self.createCtx();
  1001. self.observer();
  1002. self.cutt();
  1003. self.methods();
  1004. self.init();
  1005. self.update();
  1006. return self
  1007. };
  1008. WeCropper.prototype.init = function init () {
  1009. var self = this;
  1010. var src = self.src;
  1011. self.version = version;
  1012. typeof self.onReady === 'function' && self.onReady(self.ctx, self);
  1013. if (src) {
  1014. self.pushOrign(src);
  1015. } else {
  1016. self.updateCanvas();
  1017. }
  1018. setTouchState(self, false, false, false);
  1019. self.oldScale = 1;
  1020. self.newScale = 1;
  1021. return self
  1022. };
  1023. Object.assign(WeCropper.prototype, handle);
  1024. WeCropper.prototype.prepare = prepare;
  1025. WeCropper.prototype.observer = observer;
  1026. WeCropper.prototype.methods = methods;
  1027. WeCropper.prototype.cutt = cut;
  1028. WeCropper.prototype.update = update;
  1029. return WeCropper;
  1030. })));