import cv2
import io
import numpy as np
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import HTMLResponse, StreamingResponse
app = FastAPI()
HTML = '''
Sprite Flipper
🔄 Sprite Flipper
將 Sprite Sheet 中每個格子水平翻轉(左右鏡像),並輸出新圖片。
預覽(原圖)
'''
def _flip_sprite_sheet(img_bytes: bytes, cols: int, rows: int) -> bytes:
"""核心翻轉邏輯(來自 rotate.py):將每個 cell 水平翻轉。"""
arr = np.frombuffer(img_bytes, dtype=np.uint8)
img = cv2.imdecode(arr, cv2.IMREAD_UNCHANGED)
if img is None:
raise ValueError("無法解碼圖片")
h, w = img.shape[:2]
cell_w = w / cols
cell_h = h / rows
output = img.copy()
for r in range(rows):
for c in range(cols):
x1 = int(c * cell_w)
y1 = int(r * cell_h)
x2 = int((c + 1) * cell_w)
y2 = int((r + 1) * cell_h)
cell = img[y1:y2, x1:x2]
if cell.size == 0:
continue
output[y1:y2, x1:x2] = cv2.flip(cell, 1)
success, buf = cv2.imencode(".png", output)
if not success:
raise ValueError("圖片編碼失敗")
return buf.tobytes()
@app.get("/", response_class=HTMLResponse)
def home():
return HTML
@app.post("/flip")
async def flip(
file: UploadFile = File(...),
cols: int = Form(10),
rows: int = Form(6),
):
data = await file.read()
try:
result = _flip_sprite_sheet(data, cols, rows)
except ValueError as e:
from fastapi.responses import PlainTextResponse
return PlainTextResponse(str(e), status_code=400)
return StreamingResponse(
io.BytesIO(result),
media_type="image/png",
headers={"Content-Disposition": 'attachment; filename="flipped.png"'},
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)