navigator.clipboard.write API를 사용해서 이미지를 복사하는 방법과, 과정에서 만났던 오류와 해결 방법 정리
1. 기본 이미지 복사하기
navigator.clipboard.write 메서드를 사용하면 이미지 같은 바이너리 데이터(Blob) 를 클립보드에 넣을 수 있다.
단, 주의할 점은 HTTPS 환경에서만 동작한다는 것.
const copyImage = async () => {
try {
const response = await fetch(props.resultImg);
let blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({
[blob.type]: blob,
}),
]);
console.log('Image copied to clipboard');
} catch (err) {
console.error('Failed to copy image: ', err);
}
};
2. MIME 타입 문제
이미지 복사 시 binary/octet-stream 타입으로 들어오는 경우가 있다.
이는 실제 타입을 알 수 없는 이진 데이터라는 뜻인데, 브라우저에서 제대로 처리되지 않을 수 있다.
따라서 blob.slice() 메서드를 사용해 지원되는 형식(예: image/png)으로 바꿔주는 것이 필요하다.
const copyImage = async () => {
const response = await fetch(props.resultImg);
let blob = await response.blob();
blob = blob.slice(0, blob.size, 'image/png'); // MIME 타입 변경
await navigator.clipboard.write([
new ClipboardItem({
'image/png': blob
})
]);
};
참고: MIME 타입 문서 (MDN)
3. NotAllowedError: Document is not focused
여기서 또 다른 문제를 만났다.
Failed to copy image: NotAllowedError:
Failed to execute 'write' on 'Clipboard': Document is not focused.
이 에러는 클립보드 API가 실행될 때 문서가 포커스되지 않은 상태라서 발생했다.
브라우저는 보안상의 이유로 사용자가 직접 상호작용하는 시점에서만 클립보드를 허용하기 때문이다.
해결 방법은 사용자 액션(버튼 클릭 등) 과 함께 동기적으로 실행되도록 보장하는 것이다.
const copyImage = async () => {
try {
const response = await fetch(props.resultImg);
let blob = await response.blob();
blob = blob.slice(0, blob.size, 'image/png');
await navigator.clipboard.write([
new ClipboardItem({ [blob.type]: blob }),
]);
console.log('Image copied to clipboard');
} catch (err) {
console.error('Failed to copy image:', err);
}
};
4. 더 안정적인 방법: Canvas 활용
가장 확실한 방법은 이미지를 Canvas에 그린 후 PNG blob으로 변환하는 방식이다.
이 방법은 포맷을 확실히 지정할 수 있고, 브라우저 지원도 넓다.
const copyImage = async () => {
const img = await loadImage(props.resultImg);
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
canvas.toBlob(async blob => {
try {
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob }),
]);
openToast('이미지가 클립보드에 복사되었습니다.', 'success');
} catch (err) {
openToast('이미지 복사에 실패했습니다.', 'error');
}
}, 'image/png');
};
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = () => resolve(img);
img.onerror = reject;
img.src = url;
});
}'개발 > JS|TS' 카테고리의 다른 글
| FormData와 JSON을 함께 보내는 방법 (0) | 2024.11.11 |
|---|---|
| [JS] FileReader를 사용하여 file을 Base64 문자열로 변환하기 (0) | 2024.07.09 |
| [JS+VUE] 자바스크립트로 툴팁 위치 제어하기 ( 스크롤 영역 툴팁 ) (0) | 2024.03.13 |
| 특정 일의 월요일, 일요일 찾기 (feat.Chat GPT) (0) | 2023.08.02 |
| parseInt 백단위 쉼표 (0) | 2018.09.13 |