ARTICLE AD BOX
I’m building an AI image extender UI in React 18.
The backend API is documented here (for context only):
https://www.ailabtools.com/docs/ai-image/editing/ai-image-extender/api
On the frontend I want the user to:
Upload an image
See the image inside a fixed 512×512 preview area
Drag/resize a rectangle (“extend area” box) on top of the image
Click a button, and I convert that rectangle into coordinates in the original image’s pixel space (to send to the API)
Right now I have a simplified React component like this:
import React, { useRef, useState } from "react"; type Box = { x: number; // left in preview pixels y: number; // top in preview pixels width: number; height: number; }; export default function ImageExtender({ imageUrl, originalWidth, originalHeight, }: { imageUrl: string; originalWidth: number; originalHeight: number; }) { const containerRef = useRef<HTMLDivElement | null>(null); const [box, setBox] = useState<Box>({ x: 100, y: 100, width: 200, height: 200 }); const handleSubmit = () => { const container = containerRef.current; if (!container) return; const containerWidth = container.clientWidth; const containerHeight = container.clientHeight; // This is where I am stuck const scaleX = originalWidth / containerWidth; const scaleY = originalHeight / containerHeight; const apiX = Math.round(box.x * scaleX); const apiY = Math.round(box.y * scaleY); const apiWidth = Math.round(box.width * scaleX); const apiHeight = Math.round(box.height * scaleY); console.log({ apiX, apiY, apiWidth, apiHeight }); // These values do NOT match the intended area on the original image // because the image is letterboxed inside the container. }; return ( <div ref={containerRef} className="relative w-[512px] h-[512px] bg-black" > <img src={imageUrl} alt="preview" className="w-full h-full object-contain" /> {/* draggable overlay box */} <div className="absolute border-2 border-blue-500" style={{ left: box.x, top: box.y, width: box.width, height: box.height, }} /> <button onClick={handleSubmit}>Send to API</button> </div> ); }Because the <img> uses object-contain, the image is centered and can have empty space on the sides or top/bottom.
Simply scaling by originalWidth / containerWidth and originalHeight / containerHeight gives incorrect coordinates for the API.
Question
How can I correctly convert the overlay box (box.x, box.y, box.width, box.height in the 512×512 preview container) into coordinates in the original image’s pixel space, taking into account the object-contain letterboxing?
