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

🔄 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)