Spaces:
Sleeping
Sleeping
| 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 | |
| def home_page(): | |
| return """ | |
| <html> | |
| <head> | |
| <title>Part of Idoia's Developer Portfolio - Innovating the Web</title> | |
| <link rel="stylesheet" href="/static/styles/style.css"> | |
| <!-- Meta Tags for SEO --> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <meta name="description" content="Explore the developer portfolio of Idoia, showcasing expertise in FastAPI, web development, and cutting-edge applications."> | |
| <meta name="keywords" content="Idoia, Developer, FastAPI, Web Development, Python Projects, Image Processing, Online Portfolio"> | |
| <meta name="author" content="Idoia"> | |
| <!-- Open Graph Meta Tags --> | |
| <meta property="og:title" content="Idoia's Developer Portfolio - Innovating the Web"> | |
| <meta property="og:description" content="Showcasing FastAPI projects, web apps, and image processing expertise. Explore Idoia's developer journey."> | |
| <meta property="og:image" content="/static/images/banner.jpg"> | |
| <meta property="og:url" content="https://webdevserv.github.io/html_bites/dev/webdev.html"> | |
| <meta property="og:type" content="website"> | |
| <!-- Twitter Card Meta Tags --> | |
| <meta name="twitter:card" content="summary_large_image"> | |
| <meta name="twitter:title" content="Idoia's Developer Portfolio - Innovating the Web"> | |
| <meta name="twitter:description" content="Discover the developer profile of Idoia. Dive into FastAPI-powered web apps and creative Python projects."> | |
| <meta name="twitter:image" content="/static/images/banner.jpg"> | |
| <link rel="icon" href="/static/images/6464.ico" type="image/x-icon"> | |
| <!-- Google Fonts (Optional for Styling) --> | |
| <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> | |
| <!-- Schema.org JSON-LD (Optional for Rich Snippets) --> | |
| <script type="application/ld+json"> | |
| { | |
| "@context": "https://schema.org", | |
| "@type": "Person", | |
| "name": "Idoia", | |
| "jobTitle": "Web Developer", | |
| "url": "https://webdevserv.github.io/html_bites/dev/webdev.html", | |
| "image": "https://idoia-dev-portfolio.com/static/images/banner.jpg", | |
| "description": "Experienced web developer with a focus on Streamlit, HF, Python, and modern web applications." | |
| } | |
| </script> | |
| </head> | |
| <body> | |
| <img class="banner" src="/static/images/banner.jpg" alt="Banner" width="100%"> | |
| <h2>Rectangle and Fill Image App</h2> | |
| <p>Please select an option below:</p> | |
| <ul> | |
| <li><a href="/demo">Demo</a></li> | |
| <li><a href="/application">Application</a></li> | |
| </ul> | |
| <div id="credit">Image creations by | |
| <a href="https://stock.adobe.com/es/contributor/212598146/UMAMI%20LAB" target="_blank">Adobe Stock User Umami Lab</a> | |
| and | |
| <a href="https://www.shutterstock.com/g/Idoia+Lerchundi?rid=430751957" target="_blank">Shutterstock User PhoArt101</a>. | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| # Demo Page | |
| 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""" | |
| <html> | |
| <head> | |
| <title>Part of Idoia's Developer Portfolio - Innovating the Web</title> | |
| <link rel="stylesheet" href="/static/styles/style.css"> | |
| </head> | |
| <body> | |
| <img class="banner" src="/static/images/banner.jpg" alt="Banner" width="100%"> | |
| <h2>Rectangle Image Demo</h2> | |
| <p>Image will be rectangled with color filler where applicable.</p> | |
| <h3>Result 1:</h3> | |
| <img src="data:image/jpeg;base64,{encoded_img1}" /> | |
| <h3>Result 2:</h3> | |
| <img src="data:image/jpeg;base64,{encoded_img2}" /> | |
| <p><a href="/">Back</a></p> | |
| <div id="credit">Image creations by | |
| <a href="https://stock.adobe.com/es/contributor/212598146/UMAMI%20LAB" target="_blank">Adobe Stock User Umami Lab</a> | |
| and | |
| <a href="https://www.shutterstock.com/g/Idoia+Lerchundi?rid=430751957" target="_blank">Shutterstock User PhoArt101</a>. | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| # Application Page | |
| def application_page(): | |
| return """ | |
| <html> | |
| <head> | |
| <title>Part of Idoia's Developer Portfolio - Innovating the Web</title> | |
| <link rel="stylesheet" href="/static/styles/style.css"> | |
| </head> | |
| <body> | |
| <img class="banner" src="/static/images/banner.jpg" alt="Banner" width="100%"> | |
| <h2>Rectangle Image Application</h2> | |
| <p>Upload a JPG image to rectangle and fill with color filler.</p> | |
| <form action="/upload/" enctype="multipart/form-data" method="post"> | |
| <label for="file">Upload your image:</label> | |
| <input name="file" type="file" required><br><br> | |
| <label>Choose the padding direction:</label><br> | |
| <input type="radio" id="top_bottom" name="padding_type" value="top_bottom" checked> | |
| <label for="top_bottom">Top/Bottom</label><br> | |
| <input type="radio" id="left_right" name="padding_type" value="left_right"> | |
| <label for="left_right">Left/Right</label><br><br> | |
| <input type="submit" value="Rectangle It"> | |
| </form> | |
| <a href="/">Back</a> | |
| <div id="credit">Image creations by | |
| <a href="https://stock.adobe.com/es/contributor/212598146/UMAMI%20LAB" target="_blank">Adobe Stock User Umami Lab</a> | |
| and | |
| <a href="https://www.shutterstock.com/g/Idoia+Lerchundi?rid=430751957" target="_blank">Shutterstock User PhoArt101</a>. | |
| </div> | |
| </body> | |
| </html> | |
| """ | |
| 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""" | |
| <html> | |
| <head> | |
| <title>Part of Idoia's Developer Portfolio - Innovating the Web</title> | |
| <link rel="stylesheet" href="/static/styles/style.css"> | |
| </head> | |
| <body> | |
| <img class="banner" src="/static/images/banner.jpg" alt="Banner" width="100%"> | |
| <h2>Image successfully rectangled!</h2> | |
| <!--<img src='data:image/jpeg;base64,display_encoded_img'/>--> | |
| <img src='data:image/jpeg;base64,{display_encoded_img}' width="512"/> | |
| <p><a href="data:image/jpeg;base64,{full_size_encoded_img}" download="rectangled_image.jpg"> | |
| Download Full-Size Image</a></p> | |
| <p><a href="/">Back</a></p> | |
| <div id="credit">Image creations by | |
| <a href="https://stock.adobe.com/es/contributor/212598146/UMAMI%20LAB" target="_blank">Adobe Stock User Umami Lab</a> | |
| and | |
| <a href="https://www.shutterstock.com/g/Idoia+Lerchundi?rid=430751957" target="_blank">Shutterstock User PhoArt101</a>. | |
| </div> | |
| </body> | |
| </html> | |
| """, | |
| media_type="text/html" | |
| ) | |
| except Exception as e: | |
| return HTMLResponse(content=f"<h3>An error occurred: {e}</h3>", media_type="text/html") | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", 7860))) |