favicon-master / app.py
duqing2026's picture
丰富功能和优化
85cae67
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
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)
new_im = Image.new('RGBA', (size, size), fill_color)
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
bg_color_hex = request.form.get('bgColor', '')
site_name = request.form.get('siteName', 'My Website') or 'My Website'
short_name = request.form.get('shortName', 'Website') or 'Website'
fill_color = (255, 255, 255, 0)
theme_color = "#ffffff"
if bg_color_hex and bg_color_hex != 'transparent':
try:
rgb = ImageColor.getrgb(bg_color_hex)
fill_color = rgb + (255,)
theme_color = bg_color_hex
except Exception:
pass
try:
img = Image.open(file.stream)
if img.mode != 'RGBA':
img = img.convert('RGBA')
img_square = make_square(img, fill_color=fill_color)
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)
img_square = bg_layer
memory_file = io.BytesIO()
with zipfile.ZipFile(memory_file, 'w', zipfile.ZIP_DEFLATED) as zf:
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())
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())
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())
favicon32_io = io.BytesIO()
img_32 = img_square.resize((32, 32), Image.Resampling.LANCZOS)
img_32.save(favicon32_io, format='PNG')
favicon32_io.seek(0)
zf.writestr('favicon-32x32.png', favicon32_io.read())
favicon16_io = io.BytesIO()
img_16 = img_square.resize((16, 16), Image.Resampling.LANCZOS)
img_16.save(favicon16_io, format='PNG')
favicon16_io.seek(0)
zf.writestr('favicon-16x16.png', favicon16_io.read())
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())
manifest = {
"name": site_name,
"short_name": short_name,
"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)