Bitwise and image resolution calculation in python. Can someone explain the code?

Viewed 188
with open("image.jpg",'rb') as file:
    file.seek(163)
    a = file.read(2)
    height = (a[0] << 8) - a[1]
    a = file.read(2)
    width = (a[0] << 8) - a[1]
print(str(height) + " x " + str(width))

I am still learning python. I know bitwise operators leftshift and rightshift. But I don't understand this code.

What I understand is:

  1. We open the image with binary reading as file.
  2. Move the cursor to 163 with file.seek(). Why 163?
  3. Read the file with size of 2 bytes. Why?

I don't understand the 4th line and 6th line at all. Print function is okay.

I tried with Pillow and cv2. But in case, I can't work with those modules, I think I should know this one.

2 Answers

It's crude and ugly but reading SOF0 which contains image height and width, see near the end of this article. It is actually incorrect too. It should be:

with open("image.jpg",'rb') as file:
   file.seek(163)
   a = file.read(2)
   height = (a[0] << 8) | a[1]     # It should be ORed in not subtracted
   print(height)
   a = file.read(2)
   width = (a[0] << 8)  | a[1]     # It should be ORed in not subtracted
   print(width)

See also Wikipedia entry on JPEG.


As a mini example, let's make a 640x480 red JPEG with ImageMagick:

magick -size 640x480 xc:red image.jpg

Now let's look for the SOF0 marker which is FF C0:

xxd -c16 -g1 -u image.jpg | grep -A2 "FF C0"
00000090: 10 10 10 10 10 10 10 10 10 10 10 10 10 10 FF C0  ................
000000a0: 00 11 08 01 E0 02 80 03 01 11 00 02 11 01 03 11  ................
000000b0: 01 FF C4 00 15 00 01 01 00 00 00 00 00 00 00 00  ................

If we check what 640 and 480 look like in hex:

printf "%x %x" 480 640
1e0 280

and you can see them at offset 163 into the file, because offset a0 is 160 and we are 3 bytes on from that.

Here is that code in plain language:

  1. Open the image.jpg file in read mode as a binary as variable 'file'
  2. Move the cursor to 163 (to get to where the size is stored for Frame 0 (part of the internals of a JPEG file, not necessarily always in that position))
  3. Read the 2 bytes that store the height into variable a
  4. Get the height by left shifting the first byte by 8 places and left then subtracting the second byte (note this doesn't give the correct answer, the - should be an | instead)
  5. Read the 2 bytes that store the width into variable a
  6. Get the width by left shifting the first byte by 8 places and then subtracting the second byte (note this doesn't give the correct answer, the - should be an | instead)
  7. Print the height and width as strings in 'height x width' format

There is a good writeup on decoding JPEG here 1

Related