title: cropper js resize and crop with image magic
body: <p>How to perform resize and crop with ImageMagick using the data from <a href="https://github.com/fengyuanchen/cropper" rel="nofollow noreferrer">cropperjs</a>?</p>
  
  <p>The user can upload a large image and zoom/pan to crop. Tried using blob but it looses too much quality and times out too often. </p>
  
  <p><a href="https://i.stack.imgur.com/PRVLp.jpg" rel="nofollow noreferrer">Example</a> from fiddle with the following data:</p>
  
  <pre><code>Original Width: 1280
  Original Height: 720
  Width: 424.8717011756327
  Height: 238.9903319112934
  X: -155.17118867901692
  Y: -1.4989251522088705
  Scale: 23.82
  </code></pre>
  
  <p>Tried with this but it crops the wrong area. Also tried scaling the original image but that's too big for the server to handle.  </p>
  
  <pre><code>convert orignial.jpg -resize "1280x720^" -gravity center -crop 424x238+-155+-1 +repage result.jpg 
  </code></pre>
  
  <p>Example:
  <a href="https://jsfiddle.net/1knw3a5e/" rel="nofollow noreferrer">https://jsfiddle.net/1knw3a5e/</a></p>
  
  <p>JS code:</p>
  
  <pre><code>$(function() {
      var image = $('#crop-image');
      var zoomSlider = document.getElementById('zoom-slider');
      var canvasSize = null;
      var pictureContainer = $('.picture-frame');
      var maxPictureContainerWidth = parseFloat(pictureContainer.css('max-width')) || 450;
      var maxPictureContainerHeight = parseFloat(pictureContainer.css('max-height')) || 350;
      var isSliderInUse = false;
  
      // Wall is in Cm, convert to Inches to work out pixel sizes at 300dpi
      var wallWpx = (0.393700787 * pictureContainer.attr('data-width')) * 300; // data-width is the wall width in pixels
      var wallHpx = (0.393700787 * pictureContainer.attr('data-height')) * 300; // data-height is the wall height in pixels
  
      var sampleImageScaleFactor = (image.attr('width') / image.attr('original-width'));
  
      var wallSize = {
          width: wallWpx * sampleImageScaleFactor, // scaling the wall size corresponding the sample size
          height: wallHpx * sampleImageScaleFactor,
          originalWidth: pictureContainer.attr('data-width'),
          originalHeight: pictureContainer.attr('data-height')
      };
      var wallAspectRatio = wallSize.originalWidth/wallSize.originalHeight;
      var pictureContainerSizes = {
          'width': maxPictureContainerWidth * (wallAspectRatio &gt; 1 ? 1 : wallAspectRatio) ,
          'height': maxPictureContainerHeight / (wallAspectRatio &gt; 1 ? wallAspectRatio : 1)
      };
      pictureContainer.css(pictureContainerSizes).removeClass('hidden');
      var zoomStep = 0.2;
      var biggerSide = null;
  
      var zoomModal = $('#modal-warning');
      var handleZoomHold, handleZoomFired;
  
      image.cropper({
          zoom: 0.2,
          guides: false,
          cropBoxResizable: false,
          cropBoxMovable: false,
          //viewMode: 3,
          dragMode: 'move',
          left: 0,
          top: 0,
          //width: canvasSize.width,
          //height: canvasSize.height,
          //aspectRatio: 1,
          toggleDragModeOnDblclick: false,
          zoomOnTouch: true,
          zoomOnWheel: true
      });  
  
      // Event
      image.on('built.cropper', function() {
          image.cropper('setCropBoxData', {
              left: 0,
              top: 0,
              width: pictureContainerSizes.width,
              height: pictureContainerSizes.height
          });
          canvasSize = {
              width: image.cropper('getCropBoxData').width,
              height: image.cropper('getCropBoxData').height
          };
          biggerSide = canvasSize.width === image.cropper('getImageData').width ? 'width' : 'height';
  
          var savedCropperSettings = {
              sliceW: parseFloat($('input[name=sliceW]').val()),
              sliceH: parseFloat($('input[name=sliceH]').val()),
              sliceX: parseFloat($('input[name=sliceX]').val()),
              sliceY: parseFloat($('input[name=sliceY]').val()),
              scale: parseFloat($('input[name=scale]').val()) // saved adoptedZoomFactor
          };
  
          if (!savedCropperSettings.scale) {
              return;
          }
  
          /* restoring saved settings */
          image.cropper('zoomTo', canvasSize[biggerSide]/(wallSize[biggerSide]/savedCropperSettings.scale.toFixed(1)));
  
          var cropboxData = image.cropper('getCropBoxData');
          var scaleFactor = wallSize.originalHeight / cropboxData.height;
          image.cropper('setCanvasData', {
              left: savedCropperSettings.sliceX / scaleFactor + cropboxData.left,
              top: savedCropperSettings.sliceY / scaleFactor + cropboxData.top
          });
      });
  
      var adoptedZoomFactor = NaN;
      var adoptedZoomElement = $('#adoptedZoom');
      image.on('crop.cropper', function() {
          var data = image.cropper('getData');
          var canvasData = image.cropper('getCanvasData');
          var cropboxData = image.cropper('getCropBoxData');
          var scaleFactor = wallSize.originalHeight / cropboxData.height;
          adoptedZoomFactor = parseFloat((wallSize[biggerSide] / data[biggerSide]).toFixed(2));
          adoptedZoomElement.text(adoptedZoomFactor);
  
          $('input[name=sliceW]').val(canvasData.width * scaleFactor);
          $('input[name=sliceH]').val(canvasData.height * scaleFactor);
          $('input[name=sliceX]').val((canvasData.left - cropboxData.left) * scaleFactor);
          $('input[name=sliceY]').val(canvasData.top * scaleFactor);
          $('input[name=scale]').val(adoptedZoomFactor);
  
      });
  
  });
  </code></pre>