Image Picker is the result of a larger project I’ve been working on that needed an interface for allowing a user to select and upload an image to a CloudKit database as part of a web app for maintaining a list of movie screenings. I pulled out the relevant code to make this stand-alone HTML/CSS/JavaScript module.

My task is to give the user an easy way to select an image from their file system. But I need to keep things efficient for the CloudKit database and I have a specific design spec for how the images are displayed in the final product. Users are free to choose any image but the width and height must meet a minimum pixel size and the final image must adhere to a specific aspect ratio. In my case, I want square images at 440px by 440px.
I jumped in and started working with HTML’s <input>
tag using the type: file. The input appears as a button with a label that identifies a chosen file. It’s an easy-to-implement feature but it comes with drawbacks. The developer has almost no ability to style the button and label it.
|
|
But a button isn’t enough, I also want a drop zone to allow a user to drag and drop an image file. Drag events are another HMTL5 feature that are relatively easy to implement. I added drag event handlers to a drop zone <div>
. The ondrop handler passes in an event with a dataTransfer.files property.
|
|
Conveniently, the ondrop event can piggyback on the file-input onchange event handler function. A newly instantiated fileReader object will process the file as an arrayBuffer.
|
|
The user needs to be given an opportunity to see the original image as well as the final (cropped) version and make some adjustment to get the best composition from the original. There are a lot of examples online of JavaScript libraries for image cropping and resizing. But in my case they were overkill. I didn’t need the ability to grab and stretch the corners of a resize window or move an overlay in 360 degrees. I just need a simple overlay that conforms to the aspect ratio I desire and gives the user the ability to slide it across their image either up & down or side to side, whichever is the larger dimension.

The overlay slides side to side and highlights the final cropped composition.
Most of my time went into this aspect of the work. It involves two overlapping <canvas>
elements (one to hold the selected image and the other to render an overlay box to indicate the cropped composition) and a container <div>
to manage the mouse or touch events to move the overlay box.
|
|
When the image is loaded, the <canvas>
and <div>
change size to accommodate the aspect ratio of the selected image. A portrait oriented image will increase the height while a landscape oriented image will increase the width of the tags. It requires a final function to read the pixel dimensions from the selected files. No small task as you may know if you’ve ever tried to read the technical spec for evaluating the raw data of a JPEG. There’s a possible EXIF IFD header marker with an optional SubIFD marker and 16 available Start Of Frame markers — each of which may or may not have pixel dimension data that could refer to the actual image or it could refer to the thumbnail image (augghhhh!).
For all the effort the final product seems to have been worth it. The complete HTML/CSS/JavaScript files are at Codepen and GitHub. So far it handles any PNG or JPEG file I throw at it. I’ll add TIFF and GIF formats when I get around to it.