먼저, 왜 뒤집어 캡쳐하는 방법을 알아야할까?
그것은 미디어를 뒤집어 보여주어야 할 경우에는 캡쳐 또한 뒤집어서 해주어야 하기 때문이다.
미디어를 뒤집어 보여주어야 하는 대표적인 경우는 전면카메라의 미디어 스트림을 이용하는 경우이다. 전면카메라를 사용할 때, 우리는 보통 '거울모드' 에 익숙해져 있다. 다음의 코드를 실행시켜 거울모드가 아닌 전면카메라를 체험해보기를 권한다.
<video autoplay playsinline muted></video>
<script>
const video = document.querySelector('video');
navigator.getUserMedia({
video: true
}).then((stream) => {
video.srcObject = stream;
video.play();
video.addEventListener('loadedmetadata', () => {
video.style.setProperty('width', `${video.videoWidth}`);
video.style.setProperty('height', `${video.videoHeight}`);
})
})
</script>
마치 카트라이더에서 아이템을 맞아 좌우가 반전된 것처럼 느껴질 것이다. 그렇다면 우리가 익숙한 방향으로 다시 좌우를 반전시켜 보여주기 위해서는,
video {
transform: scale(-1, 1);
}
이렇게 negative scaling을 통해 익숙한 좌우반전 모드로 미디어 스트림을 확인할 수 있다.
그러나 drawImage 를 사용해 이렇게 반전된 video를 캡쳐하면 어떤 결과가 나오는지 확인해보자. 캡쳐에 사용된 코드와 결과는 다음과 같다.
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
// 비디오의 크기 그대로 캡쳐
ctx.drawImage(
video,
0,
0,
video.videoWidth,
video.videoHeight
);

왼쪽이 scaleX(-1, 1) 를 사용해 반전된 비디오이고, 오른쪽은 해당 비디오가 캡쳐된 결과이다.
왜 보여지는 것과 반대로 캡쳐될까? 우리가 CSS로 뒤집은 것은 단지 video element이기 때문이다. drawImage에는 비디오 소스가 직접 전달되므로, 캔버스에서 이 소스는 뒤집히지 않은 상태로 여겨진다.
따라서 drawImage를 사용해 소스를 캡쳐할 때에는 '거울모드' 가 적용되지 않은 상태를 가정해야 한다. 어떻게 뒤집어 캡쳐할 수 있을까?
캡쳐 컨텍스트에 scaleX와 translate를 적용하면 된다. 코드는 다음과 같다.

const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
ctx.scaleX(-1, 1);
ctx.translate(-video.videoWidth, 0);
ctx.drawImage(
video,
0,
0,
video.videoWidth,
video.videoHeight
);
간단해 보이지만 여기에서 컨텍스트 변형(transformation)이 적용된 순서와 그 결과에 대해 생각해볼거리가 존재한다.
1) 컨텍스트에 scaleX(-1, 1) 을 적용한다. translate가 적용되지 않은 기본 컨텍스트는 (0, 0)을 기본 축으로 하고 있기 때문에, 결과물은 캔버스의 가장 왼쪽을 기준으로 뒤집히게 될 것이다.
2) 그러면 캔버스를 왼쪽으로, 비디오의 너비만큼 벗어나게 될 것이다. 뭐야, 그런데 왜 -videoWidth를 적용한걸까? +를 시켜줘야 그만큼 왼쪽으로 밀지 않나?
3) 둘의 순서를 바꾸면 그 생각이 맞다. 하지만 우리의 코드에서는 scaleX가 먼저 적용되어 있고, 컨텍스트의 이러한 transformation은 행렬변환의 곱으로 이루어지기 때문에 스케일을 먼저 적용시킨 상태를 가정하고 translate의 효과를 상상해야 맞다.
4) 따라서 scale(-1, 1)이 먼저 적용되었다면 x축이 뒤집혀 있는 상태이기 때문에 결과물을 원하는 만큼 오른쪽으로 밀어내기 위해서는 -translate을 적용시켜야 하는 것이다.