公司发布微信H5前端阵子刚刚弄好的H5端的图片上传插件,现在有需要裁剪图片。前端找了一个插件---cropper

本人对这插件不怎么熟悉,这个案例最好用在一个页面只有一个上传图片的功能上而且只适合单个图片上传:

本案例的主要思路是:使用H5的canvas对象,通过canvas对象调用方法把图片转换成base64上传图片

引入CSS以及js:

1 <link rel="stylesheet" href="css/cropper.css"/>
2 <link rel="stylesheet" href="css/cropper-main.css"/>
3 <script src="js/cropper.js"></script>
4 <script src="js/upload-main.js"></script>

html:

1 <div class="head-img">>
2   <input type="file" class="hidden" id="inputImage" accept="image/*" />
3 </div>

cropper.js:

   1 /*!
   2  * Cropper v0.9.2
   3  * https://github.com/fengyuanchen/cropper
   4  *
   5  * Copyright (c) 2014-2015 Fengyuan Chen and contributors
   6  * Released under the MIT license
   7  *
   8  * Date: 2015-04-18T04:35:01.500Z
   9  */
  10
  11 (function (factory) {
  12   if (typeof define === 'function' && define.amd) {
  13     // AMD. Register as anonymous module.
  14     define(['jquery'], factory);
  15   } else if (typeof exports === 'object') {
  16     // Node / CommonJS
  17     factory(require('jquery'));
  18   } else {
  19     // Browser globals.
  20     factory(jQuery);
  21   }
  22 })(function ($) {
  23
  24   'use strict';
  25
  26   var $window = $(window),
  27       $document = $(document),
  28       location = window.location,
  29
  30       // Constants
  31       CROPPER_NAMESPACE = '.cropper',
  32       CROPPER_PREVIEW = 'preview' + CROPPER_NAMESPACE,
  33
  34       // RegExps
  35       REGEXP_DRAG_TYPES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/,
  36
  37       // Classes
  38       CLASS_MODAL = 'cropper-modal',
  39       CLASS_HIDE = 'cropper-hide',
  40       CLASS_HIDDEN = 'cropper-hidden',
  41       CLASS_INVISIBLE = 'cropper-invisible',
  42       CLASS_MOVE = 'cropper-move',
  43       CLASS_CROP = 'cropper-crop',
  44       CLASS_DISABLED = 'cropper-disabled',
  45       CLASS_BG = 'cropper-bg',
  46
  47       // Events
  48       EVENT_MOUSE_DOWN = 'mousedown touchstart',
  49       EVENT_MOUSE_MOVE = 'mousemove touchmove',
  50       EVENT_MOUSE_UP = 'mouseup mouseleave touchend touchleave touchcancel',
  51       EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll',
  52       EVENT_DBLCLICK = 'dblclick',
  53       EVENT_RESIZE = 'resize' + CROPPER_NAMESPACE, // Bind to window with namespace
  54       EVENT_BUILD = 'build' + CROPPER_NAMESPACE,
  55       EVENT_BUILT = 'built' + CROPPER_NAMESPACE,
  56       EVENT_DRAG_START = 'dragstart' + CROPPER_NAMESPACE,
  57       EVENT_DRAG_MOVE = 'dragmove' + CROPPER_NAMESPACE,
  58       EVENT_DRAG_END = 'dragend' + CROPPER_NAMESPACE,
  59       EVENT_ZOOM_IN = 'zoomin' + CROPPER_NAMESPACE,
  60       EVENT_ZOOM_OUT = 'zoomout' + CROPPER_NAMESPACE,
  61
  62       // Supports
  63       SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext),
  64
  65       // Others
  66       sqrt = Math.sqrt,
  67       min = Math.min,
  68       max = Math.max,
  69       abs = Math.abs,
  70       sin = Math.sin,
  71       cos = Math.cos,
  72       num = parseFloat,
  73
  74       // Prototype
  75       prototype = {};
  76
  77   function isNumber(n) {
  78     return typeof n === 'number';
  79   }
  80
  81   function isUndefined(n) {
  82     return typeof n === 'undefined';
  83   }
  84
  85   function toArray(obj, offset) {
  86     var args = [];
  87
  88     if (isNumber(offset)) { // It's necessary for IE8
  89       args.push(offset);
  90     }
  91
  92     return args.slice.apply(obj, args);
  93   }
  94
  95   // Custom proxy to avoid jQuery's guid
  96   function proxy(fn, context) {
  97     var args = toArray(arguments, 2);
  98
  99     return function () {
 100       return fn.apply(context, args.concat(toArray(arguments)));
 101     };
 102   }
 103
 104   function isCrossOriginURL(url) {
 105     var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);
 106
 107     return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port);
 108   }
 109
 110   function addTimestamp(url) {
 111     var timestamp = 'timestamp=' + (new Date()).getTime();
 112
 113     return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
 114   }
 115
 116   function inRange(source, target) {
 117     return target.left < 0 && source.width < (target.left + target.width) && target.top < 0 && source.height < (target.top + target.height);
 118   }
 119
 120   function getRotateValue(degree) {
 121     return degree ? 'rotate(' + degree + 'deg)' : 'none';
 122   }
 123
 124   function getRotatedSizes(data, reverse) {
 125     var deg = abs(data.degree) % 180,
 126         arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180,
 127         sinArc = sin(arc),
 128         cosArc = cos(arc),
 129         width = data.width,
 130         height = data.height,
 131         aspectRatio = data.aspectRatio,
 132         newWidth,
 133         newHeight;
 134
 135     if (!reverse) {
 136       newWidth = width * cosArc + height * sinArc;
 137       newHeight = width * sinArc + height * cosArc;
 138     } else {
 139       newWidth = width / (cosArc + sinArc / aspectRatio);
 140       newHeight = newWidth / aspectRatio;
 141     }
 142
 143     return {
 144       width: newWidth,
 145       height: newHeight
 146     };
 147   }
 148
 149   function getSourceCanvas(image, data) {
 150     var canvas = $('<canvas>')[0],
 151         context = canvas.getContext('2d'),
 152         width = data.naturalWidth,
 153         height = data.naturalHeight,
 154         rotate = data.rotate,
 155         rotated = getRotatedSizes({
 156           width: width,
 157           height: height,
 158           degree: rotate
 159         });
 160
 161     if (rotate) {
 162       canvas.width = rotated.width;
 163       canvas.height = rotated.height;
 164       context.save();
 165       context.translate(rotated.width / 2, rotated.height / 2);
 166       context.rotate(rotate * Math.PI / 180);
 167       context.drawImage(image, -width / 2, -height / 2, width, height);
 168       context.restore();
 169     } else {
 170       canvas.width = width;
 171       canvas.height = height;
 172       context.drawImage(image, 0, 0, width, height);
 173     }
 174
 175     return canvas;
 176   }
 177
 178   function Cropper(element, options) {
 179     this.$element = $(element);
 180     this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
 181
 182     this.ready = false;
 183     this.built = false;
 184     this.rotated = false;
 185     this.cropped = false;
 186     this.disabled = false;
 187     this.canvas = null;
 188     this.cropBox = null;
 189
 190     this.load();
 191   }
 192
 193   prototype.load = function (url) {
 194     var options = this.options,
 195         $this = this.$element,
 196         crossOrigin,
 197         bustCacheUrl,
 198         buildEvent,
 199         $clone;
 200
 201     if (!url) {
 202       if ($this.is('img')) {
 203         if (!$this.attr('src')) {
 204           return;
 205         }
 206
 207         url = $this.prop('src');
 208       } else if ($this.is('canvas') && SUPPORT_CANVAS) {
 209         url = $this[0].toDataURL();
 210       }
 211     }
 212
 213     if (!url) {
 214       return;
 215     }
 216
 217     buildEvent = $.Event(EVENT_BUILD);
 218     $this.one(EVENT_BUILD, options.build).trigger(buildEvent); // Only trigger once
 219
 220     if (buildEvent.isDefaultPrevented()) {
 221       return;
 222     }
 223
 224     if (options.checkImageOrigin && isCrossOriginURL(url)) {
 225       crossOrigin = 'anonymous';
 226
 227       if (!$this.prop('crossOrigin')) { // Only when there was not a "crossOrigin" property
 228         bustCacheUrl = addTimestamp(url); // Bust cache (#148)
 229       }
 230     }
 231
 232     this.$clone = $clone = $('<img>');
 233
 234     $clone.one('load', $.proxy(function () {
 235       var naturalWidth = $clone.prop('naturalWidth') || $clone.width(),
 236           naturalHeight = $clone.prop('naturalHeight') || $clone.height();
 237
 238       this.image = {
 239         naturalWidth: naturalWidth,
 240         naturalHeight: naturalHeight,
 241         aspectRatio: naturalWidth / naturalHeight,
 242         rotate: 0
 243       };
 244
 245       this.url = url;
 246       this.ready = true;
 247       this.build();
 248     }, this)).one('error', function () {
 249       $clone.remove();
 250     }).attr({
 251       src: bustCacheUrl || url,
 252       crossOrigin: crossOrigin
 253     });
 254
 255     // Hide and insert into the document
 256     $clone.addClass(CLASS_HIDE).insertAfter($this);
 257   };
 258
 259   prototype.build = function () {
 260     var $this = this.$element,
 261         $clone = this.$clone,
 262         options = this.options,
 263         $cropper,
 264         $cropBox;
 265
 266     if (!this.ready) {
 267       return;
 268     }
 269
 270     if (this.built) {
 271       this.unbuild();
 272     }
 273
 274     // Create cropper elements
 275     this.$cropper = $cropper = $(Cropper.TEMPLATE);
 276
 277     // Hide the original image
 278     $this.addClass(CLASS_HIDDEN);
 279
 280     // Show the clone iamge
 281     $clone.removeClass(CLASS_HIDE);
 282
 283     this.$container = $this.parent().append($cropper);
 284     this.$canvas = $cropper.find('.cropper-canvas').append($clone);
 285     this.$dragBox = $cropper.find('.cropper-drag-box');
 286     this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
 287     this.$viewBox = $cropper.find('.cropper-view-box');
 288
 289     this.addListeners();
 290     this.initPreview();
 291
 292     // Format aspect ratio
 293     options.aspectRatio = num(options.aspectRatio) || NaN; // 0 -> NaN
 294
 295     if (options.autoCrop) {
 296       this.cropped = true;
 297
 298       if (options.modal) {
 299         this.$dragBox.addClass(CLASS_MODAL);
 300       }
 301     } else {
 302       $cropBox.addClass(CLASS_HIDDEN);
 303     }
 304
 305     if (options.background) {
 306       $cropper.addClass(CLASS_BG);
 307     }
 308
 309     if (!options.highlight) {
 310       $cropBox.find('.cropper-face').addClass(CLASS_INVISIBLE);
 311     }
 312
 313     if (!options.guides) {
 314       $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
 315     }
 316
 317     if (!options.movable) {
 318       $cropBox.find('.cropper-face').data('drag', 'move');
 319     }
 320
 321     if (!options.resizable) {
 322       $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
 323     }
 324
 325     this.setDragMode(options.dragCrop ? 'crop' : 'move');
 326
 327     this.built = true;
 328     this.render();
 329     $this.one(EVENT_BUILT, options.built).trigger(EVENT_BUILT); // Only trigger once
 330   };
 331
 332   prototype.unbuild = function () {
 333     if (!this.built) {
 334       return;
 335     }
 336
 337     this.built = false;
 338     this.container = null;
 339     this.canvas = null;
 340     this.cropBox = null; // This is necessary when replace
 341     this.removeListeners();
 342
 343     this.resetPreview();
 344     this.$preview = null;
 345
 346     this.$viewBox = null;
 347     this.$cropBox = null;
 348     this.$dragBox = null;
 349     this.$canvas = null;
 350     this.$container = null;
 351
 352     this.$cropper.remove();
 353     this.$cropper = null;
 354   };
 355
 356   $.extend(prototype, {
 357     render: function () {
 358       this.initContainer();
 359       this.initCanvas();
 360       this.initCropBox();
 361
 362       this.renderCanvas();
 363
 364       if (this.cropped) {
 365         this.renderCropBox();
 366       }
 367     },
 368
 369     initContainer: function () {
 370       var $this = this.$element,
 371           $container = this.$container,
 372           $cropper = this.$cropper,
 373           options = this.options;
 374
 375       $cropper.addClass(CLASS_HIDDEN);
 376       $this.removeClass(CLASS_HIDDEN);
 377
 378       $cropper.css((this.container = {
 379         width: max($container.width(), num(options.minContainerWidth) || 200),
 380         height: max($container.height(), num(options.minContainerHeight) || 100)
 381       }));
 382
 383       $this.addClass(CLASS_HIDDEN);
 384       $cropper.removeClass(CLASS_HIDDEN);
 385     },
 386
 387     // image box (wrapper)
 388     initCanvas: function () {
 389       var container = this.container,
 390           containerWidth = container.width,
 391           containerHeight = container.height,
 392           image = this.image,
 393           aspectRatio = image.aspectRatio,
 394           canvas = {
 395             aspectRatio: aspectRatio,
 396             width: containerWidth,
 397             height: containerHeight
 398           };
 399
 400       if (containerHeight * aspectRatio > containerWidth) {
 401         canvas.height = containerWidth / aspectRatio;
 402       } else {
 403         canvas.width = containerHeight * aspectRatio;
 404       }
 405
 406       canvas.oldLeft = canvas.left = (containerWidth - canvas.width) / 2;
 407       canvas.oldTop = canvas.top = (containerHeight - canvas.height) / 2;
 408
 409       this.canvas = canvas;
 410       this.limitCanvas(true, true);
 411       this.initialImage = $.extend({}, image);
 412       this.initialCanvas = $.extend({}, canvas);
 413     },
 414
 415     limitCanvas: function (size, position) {
 416       var options = this.options,
 417           strict = options.strict,
 418           container = this.container,
 419           containerWidth = container.width,
 420           containerHeight = container.height,
 421           canvas = this.canvas,
 422           aspectRatio = canvas.aspectRatio,
 423           cropBox = this.cropBox,
 424           cropped = this.cropped && cropBox,
 425           minCanvasWidth,
 426           minCanvasHeight;
 427
 428       if (size) {
 429         minCanvasWidth = num(options.minCanvasWidth) || 0;
 430         minCanvasHeight = num(options.minCanvasHeight) || 0;
 431
 432         if (minCanvasWidth) {
 433           if (strict) {
 434             minCanvasWidth = max(cropped ? cropBox.width : containerWidth, minCanvasWidth);
 435           }
 436
 437           minCanvasHeight = minCanvasWidth / aspectRatio;
 438         } else if (minCanvasHeight) {
 439
 440           if (strict) {
 441             minCanvasHeight = max(cropped ? cropBox.height : containerHeight, minCanvasHeight);
 442           }
 443
 444           minCanvasWidth = minCanvasHeight * aspectRatio;
 445         } else if (strict) {
 446           if (cropped) {
 447             minCanvasWidth = cropBox.width;
 448             minCanvasHeight = cropBox.height;
 449
 450             if (minCanvasHeight * aspectRatio > minCanvasWidth) {
 451               minCanvasWidth = minCanvasHeight * aspectRatio;
 452             } else {
 453               minCanvasHeight = minCanvasWidth / aspectRatio;
 454             }
 455           } else {
 456             minCanvasWidth = containerWidth;
 457             minCanvasHeight = containerHeight;
 458
 459             if (minCanvasHeight * aspectRatio > minCanvasWidth) {
 460               minCanvasHeight = minCanvasWidth / aspectRatio;
 461             } else {
 462               minCanvasWidth = minCanvasHeight * aspectRatio;
 463             }
 464           }
 465         }
 466
 467         $.extend(canvas, {
 468           minWidth: minCanvasWidth,
 469           minHeight: minCanvasHeight,
 470           maxWidth: Infinity,
 471           maxHeight: Infinity
 472         });
 473       }
 474
 475       if (position) {
 476         if (strict) {
 477           if (cropped) {
 478             canvas.minLeft = min(cropBox.left, (cropBox.left + cropBox.width) - canvas.width);
 479             canvas.minTop = min(cropBox.top, (cropBox.top + cropBox.height) - canvas.height);
 480             canvas.maxLeft = cropBox.left;
 481             canvas.maxTop = cropBox.top;
 482           } else {
 483             canvas.minLeft = min(0, containerWidth - canvas.width);
 484             canvas.minTop = min(0, containerHeight - canvas.height);
 485             canvas.maxLeft = max(0, containerWidth - canvas.width);
 486             canvas.maxTop = max(0, containerHeight - canvas.height);
 487           }
 488         } else {
 489           canvas.minLeft = -canvas.width;
 490           canvas.minTop = -canvas.height;
 491           canvas.maxLeft = containerWidth;
 492           canvas.maxTop = containerHeight;
 493         }
 494       }
 495     },
 496
 497     renderCanvas: function (changed) {
 498       var options = this.options,
 499           canvas = this.canvas,
 500           image = this.image,
 501           aspectRatio,
 502           rotated;
 503
 504       if (this.rotated) {
 505         this.rotated = false;
 506
 507         // Computes rotatation sizes with image sizes
 508         rotated = getRotatedSizes({
 509           width: image.width,
 510           height: image.height,
 511           degree: image.rotate
 512         });
 513
 514         aspectRatio = rotated.width / rotated.height;
 515
 516         if (aspectRatio !== canvas.aspectRatio) {
 517           canvas.left -= (rotated.width - canvas.width) / 2;
 518           canvas.top -= (rotated.height - canvas.height) / 2;
 519           canvas.width = rotated.width;
 520           canvas.height = rotated.height;
 521           canvas.aspectRatio = aspectRatio;
 522           this.limitCanvas(true, false);
 523         }
 524       }
 525
 526       if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) {
 527         canvas.left = canvas.oldLeft;
 528       }
 529
 530       if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) {
 531         canvas.top = canvas.oldTop;
 532       }
 533
 534       canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth);
 535       canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight);
 536
 537       this.limitCanvas(false, true);
 538
 539       canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft);
 540       canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop);
 541
 542       this.$canvas.css({
 543         width: canvas.width,
 544         height: canvas.height,
 545         left: canvas.left,
 546         top: canvas.top
 547       });
 548
 549       this.renderImage();
 550
 551       if (this.cropped && options.strict && !inRange(this.container, canvas)) {
 552         this.limitCropBox(true, true);
 553       }
 554
 555       if (changed) {
 556         this.output();
 557       }
 558     },
 559
 560     renderImage: function () {
 561       var canvas = this.canvas,
 562           image = this.image,
 563           reversed;
 564
 565       if (image.rotate) {
 566         reversed = getRotatedSizes({
 567           width: canvas.width,
 568           height: canvas.height,
 569           degree: image.rotate,
 570           aspectRatio: image.aspectRatio
 571         }, true);
 572       }
 573
 574       $.extend(image, reversed ? {
 575         width: reversed.width,
 576         height: reversed.height,
 577         left: (canvas.width - reversed.width) / 2,
 578         top: (canvas.height - reversed.height) / 2
 579       } : {
 580         width: canvas.width,
 581         height: canvas.height,
 582         left: 0,
 583         top: 0
 584       });
 585
 586       this.$clone.css({
 587         width: image.width,
 588         height: image.height,
 589         marginLeft: image.left,
 590         marginTop: image.top,
 591         transform: getRotateValue(image.rotate)
 592       });
 593     },
 594
 595     initCropBox: function () {
 596       var options = this.options,
 597           canvas = this.canvas,
 598           aspectRatio = options.aspectRatio,
 599           autoCropArea = num(options.autoCropArea) || 0.8,
 600           cropBox = {
 601             width: canvas.width,
 602             height: canvas.height
 603           };
 604
 605       if (aspectRatio) {
 606         if (canvas.height * aspectRatio > canvas.width) {
 607           cropBox.height = cropBox.width / aspectRatio;
 608         } else {
 609           cropBox.width = cropBox.height * aspectRatio;
 610         }
 611       }
 612
 613       this.cropBox = cropBox;
 614       this.limitCropBox(true, true);
 615
 616       // Initialize auto crop area
 617       cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
 618       cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);
 619
 620       // The width of auto crop area must large than "minWidth", and the height too. (#164)
 621       cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea);
 622       cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea);
 623       cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2;
 624       cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2;
 625
 626       this.initialCropBox = $.extend({}, cropBox);
 627     },
 628
 629     limitCropBox: function (size, position) {
 630       var options = this.options,
 631           strict = options.strict,
 632           container = this.container,
 633           containerWidth = container.width,
 634           containerHeight = container.height,
 635           canvas = this.canvas,
 636           cropBox = this.cropBox,
 637           aspectRatio = options.aspectRatio,
 638           minCropBoxWidth,
 639           minCropBoxHeight;
 640
 641       if (size) {
 642         minCropBoxWidth = num(options.minCropBoxWidth) || 0;
 643         minCropBoxHeight = num(options.minCropBoxHeight) || 0;
 644
 645         // min/maxCropBoxWidth/Height must less than conatiner width/height
 646         cropBox.minWidth = min(containerWidth, minCropBoxWidth);
 647         cropBox.minHeight = min(containerHeight, minCropBoxHeight);
 648         cropBox.maxWidth = min(containerWidth, strict ? canvas.width : containerWidth);
 649         cropBox.maxHeight = min(containerHeight, strict ? canvas.height : containerHeight);
 650
 651         if (aspectRatio) {
 652           // compare crop box size with container first
 653           if (cropBox.maxHeight * aspectRatio > cropBox.maxWidth) {
 654             cropBox.minHeight = cropBox.minWidth / aspectRatio;
 655             cropBox.maxHeight = cropBox.maxWidth / aspectRatio;
 656           } else {
 657             cropBox.minWidth = cropBox.minHeight * aspectRatio;
 658             cropBox.maxWidth = cropBox.maxHeight * aspectRatio;
 659           }
 660         }
 661
 662         // The "minWidth" must be less than "maxWidth", and the "minHeight" too.
 663         cropBox.minWidth = min(cropBox.maxWidth, cropBox.minWidth);
 664         cropBox.minHeight = min(cropBox.maxHeight, cropBox.minHeight);
 665       }
 666
 667       if (position) {
 668         if (strict) {
 669           cropBox.minLeft = max(0, canvas.left);
 670           cropBox.minTop = max(0, canvas.top);
 671           cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
 672           cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height;
 673         } else {
 674           cropBox.minLeft = 0;
 675           cropBox.minTop = 0;
 676           cropBox.maxLeft = containerWidth - cropBox.width;
 677           cropBox.maxTop = containerHeight - cropBox.height;
 678         }
 679       }
 680     },
 681
 682     renderCropBox: function () {
 683       var options = this.options,
 684           container = this.container,
 685           containerWidth = container.width,
 686           containerHeight = container.height,
 687           $cropBox = this.$cropBox,
 688           cropBox = this.cropBox;
 689
 690       if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
 691         cropBox.left = cropBox.oldLeft;
 692       }
 693
 694       if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) {
 695         cropBox.top = cropBox.oldTop;
 696       }
 697
 698       cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
 699       cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);
 700
 701       this.limitCropBox(false, true);
 702
 703       cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft);
 704       cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);
 705
 706       if (options.movable) {
 707         $cropBox.find('.cropper-face').data('drag', (cropBox.width === containerWidth && cropBox.height === containerHeight) ? 'move' : 'all');
 708       }
 709
 710       $cropBox.css({
 711         width: cropBox.width,
 712         height: cropBox.height,
 713         left: cropBox.left,
 714         top: cropBox.top
 715       });
 716
 717       if (this.cropped && options.strict && !inRange(container, this.canvas)) {
 718         this.limitCanvas(true, true);
 719       }
 720
 721       if (!this.disabled) {
 722         this.output();
 723       }
 724     },
 725
 726     output: function () {
 727       var options = this.options;
 728
 729       this.preview();
 730
 731       if (options.crop) {
 732         options.crop.call(this.$element, this.getData());
 733       }
 734     }
 735   });
 736
 737   prototype.initPreview = function () {
 738     var url = this.url;
 739
 740     this.$preview = $(this.options.preview);
 741     this.$viewBox.html('<img src="' + url + '">');
 742
 743     // Override img element styles
 744     // Add `display:block` to avoid margin top issue (Occur only when margin-top <= -height)
 745     this.$preview.each(function () {
 746       var $this = $(this);
 747
 748       $this.data(CROPPER_PREVIEW, {
 749         width: $this.width(),
 750         height: $this.height(),
 751         original: $this.html()
 752       }).html('<img src="' + url + '" style="display:block;width:100%;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation: 0deg!important">');
 753     });
 754   };
 755
 756   prototype.resetPreview = function () {
 757     this.$preview.each(function () {
 758       var $this = $(this);
 759
 760       $this.html($this.data(CROPPER_PREVIEW).original).removeData(CROPPER_PREVIEW);
 761     });
 762   };
 763
 764   prototype.preview = function () {
 765     var image = this.image,
 766         canvas = this.canvas,
 767         cropBox = this.cropBox,
 768         width = image.width,
 769         height = image.height,
 770         left = cropBox.left - canvas.left - image.left,
 771         top = cropBox.top - canvas.top - image.top,
 772         rotate = image.rotate;
 773
 774     if (!this.cropped || this.disabled) {
 775       return;
 776     }
 777
 778     this.$viewBox.find('img').css({
 779       width: width,
 780       height: height,
 781       marginLeft: -left,
 782       marginTop: -top,
 783       transform: getRotateValue(rotate)
 784     });
 785
 786     this.$preview.each(function () {
 787       var $this = $(this),
 788           data = $this.data(CROPPER_PREVIEW),
 789           ratio = data.width / cropBox.width,
 790           newWidth = data.width,
 791           newHeight = cropBox.height * ratio;
 792
 793       if (newHeight > data.height) {
 794         ratio = data.height / cropBox.height;
 795         newWidth = cropBox.width * ratio;
 796         newHeight = data.height;
 797       }
 798
 799       $this.width(newWidth).height(newHeight).find('img').css({
 800         width: width * ratio,
 801         height: height * ratio,
 802         marginLeft: -left * ratio,
 803         marginTop: -top * ratio,
 804         transform: getRotateValue(rotate)
 805       });
 806     });
 807   };
 808
 809   prototype.addListeners = function () {
 810     var options = this.options;
 811
 812     this.$element.on(EVENT_DRAG_START, options.dragstart).on(EVENT_DRAG_MOVE, options.dragmove).on(EVENT_DRAG_END, options.dragend).on(EVENT_ZOOM_IN, options.zoomin).on(EVENT_ZOOM_OUT, options.zoomout);
 813     this.$cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this)).on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
 814
 815     if (options.zoomable && options.mouseWheelZoom) {
 816       this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
 817     }
 818
 819     $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this)));
 820
 821     if (options.responsive) {
 822       $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
 823     }
 824   };
 825
 826   prototype.removeListeners = function () {
 827     var options = this.options;
 828
 829     this.$element.off(EVENT_DRAG_START, options.dragstart).off(EVENT_DRAG_MOVE, options.dragmove).off(EVENT_DRAG_END, options.dragend).off(EVENT_ZOOM_IN, options.zoomin).off(EVENT_ZOOM_OUT, options.zoomout);
 830     this.$cropper.off(EVENT_MOUSE_DOWN, this.dragstart).off(EVENT_DBLCLICK, this.dblclick);
 831
 832     if (options.zoomable && options.mouseWheelZoom) {
 833       this.$cropper.off(EVENT_WHEEL, this.wheel);
 834     }
 835
 836     $document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend);
 837
 838     if (options.responsive) {
 839       $window.off(EVENT_RESIZE, this._resize);
 840     }
 841   };
 842
 843   $.extend(prototype, {
 844     resize: function () {
 845       var $container = this.$container,
 846           container = this.container,
 847           canvasData,
 848           cropBoxData,
 849           ratio;
 850
 851       if (this.disabled) {
 852         return;
 853       }
 854
 855       ratio = $container.width() / container.width;
 856
 857       if (ratio !== 1 || $container.height() !== container.height) {
 858         canvasData = this.getCanvasData();
 859         cropBoxData = this.getCropBoxData();
 860
 861         this.render();
 862         this.setCanvasData($.each(canvasData, function (i, n) {
 863           canvasData[i] = n * ratio;
 864         }));
 865         this.setCropBoxData($.each(cropBoxData, function (i, n) {
 866           cropBoxData[i] = n * ratio;
 867         }));
 868       }
 869     },
 870
 871     dblclick: function () {
 872       if (this.disabled) {
 873         return;
 874       }
 875
 876       if (this.$dragBox.hasClass(CLASS_CROP)) {
 877         this.setDragMode('move');
 878       } else {
 879         this.setDragMode('crop');
 880       }
 881     },
 882
 883     wheel: function (event) {
 884       var e = event.originalEvent,
 885           delta = 1;
 886
 887       if (this.disabled) {
 888         return;
 889       }
 890
 891       event.preventDefault();
 892
 893       if (e.deltaY) {
 894         delta = e.deltaY > 0 ? 1 : -1;
 895       } else if (e.wheelDelta) {
 896         delta = -e.wheelDelta / 120;
 897       } else if (e.detail) {
 898         delta = e.detail > 0 ? 1 : -1;
 899       }
 900
 901       this.zoom(-delta * 0.1);
 902     },
 903
 904     dragstart: function (event) {
 905       var options = this.options,
 906           originalEvent = event.originalEvent,
 907           touches = originalEvent && originalEvent.touches,
 908           e = event,
 909           dragType,
 910           dragStartEvent,
 911           touchesLength;
 912
 913       if (this.disabled) {
 914         return;
 915       }
 916
 917       if (touches) {
 918         touchesLength = touches.length;
 919
 920         if (touchesLength > 1) {
 921           if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
 922             e = touches[1];
 923             this.startX2 = e.pageX;
 924             this.startY2 = e.pageY;
 925             dragType = 'zoom';
 926           } else {
 927             return;
 928           }
 929         }
 930
 931         e = touches[0];
 932       }
 933
 934       dragType = dragType || $(e.target).data('drag');
 935
 936       if (REGEXP_DRAG_TYPES.test(dragType)) {
 937         event.preventDefault();
 938
 939         dragStartEvent = $.Event(EVENT_DRAG_START, {
 940           originalEvent: originalEvent,
 941           dragType: dragType
 942         });
 943
 944         this.$element.trigger(dragStartEvent);
 945
 946         if (dragStartEvent.isDefaultPrevented()) {
 947           return;
 948         }
 949
 950         this.dragType = dragType;
 951         this.cropping = false;
 952         this.startX = e.pageX;
 953         this.startY = e.pageY;
 954
 955         if (dragType === 'crop') {
 956           this.cropping = true;
 957           this.$dragBox.addClass(CLASS_MODAL);
 958         }
 959       }
 960     },
 961
 962     dragmove: function (event) {
 963       var options = this.options,
 964           originalEvent = event.originalEvent,
 965           touches = originalEvent && originalEvent.touches,
 966           e = event,
 967           dragType = this.dragType,
 968           dragMoveEvent,
 969           touchesLength;
 970
 971       if (this.disabled) {
 972         return;
 973       }
 974
 975       if (touches) {
 976         touchesLength = touches.length;
 977
 978         if (touchesLength > 1) {
 979           if (options.zoomable && options.touchDragZoom && touchesLength === 2) {
 980             e = touches[1];
 981             this.endX2 = e.pageX;
 982             this.endY2 = e.pageY;
 983           } else {
 984             return;
 985           }
 986         }
 987
 988         e = touches[0];
 989       }
 990
 991       if (dragType) {
 992         event.preventDefault();
 993
 994         dragMoveEvent = $.Event(EVENT_DRAG_MOVE, {
 995           originalEvent: originalEvent,
 996           dragType: dragType
 997         });
 998
 999         this.$element.trigger(dragMoveEvent);
1000
1001         if (dragMoveEvent.isDefaultPrevented()) {
1002           return;
1003         }
1004
1005         this.endX = e.pageX;
1006         this.endY = e.pageY;
1007
1008         this.change();
1009       }
1010     },
1011
1012     dragend: function (event) {
1013       var dragType = this.dragType,
1014           dragEndEvent;
1015
1016       if (this.disabled) {
1017         return;
1018       }
1019
1020       if (dragType) {
1021         event.preventDefault();
1022
1023         dragEndEvent = $.Event(EVENT_DRAG_END, {
1024           originalEvent: event.originalEvent,
1025           dragType: dragType
1026         });
1027
1028         this.$element.trigger(dragEndEvent);
1029
1030         if (dragEndEvent.isDefaultPrevented()) {
1031           return;
1032         }
1033
1034         if (this.cropping) {
1035           this.cropping = false;
1036           this.$dragBox.toggleClass(CLASS_MODAL, this.cropped && this.options.modal);
1037         }
1038
1039         this.dragType = '';
1040       }
1041     }
1042   });
1043
1044   $.extend(prototype, {
1045     reset: function () {
1046       if (!this.built || this.disabled) {
1047         return;
1048       }
1049
1050       this.image = $.extend({}, this.initialImage);
1051       this.canvas = $.extend({}, this.initialCanvas);
1052       this.renderCanvas();
1053
1054       if (this.cropped) {
1055         this.cropBox = $.extend({}, this.initialCropBox);
1056         this.renderCropBox();
1057       }
1058     },
1059
1060     clear: function () {
1061       if (!this.cropped || this.disabled) {
1062         return;
1063       }
1064
1065       $.extend(this.cropBox, {
1066         left: 0,
1067         top: 0,
1068         width: 0,
1069         height: 0
1070       });
1071
1072       this.cropped = false;
1073       this.renderCropBox();
1074
1075       this.limitCanvas();
1076       this.renderCanvas(); // Render canvas after render crop box
1077
1078       this.$dragBox.removeClass(CLASS_MODAL);
1079       this.$cropBox.addClass(CLASS_HIDDEN);
1080     },
1081
1082     destroy: function () {
1083       var $this = this.$element;
1084
1085       if (this.ready) {
1086         this.unbuild();
1087         $this.removeClass(CLASS_HIDDEN);
1088       } else {
1089         this.$clone.off('load').remove();
1090       }
1091
1092       $this.removeData('cropper');
1093     },
1094
1095     replace: function (url) {
1096       if (!this.disabled && url) {
1097         this.load(url);
1098       }
1099     },
1100
1101     enable: function () {
1102       if (this.built) {
1103         this.disabled = false;
1104         this.$cropper.removeClass(CLASS_DISABLED);
1105       }
1106     },
1107
1108     disable: function () {
1109       if (this.built) {
1110         this.disabled = true;
1111         this.$cropper.addClass(CLASS_DISABLED);
1112       }
1113     },
1114
1115     move: function (offsetX, offsetY) {
1116       var canvas = this.canvas;
1117
1118       if (this.built && !this.disabled && isNumber(offsetX) && isNumber(offsetY)) {
1119         canvas.left += offsetX;
1120         canvas.top += offsetY;
1121         this.renderCanvas(true);
1122       }
1123     },
1124
1125     zoom: function (delta) {
1126       var canvas = this.canvas,
1127           zoomEvent,
1128           width,
1129           height;
1130
1131       delta = num(delta);
1132
1133       if (delta && this.built && !this.disabled && this.options.zoomable) {
1134         zoomEvent = delta > 0 ? $.Event(EVENT_ZOOM_IN) : $.Event(EVENT_ZOOM_OUT);
1135         this.$element.trigger(zoomEvent);
1136
1137         if (zoomEvent.isDefaultPrevented()) {
1138           return;
1139         }
1140
1141         delta = delta <= -1 ? 1 / (1 - delta) : delta <= 1 ? (1 + delta) : delta;
1142         width = canvas.width * delta;
1143         height = canvas.height * delta;
1144         canvas.left -= (width - canvas.width) / 2;
1145         canvas.top -= (height - canvas.height) / 2;
1146         canvas.width = width;
1147         canvas.height = height;
1148         this.renderCanvas(true);
1149         this.setDragMode('move');
1150       }
1151     },
1152
1153     rotate: function (degree) {
1154       var image = this.image;
1155
1156       degree = num(degree);
1157
1158       if (degree && this.built && !this.disabled && this.options.rotatable) {
1159         image.rotate = (image.rotate + degree) % 360;
1160         this.rotated = true;
1161         this.renderCanvas(true);
1162       }
1163     },
1164
1165     getData: function () {
1166       var cropBox = this.cropBox,
1167           canvas = this.canvas,
1168           image = this.image,
1169           ratio,
1170           data;
1171
1172       if (this.built && this.cropped) {
1173         data = {
1174           x: cropBox.left - canvas.left,
1175           y: cropBox.top - canvas.top,
1176           width: cropBox.width,
1177           height: cropBox.height
1178         };
1179
1180         ratio = image.width / image.naturalWidth;
1181
1182         $.each(data, function (i, n) {
1183           n = n / ratio;
1184           data[i] = n;
1185         });
1186
1187       } else {
1188         data = {
1189           x: 0,
1190           y: 0,
1191           width: 0,
1192           height: 0
1193         };
1194       }
1195
1196       data.rotate = image.rotate;
1197
1198       return data;
1199     },
1200
1201     getContainerData: function () {
1202       return this.built ? this.container : {};
1203     },
1204
1205     getImageData: function () {
1206       return this.ready ? this.image : {};
1207     },
1208
1209     getCanvasData: function () {
1210       var canvas = this.canvas,
1211           data;
1212
1213       if (this.built) {
1214         data = {
1215           left: canvas.left,
1216           top: canvas.top,
1217           width: canvas.width,
1218           height: canvas.height
1219         };
1220       }
1221
1222       return data || {};
1223     },
1224
1225     setCanvasData: function (data) {
1226       var canvas = this.canvas,
1227           aspectRatio = canvas.aspectRatio;
1228
1229       if (this.built && !this.disabled && $.isPlainObject(data)) {
1230         if (isNumber(data.left)) {
1231           canvas.left = data.left;
1232         }
1233
1234         if (isNumber(data.top)) {
1235           canvas.top = data.top;
1236         }
1237
1238         if (isNumber(data.width)) {
1239           canvas.width = data.width;
1240           canvas.height = data.width / aspectRatio;
1241         } else if (isNumber(data.height)) {
1242           canvas.height = data.height;
1243           canvas.width = data.height * aspectRatio;
1244         }
1245
1246         this.renderCanvas(true);
1247       }
1248     },
1249
1250     getCropBoxData: function () {
1251       var cropBox = this.cropBox,
1252           data;
1253
1254       if (this.built && this.cropped) {
1255         data = {
1256           left: cropBox.left,
1257           top: cropBox.top,
1258           width: cropBox.width,
1259           height: cropBox.height
1260         };
1261       }
1262
1263       return data || {};
1264     },
1265
1266     setCropBoxData: function (data) {
1267       var cropBox = this.cropBox,
1268           aspectRatio = this.options.aspectRatio;
1269
1270       if (this.built && this.cropped && !this.disabled && $.isPlainObject(data)) {
1271
1272         if (isNumber(data.left)) {
1273           cropBox.left = data.left;
1274         }
1275
1276         if (isNumber(data.top)) {
1277           cropBox.top = data.top;
1278         }
1279
1280         if (aspectRatio) {
1281           if (isNumber(data.width)) {
1282             cropBox.width = data.width;
1283             cropBox.height = cropBox.width / aspectRatio;
1284           } else if (isNumber(data.height)) {
1285             cropBox.height = data.height;
1286             cropBox.width = cropBox.height * aspectRatio;
1287           }
1288         } else {
1289           if (isNumber(data.width)) {
1290             cropBox.width = data.width;
1291           }
1292
1293           if (isNumber(data.height)) {
1294             cropBox.height = data.height;
1295           }
1296         }
1297
1298         this.renderCropBox();
1299       }
1300     },
1301
1302     getCroppedCanvas: function (options) {
1303       var originalWidth,
1304           originalHeight,
1305           canvasWidth,
1306           canvasHeight,
1307           scaledWidth,
1308           scaledHeight,
1309           scaledRatio,
1310           aspectRatio,
1311           canvas,
1312           context,
1313           data;
1314
1315       if (!this.built || !this.cropped || !SUPPORT_CANVAS) {
1316         return;
1317       }
1318
1319       if (!$.isPlainObject(options)) {
1320         options = {};
1321       }
1322
1323       data = this.getData();
1324       originalWidth = data.width;
1325       originalHeight = data.height;
1326       aspectRatio = originalWidth / originalHeight;
1327
1328       if ($.isPlainObject(options)) {
1329         scaledWidth = options.width;
1330         scaledHeight = options.height;
1331
1332         if (scaledWidth) {
1333           scaledHeight = scaledWidth / aspectRatio;
1334           scaledRatio = scaledWidth / originalWidth;
1335         } else if (scaledHeight) {
1336           scaledWidth = scaledHeight * aspectRatio;
1337           scaledRatio = scaledHeight / originalHeight;
1338         }
1339       }
1340
1341       canvasWidth = scaledWidth || originalWidth;
1342       canvasHeight = scaledHeight || originalHeight;
1343
1344       canvas = $('<canvas>')[0];
1345       canvas.width = canvasWidth;
1346       canvas.height = canvasHeight;
1347       context = canvas.getContext('2d');
1348
1349       if (options.fillColor) {
1350         context.fillStyle = options.fillColor;
1351         context.fillRect(0, 0, canvasWidth, canvasHeight);
1352       }
1353
1354       // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
1355       context.drawImage.apply(context, (function () {
1356         var source = getSourceCanvas(this.$clone[0], this.image),
1357             sourceWidth = source.width,
1358             sourceHeight = source.height,
1359             args = [source],
1360             srcX = data.x, // source canvas
1361             srcY = data.y,
1362             srcWidth,
1363             srcHeight,
1364             dstX, // destination canvas
1365             dstY,
1366             dstWidth,
1367             dstHeight;
1368
1369         if (srcX <= -originalWidth || srcX > sourceWidth) {
1370           srcX = srcWidth = dstX = dstWidth = 0;
1371         } else if (srcX <= 0) {
1372           dstX = -srcX;
1373           srcX = 0;
1374           srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX);
1375         } else if (srcX <= sourceWidth) {
1376           dstX = 0;
1377           srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX);
1378         }
1379
1380         if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) {
1381           srcY = srcHeight = dstY = dstHeight = 0;
1382         } else if (srcY <= 0) {
1383           dstY = -srcY;
1384           srcY = 0;
1385           srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY);
1386         } else if (srcY <= sourceHeight) {
1387           dstY = 0;
1388           srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
1389         }
1390
1391         args.push(srcX, srcY, srcWidth, srcHeight);
1392
1393         // Scale destination sizes
1394         if (scaledRatio) {
1395           dstX *= scaledRatio;
1396           dstY *= scaledRatio;
1397           dstWidth *= scaledRatio;
1398           dstHeight *= scaledRatio;
1399         }
1400
1401         // Avoid "IndexSizeError" in IE and Firefox
1402         if (dstWidth > 0 && dstHeight > 0) {
1403           args.push(dstX, dstY, dstWidth, dstHeight);
1404         }
1405
1406         return args;
1407       }).call(this));
1408
1409       return canvas;
1410     },
1411
1412     setAspectRatio: function (aspectRatio) {
1413       var options = this.options;
1414
1415       if (!this.disabled && !isUndefined(aspectRatio)) {
1416         options.aspectRatio = num(aspectRatio) || NaN; // 0 -> NaN
1417
1418         if (this.built) {
1419           this.initCropBox();
1420
1421           if (this.cropped) {
1422             this.renderCropBox();
1423           }
1424         }
1425       }
1426     },
1427
1428     setDragMode: function (mode) {
1429       var $dragBox = this.$dragBox,
1430           cropable = false,
1431           movable = false;
1432
1433       if (!this.ready || this.disabled) {
1434         return;
1435       }
1436
1437       switch (mode) {
1438         case 'crop':
1439           if (this.options.dragCrop) {
1440             cropable = true;
1441             $dragBox.data('drag', mode);
1442           } else {
1443             movable = true;
1444           }
1445
1446           break;
1447
1448         case 'move':
1449           movable = true;
1450           $dragBox.data('drag', mode);
1451
1452           break;
1453
1454         default:
1455           $dragBox.removeData('drag');
1456       }
1457
1458       $dragBox.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable);
1459     }
1460   });
1461
1462   prototype.change = function () {
1463     var dragType = this.dragType,
1464         options = this.options,
1465         canvas = this.canvas,
1466         container = this.container,
1467         cropBox = this.cropBox,
1468         width = cropBox.width,
1469         height = cropBox.height,
1470         left = cropBox.left,
1471         top = cropBox.top,
1472         right = left + width,
1473         bottom = top + height,
1474         minLeft = 0,
1475         minTop = 0,
1476         maxWidth = container.width,
1477         maxHeight = container.height,
1478         renderable = true,
1479         aspectRatio = options.aspectRatio,
1480         range = {
1481           x: this.endX - this.startX,
1482           y: this.endY - this.startY
1483         },
1484         offset;
1485
1486     if (options.strict) {
1487       minLeft = cropBox.minLeft;
1488       minTop = cropBox.minTop;
1489       maxWidth = minLeft + min(container.width, canvas.width);
1490       maxHeight = minTop + min(container.height, canvas.height);
1491     }
1492
1493     if (aspectRatio) {
1494       range.X = range.y * aspectRatio;
1495       range.Y = range.x / aspectRatio;
1496     }
1497
1498     switch (dragType) {
1499       // Move cropBox
1500       case 'all':
1501         left += range.x;
1502         top += range.y;
1503         break;
1504
1505       // Resize cropBox
1506       case 'e':
1507         if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
1508           renderable = false;
1509           break;
1510         }
1511
1512         width += range.x;
1513
1514         if (aspectRatio) {
1515           height = width / aspectRatio;
1516           top -= range.Y / 2;
1517         }
1518
1519         if (width < 0) {
1520           dragType = 'w';
1521           width = 0;
1522         }
1523
1524         break;
1525
1526       case 'n':
1527         if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) {
1528           renderable = false;
1529           break;
1530         }
1531
1532         height -= range.y;
1533         top += range.y;
1534
1535         if (aspectRatio) {
1536           width = height * aspectRatio;
1537           left += range.X / 2;
1538         }
1539
1540         if (height < 0) {
1541           dragType = 's';
1542           height = 0;
1543         }
1544
1545         break;
1546
1547       case 'w':
1548         if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) {
1549           renderable = false;
1550           break;
1551         }
1552
1553         width -= range.x;
1554         left += range.x;
1555
1556         if (aspectRatio) {
1557           height = width / aspectRatio;
1558           top += range.Y / 2;
1559         }
1560
1561         if (width < 0) {
1562           dragType = 'e';
1563           width = 0;
1564         }
1565
1566         break;
1567
1568       case 's':
1569         if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) {
1570           renderable = false;
1571           break;
1572         }
1573
1574         height += range.y;
1575
1576         if (aspectRatio) {
1577           width = height * aspectRatio;
1578           left -= range.X / 2;
1579         }
1580
1581         if (height < 0) {
1582           dragType = 'n';
1583           height = 0;
1584         }
1585
1586         break;
1587
1588       case 'ne':
1589         if (aspectRatio) {
1590           if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
1591             renderable = false;
1592             break;
1593           }
1594
1595           height -= range.y;
1596           top += range.y;
1597           width = height * aspectRatio;
1598         } else {
1599           if (range.x >= 0) {
1600             if (right < maxWidth) {
1601               width += range.x;
1602             } else if (range.y <= 0 && top <= minTop) {
1603               renderable = false;
1604             }
1605           } else {
1606             width += range.x;
1607           }
1608
1609           if (range.y <= 0) {
1610             if (top > 0) {
1611               height -= range.y;
1612               top += range.y;
1613             }
1614           } else {
1615             height -= range.y;
1616             top += range.y;
1617           }
1618         }
1619
1620         if (width < 0 && height < 0) {
1621           dragType = 'sw';
1622           height = 0;
1623           width = 0;
1624         } else if (width < 0) {
1625           dragType = 'nw';
1626           width = 0;
1627         } else if (height < 0) {
1628           dragType = 'se';
1629           height = 0;
1630         }
1631
1632         break;
1633
1634       case 'nw':
1635         if (aspectRatio) {
1636           if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
1637             renderable = false;
1638             break;
1639           }
1640
1641           height -= range.y;
1642           top += range.y;
1643           width = height * aspectRatio;
1644           left += range.X;
1645         } else {
1646           if (range.x <= 0) {
1647             if (left > 0) {
1648               width -= range.x;
1649               left += range.x;
1650             } else if (range.y <= 0 && top <= minTop) {
1651               renderable = false;
1652             }
1653           } else {
1654             width -= range.x;
1655             left += range.x;
1656           }
1657
1658           if (range.y <= 0) {
1659             if (top > 0) {
1660               height -= range.y;
1661               top += range.y;
1662             }
1663           } else {
1664             height -= range.y;
1665             top += range.y;
1666           }
1667         }
1668
1669         if (width < 0 && height < 0) {
1670           dragType = 'se';
1671           height = 0;
1672           width = 0;
1673         } else if (width < 0) {
1674           dragType = 'ne';
1675           width = 0;
1676         } else if (height < 0) {
1677           dragType = 'sw';
1678           height = 0;
1679         }
1680
1681         break;
1682
1683       case 'sw':
1684         if (aspectRatio) {
1685           if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
1686             renderable = false;
1687             break;
1688           }
1689
1690           width -= range.x;
1691           left += range.x;
1692           height = width / aspectRatio;
1693         } else {
1694           if (range.x <= 0) {
1695             if (left > 0) {
1696               width -= range.x;
1697               left += range.x;
1698             } else if (range.y >= 0 && bottom >= maxHeight) {
1699               renderable = false;
1700             }
1701           } else {
1702             width -= range.x;
1703             left += range.x;
1704           }
1705
1706           if (range.y >= 0) {
1707             if (bottom < maxHeight) {
1708               height += range.y;
1709             }
1710           } else {
1711             height += range.y;
1712           }
1713         }
1714
1715         if (width < 0 && height < 0) {
1716           dragType = 'ne';
1717           height = 0;
1718           width = 0;
1719         } else if (width < 0) {
1720           dragType = 'se';
1721           width = 0;
1722         } else if (height < 0) {
1723           dragType = 'nw';
1724           height = 0;
1725         }
1726
1727         break;
1728
1729       case 'se':
1730         if (aspectRatio) {
1731           if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
1732             renderable = false;
1733             break;
1734           }
1735
1736           width += range.x;
1737           height = width / aspectRatio;
1738         } else {
1739           if (range.x >= 0) {
1740             if (right < maxWidth) {
1741               width += range.x;
1742             } else if (range.y >= 0 && bottom >= maxHeight) {
1743               renderable = false;
1744             }
1745           } else {
1746             width += range.x;
1747           }
1748
1749           if (range.y >= 0) {
1750             if (bottom < maxHeight) {
1751               height += range.y;
1752             }
1753           } else {
1754             height += range.y;
1755           }
1756         }
1757
1758         if (width < 0 && height < 0) {
1759           dragType = 'nw';
1760           height = 0;
1761           width = 0;
1762         } else if (width < 0) {
1763           dragType = 'sw';
1764           width = 0;
1765         } else if (height < 0) {
1766           dragType = 'ne';
1767           height = 0;
1768         }
1769
1770         break;
1771
1772       // Move image
1773       case 'move':
1774         canvas.left += range.x;
1775         canvas.top += range.y;
1776         this.renderCanvas(true);
1777         renderable = false;
1778         break;
1779
1780       // Scale image
1781       case 'zoom':
1782         this.zoom(function (x1, y1, x2, y2) {
1783           var z1 = sqrt(x1 * x1 + y1 * y1),
1784               z2 = sqrt(x2 * x2 + y2 * y2);
1785
1786           return (z2 - z1) / z1;
1787         }(
1788           abs(this.startX - this.startX2),
1789           abs(this.startY - this.startY2),
1790           abs(this.endX - this.endX2),
1791           abs(this.endY - this.endY2)
1792         ));
1793
1794         this.startX2 = this.endX2;
1795         this.startY2 = this.endY2;
1796         renderable = false;
1797         break;
1798
1799       // Crop image
1800       case 'crop':
1801         if (range.x && range.y) {
1802           offset = this.$cropper.offset();
1803           left = this.startX - offset.left;
1804           top = this.startY - offset.top;
1805           width = cropBox.minWidth;
1806           height = cropBox.minHeight;
1807
1808           if (range.x > 0) {
1809             if (range.y > 0) {
1810               dragType = 'se';
1811             } else {
1812               dragType = 'ne';
1813               top -= height;
1814             }
1815           } else {
1816             if (range.y > 0) {
1817               dragType = 'sw';
1818               left -= width;
1819             } else {
1820               dragType = 'nw';
1821               left -= width;
1822               top -= height;
1823             }
1824           }
1825
1826           // Show the cropBox if is hidden
1827           if (!this.cropped) {
1828             this.cropped = true;
1829             this.$cropBox.removeClass(CLASS_HIDDEN);
1830           }
1831         }
1832
1833         break;
1834
1835       // No default
1836     }
1837
1838     if (renderable) {
1839       cropBox.width = width;
1840       cropBox.height = height;
1841       cropBox.left = left;
1842       cropBox.top = top;
1843       this.dragType = dragType;
1844
1845       this.renderCropBox();
1846     }
1847
1848     // Override
1849     this.startX = this.endX;
1850     this.startY = this.endY;
1851   };
1852
1853   $.extend(Cropper.prototype, prototype);
1854
1855   Cropper.DEFAULTS = {
1856     // Defines the aspect ratio of the crop box
1857     // Type: Number
1858     aspectRatio: NaN,
1859
1860     // Defines the percentage of automatic cropping area when initializes
1861     // Type: Number (Must large than 0 and less than 1)
1862     autoCropArea: 0.8, // 80%
1863
1864     // Outputs the cropping results.
1865     // Type: Function
1866     crop: null,
1867
1868     // Add extra containers for previewing
1869     // Type: String (jQuery selector)
1870     preview: '',
1871
1872     // Toggles
1873     strict: true, // strict mode, the image cannot zoom out less than the container
1874     responsive: true, // Rebuild when resize the window
1875     checkImageOrigin: true, // Check if the target image is cross origin
1876
1877     modal: true, // Show the black modal
1878     guides: true, // Show the dashed lines for guiding
1879     highlight: true, // Show the white modal to highlight the crop box
1880     background: true, // Show the grid background
1881
1882     autoCrop: true, // Enable to crop the image automatically when initialize
1883     dragCrop: true, // Enable to create new crop box by dragging over the image
1884     movable: true, // Enable to move the crop box
1885     resizable: true, // Enable to resize the crop box
1886     rotatable: true, // Enable to rotate the image
1887     zoomable: true, // Enable to zoom the image
1888     touchDragZoom: true, // Enable to zoom the image by wheeling mouse
1889     mouseWheelZoom: true, // Enable to zoom the image by dragging touch
1890
1891     // Dimensions
1892     minCanvasWidth: 0,
1893     minCanvasHeight: 0,
1894     minCropBoxWidth: 0,
1895     minCropBoxHeight: 0,
1896     minContainerWidth: 200,
1897     minContainerHeight: 100,
1898
1899     // Events
1900     build: null, // Function
1901     built: null, // Function
1902     dragstart: null, // Function
1903     dragmove: null, // Function
1904     dragend: null, // Function
1905     zoomin: null, // Function
1906     zoomout: null // Function
1907   };
1908
1909   Cropper.setDefaults = function (options) {
1910     $.extend(Cropper.DEFAULTS, options);
1911   };
1912
1913   // Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin)
1914   Cropper.TEMPLATE = (function (source, words) {
1915     words = words.split(',');
1916     return source.replace(/\d+/g, function (i) {
1917       return words[i];
1918     });
1919   })('<0 6="5-container"><0 6="5-canvas"></0><0 6="5-2-9" 3-2="move"></0><0 6="5-crop-9"><1 6="5-view-9"></1><1 6="5-8 8-h"></1><1 6="5-8 8-v"></1><1 6="5-face" 3-2="all"></1><1 6="5-7 7-e" 3-2="e"></1><1 6="5-7 7-n" 3-2="n"></1><1 6="5-7 7-w" 3-2="w"></1><1 6="5-7 7-s" 3-2="s"></1><1 6="5-4 4-e" 3-2="e"></1><1 6="5-4 4-n" 3-2="n"></1><1 6="5-4 4-w" 3-2="w"></1><1 6="5-4 4-s" 3-2="s"></1><1 6="5-4 4-ne" 3-2="ne"></1><1 6="5-4 4-nw" 3-2="nw"></1><1 6="5-4 4-sw" 3-2="sw"></1><1 6="5-4 4-se" 3-2="se"></1></0></0>', 'div,span,drag,data,point,cropper,class,line,dashed,box');
1920
1921   /* Template source:
1922   <div class="cropper-container">
1923     <div class="cropper-canvas"></div>
1924     <div class="cropper-drag-box" data-drag="move"></div>
1925     <div class="cropper-crop-box">
1926       <span class="cropper-view-box"></span>
1927       <span class="cropper-dashed dashed-h"></span>
1928       <span class="cropper-dashed dashed-v"></span>
1929       <span class="cropper-face" data-drag="all"></span>
1930       <span class="cropper-line line-e" data-drag="e"></span>
1931       <span class="cropper-line line-n" data-drag="n"></span>
1932       <span class="cropper-line line-w" data-drag="w"></span>
1933       <span class="cropper-line line-s" data-drag="s"></span>
1934       <span class="cropper-point point-e" data-drag="e"></span>
1935       <span class="cropper-point point-n" data-drag="n"></span>
1936       <span class="cropper-point point-w" data-drag="w"></span>
1937       <span class="cropper-point point-s" data-drag="s"></span>
1938       <span class="cropper-point point-ne" data-drag="ne"></span>
1939       <span class="cropper-point point-nw" data-drag="nw"></span>
1940       <span class="cropper-point point-sw" data-drag="sw"></span>
1941       <span class="cropper-point point-se" data-drag="se"></span>
1942     </div>
1943   </div>
1944   */
1945
1946   // Save the other cropper
1947   Cropper.other = $.fn.cropper;
1948
1949   // Register as jQuery plugin
1950   $.fn.cropper = function (options) {
1951     var args = toArray(arguments, 1),
1952         result;
1953
1954     this.each(function () {
1955       var $this = $(this),
1956           data = $this.data('cropper'),
1957           fn;
1958
1959       if (!data) {
1960         $this.data('cropper', (data = new Cropper(this, options)));
1961       }
1962
1963       if (typeof options === 'string' && $.isFunction((fn = data[options]))) {
1964         result = fn.apply(data, args);
1965       }
1966     });
1967
1968     return isUndefined(result) ? this : result;
1969   };
1970
1971   $.fn.cropper.Constructor = Cropper;
1972   $.fn.cropper.setDefaults = Cropper.setDefaults;
1973
1974   // No conflict
1975   $.fn.cropper.noConflict = function () {
1976     $.fn.cropper = Cropper.other;
1977     return this;
1978   };
1979
1980 });

