fengyuanchen / cropper

⚠️ [Deprecated] No longer maintained, please use https://github.com/fengyuanchen/jquery-cropper
MIT License
7.75k stars 1.74k forks source link

How to pass the cropped image with form? #325

Closed nobutsta closed 9 years ago

nobutsta commented 9 years ago

Hello, I want to pass the cropped image along the normal form. I can make everything right - original image, cropped preview but cannot pass it with form. I wish I could use some thing like <input type="file" name="file" id="cropped_img" />. Is it possible? Here's my code:

<form class="avatar-form" action="inc/settings_customers_uploader_tn.php" enctype="multipart/form-data" method="post">
  <input type="hidden" name="id" value="xx" />
    <div class="modal-header">

      <h4 class="modal-title" id="ajaxModalLabel">Cropper</h4>
    </div>
    <div class="modal-body">
      <div class="avatar-body">

        <!-- Crop and preview -->
        <div class="row">
          <div class="col-md-9">
            <div class="avatar-wrapper">
                <img src="../../photos/hello.jpg" />
            </div>
          </div>
          <div class="col-md-3 align-center">
            <div class="avatar-preview" style="border:solid 1px #ccc;border-radius:5px;height:150px;width:120px;"></div><br />
            <button class="btn btn-primary btn-block avatar-save" type="submit"><em class="fa fa-floppy-o"></em>&nbsp;Save</button>
          </div>
        </div>

        </div>
      </div>
    </div>
    <!-- <div class="modal-footer">
      <button class="btn btn-default" data-dismiss="modal" type="button">Close</button>
    </div> -->
  </form>

Javascrip:

var $image = $('.avatar-wrapper > img'),
    cropBoxData,
    canvasData;

$('#ajaxModal').on('shown.bs.modal', function () {
  $image.cropper({
    aspectRatio: 1/1,
    autoCropArea: 0.80,
    preview: ".avatar-preview",
    built: function () {
      // Strict mode: set crop box data first
      $image.cropper('setCropBoxData', cropBoxData);
      $image.cropper('setCanvasData', canvasData);
    }
  });
}).on('hidden.bs.modal', function () {
  cropBoxData = $image.cropper('getCropBoxData');
  canvasData = $image.cropper('getCanvasData');
  $image.cropper('destroy');
});
fengyuanchen commented 9 years ago

What are you mean? This?

// https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
// https://developer.mozilla.org/en-US/docs/Web/API/FormData

$().cropper('getCroppedCanvas').toBlob(function (blob) {
  var formData = new FormData();

  formData.append('croppedImage', blob);

  $.ajax('/path/to/upload', {
    method: "POST",
    data: formData,
    processData: false,
    contentType: false,
    success: function () {
      console.log('Upload success');
    },
    error: function () {
      console.log('Upload error');
    }
  });
});
nobutsta commented 9 years ago

@fengyuanchen Thank you for the reply but the cropping area is gone by this code. By the way I swap into my code. I've got [object Object] in data.

var $image = $('.avatar-wrapper > img'),
    cropBoxData,
    canvasData,
    $btn = $('.avatar-save'),
    formData = new FormData(),croppedCanvas = $().cropper('getCroppedCanvas');

$('#ajaxModal').on('shown.bs.modal', function () {
  $image.cropper({
    aspectRatio: 1/1,
    autoCropArea: 0.80,
    preview: ".avatar-preview",
    crop: function (data) {
        cropImgData = data; // save returned data to cropImgData.
        console.log(cropImgData);   //cropImgData is the returned data from cropper
    },
    built: function () {
      // Strict mode: set crop box data first
      $image.cropper('setCropBoxData', cropBoxData);
      $image.cropper('setCanvasData', canvasData);
    $btn.on('click', function () {
        $.ajax({
        type: "POST",
        url: 'inc/settings_customers_uploader_tn.php',
        data: 'data='+cropImgData+'&cpfl_id='+<?=$_GET['id']?>,
        success: function(res) {
            console.log(res);
        }//function(res)
    });//$.ajax({
    });//$btn.on
    }
  });
}).on('hidden.bs.modal', function () {
  cropBoxData = $image.cropper('getCropBoxData');
  canvasData = $image.cropper('getCanvasData');
  $image.cropper('destroy');
});
fengyuanchen commented 9 years ago

How can you do this?!

data: 'data='+cropImgData+'&cpfl_id='+<?=$_GET['id']?>
nobutsta commented 9 years ago

What do you mean by the question? The reason I asked because I don't understand the way your code working and I can't find the example anywhere even on your example. So please teach me or even the valuable example for I can learn and finish my project.

fengyuanchen commented 9 years ago

Change

...
data: 'data='+cropImgData+'&cpfl_id='+<?=$_GET['id']?>
...

To

...
data: 'data='+JSON.stringify(cropImgData)+'&cpfl_id='+<?=$_GET['id']?>
...
nobutsta commented 9 years ago

It works now. This is another lesson I know that the data needs to be encode in JSON first. Thank you very much. [data] => {\"x\":59.99999999999999,\"y\":160,\"width\":480,\"height\":480,\"rotate\":0}

steefaan commented 9 years ago

croppedCanvas.toBlob isn't really available even in modern browsers. If someone interested in, take a look on https://github.com/blueimp/JavaScript-Canvas-to-Blob

Quadratica commented 9 years ago

Hi you all,

my target is to transfer the cropped image on the server, below is my JS code but i can't send blob data (cropped image) to the server.

Before you watch my code consider these things: 1) result var is a canvas object and it contains cropped image (if i display it i can see cropped image)

2) "upload.php" file perform this task: "var_dump($_POST); var_dump($_FILE); exit;"

