Python, how can I asynchronously save the PIL images?

Viewed 1110

For asynchronous file saving, I can use aiofiles library.

To use aiofiles library I'd have to do something like that:

async with aiofiles.open(path, "wb") as file:
   await file.write(data)

How can I asynchronously save the PIL images? Even if I use Image.tobytes function to save it with file.write(data), the saved image isn't correct.

So how can I asynchronously save a PIL image?

3 Answers

Thanks to the comment posted by @MarkSetchell I managed to find the solution.

async def save_image(path: str, image: memoryview) -> None:
    async with aiofiles.open(path, "wb") as file:
        await file.write(image)


image = Image.open(...)
buffer = BytesIO()
image.save(buffer, format="JPEG")

await save_image('./some/path', buffer.getbuffer())

I don't know how much speed one can gain, but in my case, I'm able to run some data processing code, data downloading code, and image saving code concurrently which gives me a speed up.

@CrazyChucky, thanks for point out the async sync . I worked again on this

from fastapi import File,UploadFile
from PIL import Image,ImageFont, ImageDraw
from io import BytesIO

@router.post("/users/update_user_profile")
async def upload_file(self, image_file : UploadFile = File(None)):         
   out_image_name = 'image_name'+pathlib.Path(image_file.filename).suffix    
   out_image_path = f"images/user/{out_image_name}"
   request_object_content = await image_file.read()
   photo = Image.open(BytesIO(request_object_content)) 
   # make the image editable
   drawing = ImageDraw.Draw(photo)
   black = (3, 8, 12)   
   drawing.text((0,0), 'Your_text', fill=black)#, font=font)
  
   # Create a buffer to hold the bytes
   buf = BytesIO()

   # Save the image as jpeg to the buffer
   photo.save(buf, format='JPEG')#    

   async with aiofiles.open(out_image_path, 'wb') as out_file:       
       outContent = await out_file.write(buf.getbuffer())  # async write    

  return out_image_name 

I referred @Karol suggestion. Check now, this is for fastapi async method

In my case, following worked ( using python fastapi)

from fastapi import File,UploadFile
from PIL import Image,ImageFont, ImageDraw
from io import BytesIO

async def upload_file(image_file : UploadFile = File(None)):       
    out_image_name = str(123)+pathlib.Path(image_file.filename).suffix 
    out_image_path = f"images/user/{out_image_name}"
    request_object_content = await image_file.read()
    photo = Image.open(BytesIO(request_object_content)) 
    # make the image editable
    drawing = ImageDraw.Draw(photo)
    black = (3, 8, 12)
    # font = ImageFont.truetype("Pillow/Tests/fonts/FreeMono.ttf", 40)
    drawing.text((0,0), 'text_to_water_mark', fill=black)#, font=font)
    photo.save(out_image_path)
Related