核心的js:(js里面,最主要的一个方法)upload-main.js

  1 $(function () {
  2
  3   'use strict';
  4
  5   var console = window.console || { log: function () {} },
  6       $alert = $('.docs-alert'),
  7       $message = $alert.find('.message'),
  8       showMessage = function (message, type) {
  9         $message.text(message);
 10
 11         if (type) {
 12           $message.addClass(type);
 13         }
 14
 15         $alert.fadeIn();
 16
 17         setTimeout(function () {
 18           $alert.fadeOut();
 19         }, 3000);
 20       };
 21
 22   // Demo
 23   // -------------------------------------------------------------------------
 24
 25   (function () {
 26     var $image = $('.img-container > img'),
 27         $dataX = $('#dataX'),
 28         $dataY = $('#dataY'),
 29         $dataHeight = $('#dataHeight'),
 30         $dataWidth = $('#dataWidth'),
 31         $dataRotate = $('#dataRotate'),
 32         options = {
 33
 34
 35           aspectRatio: 1 / 1,
 36           preview: '.img-preview',
 37           crop: function (data) {
 38             $dataX.val(Math.round(data.x));
 39             $dataY.val(Math.round(data.y));
 40             $dataHeight.val(Math.round(data.height));
 41             $dataWidth.val(Math.round(data.width));
 42             $dataRotate.val(Math.round(data.rotate));
 43           }
 44         };
 45
 46     $image.on({
 47       'build.cropper': function (e) {
 48         console.log(e.type);
 49       },
 50       'built.cropper': function (e) {
 51         console.log(e.type);
 52       },
 53       'dragstart.cropper': function (e) {
 54         console.log(e.type, e.dragType);
 55       },
 56       'dragmove.cropper': function (e) {
 57         console.log(e.type, e.dragType);
 58       },
 59       'dragend.cropper': function (e) {
 60         console.log(e.type, e.dragType);
 61       },
 62       'zoomin.cropper': function (e) {
 63         console.log(e.type);
 64       },
 65       'zoomout.cropper': function (e) {
 66         console.log(e.type);
 67       }
 68     }).cropper(options);
 69
 70
 71     // Methods
 72     $(document.body).on('click', '[data-method]', function () {//可以在这里处理对选择的文件进行判断,
 73       var data = $(this).data(),
 74           $target,
 75           result;
 76
 77       if (data.method) {
 78         data = $.extend({}, data); // Clone a new one
 79
 80         if (typeof data.target !== 'undefined') {
 81           $target = $(data.target);
 82
 83           if (typeof data.option === 'undefined') {
 84             try {
 85               data.option = JSON.parse($target.val());
 86             } catch (e) {
 87               console.log(e.message);
 88             }
 89           }
 90         }
 91
 92         result = $image.cropper(data.method, data.option);
 93         $("#base64ImgData").val(result.toDataURL('image/jpeg'));//这里可以保存你将上传的base64格式的图片(核心的方法toDataURL,还有,这个方法静态页面调用会保存,需要放到服务器上面运行)
 94         if (data.method === 'getCroppedCanvas') {
 95           $('.img-preview img').attr('src', result.toDataURL('image/jpeg'));
 96         }
 97
 98         if ($.isPlainObject(result) && $target) {
 99           try {
100             $target.val(JSON.stringify(result));
101           } catch (e) {
102             console.log(e.message);
103           }
104         }
105
106       }//这后面是我处理的逻辑
107       $('.step2').hide();
108       $('.modal').show();
109       $.DialogByZ.Loading('../images/wechat/loading.png');
110       $.ajax({
111         cache:false,
112         type:"post",
113         data:"base64="+result.toDataURL('image/jpeg')+"&filePath=user",
114         url:"wechatPersonalCenterAction_updateHeadPortraitByBase64.do",
115         success:function(data, textStatus){
116             debugger;
117             if(data != '0'){
118                 $('.modal').hide();
119                 $('.zbox-uploading').hide();
120                 $.DialogByZ.Autofade({Content: "上传成功!"});
121                 $(".head-img").attr("style", "background-image:url('http://m.uecun.com/uecun/attachfiles/user/"+$("#universalid").val()+"/"+data+"');");
122
123             }
124         },
125         error:function(XMLHttpRequest, textStatus, errorThrown){}
126     });
127     }).on('keydown', function (e) {
128
129       switch (e.which) {
130         case 37:
131           e.preventDefault();
132           $image.cropper('move', -1, 0);
133           break;
134
135         case 38:
136           e.preventDefault();
137           $image.cropper('move', 0, -1);
138           break;
139
140         case 39:
141           e.preventDefault();
142           $image.cropper('move', 1, 0);
143           break;
144
145         case 40:
146           e.preventDefault();
147           $image.cropper('move', 0, 1);
148           break;
149       }
150
151     });
152
153
154     // Import image
155     var $inputImage = $('#inputImage'),
156         URL = window.URL || window.webkitURL,
157         blobURL;
158
159
160
161     if (URL) {
162       $inputImage.change(function () {//或者这里可以对图片进行验证
163
164         var docObj = document.getElementById("inputImage");
165 //            return;
166         if (typeof(docObj.files[0]) == "undefined") {
167             $.DialogByZ.Autofade({Content: "请选择要上传的图片"});
168             return false;
169         } else {
170             if (docObj.files[0].size>2560000) {
171                 $.DialogByZ.Autofade({Content: "上传文件大小不能大于2M"});
172                 return false;
173             }
174             var name = docObj.value;
175             var fileName = name.substring(name.lastIndexOf(".")+1).toLowerCase();
176             if (fileName!="jpg" && fileName!="png" && fileName!="gif") {
177                 $.DialogByZ.Autofade({Content: "上传文件格式不对"});
178                 return false;
179             }
180         }
181         var files = this.files,
182             file;
183         console.info(URL,files);
184
185         if (files && files.length) {
186           file = files[0];
187           $('.step2').show();
188 //          $('.step2').fadeIn(500);
189           if (/^image\/\w+$/.test(file.type)) {
190             blobURL = URL.createObjectURL(file);
191             $image.one('built.cropper', function () {
192               URL.revokeObjectURL(blobURL); // Revoke when load complete
193             }).cropper('reset', true).cropper('replace', blobURL);
194             $inputImage.val('');
195           } else {
196             showMessage('Please choose an image file.');
197           }
198
199         }
200       });
201     } else {
202       $inputImage.parent().remove();
203     }
204
205
206     // Options
207     $('.docs-options :checkbox').on('change', function () {
208       var $this = $(this);
209
210       options[$this.val()] = $this.prop('checked');
211       $image.cropper('destroy').cropper(options);
212     });
213
214
215     // Tooltips
216     //$('[data-toggle="tooltip"]').tooltip();
217
218   }());
219
220 });

