49

I found out how to use PIL to get the image dimensions, but not the file size in bytes. I need to know the file size to decide if the file is too big to be uploaded to the database.

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Abdelouahab Pp
  • 4,252
  • 11
  • 42
  • 65

5 Answers5

51

Try:

import os
print os.stat('somefile.ext').st_size
thebjorn
  • 26,297
  • 11
  • 96
  • 138
  • there is now way to use PIL itself? – Abdelouahab Pp Aug 10 '12 at 14:56
  • 4
    Why would you need to use PIL? – thebjorn Aug 10 '12 at 15:00
  • to control if it's an image not a forged image header, to make an upload profil, and then store it to the database, so it is obvious to make a method in PIL to get the size in bytes no? – Abdelouahab Pp Aug 10 '12 at 15:04
  • 7
    No, not obvious at all. PIL deals with image manipulations in memory, and for that it uses an internal representation that is efficient for manipulating pixels. This representation may, or may not, correspond to the size the image will have when saved as a specific format... – thebjorn Aug 10 '12 at 15:06
  • but i think the size is hidden somewhere in image header file when converting to bytes? like its extension? – Abdelouahab Pp Aug 10 '12 at 15:07
  • You can certainly do `len(pilimg.tostring())`, but that number has no practical value if you're going to store the image in a database. You should store the file as-is (on disk). If you try to save the "bytes" that you somehow extract from PIL, you'll just end up having to use PIL to convert it back to an image when reading it from the database -- which would make it infinitely less useful. – thebjorn Aug 10 '12 at 15:23
  • finally, the problem is from the beginnig, if someone will upload a picture that have 1 giga (forged one) he'll kill the server before PIL will do its stuff, so i must block the request before it finishs! – Abdelouahab Pp Aug 10 '12 at 17:52
25

If you already have the image on the filesystem:

import os
os.path.getsize('path_to_file.jpg')    # Get the size in bytes.

If, however, you want to get the saved size of an image that is in memory and has not been saved to the filesystem:

from io import BytesIO
img_file = BytesIO()
# quality='keep' is a Pillow setting that maintains the quantization of the image.
# Not having the same quantization can result in different sizes between the in-
# memory image and the file size on disk.
image.save(img_file, 'png', quality='keep')
image_file_size = img_file.tell()

NOTE: if you use a different quality setting for each method you can end up with a smaller size in one or the other.

This method will avoid multiple reads of the image data as with StringIO. Note, however, that it will use more RAM. Everything is a tradeoff. :-)

Edit: I just saw this comment from the OP:

finally, the problem is from the beginnig, if someone will upload a picture that have 1 giga (forged one) he'll kill the server before PIL will do its stuff, so i must block the request before it finishs!

This is a very different question, and is probably best accomplished at the web server. For nginx, you can add this to your configuration:

http {
    #...
        client_max_body_size 100m; # or whatever size you want as your limit
    #...
}
volkut
  • 85
  • 1
  • 2
  • 6
Scott A
  • 7,745
  • 3
  • 33
  • 46
  • The `BytesIO` method seems to underestimate the size compared to getting the size from desk. Any idea why? – getup8 Jan 12 '17 at 22:53
  • I'm seeing the same behavior as @getup8 ^^ – n8jadams Aug 31 '22 at 21:44
  • I've amended the code to note the quantization setting. `quality` defaults to `75`, which may or may not be the same as the image file on disk. `quality="keep"`, on the other hand, is a Pillow parameter that will keep the same quantization as the image originally had. Note: I have not tested this, but some details may be found here: https://stackoverflow.com/questions/4354543/determining-jpg-quality-in-python-pil/4355281#4355281 :-) – Scott A Sep 01 '22 at 17:34
16

I think this is the true measure and the fastest one of the size of the image in bytes in memory:

print("img size in memory in bytes: ", sys.getsizeof(img.tobytes()))

Then, the size of the file on disk depends on the format of the file:

from io import BytesIO
img_file = BytesIO()
img.save(img_file, 'png')
img_file_size_png = img_file.tell()
img_file = BytesIO()
img.save(img_file, 'jpeg')
img_file_size_jpeg = img_file.tell()
print("img_file_size png: ", img_file_size_png)
print("img_file_size jpeg: ", img_file_size_jpeg)

Possible output for 32 x 32 x 3 images from CIFAR10 dataset:

img size in memory in bytes:  3105    
img_file_size png:  2488
img_file_size jpeg:  983
Tiago Martins Peres
  • 14,289
  • 18
  • 86
  • 145
ady
  • 1,108
  • 13
  • 19
  • 1
    `sys.getsizeof()` gave me a massive overestimate of a jpeg file, an overestimate for a webp file. For the png file I tested it worked ok. Can also just call `img.tobytes().__sizeof__()` but neither of these methods seem to be reliable. – getup8 Dec 01 '19 at 07:43
6

To find the Size(In bytes) of an image using Pillow Library, please use the below code. It will working fine.

from PIL import Image
image_file = Image.open(filename)
print("File Size In Bytes:- "+str(len(image_file.fp.read()))

Make sure that you have pillow library installed:-

pip install pillow
RG Jr.
  • 87
  • 1
  • 1
  • 2
    This does not work if you modify the image (using resize, for example) and have not saved the image to disk. – jenniwren Feb 09 '20 at 20:18
5

I'm a bit late to this, but I came across this question 5 mins ago when searching how to get the size of a PIL image without saving it to disk. In case anyone else comes across this, this is a simple way of doing it:

import StringIO
output = StringIO.StringIO()
image_output.save(output, 'PNG') #a format needs to be provided
contents = output.getvalue()
output.close()

image_filesize = len(contents)
Peter
  • 3,186
  • 3
  • 26
  • 59