2

I'm using the imgly image cropper plugin, slightly modified for my app. It currently converts an image to a dataUrland spits out the image as a base64 image that I can save as a jpeg. I'm working on adapting the dataURItoBlob function found here, to my app, so I can get the image posted to an API endpoint. I have the following so far, but I'm not sure how to append the final image to the xhr.open('POST', '/', true);

renderButton.click(function (event) {
var dataUrl = 

imgly.renderToDataURL("image/jpeg", { size: "1200" }, function (err, dataUrl) {

        //Convert DataURL to Blob to send over Ajax
        function dataURItoBlob(dataUrl) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
        var byteString = atob(dataUrl.split(',')[1]);

        // separate out the mime component
        var mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0];

        // write the bytes of the string to an ArrayBuffer
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        // write the ArrayBuffer to a blob, and you're done
        //var bb = new BlobBuilder();
        //bb.append(ab);
        //return bb.getBlob(mimeString);
    }


    var blob = dataURItoBlob(dataUrl);
    var fd = new FormData(document.forms[0]);
    var xhr = new XMLHttpRequest();

    fd.append("myFile", blob);
    xhr.open('POST', '/', true);
    xhr.send(fd);



//Appends generated dataUrl to a div 
var image = $("<img><br>").attr({
        src: dataUrl
      });
//Remove button
      image.appendTo($(".result"))
      $button = $('<button class="btn btn-default remove">')
            .text('Remove Image')
            .on('click', function () {
                image.remove();
                $(this).remove();
                return false;
            });
        $button.appendTo($(".result"));
    });
  });
});
Community
  • 1
  • 1
Matt
  • 1,239
  • 4
  • 24
  • 53
  • See https://github.com/ebidel/filer.js/blob/master/src/filer.js#L137 – guest271314 Mar 19 '15 at 18:26
  • I switched updated the function with the ` dataURLToBlob: function(dataURL)`, but it isn't allowing the image to load, and showing the results div before the render button is clicked. I've created a fiddle with all the js used: http://jsfiddle.net/Lgduvce1/ – Matt Mar 19 '15 at 19:20
  • `html` ? loaded jquery at "Frameworks & Extensions" http://jsfiddle.net/Lgduvce1/1/ – guest271314 Mar 19 '15 at 19:28
  • I've updated the fiddle with all the JS and UI: http://jsfiddle.net/mattography/Lgduvce1/2/ – Matt Mar 19 '15 at 19:37

1 Answers1

1

Updated

"Assuming I keep the app in the same form, I'm trying to figure out how to get the dataURL into the post function."

