from fastapi import FastAPI, File, UploadFile, Form from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles import numpy as np from PIL import Image from io import BytesIO import requests import base64 import os from tkinter import Tk, Label, Button, Radiobutton, IntVar app = FastAPI() # Mount the static folder for CSS and other assets app.mount("/static", StaticFiles(directory="static"), name="static") # Function to add padding def fill_rectangle_cropper(img, padding_type): # Ensure the image is correctly converted to a NumPy array for color calculations avg_color_per_row = np.average(np.array(img), axis=0) avg_color = np.average(avg_color_per_row, axis=0) if padding_type == "top_bottom": # Ensure height is less than width before adding padding if img.height < img.width: new_height = img.width # Set new height equal to width newimg = Image.new( 'RGB', (img.width, new_height), (round(avg_color[0]), round(avg_color[1]), round(avg_color[2])) # Fill with average color ) padding_top = (new_height - img.height) // 2 newimg.paste(img, (0, padding_top)) # Center the image vertically return newimg else: print("No padding needed for top/bottom.") # Debug message return img elif padding_type == "left_right": # Ensure width is less than height before adding padding if img.width < img.height: new_width = img.height # Set new width equal to height newimg = Image.new( 'RGB', (new_width, img.height), (round(avg_color[0]), round(avg_color[1]), round(avg_color[2])) # Fill with average color ) padding_left = (new_width - img.width) // 2 newimg.paste(img, (padding_left, 0)) # Center the image horizontally return newimg else: print("No padding needed for left/right.") # Debug message return img else: print("Invalid padding type.") # Debug message return img # Function for cropping and filling the image def fill_rectangle_cropper1(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 """
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/squareportrait.png" url2 = "https://raw.githubusercontent.com/webdevserv/images_video/main/squarelandscape.png" # Process the first image response = requests.get(url1) img1 = Image.open(BytesIO(response.content)).convert("RGB") rectangled_img1 = fill_rectangle_cropper(img1, "top_bottom") output1 = BytesIO() rectangled_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") rectangled_img2 = fill_rectangle_cropper(img2, "left_right") output2 = BytesIO() rectangled_img2.save(output2, format="JPEG") encoded_img2 = base64.b64encode(output2.getvalue()).decode("utf-8") return f"""Image will be rectangled with color filler where applicable.
Upload a JPG image to rectangle and fill with color filler.
Back """ @app.post("/upload/") async def upload_file(file: UploadFile = File(...), padding_type: str = Form(...)): try: # Await file upload contents = await file.read() img = Image.open(BytesIO(contents)).convert("RGB") # Apply padding based on user's choice rectangled_img = fill_rectangle_cropper(img,padding_type) # Save the rectangle image (original size) output = BytesIO() rectangled_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 = rectangled_img.copy() desired_width = 512 aspect_ratio = display_img.height / display_img.width desired_height = int(desired_width * aspect_ratio) display_img.thumbnail((desired_width, desired_height)) 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"""