GH

Unexplained image rotation with Jekyll

In building this site, one of the things I encountered was that an image I was trying to include in a post keep appearing rotated for some unknown reason. Having been a little rusty on the web development front, I kept assuming that I must be doing something wrong–perhaps a mistake in the HTML, or more likely, some sort of “confusion” in the CSS. But I also use Jekyll? Who the heck knows what’s going on here!!

The Devil is in the Details

After trying everything I could think of, to include using Firebug and looking at all of the computed CSS affecting my image element, I decided it was time to drill down deeper. Perhaps there would be something in the EXIF metadata of the image itself?

Lets take a look; I used the below Python code to print out EXIF data for the image in question.

1
2
3
4
5
6
7
8
9
10
from PIL.ExifTags import TAGS
from PIL import Image

image_file = "IMG_0646.JPG"
im = Image.open(image_file)

print "exif data:",
for tag, value in im._getexif().items():
    tag_name = TAGS.get(tag, tag)
    print "{}:{}".format(tag_name, value)

I saw the following EXIF entries:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
exif data: ExifVersion:('0221',)
ComponentsConfiguration:('\x01\x02\x03\x00',)
ApertureValue:(2.2750071245369052,)
DateTimeOriginal:(u'2015:08:30 11:34:35',)
DateTimeDigitized:(u'2015:08:30 11:34:35',)
FocalLengthIn35mmFilm:(31,)
FlashPixVersion:('0100',)
MeteringMode:(5,)
Flash:(32,)
FocalLength:(2.65,)
ExifImageWidth:(1280,)
Make:Apple
Model:iPhone 6 Plus
SubsecTimeOriginal:(u'536',)
Orientation:6
YCbCrPositioning:1
SensingMethod:(2,)
ExposureBiasValue:(0.0,)
XResolution:72.0
YResolution:72.0
ExposureTime:(0.016666666666666666,)
ExposureProgram:(2,)
ColorSpace:(1,)
SceneCaptureType:(0,)
ISOSpeedRatings:(40,)
ResolutionUnit:2
WhiteBalance:(0,)
LensSpecification:(2.65, 2.65, 2.2, 2.2)
FNumber:(2.2,)
Software:8.4.1
DateTime:2015:08:30 11:34:35
LensMake:(u'Apple',)
ShutterSpeedValue:(5.906947890818858,)
LensModel:(u'iPhone 6 Plus front camera 2.65mm f/2.2',)
SceneType:('\x01',)
ExifImageHeight:(960,)
ExposureMode:(0,)
ExifOffset:196
SubsecTimeDigitized:(u'536',)
BrightnessValue:(5.108784473953014,)
MakerNote:('Apple iOS\x00\x00\x01MM\x00\x08\x00\x01\x00\t\x00\x00\x00\x01\x00\x00\x00\x02\x00\x03\x00\x07\x00\x00\x00h\x00\x00\x00t\x00\x04\x00\t\x00\x00\x00\x01\x00\x00\x00\x01\x00\x05\x00\t\x00\x00\x00\x01\x00\x00\x00\xb8\x00\x06\x00\t\x00\x00\x00\x01\x00\x00\x00\xb8\x00\x07\x00\t\x00\x00\x00\x01\x00\x00\x00\x01\x00\x08\x00\n\x00\x00\x00\x03\x00\x00\x00\xdc\x00\x0e\x00\t\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00bplist00\xd4\x01\x02\x03\x04\x05\x06\x07\x08UflagsUvalueUepochYtimescale\x10\x01\x13\x00\x01\xe6\xcb\x0b{\xad\xb8\x10\x00\x12;\x9a\xca\x00\x08\x11\x17\x1d#-/8:\x00\x00\x00\x00\x00\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x01\x85\x00\x002\xf3\xff\xff\xe0;\x00\x00"\xbd\xff\xff\xfa)\x00\x00\x0f\xf1',)

What is that, burried on line 15, Orientation:6? According to http://www.impulseadventure.com/photo/exif-orientation.html, this piece of EXIF data was placed by the camera to denote the camera’s orientation relative to the ground when the picture was taken.

It turns out that most “sophisticated” image viewers will read this tag and impose the necessary rotation on the encoded image to make it once again appear correct. In my case, that means the image will be rotated 90 degrees clockwise only when displayed by that viewer. Modern web browsers do not seem to fall into this class of “sophisticated” image viewers, rendering only the image as it was encoded, and hence telling the story of why my image was appearing to be randomly rotated by my website. How can I fix it?

The fix

The solution to the problem is to re-encode the image with the correct orientation. For example, an image with a size of 640x480 needs to become the same image translated 90 degrees, giving it a new size of 480x640. Fortunately, we can easily accomplish this in Python, building off of our code from before, by transposing the image and saving it back out to disk:

1
im.transpose(Image.ROTATE_270).save(image_file)

Just like that, we now have a correctly rotated image that less sophisticated image viewers, like web browsers, will render as intended.

If you liked this post, you can share it with your followers or follow me on Twitter!