"chrome.tabs.captureVisibleTab 이 전체 tab 을 dataURL 로 줘. Selection rect 가 어느 pixel 이 중요한지 알려 줘. Lesson 4 가 그 둘을 wire 해서 모든 ClipDeck clip 이 어디서 왔는지의 tightly-cropped screenshot 휴대 가능."
chrome.tabs.captureVisibleTab
API 가 작아. 두 인자:
windowId— optional. 주어진 window 의 active tab capture; 생략하면 현재 window capture.options— optional.{ format: 'png' | 'jpeg', quality: 0..100 }. Default PNG. 텍스트 많은 page 의 screenshot 엔 quality 80 의 JPEG 가 보통 5x 작음.
data: URL 반환. Capture 가 현재 visible viewport — user 가 보는 것 — 만 cover. Off-screen content 는 capture 안 됨.
Permission: activeTab (user gesture 후) OR URL 의 host_permissions OR tabs permission. ClipDeck 이 이 시점에 관련된 셋 다 가짐.
Crop workflow
Captured 이미지가 full-tab. ClipDeck 이 user selection 의 rect 원함. 수학:
- Content script 에서 selection 의
getBoundingClientRect()얻기 — viewport-relative 좌표. - Device pixel ratio (
window.devicePixelRatio) 얻기. Captured 이미지가 native 해상도; rect 는 CSS pixel. - SW 가 dataURL + rect + dpr 받음. Offscreen canvas 에 load. 맞는 pixel 좌표에서 cropped 으로 draw.
- Cropped canvas 를 또 다른 dataURL 로 export. Clip 과 저장.
Canvas 위한 offscreen document
Service worker 가 DOM 사용 못 함, 그래서 normal canvas 생성 못 함. MV3 가 chrome.offscreen 도입 — SW 가 DOM API (canvas, Blob 처리 가진 fetch, audio) 필요할 때 spawn 하는 hidden document. Shape:
await chrome.offscreen.createDocument({
url: 'offscreen.html',
reasons: ['BLOBS'],
justification: 'Crop captured tab screenshots for ClipDeck clips',
});
offscreen.html 이 SW 에서 메시지 받고, canvas work 하고, 결과 다시 post 하는 offscreen.js 가진 작은 page. 사용 후 chrome.offscreen.closeDocument() 호출 — 열어 두는 게 약간 메모리 낭비.
Crop 코드
Offscreen document 안:
const img = new Image();
img.src = dataURL;
await new Promise((r) => (img.onload = r));
const canvas = new OffscreenCanvas(
Math.round(rect.width * dpr),
Math.round(rect.height * dpr),
);
const ctx = canvas.getContext('2d');
ctx.drawImage(
img,
rect.left * dpr, rect.top * dpr,
rect.width * dpr, rect.height * dpr,
0, 0,
rect.width * dpr, rect.height * dpr,
);
const blob = await canvas.convertToBlob({ type: 'image/png' });
const reader = new FileReader();
reader.readAsDataURL(blob);
await new Promise((r) => (reader.onload = r));
return reader.result; // cropped dataURL
OffscreenCanvas 가 offscreen document 에서 지원되고 Worker-friendly canvas 제공. 9-인자 drawImage form: sx, sy, sw, sh, dx, dy, dw, dh. Source 좌표가 rect 에서; destination 이 0,0 에서 시작.
Size 예산
Typical 텍스트 selection 의 각 PNG screenshot 이 ~10–50 KB. PNG 이 텍스트엔 fine; JPEG quality 80 이 또 30–50% cut. dataURL 을 chrome.storage.local 에 직접 저장 — quota 가 약 10 MB, cropped 유지하면 몇 백 screenshot 에 plenty. Clip 카운트 자라면 공격적 압축, JPEG 전환, 또는 user 가 clip 별 screenshot opt-out 고려.
Clip 에 들어가는 것
Clip schema 확장:
{ id, text, url, title, savedAt, screenshot?: string /* dataURL */ }
Side panel 이 있으면 screenshot inline 렌더 (작은 thumbnail; click 으로 확대). Export flow 가 포함; clipboard copy 는 여전히 text 만.