Try, at lines 15 - 103 at http://jsfiddle.net/mattography/Lgduvce1/6/

  var blob; // declare `blob`
  // As soon as the user selects a file...
  fileInput.addEventListener("change", function (event) {
    var file; // declare `file`    
    var fileToBlob = event.target.files[0];
          blob = new Blob([fileToBlob], {"type":fileToBlob.type});
          // do stuff with blob
          console.log(blob);
    // Find the selected file
    if(event.target.files) {
      file = event.target.files[0];
    } else {
      file = event.target.value;
    }

    // Use FileReader to turn the selected
    // file into a data url. ImglyKit needs
    // a data url or an image
    var reader = new FileReader();
    reader.onload = (function(file) {
      return function (e) {
        data = e.target.result;

        // Run ImglyKit with the selected file
        try {
          imgly.run(data);
        } catch (e) {
          if(e.name == "NoSupportError") {
            alert("Your browser does not support canvas.");
          } else if(e.name == "InvalidError") {
            alert("The given file is not an image");
          }
        }
      };
    })(file);
    reader.readAsDataURL(file);
  });

  // As soon as the user clicks the render button...
  // Listen for "Render final image" click
  renderButton.click(function (event) {
    var dataUrl;


    imgly.renderToDataURL("image/jpeg", { size: "1200" }
    , function (err, dataUrl) {
        // `dataUrl` now contains a resized rendered image with
        // a width of 300 pixels while keeping the ratio

        // Convert DataURL to Blob to send over Ajax
        // function dataURItoBlob(dataUrl) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs 
        // - see SO answer #6850276 for code that does this
        // var byteString = atob(dataUrl.split(',')[1]);

        // separate out the mime component
        // var mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0];

        // write the bytes of the string to an ArrayBuffer
        // var ab = new ArrayBuffer(byteString.length);
        // var ia = new Uint8Array(ab);
        // for (var i = 0; i < byteString.length; i++) {
        //    ia[i] = byteString.charCodeAt(i);
        // }
        // write the ArrayBuffer to a blob, and you're done
        // var bb = new BlobBuilder();
        // bb.append(ab);
        // return bb.getBlob(mimeString);
    // }


    var _data = dataUrl.split(/,/)[1];
    // var fd = new FormData(document.forms[0]);
    var xhr = new XMLHttpRequest();
        function success(response) {
            if (response.target.readyState === 4) {
                var data = JSON.parse(response.target.response);
                var image = "data:" + data.type + ";base64," + data.file;
                console.log(image); // `data URI` of resized image
            }
        }
        xhr.onload = success;
    // fd.append("myFile", blob);
    xhr.open("POST", "/echo/json/", true);
    xhr.send("json=" + encodeURIComponent(
                           JSON.stringify({"file": _data,"type":blob.type})
                       )
    );

See also Handling_the_upload_process_for_a_file

guest271314
  • 1
  • 15
  • 104
  • 177
  • Thanks for that! I've got it in the solution now, but trying to figure out how to apply it to convert to blob after the user has hit the render button, not just loaded the image. It would also need to only be posted when the user hits `submit`, from the newly attached submit button in this revised fiddle: http://jsfiddle.net/mattography/Lgduvce1/6/ – Matt Mar 20 '15 at 15:52
  • `var blob = dataURItoBlob(dataUrl);` appear to return `undefined` ? Difficult to navigate at jsfiddle containing 24804 lines . Alternative approach could possibly be utilize initial `Blob` as `src` for rendered image , without converting to `data URI` ? , resize rendered image with `width` , `height` attributes ? – guest271314 Mar 20 '15 at 17:22
  • The important parts of the fiddle that we're dealing with in this SO post only go down to line 119. The image has to be in dataURI for image cropping(what the rest of the code is for). – Matt Mar 20 '15 at 17:26
  • _"The image has to be in dataURI for image cropping"_ ? `width` , `height` attributes at `img` element not "crop" image ?, or, `css` , `transform:scale(n,n)` ? What data type is server expecting ? See also http://stackoverflow.com/questions/28856729/upload-multiple-image-using-ajax-php-and-jquery/ , http://stackoverflow.com/questions/28923269/display-portion-of-scaled-image-in-div – guest271314 Mar 20 '15 at 17:31
  • @Matt What is the expected "crop" , or `scale` ratio ? Is the a) original image, or b) "cropped" image uploaded ? – guest271314 Mar 20 '15 at 17:38
  • There are three scales: Square, 9:16(portrait) and 16:9(landscape) crop ratio options. Once the user has selected an option, and adjusted the crop, they then click on a button that generates the cropped image. The idea is that they will be able to click a `submit` button under the cropped image they want, and that image will be uploaded. – Matt Mar 20 '15 at 18:10
  • @Matt _"There are three scales: Square, 9:16(portrait) and 16:9(landscape) crop ratio options."_ Relative to ? – guest271314 Mar 20 '15 at 18:34
  • You asked what the expected crop ratio is. The scale options are irrelevant to the end result of trying to upload the image after cropping and rendering the result. – Matt Mar 20 '15 at 18:36
  • Perhaps not interpreting requirement correctly , here ? a) `input type="file"` uploads image; b) display original image; c) viewer selects one of three "scale" options , relative to original image dimensions; d) selected "scale" option uploaded to server ? – guest271314 Mar 20 '15 at 18:40
  • Yes, that's correct. After they have selected a "scale" option, they can then adjust the cropper(with locked ratio), and click "Render", when they are done. The current implementation will render the cropped image to the right of the cropper area. It can then be removed if desired. However, I'm trying to be able to `POST` the rendered image to a server as a blob. Does that make more sense? – Matt Mar 20 '15 at 18:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73443/discussion-between-guest271314-and-matt). – guest271314 Mar 20 '15 at 18:50