2

I am currently using the bootstrap-wysiwyg rich text editor. This allows users to drag an image file into the editor, which is great, however I would like to resize this image on the fly. I believe I have found the location in bootstrap-wysiwyg.js where I should attempt to resize the image before it gets displayed in the editor and subsequently posted to a PHP page when the user clicks submit.

From reading other stackoverflow posts, it seems that the preferred way of doing this is using HTML5's canvas functionality. I have jQuery available as well. The only browser the solution must support is either the current version of Chrome or Firefox.

I believe I have found a good entry point for this resize functionality:

function (files) {
  editor.focus();
  $.each(files, function (idx, fileInfo) {
    if (/^image\//.test(fileInfo.type)) {

      // ENTRYPOINT: attempt to resize

      $.when(readFileIntoDataUrl(fileInfo)).done(function (dataUrl) {
        execCommand('insertimage', dataUrl);
        editor.trigger('image-inserted');
      }).fail(function (e) {
        options.fileUploadError("file-reader", e);
      });
    } else {
      options.fileUploadError("unsupported-file-type", fileInfo.type);
    }
  });
},

This above code is pre-existing in the bootstrap-wysiwg library. I'm thinking that I can somehow take the fileInfo object, turn it into an Image object, do the resizing, generate a dataurl version of the image, and then call:

execCommand('insertimage', dataUrl);
editor.trigger('image-inserted');

I feel like this would eliminate the need for the $.when function which currently encloses those two function calls.

I have tried integrating other examples from StackExchange, this one was especially promising, but I must not understand JS well enough to properly adapt it to my needs.

I realize I can resize the image server-side after it gets POST/uploaded, but this is not desirable as the goal is to automatically resize a very large image which is dragged into the editor window to something which is more manageable to the end user who is using the editor window and doesn't fill the entire editor window in all directions.

Quality of the resulting image isn't all that important, so I'm not concerned with those types of optimizations and such which have been mentioned elsewhere.

enter image description here

Rohn Adams
  • 828
  • 8
  • 16

2 Answers2

1

I recently did a side-project (kropimg.com) that does something similar - resizes images on the client-side entirely using the canvas.

You have more options though:

The Client-side Only Way

If you insist on doing everything on the client-side, you'll need to use the canvas to resize the image - as you suspected replace the $.when part with the a function call from this answer. (You may need to first pass it trough img = readFileIntoDataUrl(fileInfo); )

The Server-sided Only way

I don't know if you know this but you can't make ajax calls with file object directly. You should use the FileReader Interface to read the content first to do is async. Refer to this answer. After you are done resizing on the server you can return the url of you image back to the front. Meanwhile you can show a spinner (like Gmail does).

Edit: Realised you don't want server-side method

The Hybrid way

Another way is to resize the image using CSS/JS and then upon uploading, send the new dimensions to the server and resize it there as well (Using GD or ImageMagik). Simply use jQuery to set some CSS on that image. If I were you, I'd go with this method. Although you said you don't care about quality, resizing huge images down to below 25% can look pretty ugly (lot's of aliasing). The downside of this method is that it will take a while to upload a huge image.

Hope this helps.

Community
  • 1
  • 1
Miro
  • 8,402
  • 3
  • 34
  • 72
  • Thank you for your response. I decided to go with the client-side only option. This is solution best fits my needs as it kills two birds with one stone: 1) smaller image size results in more manageable editor window for the user. 2) smaller image size before upload results in less upload bandwidth required This is not a commercial project, so for my use case, resource load on the client machine is not important. I am going to post my final solution below, however, I feel I should accept your answer since it was informative and lead me to my solution? Is this correct practice? – Rohn Adams Mar 03 '17 at 13:28
0

I chose to go with the purely client-side option as a solution for my problem. This was mainly due to the specific nature of my use-case. Not only did this allow me to shrink the image before it was inserted into the "bootstrap-wysiwg editor", this also decreased the size of the images before they are uploaded to the server. Our upload bandwidth is quite low, so this was a point of major importance. Legacy browser support and client-side resource usage were not concerns for my use case.

I was able to use the resize functionality provided by this answer, which I have replicated below for ease of access:

// resize function
function imageToDataUri(img, width, height) {

    // create an off-screen canvas
    var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');

    // set its dimension to target size
    canvas.width = width;
    canvas.height = height;

    // draw source image into the off-screen canvas:
    ctx.drawImage(img, 0, 0, width, height);

    // encode image to data-uri with base64 version of compressed image
    return canvas.toDataURL();
}

I was then able to make some slight changes the the existing "bootstrap-wysiwyg.js" to integrate the resize functionality:

insertFiles = function (files) {
  editor.focus();
  $.each(files, function (idx, fileInfo) {
    if (/^image\//.test(fileInfo.type)) {
      // resize
      var img = new Image();

      img.onload = function() {
        // TODO: add some error checking and gracefully handle errors
        var dataUrl = imageToDataUri(img, 300, 200);

        execCommand("insertimage", dataUrl);
        editor.trigger("image-inserted");

        URL.revokeObjectURL(img.src)
      }
      img.src = URL.createObjectURL(fileInfo);
    } else {
      options.fileUploadError("unsupported-file-type", fileInfo.type);
    }
  });

This works great for my purposes, although I will likely be modifying it so that it only resizes images larger than a certain threshold as well as changing it so that the aspect ratio of the original image is preserved.

Rohn Adams
  • 828
  • 8
  • 16