ImageClipper.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. MWF.widget = MWF.widget || {};
  2. MWF.widget.ImageClipper = MWF.ImageClipper = new Class({
  3. Implements: [Options, Events],
  4. Extends: MWF.widget.Common,
  5. options: {
  6. "style": "default",
  7. "path": MWF.defaultPath+"/widget/$ImageClipper/",
  8. "imageUrl" : "",
  9. "editorSize" : 400, //图形容器
  10. "aspectRatio" : 1, //生成图片的宽高比, 0 表示不限制
  11. "frameMinSize" : 30, //选择框的最小宽度
  12. "previewerSize" : 300, //预览区域大小
  13. "resultMaxSize" : 800, //生成图片的最大宽或高
  14. "reference": "",
  15. "referenceType" : "",
  16. "showPreviewer" : true,
  17. "formLocalEnable" : true, //本地图片
  18. "formFileEnable" : true, //云文件图片
  19. "resetEnable" : false
  20. },
  21. initialize: function(node, options){
  22. this.node = node;
  23. this.setOptions(options);
  24. this.path = this.options.path || (MWF.defaultPath+"/widget/$ImageClipper/");
  25. this.cssPath = this.path + this.options.style+"/css.wcss";
  26. this.fileName = "untitled.png";
  27. this.fileType = "image/png";
  28. this.fileSize = null;
  29. this._loadCss();
  30. this.fireEvent("init");
  31. },
  32. load: function( imageBase64 ){
  33. this.container = new Element("div.container", { styles : this.css.container}).inject(this.node);
  34. this.container.addEvent("selectstart", function(e){
  35. e.preventDefault();
  36. e.stopPropagation();
  37. });
  38. if( !this.checkBroswer() )return;
  39. this.lastPoint=null;
  40. this.loadToolBar();
  41. this.contentNode = new Element("div.contentNode", { styles : this.css.contentNode}).inject(this.container);
  42. this.loadEditorNode();
  43. this.loadResultNode();
  44. if( this.options.imageUrl ){
  45. this.loadImageAsUrl( this.options.imageUrl );
  46. }
  47. if( imageBase64 ){
  48. this.loadImageAsFile( this.base64ToBlob( imageBase64 ) );
  49. }
  50. },
  51. uploadImage: function( success, failure ){
  52. if( this.resizedImage ){
  53. MWF.xDesktop.uploadImageByScale(
  54. this.options.reference,
  55. this.options.referenceType,
  56. 800,
  57. this.getFormData(),
  58. this.resizedImage,
  59. success,
  60. failure
  61. );
  62. }else{
  63. }
  64. },
  65. getFormData : function(){
  66. var formData = new FormData();
  67. formData.append('file',this.resizedImage, this.fileName );
  68. return formData;
  69. },
  70. getResizedImage : function(){
  71. return this.resizedImage;
  72. },
  73. getBase64Code : function(){
  74. return this.base64Code;
  75. },
  76. getBase64Image: function(){
  77. if( !this.base64Code )return null;
  78. return 'data:'+ this.fileType +';base64,' + this.base64Code;
  79. },
  80. checkBroswer : function(){
  81. if( Uint8Array && HTMLCanvasElement && atob && Blob){
  82. this.available = true;
  83. return true;
  84. }else{
  85. this.available = false;
  86. this.container.set("html", "<p>您的浏览器不支持以下特性:</p><ul><li>canvas</li><li>Blob</li><li>Uint8Array</li><li>FormData</li><li>atob</li></ul>");
  87. return false;
  88. }
  89. },
  90. close : function(){
  91. this.docBody.removeEvent("touchmove",this.bodyMouseMoveFun);
  92. this.docBody.removeEvent("mousemove",this.bodyMouseMoveFun);
  93. this.docBody.removeEvent("touchend",this.bodyMouseEndFun);
  94. this.docBody.removeEvent("mouseup",this.bodyMouseEndFun);
  95. this.container.destroy();
  96. delete this;
  97. },
  98. loadToolBar: function(){
  99. this.uploadToolbar = new Element("div.uploadToolbar", {
  100. "styles" : this.css.uploadToolbar
  101. }).inject(this.container);
  102. //var width = this.options.editorSize;
  103. //this.uploadToolbar.setStyle( "width" , width+ "px");
  104. if( this.options.formLocalEnable ){
  105. this.uploadLocalImage = new Element("button.uploadActionNode",{
  106. "styles" : this.css.uploadActionNode,
  107. "text" : "选择本地图片"
  108. }).inject(this.uploadToolbar);
  109. this.uploadLocalImage.addEvents({
  110. "click": function(){ this.fileNode.click(); }.bind(this)
  111. });
  112. this.fileNode = new Element("input.file", {
  113. "type" : "file",
  114. "accept":"images/*",
  115. "styles" : {"display":"none"}
  116. }).inject(this.container);
  117. this.fileNode.addEvent("change", function(event){
  118. var file=this.fileNode.files[0];
  119. this.fileType = file.type;
  120. this.fileName = file.name;
  121. this.fileSize = file.size;
  122. this.loadImageAsFile( file );
  123. }.bind(this));
  124. }
  125. this._createUploadButtom();
  126. if( this.options.formFileEnable ){
  127. this.uploadCloudFile = new Element("button.uploadActionNode",{
  128. "styles" : this.css.uploadActionNode,
  129. "text" : "选择云文件图片"
  130. }).inject(this.uploadToolbar);
  131. this.uploadCloudFile.addEvents({
  132. "click": function(){ this.selectFileImage(
  133. function( url, id ,attachmentInfo ){
  134. this.fileName = attachmentInfo.name;
  135. this.fileType = ["jpeg","jpg"].contains( attachmentInfo.extension.toLowerCase() ) ? "image/jpeg" : "image/png" ;
  136. this.fileSize = attachmentInfo.length;
  137. this.loadImageAsUrl( url );
  138. }.bind(this)
  139. ); }.bind(this)
  140. });
  141. }
  142. if( this.options.resetEnable ){
  143. this.resetAction = new Element("button.resetAction",{
  144. "styles" : this.css.resetActionNode,
  145. "text" : "重置"
  146. }).inject(this.uploadToolbar);
  147. this.resetAction.addEvents({
  148. "click": function(){ this.reset(); }.bind(this)
  149. });
  150. }
  151. },
  152. _createUploadButtom : function(){
  153. },
  154. reset: function(){
  155. this.fileName = "untitled.png";
  156. this.fileType = "image/png";
  157. this.fileSize = null;
  158. this.resizedImage = "";
  159. this.base64Code = "";
  160. this.resetImage();
  161. this.setFrameSize({width:0, height:0});
  162. this.frameOffset.top = 0;
  163. this.frameOffset.left = 0;
  164. this.frameNode.setStyles({
  165. top:0,
  166. left:0
  167. });
  168. this.resultNode.empty();
  169. this.editorContainer.setStyles( this.css.editorContainer );
  170. this.imageNode.setStyle("display","none");
  171. this.innerNode.setStyles({
  172. "width" : 0,
  173. "height" : 0
  174. })
  175. },
  176. selectFileImage : function( callback ){
  177. var _self = this;
  178. MWF.xDesktop.requireApp("File", "FileSelector", function(){
  179. _self.selector_cloud = new MWF.xApplication.File.FileSelector( document.body ,{
  180. "style" : "default",
  181. "title": "选择云文件图片",
  182. "copyToPublic" : false,
  183. //"reference" : _self.options.reference,
  184. //"referenceType" : _self.options.referenceType,
  185. "listStyle": "preview",
  186. "selectType" : "images",
  187. "onPostSelectAttachment" : function( url, id, attachmentInfor ){
  188. if(callback)callback(url, id, attachmentInfor );
  189. }
  190. });
  191. _self.selector_cloud.load();
  192. }, true);
  193. },
  194. loadResultNode: function(){
  195. if( this.options.showPreviewer ){
  196. this.resultContainer = new Element("div", {"styles":this.css.resultContainer}).inject(this.contentNode);
  197. var containerHeight = Math.max( this.options.editorSize ,this.options.previewerSize ) - (parseInt(this.resultContainer.getStyle("padding-left"))*2);
  198. this.resultContainer.setStyles( {
  199. "width": this.options.previewerSize+"px",
  200. "height": containerHeight +"px"
  201. } );
  202. this.resultTitleNode = new Element("div", {
  203. "styles":this.css.resultTitleNode,
  204. "text" : "预览"
  205. }
  206. ).inject(this.resultContainer);
  207. var titleHeight = this.resultTitleNode.getSize().y;
  208. var nodeHeight = this.options.aspectRatio ? ( this.options.previewerSize / this.options.aspectRatio) : this.options.previewerSize ;
  209. this.resultNode = new Element("div.resultNode", {
  210. "styles":this.css.resultNode
  211. }).inject(this.resultContainer);
  212. this.resultNode.setStyles( {
  213. "padding-top": (containerHeight-titleHeight-nodeHeight)/2 - 10 +"px"
  214. } );
  215. }else{
  216. this.resultNode = new Element("div", {
  217. styles : {display : "none"}
  218. }).inject(this.contentNode);
  219. }
  220. },
  221. loadEditorNode: function(){
  222. this.docBody = window.document.body;
  223. this.editorContainer = new Element("div.editorContainer", { styles : this.css.editorContainer}).inject(this.contentNode);
  224. this.editorContainer.setStyles( {
  225. "width": this.options.editorSize+"px",
  226. "height": this.options.editorSize+"px"
  227. } );
  228. this.editorNode = new Element("div.editorNode", { styles : this.css.editorNode}).inject(this.editorContainer);
  229. this.innerNode = new Element("div.innerNode",{ styles : this.css.innerNode } ).inject(this.editorNode);
  230. this.imageNode = new Element("img",{
  231. styles : this.css.imageNode
  232. }).inject(this.innerNode);
  233. this.imageNode.ondragstart = function(){
  234. return false;
  235. };
  236. this.frameNode = new Element("div.frameNode",{ styles : this.css.frameNode }).inject(this.innerNode);
  237. this.frameOffset={ top:0, left:0 };
  238. this.frameNode.addEvents({
  239. "touchstart" : function(ev){ this.getOffset(ev) }.bind(this),
  240. "mousedown" : function(ev){ this.getOffset(ev) }.bind(this),
  241. "touchmove" : function(ev){
  242. if(!this.lastPoint)return;
  243. var offset= this.getOffset(ev);
  244. if( this.resizeMode ){
  245. this.resizeFrames( offset );
  246. }else{
  247. this.moveFrames( offset );
  248. }
  249. ev.stopPropagation();
  250. }.bind(this),
  251. "mousemove" : function(ev){
  252. if(!this.lastPoint)return;
  253. var offset= this.getOffset(ev);
  254. if( this.resizeMode ){
  255. this.resizeFrames( offset );
  256. }else{
  257. this.moveFrames( offset );
  258. }
  259. ev.stopPropagation();
  260. }.bind(this),
  261. "touchend" : function(ev){
  262. this.lastPoint=null;
  263. if( this.resizeMode ){
  264. this.frameNode.setStyle("cursor", "move" );
  265. this.docBody.setStyle("cursor", "default" );
  266. this.resizeMode = false;
  267. }
  268. this.clipImage();
  269. ev.stopPropagation();
  270. }.bind(this),
  271. "mouseup" : function(ev){
  272. this.lastPoint=null;
  273. if( this.resizeMode ){
  274. this.frameNode.setStyle("cursor", "move" );
  275. this.docBody.setStyle("cursor", "default" );
  276. this.resizeMode = false;
  277. }
  278. this.clipImage();
  279. ev.stopPropagation();
  280. }.bind(this)
  281. });
  282. this.reizeNode = new Element("div.reizeNode",{ styles : this.css.reizeNode }).inject(this.frameNode);
  283. this.reizeNode.addEvents({
  284. "touchstart" : function(ev){
  285. this.frameNode.setStyle("cursor", "nw-resize" );
  286. this.docBody.setStyle("cursor", "nw-resize" );
  287. this.resizeMode = true;
  288. this.getOffset(ev);
  289. ev.stopPropagation();
  290. }.bind(this),
  291. "mousedown" : function(ev){
  292. this.frameNode.setStyle("cursor", "nw-resize" );
  293. this.docBody.setStyle("cursor", "nw-resize" );
  294. this.resizeMode = true;
  295. this.getOffset(ev);
  296. ev.stopPropagation();
  297. }.bind(this),
  298. "touchmove" : function(ev){
  299. if(!this.lastPoint)return;
  300. var offset= this.getOffset(ev);
  301. this.resizeFrames( offset );
  302. ev.stopPropagation();
  303. }.bind(this),
  304. "mousemove" : function(ev){
  305. if(!this.lastPoint)return;
  306. var offset= this.getOffset(ev);
  307. this.resizeFrames( offset );
  308. ev.stopPropagation();
  309. }.bind(this),
  310. "touchend" : function(ev){
  311. this.frameNode.setStyle("cursor", "move" );
  312. this.docBody.setStyle("cursor", "default" );
  313. this.resizeMode = false;
  314. this.lastPoint=null;
  315. this.clipImage();
  316. ev.stopPropagation();
  317. }.bind(this),
  318. "mouseup" : function(ev){
  319. this.frameNode.setStyle("cursor", "move" );
  320. this.docBody.setStyle("cursor", "default" );
  321. this.resizeMode = false;
  322. this.lastPoint=null;
  323. this.clipImage();
  324. ev.stopPropagation();
  325. }.bind(this)
  326. });
  327. this.bodyMouseMoveFun = this.bodyMouseMove.bind(this);
  328. this.docBody.addEvent("touchmove", this.bodyMouseMoveFun);
  329. this.docBody.addEvent("mousemove", this.bodyMouseMoveFun);
  330. this.bodyMouseEndFun = this.bodyMouseEnd.bind(this);
  331. this.docBody.addEvent("touchend", this.bodyMouseEndFun);
  332. this.docBody.addEvent("mouseup", this.bodyMouseEndFun);
  333. },
  334. bodyMouseMove: function(ev){
  335. if(!this.lastPoint)return;
  336. if( this.resizeMode ){
  337. var offset= this.getOffset(ev);
  338. this.resizeFrames( offset );
  339. }
  340. },
  341. bodyMouseEnd: function(ev){
  342. this.lastPoint=null;
  343. if( this.resizeMode ){
  344. this.frameNode.setStyle("cursor", "move" );
  345. this.docBody.setStyle("cursor", "default" );
  346. this.resizeMode = false;
  347. this.clipImage();
  348. }
  349. },
  350. clipImage: function(){
  351. this.resultNode.empty();
  352. var nh=this.imageNode.naturalHeight,
  353. nw=this.imageNode.naturalWidth,
  354. max = this.options.resultMaxSize,
  355. size,
  356. ratio;
  357. ratio = this.options.aspectRatio ? this.options.aspectRatio : (this.frameOffset.size.width / this.frameOffset.size.height );
  358. if( max == 0 || ( nh<=max && nw<=max )){
  359. size = this.getRatioMaxSize(nw, nh , ratio);
  360. }else{
  361. var min = Math.min(max, nh, nw);
  362. size = this.getRatioMaxSize(min, min, ratio);
  363. }
  364. var canvas = new Element("canvas", size);
  365. var ctx=canvas.getContext('2d'),
  366. scale=nw/this.offset.width,
  367. x=this.frameOffset.left*scale,
  368. y=this.frameOffset.top*scale,
  369. w=this.frameOffset.size.width*scale,
  370. h=this.frameOffset.size.height*scale;
  371. ctx.drawImage(this.imageNode,x,y,w,h,0,0,size.width,size.height);
  372. var src=canvas.toDataURL( this.fileType );
  373. this.canvas=canvas;
  374. canvas.inject(this.resultNode);
  375. src=src.split(',')[1];
  376. if(!src){
  377. this.resizedImage = null;
  378. this.base64Code = "";
  379. return;
  380. }
  381. this.base64Code = src;
  382. src=window.atob(src);
  383. var ia = new Uint8Array(src.length);
  384. for (var i = 0; i < src.length; i++) {
  385. ia[i] = src.charCodeAt(i);
  386. }
  387. this.resizedImage = new Blob([ia], {type: this.fileType });
  388. var min = Math.min(this.options.previewerSize, nh, nw);
  389. size = this.getRatioMaxSize(min, min, ratio);
  390. canvas.setStyles({
  391. width : size.width + "px",
  392. height : size.height + "px"
  393. });
  394. },
  395. loadImageAsFile: function( file ){
  396. this.resetImage();
  397. this.editorContainer.setStyles( this.css.editorContainer_active );
  398. this.imageNode.setStyle("display","");
  399. this.setFrameSize({width:0, height:0});
  400. this.frameOffset.top = 0;
  401. this.frameOffset.left = 0;
  402. this.frameNode.setStyles({
  403. top:0,
  404. left:0
  405. });
  406. var reader=new FileReader();
  407. reader.onload=function(){
  408. this.imageNode.src=reader.result;
  409. reader = null;
  410. //this.setImageSize();
  411. //this.setFrameSize( this.getDefaultSize() );
  412. //this.clipImage();
  413. this.onImageLoad();
  414. }.bind(this);
  415. reader.readAsDataURL(file);
  416. },
  417. loadImageAsUrl: function( url ){
  418. this.resetImage();
  419. this.editorContainer.setStyles( this.css.editorContainer_active );
  420. this.imageNode.setStyle("display","");
  421. this.setFrameSize({width:0, height:0});
  422. this.frameOffset.top = 0;
  423. this.frameOffset.left = 0;
  424. this.frameNode.setStyles({
  425. top:0,
  426. left:0
  427. });
  428. this.onImageLoadFun = this.onImageLoad.bind(this);
  429. this.imageNode.addEvent( "load",this.onImageLoadFun );
  430. this.imageNode.src = url;
  431. },
  432. onImageLoad: function(){
  433. debugger;
  434. var nh=this.imageNode.naturalHeight,
  435. nw=this.imageNode.naturalWidth;
  436. if( isNaN(nh) || isNaN(nw) || nh == 0 || nw == 0 ){
  437. setTimeout( function(){
  438. this.onImageLoad();
  439. }.bind(this), 100 );
  440. }else{
  441. this._onImageLoad();
  442. }
  443. },
  444. _onImageLoad: function(){
  445. this.setImageSize();
  446. this.setFrameSize( this.getDefaultSize() );
  447. this.clipImage();
  448. if(this.onImageLoadFun){
  449. this.imageNode.removeEvent("load", this.onImageLoadFun);
  450. this.onImageLoadFun = null;
  451. }
  452. },
  453. resetImage: function(){
  454. this.imageNode.src='';
  455. if( this.canvas )this.canvas.destroy();
  456. },
  457. setImageSize: function(){
  458. var nh=this.imageNode.naturalHeight,
  459. nw=this.imageNode.naturalWidth,
  460. size;
  461. if( nw > nh ){
  462. size = {
  463. width : this.options.editorSize,
  464. height : this.options.editorSize * (nh / nw)
  465. }
  466. }else{
  467. size = {
  468. width : this.options.editorSize * (nw / nh),
  469. height : this.options.editorSize
  470. }
  471. }
  472. //if( isNaN(size.width) || isNaN(size.height) ){
  473. // debugger;
  474. //}
  475. this.offset = size;
  476. this.imageNode.setStyles( size );
  477. },
  478. setFrameSize: function(size){
  479. this.frameOffset.size=size;
  480. return this.frameNode.setStyles({
  481. width:size.width+'px',
  482. height:size.height+'px'
  483. });
  484. },
  485. getDefaultSize: function(){
  486. this.innerNode.setStyles({
  487. "width" : this.offset.width,
  488. "height" : this.offset.height,
  489. "margin-left" : (this.options.editorSize-this.offset.width)/2 +"px",
  490. "margin-top" : (this.options.editorSize-this.offset.height)/2 +"px"
  491. });
  492. if( this.options.aspectRatio ){
  493. return this.getRatioMaxSize(this.offset.width, this.offset.height);
  494. }else{
  495. //var min = Math.min(this.offset.width, this.offset.height);
  496. //return { width : min, height : min };
  497. return {
  498. width : this.offset.width,
  499. height : this.offset.height
  500. };
  501. }
  502. },
  503. getRatioMaxSize: function( width, height , radio ){
  504. if( !radio )radio = this.options.aspectRatio;
  505. var r = width / height;
  506. if( r > radio ){
  507. return {
  508. width : height * radio,
  509. height : height
  510. }
  511. }else{
  512. return {
  513. width : width,
  514. height : width / radio
  515. }
  516. }
  517. },
  518. resizeFrames: function( offset ){
  519. var x=offset.x;
  520. if( x == 0 )return;
  521. var y=offset.y;
  522. if( y == 0 )return;
  523. var top=this.frameOffset.top,
  524. left=this.frameOffset.left,
  525. size=this.frameOffset.size,
  526. width=this.offset.width,
  527. height=this.offset.height,
  528. ratio = this.options.aspectRatio,
  529. w,
  530. h;
  531. if( ratio ){
  532. if( Math.abs(x)/Math.abs(y) > ratio ){
  533. if( x+size.width+left>width ){
  534. return;
  535. }else{
  536. w = x + size.width;
  537. h = w / ratio;
  538. if( h+top > height ){
  539. return;
  540. }
  541. }
  542. }else{
  543. if(y+size.height+top>height){
  544. return;
  545. }else{
  546. h = y+ size.height;
  547. w = h * ratio;
  548. }
  549. if( w+left > width ){
  550. return;
  551. }
  552. }
  553. }else{
  554. if( x+size.width+left>width ){
  555. return;
  556. }else{
  557. w = x + size.width
  558. }
  559. if(y+size.height+top>height){
  560. return;
  561. }else{
  562. h = y+ size.height;
  563. }
  564. }
  565. var minWidth = this.options.frameMinSize;
  566. var minHeight = ratio ? minWidth / ratio : minWidth;
  567. w=w< minWidth ?minWidth:w;
  568. h=h< minHeight ? minHeight:h;
  569. this.frameNode.setStyles({
  570. width:w+'px',
  571. height:h+'px'
  572. });
  573. this.frameOffset.size={
  574. width : w,
  575. height : h
  576. }
  577. },
  578. moveFrames: function(offset){
  579. var x=offset.x,
  580. y=offset.y,
  581. top=this.frameOffset.top,
  582. left=this.frameOffset.left,
  583. size=this.frameOffset.size,
  584. width=this.offset.width,
  585. height=this.offset.height;
  586. if(x+size.width+left>width){
  587. x=width-size.width;
  588. }else{
  589. x=x+left;
  590. }
  591. if(y+size.height+top>height){
  592. y=height-size.height;
  593. }else{
  594. y=y+top;
  595. }
  596. x=x<0?0:x;
  597. y=y<0?0:y;
  598. this.frameNode.setStyles({
  599. top:y+'px',
  600. left:x+'px'
  601. });
  602. this.frameOffset.top=y;
  603. this.frameOffset.left=x;
  604. },
  605. getOffset: function(event){
  606. event=event.event;
  607. var x,y;
  608. if(event.touches){
  609. var touch=event.touches[0];
  610. x=touch.clientX;
  611. y=touch.clientY;
  612. }else{
  613. x=event.clientX;
  614. y=event.clientY;
  615. }
  616. if(!this.lastPoint){
  617. this.lastPoint={
  618. x:x,
  619. y:y
  620. };
  621. }
  622. var offset={
  623. x:x-this.lastPoint.x,
  624. y:y-this.lastPoint.y
  625. };
  626. this.lastPoint={
  627. x:x,
  628. y:y
  629. };
  630. return offset;
  631. },
  632. base64ToBlob : function( base64 ){
  633. if( base64.substr( 0, 10 ) == 'data:image' ){
  634. var bytes=window.atob(base64.split(',')[1]); //去掉url的头,并转换为byte
  635. }else{
  636. var bytes=window.atob(base64)
  637. }
  638. //处理异常,将ascii码小于0的转换为大于0
  639. var ab = new ArrayBuffer(bytes.length);
  640. var ia = new Uint8Array(ab);
  641. for (var i = 0; i < bytes.length; i++) {
  642. ia[i] = bytes.charCodeAt(i);
  643. }
  644. return new Blob( [ab] , {type : this.fileType });
  645. }
  646. });