favicon-master / app_flask_backup.py
duqing2026's picture
修复 hf 运行不起来问题
b3a8030
import os
import io
import zipfile
import json
from flask import Flask, render_template, request, send_file, jsonify
from PIL import Image, ImageOps, ImageColor
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 16MB limit
# Standard sizes
ICO_SIZES = [(16, 16), (32, 32), (48, 48), (64, 64)]
APPLE_ICON_SIZE = (180, 180)
ANDROID_192_SIZE = (192, 192)
ANDROID_512_SIZE = (512, 512)
@app.route('/')
def index():
return render_template('index.html')
def make_square(im, min_size=256, fill_color=(255, 255, 255, 0)):
"""
Pads the image to make it square without distorting aspect ratio.
"""
x, y = im.size
size = max(min_size, x, y)
# Create a new square image
new_im = Image.new('RGBA', (size, size), fill_color)
# Calculate position to center the image
paste_x = (size - x) // 2
paste_y = (size - y) // 2
new_im.paste(im, (paste_x, paste_y))
return new_im
@app.route('/api/generate', methods=['POST'])
def generate():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
# Get background color from form data (hex code)
bg_color_hex = request.form.get('bgColor', '')
# Parse background color
fill_color = (255, 255, 255, 0) # Default transparent
theme_color = "#ffffff" # For manifest
if bg_color_hex and bg_color_hex != 'transparent':
try:
# Convert hex to RGBA
rgb = ImageColor.getrgb(bg_color_hex)
fill_color = rgb + (255,) # Add alpha=255
theme_color = bg_color_hex
except Exception:
pass # Fallback to transparent
try:
# Open image
img = Image.open(file.stream)
# Convert to RGBA if not already
if img.mode != 'RGBA':
img = img.convert('RGBA')
# Process image: make it square and apply background
# If user selected a background color, we use that for padding
# If user wants transparent, we use transparent padding
# First, ensure it's square without distortion
img_square = make_square(img, fill_color=fill_color)
# If a background color is set, we might want to composite the whole image over that color
# (in case the original image has transparency within it)
if bg_color_hex and bg_color_hex != 'transparent':
bg_layer = Image.new('RGBA', img_square.size, fill_color)
bg_layer.paste(img_square, (0, 0), img_square) # Use img_square alpha as mask
img_square = bg_layer
# Create ZIP in memory
memory_file = io.BytesIO()
with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
# 1. favicon.ico (multi-size)
ico_io = io.BytesIO()
img_square.save(ico_io, format='ICO', sizes=ICO_SIZES)
ico_io.seek(0)
zf.writestr('favicon.ico', ico_io.read())
# 2. apple-touch-icon.png
apple_io = io.BytesIO()
img_apple = img_square.resize(APPLE_ICON_SIZE, Image.Resampling.LANCZOS)
img_apple.save(apple_io, format='PNG')
apple_io.seek(0)
zf.writestr('apple-touch-icon.png', apple_io.read())
# 3. android-chrome-192x192.png
android192_io = io.BytesIO()
img_192 = img_square.resize(ANDROID_192_SIZE, Image.Resampling.LANCZOS)
img_192.save(android192_io, format='PNG')
android192_io.seek(0)
zf.writestr('android-chrome-192x192.png', android192_io.read())
# 4. android-chrome-512x512.png
android512_io = io.BytesIO()
img_512 = img_square.resize(ANDROID_512_SIZE, Image.Resampling.LANCZOS)
img_512.save(android512_io, format='PNG')
android512_io.seek(0)
zf.writestr('android-chrome-512x512.png', android512_io.read())
# 5. site.webmanifest
manifest = {
"name": "My Website",
"short_name": "Website",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": theme_color,
"background_color": theme_color,
"display": "standalone"
}
zf.writestr('site.webmanifest', json.dumps(manifest, indent=2))
memory_file.seek(0)
return send_file(
memory_file,
mimetype='application/zip',
as_attachment=True,
download_name='favicons.zip'
)
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port)