WeCropper.js 31 KB

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