As noted by comments, PIL does not load the image into memory when .open called. Looking at the PIL 1.1.7 docs, the docstring for .open says:
def open(fp, mode="r"): "Open an image file, without loading the raster data"
There are several file operations in the source, for example:
... prefix = fp.read(16) ... fp.seek(0) ...
but they hardly constitute reading the entire file. In fact .open simply returns the file object and file name on success. In addition, docs say:
open (file, mode = "r")
Opens and identifies the given image file.
This is a lazy operation; this function identifies the file, but the actual image data is not read from the file until you try to process the data (or call the load method).
Digging deeper, we see that .open calls _open , which is a specific overload in image format. Each of the _open implementations can be found in a new file, for example JpegImagePlugin.py are in JpegImagePlugin.py . Let's look at it in depth.
Here, it seems a bit complicated, it has an infinite loop that breaks from when the jpeg marker is found:
while True: s = s + self.fp.read(1) i = i16(s) if i in MARKER: name, description, handler = MARKER[i] # print hex(i), name, description if handler is not None: handler(self, i) if i == 0xFFDA: # start of scan rawmode = self.mode if self.mode == "CMYK": rawmode = "CMYK;I" # assume adobe conventions self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))] # self.__offset = self.fp.tell() break s = self.fp.read(1) elif i == 0 or i == 65535: # padded marker or junk; move on s = "\xff" else: raise SyntaxError("no marker found")
It looks like he could read the whole file if it was garbled. If he reads the information marker OK, he should exit earlier. The handler function ultimately sets self.size , which are the dimensions of the image.