Spaces:
Running
Running
File size: 11,567 Bytes
dcc674f 2974de7 68e9567 2974de7 c3f998c 2974de7 c3f998c 26ce874 3607789 56a1f7e 2974de7 68e9567 56a1f7e 225022a 44ac58f 56a1f7e 225022a 56a1f7e 225022a 9ee679e 2974de7 44a8ab0 2974de7 fa65478 d9d2171 2974de7 fa65478 2974de7 985559c 56a1f7e c3f998c 2974de7 495811a 2974de7 68e9567 fe863b2 6610b06 2974de7 c0a55f7 ab7e106 b02f32f c3f998c 8e44a0c c3f998c 985559c c3f998c 56a1f7e c3f998c ab7e106 c3f998c 56a1f7e c3f998c ab7e106 c3f998c 6610b06 c3f998c c0a55f7 807774d ab7e106 c3f998c cf08216 8e44a0c c3f998c 6610b06 c3f998c c0a55f7 807774d 2974de7 56a1f7e 2974de7 cf08216 8e44a0c 2974de7 c3f998c 2974de7 0faec7c fe496f4 c3f998c fe496f4 0faec7c 44a8ab0 fe496f4 ab7e106 fe496f4 ab7e106 fe496f4 2974de7 5964a73 ab7e106 260965a 5964a73 fe496f4 5964a73 0de1553 c0a55f7 ab7e106 260965a 6f8ddad ab7e106 6610b06 8e44a0c 0de1553 5964a73 fe496f4 2974de7 495811a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
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
# 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 """
<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">Images courtesy of
<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
@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"""
<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">Images courtesy of
<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
@app.get("/application", response_class=HTMLResponse)
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">Images courtesy of
<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>
"""
@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"""
<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">Images courtesy of
<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))) |