I am attempting to save an image in PNG format into a BytesIO object and read the same from buffer, but I get the following error:
ValueError: not enough image data
This is what I am attempting:
i = Image.open('sample_small.png') # Image.fromarray(img_array)
buf = BytesIO()
i = i.resize(size=(int(i.width/2), int(i.height/2)))
i.save(buf, format="PNG", compress_level=9)
buf.seek(0)
i = Image.frombuffer(data=buf.getvalue(), size=i.size, mode=i.mode, decoder_name="raw")
buf.close()
i.show()
could someone point out the right way to do this?
In the real use case, the original image is available as an array, so it is obtained by first loading the array as an Image using:
i = Image.fromarray(img_array)
The objective is to send the image to a zmq receiver as bytes object and hence I need to compress the image as PNG with max. compression, store it into a temporary file-like object as bytes and then publish it using zmq, hence saving the image to a file and then loading the image to use i.tobytes()
is also not optimal.
Since the receiver uses the Image.frombuffer()/ Image.frombytes() method to load the image, I want to know the right way to save the image data to a buffer that can be read by the receiver.
Thanks in advance!
The image I used in this example:
frombuffer
is expecting pixel data, but you are giving it a compressed png. Since it's already a png file, open
it.
from PIL import Image
from io import BytesIO
def png_bytes(path:str, scale:float, compress_level:int=9) -> bytes:
#image setup
img = Image.open(path)
img = img.resize(size=(int(img.width*scale), int(img.height*scale)))
with BytesIO() as buff:
#save png file to buff
img.save(buff, format="PNG", compress_level=compress_level)
#get bytes
buff.seek(0)
out = buff.read()
return out #return bytes
#get bytes
img = png_bytes('sample_small.png', .5)
#open bytes as BytesIO
Image.open(BytesIO(img)).show()