0

I currently use PILLOW to convert some images to base64 for use in a flask API, It works quite well but for some reason it crashes on a BMP file and I don't know why.

Here is my code :

def get_img_base64(filename):
    # Open Image
    image = Image.open(filename)
    # Saving the format
    format = image.format
    buffered = BytesIO()
    image.save(buffered, format)
    img_str = base64.b64encode(buffered.getvalue())
    return "data:image/" + format + ";base64," + img_str.decode()

And here is the error I get :

Traceback (most recent call last):
  File "test.py", line XXX, in XXX
    imgBase64 = get_img_base64(path)
  File "test.py", line XXX, in get_img_base64
    image.save(buffered, format)
  File "python3.10/site-packages/PIL/Image.py", line 2264, in save
    self._ensure_mutable()
  File "python3.10/site-packages/PIL/Image.py", line 626, in _ensure_mutable
    self._copy()
  File "python3.10/site-packages/PIL/Image.py", line 619, in _copy
    self.load()
  File "python3.10/site-packages/PIL/ImageFile.py", line 234, in load
    err_code = decoder.decode(b"")[1]
  File "python3.10/site-packages/PIL/BmpImagePlugin.py", line 326, in decode
    self.set_as_raw(bytes(data), ("P", 0, self.args[-1]))
  File "python3.10/site-packages/PIL/ImageFile.py", line 684, in set_as_raw
    d = Image._getdecoder(self.mode, "raw", (rawmode))
  File "python3.10/site-packages/PIL/Image.py", line 435, in _getdecoder
    return decoder(mode, *args + extra)
ValueError: unknown raw mode for given image mode

I already tried this solution by converting the image to "P" but the error ValueError: unknown raw mode for given image mode is also showing on this conversion.

Here is the image in question

Here is the reuslt of the exiftool -v IMG.BMP command :

  ExifToolVersion = 12.40
  FileName = IMG.BMP
  Directory = .
  FileSize = 44978
  FileModifyDate = 1655391432
  FileAccessDate = 1655391514
  FileInodeChangeDate = 1655454712
  FilePermissions = 33272
  FileType = BMP
  FileTypeExtension = BMP
  MIMEType = image/bmp
  + [BinaryData directory, 40 bytes]
  | BMPVersion = 40
  | ImageWidth = 594
  | ImageHeight = 163
  | Planes = 1
  | BitDepth = 8
  | Compression = 1
  | ImageLength = 43900
  | PixelsPerMeterX = 2833
  | PixelsPerMeterY = 2833
  | NumColors = 256
  | NumImportantColors = 256

3 Answers3

3

Adding this line has solved my problem

mask = mask.convert('P')
1

This doesn't make much sense to me. You appear to have a JPEG, PNG or BMP-encoded image on disk in a file called filename. You then decode/decompress it into memory with:

image = Image.open(filename)

You then re-encode it back to exactly the same format (JPEG/PNG/BMP) as it was using before, but in RAM:

format = image.format
buffered = BytesIO()
image.save(buffered, format)

What is the point of that? You might just as well simply read the already-encoded file from disk:

with open(filename, 'rb') as fd:
   image = fd.read()

It might make sense if you always wanted to encode to a specific format regardless of input format, e.g. always make a PNG or always make a JPEG, but you didn't say that was the case and it might not be sensible to convert PNGs with transparency to JPEG which cannot support transparency.


It might make sense if you always want to encode to a specific quality setting, but you did't say that either.


It might make sense if you have some images in a format that flask and the user's web browser don't accept, but you didn't say that either.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • Yes, what I failed to mention is that, I have an optional param that I use to sometimes resize the image using pillow and then returning the resized base64 string instead of actually resizing the file. – PythonNewbie Jun 16 '22 at 19:44
  • I'm guessing the problem will arise either when a palette or transparency is involved, i.e. `mode` contains `P` or `A`. I suggest you print the image mode as soon as you open it and try to see if there is a mode that causes problems. Then click `edit` and add your problematic image and details of what you find. – Mark Setchell Jun 16 '22 at 20:53
  • The image mode is `L` is that makes sense – PythonNewbie Jun 17 '22 at 07:09
  • You could check if mode is `L`, see https://stackoverflow.com/a/52307690/2836621 and if so, convert to `RGB` with `image = image.convert('RGB')` – Mark Setchell Jun 17 '22 at 07:12
  • I get the same `ValueError: unknown raw mode for given image mode` on the convert – PythonNewbie Jun 17 '22 at 07:16
  • I can't really guess much more without 1) seeing the exact code you are running 2) seeing the full error traceback and 3) seeing the image causing the problem - - in its full natural state - i.e. not in reduced resolution nor a screengrab of it nor a JPEG version of a TIFF or similar. – Mark Setchell Jun 17 '22 at 07:23
  • I woulkd gladly send you the image but I don't know how. The code I posted is minimum viable exemple for you to repoduce the crash if you have the image in question. – PythonNewbie Jun 17 '22 at 07:54
  • You can maybe use Dropbox, or Google Drive or something similar. – Mark Setchell Jun 17 '22 at 08:02
  • Or you can click [edit] and add to your question the output from `exiftool -v YOURIMAGE` or from **ImageMagick** `identify -verbose YOURIMAGE` – Mark Setchell Jun 17 '22 at 08:18
  • I uploaded the image on a google drive, it should be better than the default upload from stackoverflow – PythonNewbie Jun 17 '22 at 08:36
  • Your image is a BMP with RLE compression. Pillow only supports that from version 9.1.0 You can check your version and what is supported with `python3 -m PIL` – Mark Setchell Jun 17 '22 at 09:49
  • I have PIL last version `9.1.1` and Python `3.10.4` – PythonNewbie Jun 17 '22 at 10:01
  • Mmmmm... I think you may need to raise an issue with the PIL developers. It is enough to do `im = Image.open('YOURIMAGE').convert('RGB')` to cause the issue. – Mark Setchell Jun 17 '22 at 18:40
1

It was an issue with the PILLOW Library. It should be fixed in the next release as this PR suggests