Impressed by the likes of Facebook, Instagram and Twitter, and how they handle image upload, I decided I wanted to offer the same kind of accessible experience for an application I'm working on. Not able to find a turnkey component that met all of the requirements, I decided to built the perfect solution myself (of course, building is the part that's most fun for a software developer!).
I think the user experience is the most important thing here. Uploading a photo shouldn't be a hassle at all. Want to drag'n drop a picture from the file system? Shouldn't be a problem. Rather browse and select an image on your hard drive? Shouldn't be a problem either. Use Google's image search and drag from there? Sure, why not!? I mean one should not be hindered by technology... Of course, creating functionality that is that easy to use usually does present a bit of a challenge, but that's actually the fun part! I find it very rewarding to meet such a challenge and end up with something that works out as designed.
- Minimal interaction
- Support for drag 'n drop
- Crop at desired resolution
To build something that's fast, or at least perceived as fast, I implemented background uploading. People are used to uploading images straight from their camera. This gives high resolution and extremely large files. To further speedup the upload, the image is scaled to a lower resolution and cropped on the browser side. When the image manipulation is done, the upload starts. The image sent to the server is as small as possible. During upload, the progress is visible.
Mozilla Developer Network has excellent documentation online that got me up and running in no time [1
]. The sample code is a little rough, but at least I got my first prototype running real quick.
The first thing to do is handle file input. Either use drag 'n drop or use the good old file selector [2
]. Both are supported. To do image manipulations, modern browsers expose a canvas element [3
]. We use the canvas to scale down our image. Basically, the possibilities with the canvas are infinite, it supports all kinds of raw pixel manipulations. Later on for example, we use the canvas to rotate our image.
When image processing is done, the upload is started. To do background uploading, browsers support the XMLHttpRequest object [4
]. XMLHttpRequest makes sending HTTP requests very easy. You simply create an instance of the object, open a URL, and send the request, in our case the image.
iPhone and iPad
From iOS version 6 and up it is possible to upload images straight from mobile Safari, the default browser on iOS. Unfortunately, this is not without a struggle. Due to an error in Safari for iOS, large photos will not display properly [5
]. Fortunately, it is easy to detect whether the rendering of the image was successful. In case the image does not appear to have been rendered correctly, the image is re-rendered with a fix applied.
Image Orientation Flag
Exchangeable image file format (EXIF) is a standard that specifies a format for tags used by digital cameras, including smartphones [7
]. Many digital cameras have a built-in orientation sensor. The output of this sensor is used to set the EXIF orientation flag in the image file's metatdata to reflect the positioning of the camera with respect to the ground [8
]. To respect the image orientation, we have to parse the meta data [9
]. Unfortunately it is currently not (yet) possible to write meta data back to the image, so we have to apply the rotation to the image. Fortunately, our canvas elements supports rotation.
Internet Explorer is still a challenge. Unfortunately, older versions do not enjoy the same level of user experience. The aim is full support even for older Internet Explorer version. Currently no version other then 10 is supported. Expect some fixes in this area later on...
Altogether summarized, the current list of features:
- Drag 'n drop support (drag from filesystem and webpage)
- Awareness of rotation info saved within JPEG (EXIF)
- Scaling and cropping is performed on the browser side
- Upload to server in the background
- Progress indicator shows current upload status
Well, enough text, see the results for yourself in this live demo!