java后台代码:

 1 /**
 2      * 用户h5头像上传
 3      */
 4     public void updateHeadPortraitByBase64(){
 5         try {
 6             response.setCharacterEncoding("utf-8");
 7             String iconBase64 = request.getParameter("base64");//需要把 data:image/jpeg(png具体看图片的类型);base64, 去掉,需要截取后面的图片数据(不截取这段字符串会导致图片无法生成)
 8             if(StringUtils.isBlank(iconBase64)){
 9                 response.getWriter().print("0");
10             }
11             iconBase64 = iconBase64.split(",")[1].replaceAll(" ", "+");//由于请求的过程中,会把+好替换成空字符串,如果不替换+好,生成的图片会出现乱码
12             User user = SessionUtil.getSysUserFormSession(request);
13             File file = new File(IMG_PATH+"/"+model.getFilePath()+"/"+user.getUniversalid());
14             if (!file.exists() && !file.isDirectory()) {
15                 file.mkdirs();
16             }
17             String l = System.currentTimeMillis()+".jpg";
18             System.out.println("修改头像:               "+l);
19             byte[] buffer = new BASE64Decoder().decodeBuffer(iconBase64);//把base64的图片以二进制的形式读取到字节数组,然后在写入某个文件或者文件夹
20             FileOutputStream out = new FileOutputStream(IMG_PATH+"/"+model.getFilePath()+"/"+user.getUniversalid()+"/"+l);
21             out.write(buffer);
22             out.close();
23             int update = userService.updateUserHeadPortrait(l+"",user.getUniversalid());
24             if(update <= 0){
25                 response.getWriter().print("0");
26             } else {
27                 user = userService.findUserDetailById(user.getUniversalid().toString());
28                 SessionUtil.setSysUserToSession(request, user);
29                 response.getWriter().print(l);
30             }
31 //            uploadPhotoService.saveUploadPhoto(l, model.getFileDataId(), model.getInputPicFileFileName(), "1", model.getTableName());
32         } catch (Exception e) {
33             e.printStackTrace();
34         }
35
36     }

