Many apps have features that allow users to post images and share with other users. A very soon to be released version of Kids In Touch allows users to send pictures to their friends and family.
There are many solutions for hosting images. However, with most of them, all the image processing is left up to the developer. For example, you can push images and host quite easily to Amazon's S3. However, your app probably shouldn't be displaying full resolution images to it's users. Imagine having 60 8MB images in your twitter feed all sitting in the DOM. Your user's data would be out the roof and the app would slow down like crazy. So, with S3, you'd need to know when a new picture was posted, run a processing script to resize it in various dimensions, update your database with all of these different locations, and finally make them available to your users.
Using Cloudinary makes all of those issues simply go away. You can configure Cloudinary to do "eager transformations" so that every time a picture is uploaded, they automatically create duplicates in all the correct dimensions. Or, you can just leave the original image there. Then, in your app, you configure the dimensions you want to retrieve. When an image in those dimensions is requested, Cloudinary will create it on the fly. Pretty amazing stuff really.
So, how do you get your images from an Ionic Framework app into Cloudinary? Whew. There are lots of options. Unfortunately, Cloudinary really likes jQuery. They also have an AngularJS uploader, but it uses jQuery. They also use a process where your server must provide the client a signature in order to push an image to Cloudinary. I struggled over and over with all these options and never got any of them to work. Every signature I generated failed.
Finally, I discovered Unsigned Uploads. This setting allows you to push images to Cloudinary without signatures. Even neater, is that you can assign "Upload Presets" that have settings for all the transformations you want. You can even create nice profile photos from face detection. Pretty cool!
Now, getting the images from your app to Cloudinary is as simple as installing 2 Cordova/PhoneGap plugins:
cordova plugin add org.apache.cordova.file
cordova plugin add org.apache.cordova.file-transfer
Here's an Image Upload service that processes a request to upload an image:
``` | |
(function() { | |
/** | |
* @ngInject | |
*/ | |
function ius($q, $ionicLoading, $cordovaFile, $translate, CLOUDINARY_CONFIGS) { | |
var service = {}; | |
service.uploadImage = uploadImage; | |
return service; | |
function uploadImage(imageURI) { | |
var deferred = $q.defer(); | |
var fileSize; | |
var percentage; | |
// Find out how big the original file is | |
window.resolveLocalFileSystemURL(imageURI, function(fileEntry) { | |
fileEntry.file(function(fileObj) { | |
fileSize = fileObj.size; | |
// Display a loading indicator reporting the start of the upload | |
$ionicLoading.show({template : 'Uploading Picture : ' + 0 + '%'}); | |
// Trigger the upload | |
uploadFile(); | |
}); | |
}); | |
function uploadFile() { | |
// Add the Cloudinary "upload preset" name to the headers | |
var uploadOptions = { | |
params : { 'upload_preset': CLOUDINARY_CONFIGS.UPLOAD_PRESET} | |
}; | |
$cordovaFile | |
// Your Cloudinary URL will go here | |
.uploadFile(CLOUDINARY_CONFIGS.API_URL, imageURI, uploadOptions) | |
.then(function(result) { | |
// Let the user know the upload is completed | |
$ionicLoading.show({template : 'Upload Completed', duration: 1000}); | |
// Result has a "response" property that is escaped | |
// FYI: The result will also have URLs for any new images generated with | |
// eager transformations | |
var response = JSON.parse(decodeURIComponent(result.response)); | |
deferred.resolve(response); | |
}, function(err) { | |
// Uh oh! | |
$ionicLoading.show({template : 'Upload Failed', duration: 3000}); | |
deferred.reject(err); | |
}, function (progress) { | |
// The upload plugin gives you information about how much data has been transferred | |
// on some interval. Use this with the original file size to show a progress indicator. | |
percentage = Math.floor(progress.loaded / fileSize * 100); | |
$ionicLoading.show({template : 'Uploading Picture : ' + percentage + '%'}); | |
}); | |
} | |
return deferred.promise; | |
} | |
} | |
angular.module('yourAppName').factory('ImageUploadService', ius); | |
})(); | |
``` |
Now, you send a request to the service like this:
ImageUploadService.uploadImage(scope.imageURI).then( | |
function(result) { | |
var url = result.secure_url || ''; | |
var urlSmall; | |
if(result && result.eager[0]) urlSmall = result.eager[0].secure_url || ''; | |
// Do something with the results here. | |
$cordovaCamera.cleanup(); | |
}, | |
function(err) { | |
// Do something with the error here | |
$cordovaCamera.cleanup(); | |
} |