Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, File, UploadFile | |
| from fastapi.responses import Response, JSONResponse | |
| from insightface.app import FaceAnalysis | |
| from rembg import remove | |
| from PIL import Image | |
| import numpy as np | |
| import io | |
| app = FastAPI() | |
| # Simple homepage (fixes 404 on HF Spaces) | |
| def home(): | |
| return {"message": "ID Photo API is running. Use POST /process"} | |
| # Load face detection model | |
| face_app = FaceAnalysis(name="buffalo_l", providers=["CPUExecutionProvider"]) | |
| face_app.prepare(ctx_id=0, det_size=(640, 640)) | |
| def resize_to_4x6(img): | |
| return img.resize((472, 709), Image.LANCZOS) | |
| async def process_img(file: UploadFile = File(...)): | |
| try: | |
| img_bytes = await file.read() | |
| img = Image.open(io.BytesIO(img_bytes)).convert("RGB") | |
| np_img = np.array(img) | |
| faces = face_app.get(np_img) | |
| if not faces: | |
| return JSONResponse({"error": "No face detected"}, status_code=400) | |
| face = faces[0] | |
| # --- Extract face bounding box --- | |
| x1, y1, x2, y2 = face.bbox.astype(int) | |
| cropped = img.crop((x1, y1, x2, y2)) | |
| # --- Resize cropped face with preserved aspect ratio --- | |
| max_face_height = int(709 * 0.75) # face occupies 75% of final height | |
| w, h = cropped.size | |
| scale_factor = max_face_height / h | |
| new_w = int(w * scale_factor) | |
| new_h = int(h * scale_factor) | |
| resized_face = cropped.resize((new_w, new_h), Image.LANCZOS) | |
| # --- Create final white 4x6 canvas --- | |
| final_w, final_h = 472, 709 | |
| canvas = Image.new("RGB", (final_w, final_h), (255, 255, 255)) | |
| # --- Center image on canvas --- | |
| paste_x = (final_w - new_w) // 2 | |
| paste_y = (final_h - new_h) // 2 | |
| canvas.paste(resized_face, (paste_x, paste_y)) | |
| # --- Output final image --- | |
| buf = io.BytesIO() | |
| canvas.save(buf, format="JPEG") | |
| buf.seek(0) | |
| return Response(buf.getvalue(), media_type="image/jpeg") | |
| except Exception as e: | |
| print("ERROR:", e) | |
| return JSONResponse({"error": str(e)}, status_code=500) | |