import zipfile
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import HTMLResponse, FileResponse
from PIL import Image
import io, math, json, os
app = FastAPI()
BASE = os.getcwd()
OUTPUT_DIR = os.path.join(BASE, 'output')
os.makedirs(OUTPUT_DIR, exist_ok=True)
HTML = '''
'''
@app.get('/', response_class=HTMLResponse)
def home():
return HTML
@app.post('/export_picker')
async def export_picker(
file: UploadFile = File(...),
outCols: int = Form(...),
outWH: int = Form(...), # 新增參數
name: str = Form(...),
picks: str = Form(...)
):
data = await file.read()
img = Image.open(io.BytesIO(data)).convert('RGBA')
pick_list = json.loads(picks)
if not pick_list:
return HTMLResponse('None', status_code=400)
# 輸出尺寸現在統一使用使用者設定的 outWH
tw = th = outWH
base_name = os.path.splitext(name)[0]
num_picks = len(pick_list)
num_images = num_picks // outCols
if num_images == 0:
return HTMLResponse('選取數量不足以構成一列', status_code=400)
generated_files = []
for img_idx in range(num_images):
# 建立畫布,寬度為 (OutWH * Cols),高度為 OutWH
out_img = Image.new('RGBA', (outCols * tw, th), (0, 0, 0, 0))
for col_idx in range(outCols):
p_idx = img_idx * outCols + col_idx
p = pick_list[p_idx]
box = (p['x'], p['y'], p['x'] + p['w'], p['y'] + p['h'])
# 1. 裁切原始大小
tile = img.crop(box)
# 2. 強制縮放至目標 OutWH
# 使用 Resampling.LANCZOS 保持像素品質,若要保留像素感可用 NEAREST
tile = tile.resize((tw, th), Image.Resampling.LANCZOS)
# 3. 貼上
out_img.paste(tile, (col_idx * tw, 0))
file_path = os.path.join(OUTPUT_DIR, f"{base_name}_{img_idx+1}.png")
out_img.save(file_path)
generated_files.append(file_path)
# 如果只有一張圖,直接回傳圖片
if len(generated_files) == 1:
return FileResponse(generated_files[0], filename=f"{base_name}.png", media_type='image/png')
# 如果有多張圖,打包成 ZIP
zip_path = os.path.join(OUTPUT_DIR, f"{base_name}_batch.zip")
with zipfile.ZipFile(zip_path, 'w') as zipf:
for f in generated_files:
zipf.write(f, os.path.basename(f))
return FileResponse(zip_path, filename=f"{base_name}.zip", media_type='application/zip')
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)