好了,这个玩意我也是第一次玩,前端也是第一次玩,搞了一天的时间,顿时感觉各种丢脸,有好的方法希望大神推荐,欢迎各种搬砖!谢谢~~~

转载于:https://www.cnblogs.com/cunkouzh/p/6905145.html

cropper(裁剪图片)插件使用(案例)相关推荐

  1. java -- cropper裁剪图片并base64上传 移动端简单示例

    前言 cropper是一款使用简单且功能强大的图片剪裁jQuery插件.该图片剪裁插件支持图片放大缩小,支持图片旋转,支持触摸屏设备,支持canvas,并且支持跨浏览器使用. cropper有两种方式 ...

  2. 支持移动端裁剪图片插件Jcrop(结合WebUploader上传)

    (此教程包括前端实现图片裁剪,后端进行获取裁剪区并保存) 最近有一个需求,微信公众号上传图片,支持自定义裁剪. 以前用过一款裁剪插件cropper,很久没用了,不知道对移动端操作兼容如何,重新从网上搜 ...

  3. js截取图片 裁剪图片之cropper.js插件用法详解

    js截取图片 裁剪图片之cropper.js插件用法详解 源码:https://github.com/fengyuanchen/cropper 引入+使用 <link href="/p ...

  4. cropper(图片裁剪插件)

    https://github.com/fengyuanchen/cropper cropper使用说明 一.特性 jQuery v1.9.1以上版本支持 插件有38个options,27种method ...

  5. cropper.js 实现裁剪图片并上传(PC端)

    博客地址:http://blog.mambaxin.com 由于之前做项目的时候有需求是需要实现裁剪图片来做头像并上传到服务器,所以上网查询了很多资料,也试用了许多案例,发现cropper插件裁剪是比 ...

  6. jQuery 缩放 旋转 裁剪图片 Image Cropper

    A simple jQuery image cropping plugin. Demo cropper是一款使用简单且功能强大的图片剪裁jQuery插件.该图片剪裁插件支持图片放大缩小,支持图片旋转, ...

  7. cropper固定宽高裁剪_cropper实现基本的裁剪图片并上传

    使用cropper之前需要先引用 cropper.css 和 cropper.js cropper 官网:https://fengyuanchen.github.io/cropper/ cropper ...

  8. 微信小程序图片裁剪image-cropper插件使用

    首先非常感觉大佬的图片裁剪插件 image-cropper,下面就是大佬的地址 文章地址https://developers.weixin.qq.com/community/develop/artic ...

  9. cropper.js 裁剪图片并上传(文档翻译+demo)(转)

    官网http://fengyuanchen.github.io/cropper/ 文档https://github.com/fengyuanchen/cropper/blob/master/READM ...

