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 && (