3

Is there any best way to resize and save files to s3 in meteor.

I though about using cfs packages, but they put too much load on server.

To directly upload images to the s3 I'm using slingshot which is very fine.

but slingshot takes only file objects as inputs it doesn't take streams to store the files.

Is there any option to resize the image in client side and pass it to the slingshot package

package: https://github.com/CulturalMe/meteor-slingshot issue: https://github.com/CulturalMe/meteor-slingshot/issues/36

d_inevitable
  • 4,381
  • 2
  • 29
  • 48
user555
  • 1,489
  • 2
  • 15
  • 28
  • Do you have to use Slingshot? Have you looked into the `cfs:s3` route with `cfs:graphicsmagick` to manipulate the images? https://github.com/CollectionFS/Meteor-cfs-s3 – Joe Buckle Feb 16 '15 at 13:08
  • as I said they are putting too much pressure on server, I've tried with those packages I'm getting some issues image is displaying for a while and then disappears https://github.com/CollectionFS/Meteor-CollectionFS/issues/544 – user555 Feb 16 '15 at 14:23
  • Sorry. Missed that part of your question for some reason. If it's any consolation, I had the same thought as you (file resize, slingshot, store URL) but ended up just using GridFS instead of a CDN. That wouldn't solve your problem if you have limited resources though. – Joe Buckle Feb 16 '15 at 14:41
  • @JoeBuckle, Let me know if you find the way to do it. Thanks – user555 Feb 17 '15 at 06:39

3 Answers3

5

Yes it's possible with clientside-image-manipulation, here's my untested interpretation of the docs:

Template.upload.events({
    'change #image-upload': function(event, target) {
        var uploader = new Slingshot.Upload("myFileUploads");
        var file = event.target.files[0];
        var img = null;
        processImage(file, 300, 300, function(data){
            uploader.send(data, function (error, downloadUrl) {
                if(error)
                    throw new Meteor.Error('upload', error);
                Meteor.users.update(Meteor.userId(), {$push: {"profile.files": downloadUrl}});
            });
        });
    }
});

There are other image related plugins worth investigating at atmosphere.js

Ian Jones
  • 1,369
  • 1
  • 10
  • 15
  • That didnt work. First there is an extra ) at line 11. And the other problem is that data is base64 string. And slingshot need an file object. I've tried to convert it to an blob. But couldnt make it to work :( – Rane Mar 12 '15 at 20:16
4

I've found that the following works in order to integrate Clientside Image Manipulation with Slingshot (asynchronous code with ES6 promises):

var uploader;

function b64ToBlob(b64Data, contentType, sliceSize) {
  var byteNumbers, i, slice;
  var offset = 0;
  var byteCharacters = atob(b64Data);
  var byteArrays = [];
  sliceSize = sliceSize || 512;
  byteArrays = [];
  while (offset < byteCharacters.length) {
    slice = byteCharacters.slice(offset, offset + sliceSize);
    byteNumbers = [];
    for (i = 0; i < slice.length; ++i) {
      byteNumbers.push(slice.charCodeAt(i));
    }
    byteArrays.push(new Uint8Array(byteNumbers));
    offset += sliceSize;
  }

  return new Blob(byteArrays, {type: contentType});
}

uploader = new Slingshot.Upload("pictures");

new Promise(function (resolve) {
  processImage(file, 300, 300, resolve);
}).then(function (dataUri) {
  var match = /^data:([^;]+);base64,(.+)$/.exec(dataUri);
  return [file.name, match[1], match[2]];
}).then(function (params) {
  var name = params[0];
  var type = params[1];
  var b64 = params[2];
  return new Promise(function (resolve, reject) {
    var blob = b64ToBlob(b64, type);
    blob.name = name;
    uploader.send(blob, function (error, downloadUrl) {
      if (error != null) {
        reject(error.message);
      } else {
        resolve(downloadUrl);
      }
    });
  });
});

Conversion from Base64 to blob is borrowed from https://stackoverflow.com/a/16245768/1238764.

Community
  • 1
  • 1
aknuds1
  • 65,625
  • 67
  • 195
  • 317
  • Oops, noticed a crucial missing line at the end of `b64ToBlob` :/ Fixed it. – aknuds1 Aug 25 '15 at 12:02
  • Care to add a javascript version for us mere mortals? – Nathan Hornby Aug 25 '15 at 12:03
  • @NathanHornby Considering it. – aknuds1 Aug 25 '15 at 15:36
  • Cheers! It's a super useful answer and I'm glad you've provided it in whatever format, but I think unless someone specifically asks for coffeescript it's a bit out of place. – Nathan Hornby Aug 26 '15 at 08:58
  • I used js2.coffee to convert the code by the way, seemed to work well! I would edit it into your answer, but I have a feeling that might constitute too substantial an edit. – Nathan Hornby Aug 26 '15 at 10:24
  • 1
    @NathanHornby I've converted it to JS, untested though. – aknuds1 Aug 26 '15 at 11:00
  • I've used it with success - so a big thank you for this! I did do it without using `Promise` though - I have a feeling I'm missing a callback around where the match happens but it's working, but I'll monitor it for peculiarities! – Nathan Hornby Aug 26 '15 at 11:02
0

There are a lot of image manipulation plugins. The one I use is: cropper

It's a jquery based plugin which basically does the thing you want + a bit more. After manipulation you can convert the image to a canvas and with the dataToUrl() method you can pass the data of the new manipulated image to any datasource of your choice.