Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchCamera photos usually look correct before upload and sideways afterward because the file stores its pixels in sensor order and carries an EXIF Orientation tag that tells viewers how to rotate or mirror them. Code that resizes or re-saves the image without applying that tag produces a derivative whose pixels are still in the wrong order. The fix is to apply the orientation once, before any resize, thumbnail, or format conversion, and then deal with the metadata deliberately, because removing the orientation tag does not guarantee that every other EXIF field survives the save.
Why the photo looks right at upload and wrong after processing
A camera records the image as it came off the sensor and writes the device’s orientation into the EXIF block under tag 274 (Orientation). The value is a number from 1 to 8. A value of 1 means the pixels are already upright. Any other value means a viewer must rotate or mirror the pixels before display. Browsers, operating systems, and photo apps read that tag and show the picture upright, which is why the original looks fine.
As an Amazon Associate I earn from qualifying purchases.
Your Python worker usually does not apply the tag. It opens the file, calls resize() or thumbnail(), and saves the result. The new file has pixels in the sensor order and, in many cases, no orientation tag left to correct them. The derivative therefore looks sideways in any viewer, even though the original never did.
That gives you a simple diagnostic question for every bug report: does the original’s tag 274 value differ from 1, and does the derivative still have pixels in the un-rotated order?
#1 Best Overall
- Fast for better pictures and Full HD video. Full HD (1920x1080) video support may vary based upon host device, file attributes, and other factors
- Great choice for compact to mid-range point-and-shoot cameras
- From 32GB to 256GB(1) to store tons of pictures and even more Full HD video(2). (1)1GB=1,000,000,000 bytes Actual user storage less
- Exceptional video recording performance with UHS Speed Class 1 (U1)(5) and Class 10 rating for Full HD video (1080p)(2). (5)UHS Speed Class 1 (U1) designates a performance option to support real time video recording with UHS enabled host devices
- Quick transfer speeds up to 100MB/s. Up to 100MB/s[64GB-256GB; 90MB/s for 32GB] read speed; write speed lower Based on internal testing; performance may be lower depending on host device, usage conditions, and other factors 1MB=1,000,000 bytes
Step 1: Read the format, size, and Orientation value at ingestion
Log the file format, the pixel dimensions, and the numeric Orientation value for each upload. Log only these fields and a request or job identifier, not the full metadata dump, which can contain location and device data.
from PIL import Image
with Image.open("upload.jpg") as im:
print(im.format, im.size, im.getexif().get(274))
Typical output for a phone photo held in portrait is JPEG (3024, 4032) 6. The stored pixels are 3024 wide and 4032 tall, but the value 6 says the image must be rotated 90 degrees clockwise before display. A value of 1 or a missing tag means no transform is needed, and a sideways result in that case points to a different cause, covered in the troubleshooting section below.
Step 2: Understand what each Orientation value does
Values 2 through 8 include mirrored cases, not only rotations. Pillow’s ImageOps.exif_transpose handles all of them. The table maps each tag value to the Pillow transpose operation that the function applies.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Rank #2
- Great choice for compact to mid-range point-and-shoot cameras
- Quick transfer speeds up to 150MB/s (Up to 150MB/s read speed engineered with proprietary technology to reach speeds beyond UHS-I 104MB/s, requires compatible devices capable of reaching such speeds. Based on internal testing; performance may be lower depending on host device, interface, usage conditions and other factors. 1MB=1,000,000 bytes.)
- Up to 256GB to store tons of pictures (1GB=1,000,000,000 bytes. Actual user storage less.)
- Exceptional video recording performance with UHS Speed Class 1 (U1) Class 10 rating for Full HD video (1080p) (UHS Speed Class 1 (U1) designates a performance option designed to support real time video recording with UHS enabled host devices. See consumers speed page on SanDisk site. Full HD (1920x1080) video support may vary based upon host device, file attributes, and other factors. Visit the SanDisk Video Knowledge Base for more information.)
- Compatible with SanDisk SD UHS-I card reader (sold separately)
| Tag 274 value | Required correction for display | Pillow transpose applied |
|---|---|---|
| 1 | None; pixels are already upright | None |
| 2 | Mirror left to right | FLIP_LEFT_RIGHT |
| 3 | Rotate 180 degrees | ROTATE_180 |
| 4 | Mirror top to bottom | FLIP_TOP_BOTTOM |
| 5 | Mirror across the main diagonal | TRANSPOSE |
| 6 | Rotate 90 degrees clockwise | ROTATE_270 (Pillow’s counter-clockwise name) |
| 7 | Mirror across the anti-diagonal | TRANSVERSE |
| 8 | Rotate 90 degrees counter-clockwise | ROTATE_90 (Pillow’s counter-clockwise name) |
Mirrored values are the hard ones to notice. A mirrored photo can look almost right to a developer who checks only that the subject is upright, while text, logos, or asymmetric backgrounds show the reversal. Include at least one mirrored test image in your fixtures.
Step 3: Normalize once, before any derivative is created
Call ImageOps.exif_transpose on the opened upload and generate every derivative from its result. In Pillow’s current documentation, the default call returns a new image and leaves the original object untouched. Passing in_place=True modifies the original and returns None, so do not assign its return value to a variable and expect an image back.
from PIL import Image, ImageOps
with Image.open("upload.jpg") as im:
upright = ImageOps.exif_transpose(im)
upright.thumbnail((800, 800))
upright.save("thumb.jpg", quality=90)
Confirm the installed version before relying on the in_place argument, since it is the newer part of the API. Check it with python -c "import PIL; print(PIL.__version__)" or pip show pillow.
Rank #3
- Brand: Sandisk
The Pillow documentation describes the core behavior in one sentence: “If an image has an EXIF Orientation tag, other than 1, transpose the image accordingly, and remove the orientation data.” The second half of that sentence is what causes the metadata problem in the next section.
Recommended Free Tools
Step 4: Preserve the other EXIF fields without restoring the rotation
Removing the Orientation tag is deliberate and correct. It is also the reason a naive “keep the EXIF” approach goes wrong. If you copy the original EXIF bytes and pass them to the save call, the copy still contains tag 274 with its original value. Viewers that honor the tag will rotate the already-upright pixels a second time.
The safer pattern is to capture the original EXIF, delete the orientation entry from that copy, and pass the cleaned bytes to the encoder. Then verify the saved file, because the color conversion and encoder path can change what survives.
Rank #4
- Save time with card offload speeds of up to 200MB/s powered by SanDisk QuickFlow Technology (Up to 200MB/s read speeds, engineered with proprietary technology to reach speeds beyond UHS-I 104MB/s, require compatible devices capable of reaching such speeds. Based on internal testing; performance may be lower depending upon host device, interface, usage conditions and other factors. 1MB=1,000,000 bytes. X = 150KB/sec. SanDisk QuickFlow Technology is only available for 64GB, 128GB, 256GB, 512GB and 1TB capacities. 1GB=1,000,000,000 bytes. 1TB=1,000,000,000,000 bytes. Actual user storage less.)
- Pair with the SanDisk Professional PRO-READER SD and microSD to achieve maximum speeds (sold separately)
- Shot speeds up to 90MB/s (Write speed up to 90MB/s. Based on internal testing; performance may be lower depending upon host device. 1MB=1,000,000 bytes. X = 150KB/sec.)
- Perfect for shooting 4K UHD video and sequential burst mode photography (Full HD (1920x1080) and 4K UHD (3840 x 2160) video support may vary based upon host device, file attributes and other factors. See HD page on SanDisk site.)
- UHS Speed Class 3 (U3) and Video Speed Class 30 (V30) (UHS Speed Class 3 designates a performance option designed to support 4K UHD video recording with enabled UHS host devices. UHS Video Speed Class 30 (V30), sustained video capture rate of 30MB/s, designates a performance option designed to support real-time video recording with UHS enabled host devices. See the SD Association’s official website.)
from PIL import Image, ImageOps
with Image.open("upload.jpg") as im:
exif = im.getexif()
upright = ImageOps.exif_transpose(im)
if 0x0112 in exif:
del exif[0x0112] # Orientation is now baked into the pixels
upright.convert("RGB").save(
"out.jpg",
quality=90,
exif=exif.tobytes(),
)
Two points matter here. First, the cleaned bytes must be built from the copy you modified, not from the original file’s raw im.info["exif"], which still holds the orientation. Second, the RGB conversion before JPEG saving is exactly the kind of step that can drop or alter fields, so the presence of Make, DateTime, or other tags in the output is not guaranteed by this pattern alone. Check the saved file rather than assuming it.
Verify the output by reopening it:
from PIL import Image
with Image.open("out.jpg") as out:
print(out.size, out.getexif().get(274), out.getexif().get(271))
The Orientation value should be absent or equal to 1, and the Make value (271) should match the original if you intended to keep it. If the value is missing and you wanted it, the field was lost in conversion or saving, and you need to pass it explicitly or change the save path. Confirm support for other formats, such as PNG or WebP, in your installed Pillow version before extending this pattern to them.
Quick Recap
Test checklist
- Run the normalization on fixtures with Orientation values 1 through 8, including all four mirrored cases.
- Apply
exif_transposeto an already-normalized image and confirm that its pixels do not change again. Pillow’s own tests check that a second application does not transpose again. - Compare the derivative’s dimensions with the normalized image’s dimensions, not the raw upload’s. A 90-degree correction swaps width and height, so a portrait phone photo should come out taller than it is wide.
- Check the saved derivative’s tag 274 value and at least one non-orientation field you need.
- Check a thumbnail and a full-size output separately, because a transform applied only to one derivative is a common cause of mixed results.
Troubleshooting when the fix does not match the symptom
- The original is sideways too, and its tag is 1 or missing. The problem is not EXIF orientation. The pixels themselves are rotated, or a viewer is ignoring a different instruction. Inspect the original in a second, known-good viewer before changing code.
- The original looks correct, but the thumbnail is sideways. The thumbnail was probably created from the raw image, or the transform ran after
thumbnail(). Move the normalization call to the first line after opening. - The derivative is correct in size and content but still rotates in some viewers. The saved file still contains tag 274. Check that the EXIF bytes you passed came from the modified copy, not the original file.
- Required metadata disappeared after the change. The color conversion or the save path dropped it. Pass the EXIF explicitly, as in the example above, and verify it by reopening the file.
- A portrait image came out landscape, or the reverse. This is expected for 90-degree corrections. Update any code that assumes a fixed width and height, rather than the normalization step.
“
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




