Uploading Resized Pictures to S3 in Meteor Application
I am facing the need to upload pictures to Amazon S3 in my Meteor application, MuzHack. The pictures must be resized before storing in S3, and there’s the option of doing this either on my server or in the client. I have elected to go with the latter for now, since it’s simple and doesn’t put load on my server.
To resize pictures client side I am using the Meteor Clientside Image Manipulation library, and to upload pictures to S3 I am using Slingshot.
Combining Meteor Clientside Image Manipulation and Slingshot
Combining the two libraries isn’t straightforward. Meteor Clientside Image Manipulation returns a data URI, while Slingshot requires a file or a blob.
The data URI format returned by Meteor Clientside Image Manipulation looks like data:$type;base64,$content
. The type and the content can be used to create a blob, for compatibility with Slingshot. The following code (CoffeeScript) shows how I did this:
Example Code for Combining Meteor Clientside Image Manipulation and Slingshot
b64ToBlob = (b64Data, contentType, sliceSize) ->
sliceSize = sliceSize || 512
byteCharacters = atob(b64Data)
byteArrays = []
offset = 0
while offset < byteCharacters.length
slice = byteCharacters.slice(offset, offset + sliceSize)
byteNumbers = (slice.charCodeAt(i) for i in [0...slice.length])
byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
offset += sliceSize
uploader = new Slingshot.Upload("pictures")
new Promise((resolve, reject) ->
processImage(file, 300, 300, resolve)
)
.then((dataUri) ->
match = /^data:([^;]+);base64,(.+)$/.exec(dataUri)
[file.name, match[1], match[2]]
)
.then(([name, type, b64]) ->
new Promise((resolve, reject) ->
blob = b64ToBlob(b64, type)
blob.name = name
uploader.send(blob, (error, downloadUrl) ->
if error?
reject(error.message)
else
resolve(downloadUrl)
)
)
)