diff --git a/frontend/components/messenger/MessengerModal.tsx b/frontend/components/messenger/MessengerModal.tsx index 4e0ce1b8..b0bed09d 100644 --- a/frontend/components/messenger/MessengerModal.tsx +++ b/frontend/components/messenger/MessengerModal.tsx @@ -189,7 +189,7 @@ export function MessengerModal() { {/* Header */}

메신저

diff --git a/frontend/components/messenger/ScreenCapture.tsx b/frontend/components/messenger/ScreenCapture.tsx index 2b1901df..4d62518d 100644 --- a/frontend/components/messenger/ScreenCapture.tsx +++ b/frontend/components/messenger/ScreenCapture.tsx @@ -16,10 +16,37 @@ interface ScreenCaptureProps { export function ScreenCapture({ onCapture, onCancel }: ScreenCaptureProps) { const canvasRef = useRef(null); + const capturedImgRef = useRef(null); + const [ready, setReady] = useState(false); const [selecting, setSelecting] = useState(false); const startRef = useRef<{ x: number; y: number } | null>(null); const [rect, setRect] = useState(null); + // Pre-capture on mount so mouseup is instant + useEffect(() => { + let cancelled = false; + (async () => { + try { + const { domToPng } = await import("modern-screenshot"); + const scale = Math.max(window.devicePixelRatio || 1, 2); + const dataUrl = await domToPng(document.body, { + width: window.innerWidth, + height: window.innerHeight, + scale, + }); + if (cancelled) return; + const img = new Image(); + img.src = dataUrl; + await new Promise((res) => { img.onload = res; }); + capturedImgRef.current = img; + setReady(true); + } catch { + if (!cancelled) onCancel(); + } + })(); + return () => { cancelled = true; }; + }, [onCancel]); + // ESC to cancel useEffect(() => { const handler = (e: KeyboardEvent) => { @@ -47,70 +74,51 @@ export function ScreenCapture({ onCapture, onCancel }: ScreenCaptureProps) { setRect(getRect(startRef.current.x, startRef.current.y, e.clientX, e.clientY)); }; - const handleMouseUp = async (e: React.MouseEvent) => { + const handleMouseUp = (e: React.MouseEvent) => { if (!selecting || !startRef.current) return; setSelecting(false); const r = getRect(startRef.current.x, startRef.current.y, e.clientX, e.clientY); startRef.current = null; - if (r.w < 4 || r.h < 4) { - onCancel(); - return; - } + if (r.w < 4 || r.h < 4) { onCancel(); return; } - // Capture via modern-screenshot - try { - const { domToPng } = await import("modern-screenshot"); - const dataUrl = await domToPng(document.body, { - width: window.innerWidth, - height: window.innerHeight, - }); + const img = capturedImgRef.current; + if (!img) { onCancel(); return; } - // Crop the captured region — image is at CSS pixel scale - const img = new Image(); - img.src = dataUrl; - await new Promise((res) => { img.onload = res; }); + const scaleX = img.naturalWidth / window.innerWidth; + const scaleY = img.naturalHeight / window.innerHeight; - // Scale factor between actual image size and CSS pixels - const scaleX = img.naturalWidth / window.innerWidth; - const scaleY = img.naturalHeight / window.innerHeight; + const canvas = canvasRef.current!; + canvas.width = r.w * scaleX; + canvas.height = r.h * scaleY; + const ctx = canvas.getContext("2d")!; + ctx.drawImage( + img, + r.x * scaleX, r.y * scaleY, r.w * scaleX, r.h * scaleY, + 0, 0, r.w * scaleX, r.h * scaleY, + ); - const canvas = canvasRef.current!; - canvas.width = r.w * scaleX; - canvas.height = r.h * scaleY; - const ctx = canvas.getContext("2d")!; - ctx.drawImage( - img, - r.x * scaleX, r.y * scaleY, r.w * scaleX, r.h * scaleY, - 0, 0, r.w * scaleX, r.h * scaleY, - ); - - canvas.toBlob((blob) => { - if (!blob) { onCancel(); return; } - const file = new File([blob], `capture-${Date.now()}.png`, { type: "image/png" }); - onCapture(file); - }, "image/png"); - } catch { - onCancel(); - } + canvas.toBlob((blob) => { + if (!blob) { onCancel(); return; } + const file = new File([blob], `capture-${Date.now()}.png`, { type: "image/png" }); + onCapture(file); + }, "image/png"); }; return ( <>
- {/* instruction */}
- 드래그하여 캡처 영역을 선택하세요  ·  ESC로 취소 + {ready ? "드래그하여 캡처 영역을 선택하세요" : "캡처 준비 중..."} · ESC로 취소
- {/* selection rect */} {rect && rect.w > 0 && rect.h > 0 && (