3) I test my snippet on firefox 39 and ".toBlob" native function is already and well implemented. (for other browser i use "JavaScript-Canvas-to-Blob", just like steefaan said above")

4) At server side i can pick only "my_test_var" (this is the only positive thing :) )

Here my code:


result = canvas.cropper(data.method, data.option);
if(data.method === 'getCroppedCanvas') 
{
  var formData = new FormData();
  result.toBlob(function (blob) {
    formData.append('croppedImage', blob, "Chrysanthemum.jpg"); }
  );
  formData.append("my_test_var", "something");                  

```
$.ajax({
 url: "upload.php",
 type: "POST",
 data: formData,
 processData: false,
 contentType: false,
 success: function( text, response, xhr) {                        
   $("#show-server-result-area").html(text);
}
error: function() {
  window.alert('Upload error!');
}
```

  }); // $.ajax

} // if(data.method === 'getCroppedCanvas') 
In simple word i can't see "croppedImage" image at server side. This morning i did a lot of test and i worked a lot to reach almost nothing, i'm desperate !
steefaan commented 9 years ago

@fluctuate The problem is how you build the form data. result.toBlob is asynchronously so you will send the ajax request before your form data is created. You need something like promises to make sure that the form data was built before you create the ajax request.

Quadratica commented 9 years ago

@steefaan

"result.toBlob"is asynchronously ? What ? I don't think.

But if you have time, can you correct my code .. please ? In this way we'll solve this problem once and for all. After, fengyuanchen could include this solution in Cropper'a official docs.

steefaan commented 9 years ago

Which browsers you have tested? I was able to reproduce this only with Chrome. In other browsers you should have the same problem like before.

Quadratica commented 9 years ago

Firefox 39 on Linux XUbuntu.

And you are right, i've tested "result.toBlob" and i've seen that it's an asynchronous method. I'm a little surprised, and I wonder why it is so.

steefaan commented 9 years ago

OK I wonder that it works for you, maybe you can also try with a bigger picture. But this way you build a part of your form data outside of the beforeSave callback and another part in the callback. Seems a bit messy to me.

Quadratica commented 9 years ago

Now i delete my previous solution, in fact it doesn't work, it was my error! It was working only apparently because i was putting an alert(""), after i clicked on it, the "result.toBlob" method has properly finished to execute and all works fine, i.e. i can see my file on the server (but this is a stupid solution).

Now i've realized my final (or so now i think) and working solution: (I move $.ajax feature inside "result.toBlob" function, just after var are set )


result = canvas.cropper(data.method, data.option);
if(data.method === 'getCroppedCanvas') 
{                   
    var formData = new FormData();

    result.toBlob(function (blob) {
        formData.append('file', blob, "Chrysanthemum.jpg");       
        formData.append("my_test_var", "something");
        $.ajax({

             url: "/upload.php",

             type: "POST",

             data: formData,

             processData: false,

             contentType: false,

             success: function( text, response, xhr) {                        
                 $("header").html(text);
             },

             error: function() {          
               window.alert('Upload error!');
             }

         });                          

    }); // result.toBlob(function (blob) {

} //    if(data.method === 'getCroppedCanvas') 
steefaan commented 9 years ago

Is a possible solution but not the nicest one. I still suggest a promise solution. I don't know if you're using jQuery, if yes you should take a look on the $.Deferred object.

http://stackoverflow.com/questions/31195773/wait-for-canvas-toblob-before-continue/31195879#31195879

Maybe this helps you. Isn't a jQuery solution but the way with jQuery is quite similar.

Quadratica commented 9 years ago

Yes, i'm using jQuery and i think that using $.Deferred feature is very smart. But for now I'll settle for this solution because my client is in a hurry.

However, for me one of the possible solutions (i mean for uploading cropped images) should be written in the documentation, so doing this JS Library will acquire more prestige ;) A simple docs is an important value added.

fengyuanchen commented 9 years ago

I have added some example code for uploading cropped image to the docs just now. Thank you all!

terryBear commented 9 years ago

i am trying to upload the cropped image to localStorage, and I just can't seem to get it right.

This is the section that handles the upload:


    $previewPP = $('.preview-lg');
    $canvas = $( $previewPP ).cropper('getCroppedCanvas', { width: 200, height: 200 });

    $('.cropSave').on('click', function() {

      $cropPP = $('.preview-lg > img').attr('src');
      localStorage.setItem('cropPP', $cropPP);

      $profilePic = $('.confirmpp').html("<img src='" + localStorage.getItem('cropPP') + "' class='img-responsive img-circle' />")

    })

I can't seem to get the cropped image to upload, don't know if I'm calling it incorrectly. Can someone please help.

fengyuanchen commented 9 years ago

@terryBear

// Get a string base 64 data url
var croppedImageDataURL = $().cropper('getCroppedCanvas').toDataURL(); 

localStorage.setItem('cropPP', croppedImageDataURL);
kpomservices commented 8 years ago

I solved saving the cropped image by // client side var cropcanvas = $('#imagetocrop').cropper('getCroppedCanvas'); var croppng = cropcanvas.toDataURL("image/png");

$.ajax({ type: 'POST', url: 'savecropimage.php', data: { pngimageData: croppng, filename: 'test.png' }, success: function(output) { } }) //server side php $filename = $_POST['filename']; $img = $_POST['pngimageData']; $img = str_replace('data:image/png;base64,', '', $img); $img = str_replace(' ', '+', $img); $data = base64_decode($img); file_put_contents($filename, $data);

akartynnik commented 8 years ago

And how I can upload original image, without cropping??

vinayanvv commented 6 years ago

how to create crop button in modal example i'm not well in javascript please tell me how to create? crop button to save!

VictorBrecedaE commented 6 years ago

Does anyone have an example code?

I could not save the clipping on a local route