How I Fixed the EXIF Orientation Bug in My Browser-Based Image Resizer
A few days ago, a user reached out with a frustrating bug report for my free browser-based Image Resizer. "I uploaded a photo from my iPhone, resized it, but now my face is sideways." If you've ever built an image proc
A few days ago, a user reached out with a frustrating bug report for my free browser-based Image Resizer.
"I uploaded a photo from my iPhone, resized it, but now my face is sideways."
If you've ever built an image processing tool, you know exactly what this is: the EXIF orientation bug.
Here is why it happens, and how I fixed it.
The "It Works on My Machine" Problem
When you upload a photo from a modern smartphone, the image file is often saved in landscape (e.g., 4032×3024). But if you held the phone vertically, the camera doesn't actually rotate the pixels. Instead, it writes a tiny piece of metadata called an EXIF Orientation tag (usually 6 or 8).
The phone's gallery app reads this tag and says, "Ah, I need to rotate this 90 degrees before showing it to the user."
But when you load that image into an HTML <canvas> using the classic method:
const img = new Image();
img.src = URL.createObjectURL(file);
// ... later ...
ctx.drawImage(img, 0, 0, newWidth, newHeight);
The canvas ignores the EXIF data. It just reads the raw pixels (landscape) and draws them. That's why the resized image looks sideways.
The Old Way (and why it's a headache)
For years, developers had to parse the image file's binary data manually using libraries like exif-js, read the orientation tag, and then write complex math inside the canvas context to manually rotate, flip, or mirror the image.
It worked, but it was a lot of code and prone to breaking.
The Modern Fix: createImageBitmap()
Modern browsers have a much better API for this: createImageBitmap().
Instead of just loading an <img> tag, you can pass the raw File object directly to this function and pass a configuration object with it. The magic property is imageOrientation: "from-image".
Here is how the logic looks in my tool now:
async function handleFile(file) {
try {
// The browser reads the file AND respects the EXIF data
const bitmap = await createImageBitmap(file, {
imageOrientation: "from-image"
});
// Now the width and height are correct, and the pixels are rotated
const originalWidth = bitmap.width;
const originalHeight = bitmap.height;
// Pass the bitmap to the canvas...
const canvas = document.createElement("canvas");
canvas.width = originalWidth;
canvas.height = originalHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(bitmap, 0, 0);
// ... rest of the resizing logic
} catch (err) {
console.error("Could not read image", err);
}
}
By adding imageOrientation: "from-image", the browser handles the EXIF rotation for you. It literally takes an iPhone photo taken in portrait mode and hands you a perfectly upright ImageBitmap ready for the canvas.
The Catch: Fallback for Older Browsers
createImageBitmap with the imageOrientation option is well-supported in modern Chrome, Edge, Firefox, and Safari. However, if you need to support very old browsers, you still have to fall back to the older new Image() method (which means the image might look sideways on ancient devices).
For my tool, I decided the trade-off was worth it. The vast majority of users are on modern browsers, and fixing the bug for 99% of users was better than keeping complex legacy code.
The Conclusion
If you are building an image resizer, cropper, or compressor in the browser, don't rely on the <img> tag if you are dealing with mobile uploads. Use createImageBitmap and let the browser do the heavy lifting.
It is one line of code that saved me hours of debugging and a lot of math.
If you want to see the tool in action, you can try it here: https://toolsvibe.online/tools/image-resizer/
Have you dealt with the EXIF orientation bug before? How did you solve it?
Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.