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):
# Calculate the average color of the image
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":
# Increase height to create a rectangle
new_height = int(img.width * (4/3)) # Example: height = width * 4/3
newimg = Image.new(
'RGB',
(img.width, new_height),
(round(avg_color[0]), round(avg_color[1]), round(avg_color[2]))
)
padding_top = (new_height - img.height) // 2
newimg.paste(img, (0, padding_top)) # Center the image vertically
return newimg
elif padding_type == "left_right":
# Increase width to create a rectangle
new_width = int(img.height * (4/3)) # Example: width = height * 4/3
newimg = Image.new(
'RGB',
(new_width, img.height),
(round(avg_color[0]), round(avg_color[1]), round(avg_color[2]))
)
padding_left = (new_width - img.width) // 2
newimg.paste(img, (padding_left, 0)) # Center the image horizontally
return newimg
# Home Page
@app.get("/", response_class=HTMLResponse)
def home_page():
return """
Part of Idoia's Developer Portfolio - Innovating the Web
Rectangle 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/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"""
Part of Idoia's Developer Portfolio - Innovating the Web
Rectangle Image Demo
Image will be rectangled with color filler where applicable.
Result 1:
Result 2:
Back
"""
# Application Page
@app.get("/application", response_class=HTMLResponse)
def application_page():
return """
Part of Idoia's Developer Portfolio - Innovating the Web
Rectangle Image Application
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"""
Part of Idoia's Developer Portfolio - Innovating the Web
Image successfully rectangled!
Download Full-Size Image
Back
""",
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)))