Ruslan Valeev
Ruslan Valeev

Reputation: 1907

How to apply cropping to image with cropper.js?

I'm trying to realize, how to use cropper.js, and so far it looks pretty good, but... when I trying to crop the image, how can I put the result back to my form?

My input has id 'profile_avatar'. So I try to put there updated image, and cannot.

$('#cut_button').click(function(e) {
  e.preventDefault();
  var croppedImageDataURL = cropper.getCroppedCanvas()
  $('#profile_avatar').val(croppedImageDataURL.toDataURL("image/png"))
});

But when I click 'cut button' I got

InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable

in console. What am I doing wrong? I'm trying to beat it few hours. Thank you so much!

slim file with view:

  = form_for @profile do |f|
    = f.label :avatar
      = f.file_field :avatar
      .canvas_window
        canvas id='canvas'
      .preview
      = link_to('Cut', '', id: 'cut_button')
      = f.label :photos
      = f.file_field :photos, multiple: true
      = f.label :description
      = f.text_area :description
      = @profile.errors.messages[:description].presence
      = hidden_field :dimensions, ''
      = f.submit I18n.t('user.forms.buttons.submit')

javascript:
  var canvas  = $("#canvas"),
      context = canvas.get(0).getContext("2d"),
      $result = $('#result');

  $('#profile_avatar').on( 'change', function(){
    console.log('start')
    if (this.files && this.files[0]) {
      if ( this.files[0].type.match(/^image\//) ) {
        var reader = new FileReader();
        reader.onload = function(evt) {
          var img = new Image();
          img.onload = function() {
            context.canvas.height = img.height;
            context.canvas.width  = img.width;
            context.drawImage(img, 0, 0);
            const image = document.getElementById('canvas');
            const cropper = new Cropper(image, {
              preview: '.preview',
              aspectRatio: 16 / 9,
              crop(event) {
                dimensions = event.detail.width + 'x' + event.detail.width + '+' + event.detail.x + '+' + event.detail.y
                $('#new_profile input#dimensions_').val(dimensions)
                console.log(dimensions);
                console.log(event.detail.x);
                console.log(event.detail.y);
                console.log(event.detail.width);
                console.log(event.detail.height);
              },
            });

            $('#cut_button').click(function(e) {
              e.preventDefault();
              var croppedImageDataURL = cropper.getCroppedCanvas()
              HERE IS ERROR \/
              $('#profile_avatar').val(croppedImageDataURL.toDataURL("image/png"))
              console.log(croppedImageDataURL.toDataURL("image/png"))
             });
           };
           img.src = evt.target.result;
        };
        reader.readAsDataURL(this.files[0]);
      }
      else {
        alert("Invalid file type! Please select an image file.");
      }
    }
    else {
      alert('No file(s) selected.');
    }
  });

html:

<form class="new_profile" id="new_profile" enctype="multipart/form-data" action="/profiles" accept-charset="UTF-8" method="post">
  <input type="hidden" name="authenticity_token" value="j53mqq1th1kb17ynj2jxIMcPFRC210EQVLBSgEu2n4FLOONtFBH3Vu7wrjc+iDrogn99H/emvN5qUdyZo2pAkg==">
  <label for="profile_avatar">Avatar</label>
  <input type="file" name="profile[avatar]" id="profile_avatar">
  <div class="canvas_window">
    <canvas id="canvas"></canvas>
  </div>
  <div class="preview"></div>
  <a id="cut_button" href="">Cut</a>
  <label for="profile_photos">Photos</label>
  <input multiple="multiple" type="file" name="profile[photos][]" id="profile_photos">
  <label for="profile_description">Description</label>
  <textarea name="profile[description]" id="profile_description"></textarea>
  <input type="hidden" name="dimensions[]" id="dimensions_">
  <input type="submit" name="commit" value="Submit" data-disable-with="Submit">
</form>

Upvotes: 3

Views: 7980

Answers (2)

Minh Quang
Minh Quang

Reputation: 21

Check this link if your server need a File as input.

The overall process is: CroppedData() -> Base64 image -> Blob -> File ===> Send to Server

Upvotes: 0

Ed Lucas
Ed Lucas

Reputation: 7305

One thing that stands out is that you need to set the source of an image to the output of toDataUrl(). For example:

HTML:

<img id="cropped_image" src="/blank.gif"></img>

JS:

$("#cropped_image").attr("src", croppedImageDataURL.toDataURL("image/png"));

You could create that image on the fly with JavaScript or include the <img/> tag in your markup with a blank image or hidden (revealing it after you add the cropped image).

To pass the image in your form, you should use an input field because the value at this point is a string (e.g. "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNby").

HTML:

<input id="cropped_image" type="hidden" />

JS:

$("#cropped_image").val(croppedImageDataURL.toDataURL("image/png"));

Upvotes: 1

Related Questions