troubleshooting Question

How do I use cropper.js to create multiple dynamic crop windows over the same image

Avatar of mike99c
mike99c asked on
CSSHTMLPHPjQuery
5 Comments1 Solution19 ViewsLast Modified:
I’m creating a web application that takes a user submitted image and uploads two cropped images of different aspect ratios based on user selection.
 
It's documented that cropper.js supports multiple crops in the same window and I would like to know if it's possible (and if so how) to display two cropping windows over the same image. Ideally a user should be able to upload an image at two different crops by adjusting two different viewports on a single image and crop both at the same time, as illustrated below.


I’ve included sample code that supports single cropping and has been expanded to support multiple crops by refreshing the window with a new cropper. This approach involves displaying and submitting the crop twice as illustrated below.


The sample code below is a simple web page containing a button to upload a valid image for the user to crop.

Index.html
<!DOCTYPE html>
<html>
<head>
    <title>PHP Crop Image Before Upload using Cropper JS</title>
    <meta name="_token" content="{{ csrf_token() }}">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js" i</script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js" </script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.6/cropper.js" i</script>
</head>
<style type="text/css">
img {
  display: block;
  max-width: 100%;
}
.preview {
  overflow: hidden;
  width: 160px; 
  height: 160px;
  margin: 10px;
  border: 1px solid red;
}
.modal-lg{
  max-width: 1000px !important;
}
</style>
<body>
<div class="container">
  <h1>PHP Crop Image Before Upload using Cropper JS</h1>
  <form method="post">
  <input type="file" name="image" class="image">
  </form>
  <br />
  <div id="uploaded_image"></div>
</div>

<div class="modal fade" id="modal" tabindex="-1" role="dialog" aria-labelledby="modalLabel" aria-hidden="true">
  <div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="modalLabel">Single Crop</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true"></span>
        </button>
      </div>
      <div class="modal-body">
        <div class="img-container">
            <div class="row">
                <div class="col-md-8">
                    <img id="image" src="https://avatars0.githubusercontent.com/u/3456749">
                </div>
                <div class="col-md-4">
                    <div class="preview"></div>
                </div>
            </div>
        </div>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-primary" id="crop">Crop</button>
      </div>
    </div>
  </div>
</div>

</div>
</div>
<script>

var $modal = $('#modal');
var image = document.getElementById('image');
var cropper;
  
$("body").on("change", ".image", function(e){
    var files = e.target.files;
    var done = function (url) {
      image.src = url;
      $modal.modal('show');
    };
    var reader;
    var file;
    var url;

    if (files && files.length > 0) {
      file = files[0];

      if (URL) {
        done(URL.createObjectURL(file));
      } else if (FileReader) {
        reader = new FileReader();
        reader.onload = function (e) {
          done(reader.result);
        };
        reader.readAsDataURL(file);
      }
    }
});

$modal.on('shown.bs.modal', function () {
    cropper = new Cropper(image, {
    aspectRatio: 4/5,
    viewMode: 3,
    preview: '.preview'
    });
    
}).on('hidden.bs.modal', function () {
   cropper.destroy();
   cropper = null;
  
});

$("#crop").click(function(){
    canvas = cropper.getCroppedCanvas({
      width: 600, // Adjust here
      height: 600,
    });

    canvas.toBlob(function(blob) {
        url = URL.createObjectURL(blob);
        var reader = new FileReader();
         reader.readAsDataURL(blob); 
         reader.onloadend = function() {
            var base64data = reader.result;  
            
            $.ajax({
                type: "POST",
                dataType: "json",
                url: "upload.php",
                data: {image: base64data},
                success: function(data){
                    console.log(data);
                    
                    $modal.modal('hide');
                    
                    $("#uploaded_image").html(data);
                   
                }
              });
         }
    });
})

</script>
</body>
</html>
upload.php
<?php

if(isset($_POST["image"]))
{

        $folderPath = 'upload/';

        $image_parts = explode(";base64,", $_POST['image']);
        $image_type_aux = explode("image/", $image_parts[0]);
        $image_type = $image_type_aux[1];
        $image_base64 = base64_decode($image_parts[1]);
        $file = $folderPath . uniqid() . '.png';

        file_put_contents($file, $image_base64);
     

        echo json_encode(["image uploaded successfully."]);
}
?>

Using cropper.js the script displays a cropper canvas with the submitted image.

The user can drag, move and select an area of fixed aspect ratio to crop.

When the crop button is selected, the crop is taken from the image and uploaded.  

This process could be repeated for multiple aspect ratios by destroying the cropper canvas and creating a new one with the same original image.  

How could this program be expanded to support the cropping of multiple images, is there an alternative library that is better suited for this implementation and is this the most viable solution for a better user experience?
ASKER CERTIFIED SOLUTION
mike99c

Our community of experts have been thoroughly vetted for their expertise and industry experience.

Join our community to see this answer!
Unlock 1 Answer and 5 Comments.
Start Free Trial
Learn from the best

Network and collaborate with thousands of CTOs, CISOs, and IT Pros rooting for you and your success.

Andrew Hancock - VMware vExpert
See if this solution works for you by signing up for a 7 day free trial.
Unlock 1 Answer and 5 Comments.
Try for 7 days

”The time we save is the biggest benefit of E-E to our team. What could take multiple guys 2 hours or more each to find is accessed in around 15 minutes on Experts Exchange.

-Mike Kapnisakis, Warner Bros