캔버스에서 사용하기 위해 이미지를 디코딩하는 일은 매우 일반적입니다. 사용자가 아바타를 맞춤설정하거나, 이미지를 자르거나, 사진을 확대할 수 있기 때문입니다. 이미지를 디코딩할 때 발생하는 문제는 이 이미지가 CPU를 많이 사용할 수 있으며 경우에 따라 버벅거림이나 격자무늬가 발생할 수 있다는 점입니다. Chrome 50 및 Firefox 42 이상부터 createImageBitmap()
옵션이 제공됩니다. 이를 통해 백그라운드에서 이미지를 디코딩하고 새 ImageBitmap
원시 요소에 액세스할 수 있습니다. 이 원시 요소는 <img>
요소, 다른 캔버스 또는 동영상과 동일한 방식으로 캔버스에 그릴 수 있습니다.
createImageBitmap()으로 블롭 그리기
fetch()
(또는 XHR)을 사용하여 blob 이미지를 다운로드하고 캔버스에 그려야 한다고 가정해 보겠습니다. createImageBitmap()
가 없으면 이미지를 사용할 수 있는 형식으로 가져오기 위해 이미지 요소와 Blob URL을 만들어야 합니다. 이를 통해 훨씬 더 직접적으로 그림을 그릴 수 있습니다.
fetch(url)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => ctx.drawImage(imageBitmap, 0, 0));
이 접근 방식은 IndexedDB에 blob으로 저장된 이미지에도 작동하므로 blob은 편리한 중간 형식입니다. 실제로 Chrome 50은 캔버스 요소에서 .toBlob()
메서드도 지원합니다. 즉, 예를 들어 캔버스 요소에서 블롭을 생성할 수 있습니다.
웹 작업자에서 createImageBitmap() 사용
createImageBitmap()
의 가장 좋은 기능 중 하나는 작업자에서도 사용할 수 있다는 점입니다. 즉, 이제 원하는 위치에서 이미지를 디코딩할 수 있습니다. 디코딩할 이미지가 많고 필수적이지 않다고 생각되는 경우에는 해당 URL을 Web Worker에 보냅니다. 그러면 Web Worker에서 시간이 되면 해당 이미지를 다운로드하고 디코딩합니다. 그런 다음 캔버스에 그리기 위해 기본 스레드로 다시 전송합니다.
이를 위한 코드는 다음과 같습니다.
// In the worker.
fetch(imageURL)
.then(response => response.blob())
.then(blob => createImageBitmap(blob))
.then(imageBitmap => {
// Transfer the imageBitmap back to main thread.
self.postMessage({ imageBitmap }, [imageBitmap]);
}, err => {
self.postMessage({ err });
});
// In the main thread.
worker.onmessage = (evt) => {
if (evt.data.err)
throw new Error(evt.data.err);
canvasContext.drawImage(evt.data.imageBitmap, 0, 0);
}
현재 기본 스레드에서 createImageBitmap()
를 호출하면 바로 여기에서 디코딩이 실행됩니다. 하지만 Chrome이 다른 스레드에서 자동으로 디코딩하도록 하여 기본 스레드 워크로드를 줄이도록 지원할 계획입니다. 하지만 그때까지는 기본 스레드에서 디코딩을 실행할 때 주의해야 합니다. 디코딩은 JavaScript, 스타일 계산, 레이아웃, 페인팅, 합성 등 다른 필수 작업을 차단할 수 있는 집약적인 작업이기 때문입니다.
도우미 라이브러리
작업을 좀 더 간편하게 처리할 수 있도록, 작업자에서 디코딩을 처리하고 디코딩된 이미지를 기본 스레드로 다시 전송하고 캔버스에 그리는 도우미 라이브러리를 만들었습니다. 물론 자유롭게 리버스 엔지니어링하고 모델을 자체 앱에 적용할 수 있습니다. 주요 이점은 더 많은 제어 기능이지만, 이는 일반적으로 <img>
요소를 사용하는 것보다 더 많은 코드, 디버그할 항목, 고려해야 할 특이 사례가 있음을 의미합니다.
이미지 디코딩을 더 세부적으로 제어해야 한다면 createImageBitmap()
가 새로운 친구가 될 것입니다. Chrome 50에서 사용해 보고 의견을 알려주세요.