PILLOW throws ValueError: unknown raw mode for given image mode
Question:
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 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
Answers:
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.
It was an issue with the PILLOW Library. It should be fixed in the next release as this PR suggests
Adding this line has solved my problem
mask = mask.convert('P')
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 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
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.
It was an issue with the PILLOW Library. It should be fixed in the next release as this PR suggests
Adding this line has solved my problem
mask = mask.convert('P')