最新文章

  1. HA03-fence设置
  2. c/C++计算int / int *数组的长度;sizeof(指针),sizeof(数组名)的区别
  3. android fastjson java.lang.ClassCastException
  4. [置顶]       强大的jquery选择器
  5. Java并发编程(6):Runnable和Thread实现多线程的区别(含代码)
  6. ie不支持max-height的解决之法
  7. 3.2 读入两个参数
  8. holer实现外网访问内网数据库
  9. 27 Python - 数值 日期与时间
  10. 微服务架构的核心要点和实现原理解析
  11. Atitit..jdk java 各版本新特性 1.0 1.1 1.2 1.3 1.4 1.5(5.0) 1.6(6.0) 7.0 8.0 9.0 attilax 大总结...
  12. Mybatis案例超详解
  13. 实时时间OBS Studio插件(附下载地址与效果),实时时间插件date-and-time.lua的使用
  14. 怎么将几张pdf合并成一张_如何将多个PDF合并成一个PDF?PDF文档合并成单个的方法...
  15. 数据仓库常见建模方法与大数据领域建模实例综述
  16. 云端地球:让每个人都能在线生成大场景三维
  17. 网红漏洞“致远OA系统上的GetShell漏洞”详解
  18. 熊猫压缩怎么使用_记录随时间变化的PagerDuty事件(使用熊猫)
  19. mysql 1032_MySQL 报错 Last_SQL_Errno: 1032
  20. 计算机原理学习(2)-- 存储器和I/O设备和总线

热门文章

  1. 看MySQL数据库的观后感,【看点·光】谈谈赏析和读后感(随笔)_mysql执行语句...
  2. 小米 解析软件包时出现问题 解决
  3. 《漫画英国》的读书笔记感想4069字
  4. 【C++】模板进阶 — 模板特化
  5. 性能测试:手机IOS性能测试
  6. 2020编译原理练习记录(2)
  7. gee mysql数据库_MySQL
  8. mysql 双活_Mysql双活方案
  9. Ios android crash report,iOS App 后台 Crash 调查
  10. 【脑洞大开】从哲学角度看人工智能:介绍徐英瑾的《心智、语言和机器》