from fastapi import FastAPI, File, UploadFile from fastapi.responses import HTMLResponse import numpy as np from PIL import Image from io import BytesIO import requests import base64 import os app = FastAPI() # Function for cropping and filling the image def fill_square_cropper(img): imgsz = [img.height, img.width] avg_color_per_row = np.average(img, axis=0) avg_color = np.average(avg_color_per_row, axis=0) if img.height > img.width: newimg = Image.new( 'RGB', (img.height, img.height), (round(avg_color[0]), round(avg_color[1]), round(avg_color[2])) ) newpos = (img.height - img.width) // 2 newimg.paste(img, (newpos, 0)) return newimg elif img.width > img.height: newimg = Image.new( 'RGB', (img.width, img.width), (round(avg_color[0]), round(avg_color[1]), round(avg_color[2])) ) newpos = (img.width - img.height) // 2 newimg.paste(img, (0, newpos)) return newimg else: return img # Home Page @app.get("/", response_class=HTMLResponse) def home_page(): return """

Square and Fill Image App

Please select an option below:

""" # Demo Page @app.get("/demo", response_class=HTMLResponse) def demo_page(): # URLs for demo images url1 = "https://raw.githubusercontent.com/webdevserv/images_video/main/cowportrait.jpg" url2 = "https://raw.githubusercontent.com/webdevserv/images_video/main/cowlandscape.jpg" # Process the first image response = requests.get(url1) img1 = Image.open(BytesIO(response.content)).convert("RGB") squared_img1 = fill_square_cropper(img1) output1 = BytesIO() squared_img1.save(output1, format="JPEG") encoded_img1 = base64.b64encode(output1.getvalue()).decode("utf-8") # Process the second image response = requests.get(url2) img2 = Image.open(BytesIO(response.content)).convert("RGB") squared_img2 = fill_square_cropper(img2) output2 = BytesIO() squared_img2.save(output2, format="JPEG") encoded_img2 = base64.b64encode(output2.getvalue()).decode("utf-8") return f"""

Square Image Demo

Image will be squared with color filler where applicable.

Result 1:

Result 2:

Back

""" # Application Page @app.get("/application", response_class=HTMLResponse) def application_page(): return """

Square Image Application

Upload a JPG image to square and fill with color filler.

Back """ @app.post("/upload/") async def upload_file(file: UploadFile = File(...)): try: # Await file upload contents = await file.read() img = Image.open(BytesIO(contents)).convert("RGB") squared_img = fill_square_cropper(img) # Save the squared image (original size) output = BytesIO() squared_img.save(output, format="JPEG") output.seek(0) # Encode the full-size image for download full_size_encoded_img = base64.b64encode(output.getvalue()).decode("utf-8") # Resize the image for display (512px by 512px) display_img = squared_img.copy() display_img.thumbnail((512, 512)) # Resize for display display_output = BytesIO() display_img.save(display_output, format="JPEG") display_output.seek(0) # Encode the resized display image display_encoded_img = base64.b64encode(display_output.getvalue()).decode("utf-8") # Return the HTML response return HTMLResponse( content=f"""

Image successfully squared!


Download Full-Size Image
Download Full-Size Image
""", media_type="text/html" ) except Exception as e: return HTMLResponse(content=f"

An error occurred: {e}

", media_type="text/html") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860)))