Canvas API/Canvas tutorial/Pixel manipulation with canvas

김동현·2026년 3월 22일

Canvas로 픽셀 조작하기

지금까지 우리는 canvas의 실제 픽셀을 살펴보지 않았어요. ImageData 객체를 사용하면 픽셀 데이터를 조작하기 위해 데이터 배열을 직접 읽고 쓸 수 있어요. 또한 이미지 스무딩(안티앨리어싱)을 어떻게 제어할 수 있는지와 canvas에서 이미지를 저장하는 방법도 살펴볼 거예요.

안녕하세요! 캔버스 튜토리얼의 가장 깊숙한 곳, 바로 '픽셀 조작(Pixel manipulation)' 영역에 오신 것을 환영합니다.

지금까지는 캔버스에 선을 긋고, 도형을 그리고, 색을 채우는 등 '그리기 도구'로서 캔버스를 다뤘습니다. 하지만 이 챕터에서는 캔버스의 진짜 정체인 비트맵(픽셀들의 배열) 데이터에 직접 접근하는 방법을 배우게 됩니다. 이를 활용하면 사진의 색상을 흑백으로 바꾸거나, 이미지 필터를 만들고, 스포이드(Color Picker) 기능까지 구현할 수 있습니다!

포트폴리오의 웹 프로필 사이트나 유틸리티 프로그램 등을 만드실 때, 이미지 프로세싱이 필요하다면 이 지식이 엄청난 무기가 될 거예요. 강사의 실무 팁과 함께 자세히 번역해 드릴게요!


ImageData 객체 (The ImageData object)

ImageData 객체는 캔버스 객체의 특정 영역이 내부적으로 깔고 있는 픽셀(pixel) 데이터를 나타냅니다.
이 객체의 data 속성은 Uint8ClampedArray (또는 요청 시 Float16Array)를 반환하는데, 우리는 이 배열에 접근해서 가공되지 않은 순수한(raw) 픽셀 데이터를 직접 들여다볼 수 있습니다.

이 배열 안에서 각각의 픽셀은 4개의 1바이트(byte) 값으로 표현됩니다. 그 순서는 빨강(R), 초록(G), 파랑(B), 투명도(A) 순서이며, 즉 "RGBA" 포맷을 따릅니다. 각 색상 구성요소(채널)는 0부터 255 사이의 정수로 표현됩니다.
이 4개의 값은 1차원 배열 안에 일렬로 길게 늘어서 할당됩니다. 배열의 0번째 인덱스는 캔버스 맨 왼쪽 위(Top-Left)에 있는 첫 번째 픽셀의 '빨간색(R)' 값을 의미하죠. 그다음 픽셀 데이터들은 왼쪽에서 오른쪽으로, 그리고 한 줄이 끝나면 아래로 내려가며 배열 전체에 쭉 채워집니다.

Uint8ClampedArray 안에는 높이(height) × 너비(width) × 4 (바이트) 만큼의 데이터가 꽉 차 있으며, 인덱스 값은 0부터 시작해서 (높이 × 너비 × 4) - 1 까지 존재합니다.

💡 강사의 핵심 보충 설명:
100x100 픽셀 크기의 이미지가 있다고 해볼게요. 우리 눈에는 2차원 사각형으로 보이지만, 브라우저 메모리 안에는 이걸 한 줄로 길게 늘어뜨린 1차원 배열(길이: 100 100 4 = 40,000)로 저장합니다.
1번 픽셀: [R, G, B, A], 2번 픽셀: [R, G, B, A]... 이런 식이죠!
그래서 Uint8ClampedArray (8비트 부호 없는 정수, 0~255로 제한됨)라는 특별한 자바스크립트 배열 타입이 쓰입니다.

예를 들어, 이미지의 가로(column) 200번째, 세로(row) 50번째에 위치한 픽셀의 '파란색(blue)' 구성요소 값을 읽어오고 싶다면 다음과 같이 계산해야 합니다:

// y좌표 * 전체너비 * 4 + x좌표 * 4 + 2(파란색 인덱스)
const blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2];

만약 특정 X와 Y 좌표값이 주어졌을 때 해당 픽셀의 색상 데이터를 배열로 뽑아내고 싶다면 아래처럼 유틸리티 함수를 만들어 쓸 수 있습니다:

const xCoord = 50;
const yCoord = 100;
const canvasWidth = 1024;

const getColorIndicesForCoord = (x, y, width) => {
  // 해당 픽셀의 '빨간색(R)' 값이 있는 배열의 시작 인덱스 계산
  const red = y * (width * 4) + x * 4;
  return [red, red + 1, red + 2, red + 3]; // [R, G, B, A] 인덱스 반환
};

const colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);

// 구조 분해 할당으로 각 인덱스 추출
const [redIndex, greenIndex, blueIndex, alphaIndex] = colorIndices;

또한, 픽셀 배열의 전체 크기(바이트 단위)를 확인하고 싶다면 Uint8ClampedArray.length 속성을 읽어오면 됩니다:

const numBytes = imageData.data.length;

ImageData 객체 생성하기 (Creating an ImageData object)

완전히 비어있는 새 ImageData 객체를 만들려면 createImageData() 메서드를 사용해야 합니다. 이 메서드는 두 가지 버전이 있습니다.

const myImageData = ctx.createImageData(width, height);

위 코드는 지정된 너비(width)와 높이(height)를 가진 새로운 ImageData 객체를 생성합니다. 생성된 객체 내부의 모든 픽셀은 완전한 투명한 검은색 (rgba(0, 0, 0, 0))으로 미리 세팅되어 있습니다.

또 다른 방법으로, 기존에 있던 anotherImageData 객체와 똑같은 크기(너비와 높이)를 가진 새로운 ImageData 객체를 만들 수도 있습니다.

const myImageData = ctx.createImageData(anotherImageData);

이때 주의할 점은, 크기만 똑같이 가져올 뿐 원본의 이미지 데이터(픽셀 색상)를 복사해 오지는 않는다는 것입니다! 새로 생성된 객체의 픽셀들은 역시나 모두 투명한 검은색으로 비워져 있습니다.


캔버스에서 픽셀 데이터 가져오기 (Getting the pixel data for a context)

캔버스에 이미 그려져 있는 그림의 픽셀 데이터 복사본을 담은 ImageData 객체를 얻어오려면 getImageData() 메서드를 사용하면 됩니다.

const myImageData = ctx.getImageData(left, top, width, height);

이 메서드는 캔버스의 특정 영역에 해당하는 픽셀 데이터를 나타내는 ImageData 객체를 반환합니다. 이 영역은 (left, top)을 좌측 상단 모서리로 하고, 지정된 widthheight를 가진 사각형 영역입니다. 좌표와 크기는 캔버스의 좌표계 단위를 따릅니다.

참고:
만약 지정한 사각형 영역이 캔버스 바깥으로 삐져나가게 된다면, 캔버스 영역을 벗어난 부분의 픽셀들은 반환된 ImageData 객체 내에서 투명한 검은색으로 채워져서 나옵니다.

이 메서드가 비디오와 결합되어 어떻게 쓰이는지 궁금하시다면 캔버스를 사용해 비디오 조작하기 아티클에서 훌륭한 예제를 확인하실 수 있습니다.


컬러 피커(스포이드) 만들기 (Creating a color picker)

이 예제에서는 getImageData() 메서드를 사용해서 마우스 커서 아래에 있는 픽셀의 색상을 실시간으로 표시하는 '컬러 피커(Color Picker)'를 만들어보겠습니다.

이를 위해 가장 먼저 현재 마우스의 좌표를 구하고, 그 좌표를 사용해 getImageData()가 제공하는 픽셀 배열에서 딱 그 위치의 색상 데이터를 조회합니다. 마지막으로 그 배열 데이터(RGB 값)를 사용해서 화면 아래에 있는 <div>(예제에서는 <td> 테이블 셀)의 배경색과 텍스트를 업데이트하여 선택된 색상을 시각적으로 보여줍니다.
이미지를 클릭하면 똑같은 작업을 수행하되 "선택된 색상(Selected color)" 영역에 값을 고정시킵니다.

HTML & CSS

<table>
  <thead>
    <tr>
      <th>원본 이미지 (Source)</th>
      <th>마우스오버 색상 (Hovered color)</th>
      <th>선택된 색상 (Selected color)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <canvas id="canvas" width="300" height="227"></canvas>
      </td>
      <td class="color-cell" id="hovered-color"></td>
      <td class="color-cell" id="selected-color"></td>
    </tr>
  </tbody>
</table>
body { font-family: sans-serif; }
.color-cell { color: white; }
th { width: 30%; }
td {
  font-family: monospace;
  font-weight: bold;
  padding-left: 1rem;
}

JavaScript

const img = new Image();
img.crossOrigin = "anonymous"; // 외부 이미지의 CORS(Cross-Origin) 보안 문제를 해결하기 위한 설정
img.src = "/shared-assets/images/examples/rhino.jpg";

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

img.addEventListener("load", () => {
  ctx.drawImage(img, 0, 0); // 이미지가 로드되면 캔버스에 그립니다.
  img.style.display = "none";
});

const hoveredColor = document.getElementById("hovered-color");
const selectedColor = document.getElementById("selected-color");

const pick = (event, destination) => {
  const bounding = canvas.getBoundingClientRect();
  // 캔버스 내에서의 정확한 마우스 x, y 좌표를 계산합니다.
  const x = event.clientX - bounding.left;
  const y = event.clientY - bounding.top;
  
  // 마우스 위치의 딱 1x1 픽셀 영역만 ImageData로 가져옵니다!
  const pixel = ctx.getImageData(x, y, 1, 1);
  const data = pixel.data;

  // [R, G, B, A] 배열 값을 rgb() 문자열로 변환합니다.
  const rgbColor = `rgb(${data[0]} ${data[1]} ${data[2]} / ${data[3] / 255})`;
  
  destination.style.background = rgbColor;
  destination.textContent = rgbColor;

  return rgbColor;
};

// 마우스가 움직일 때마다 Hover 컬러 업데이트
canvas.addEventListener("mousemove", (event) => pick(event, hoveredColor));
// 클릭할 때마다 Selected 컬러 업데이트
canvas.addEventListener("click", (event) => pick(event, selectedColor));

💡 강사의 실무 팁:
여기서 getImageData(x, y, 1, 1) 처럼 너비와 높이를 1로 주면 배열의 크기가 딱 4칸([R, G, B, A])짜리인 초소형 ImageData가 반환됩니다. 마우스 포인터 하나의 픽셀 값만 필요할 때 위에서 설명했던 복잡한 배열 인덱스 수학 공식을 직접 쓰지 않아도 되게 해주는 아주 영리한 방법이죠!


캔버스에 픽셀 데이터 칠어넣기 (Painting pixel data into a context)

이제 거꾸로, 우리가 가공한 픽셀 데이터를 다시 캔버스에 덮어씌워서 그리고 싶을 때는 putImageData() 메서드를 사용합니다.

ctx.putImageData(myImageData, dx, dy);

여기서 dxdy 매개변수는 캔버스 컨텍스트 내에서, 여러분이 그리고자 하는 픽셀 데이터(myImageData)의 좌측 상단 모서리를 위치시킬 '디바이스 좌표(x, y)'를 나타냅니다.

예를 들어, myImageData가 가지고 있는 전체 이미지를 캔버스의 맨 왼쪽 위 구석(0, 0)에 덮어씌우고 싶다면 다음과 같이 작성하면 됩니다.

ctx.putImageData(myImageData, 0, 0);

이미지 흑백 처리 및 색상 반전 (Grayscaling and inverting colors)

이 예제에서는 이미지의 모든 픽셀들을 하나하나 순회하면서(iterate) 그 값을 변경한 다음, 수정된 픽셀 배열을 putImageData()를 사용하여 다시 캔버스에 덮어씌우는 놀라운 이미지 필터 처리를 보여줍니다.

  • invert(반전) 함수는 각 RGB 색상 값을 최댓값인 255에서 빼는 방식으로 동작합니다. (예: 255 - R, 255 - G)
  • grayscale(흑백/회색조) 함수는 해당 픽셀의 빨강, 초록, 파랑 값의 '평균(average)'을 구해서 3가지 색상 채널에 모두 동일한 값을 넣어버립니다. (더 사실적인 흑백 이미지를 원한다면 x = 0.299r + 0.587g + 0.114b와 같은 가중 평균 공식을 사용할 수도 있습니다. 더 자세한 정보는 위키피디아의 Grayscale 문서를 참고하세요.)

HTML

<canvas id="canvas" width="300" height="227"></canvas>
<form>
  <input type="radio" id="original" name="color" value="original" checked />
  <label for="original">Original (원본)</label>

  <input type="radio" id="grayscale" name="color" value="grayscale" />
  <label for="grayscale">Grayscale (흑백)</label>

  <input type="radio" id="inverted" name="color" value="inverted" />
  <label for="inverted">Inverted (반전)</label>

  <input type="radio" id="sepia" name="color" value="sepia" />
  <label for="sepia">Sepia (세피아)</label>
</form>

JavaScript

const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");

const img = new Image();
img.crossOrigin = "anonymous";
img.src = "/shared-assets/images/examples/rhino.jpg";
img.onload = () => {
  ctx.drawImage(img, 0, 0); // 초기 원본 이미지 렌더링
};

// 1. 원본 복구 함수
const original = () => {
  ctx.drawImage(img, 0, 0);
};

// 2. 색상 반전(Invert) 함수
const invert = () => {
  ctx.drawImage(img, 0, 0); // 항상 원본을 먼저 새로 깔아줍니다.
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); // 전체 픽셀 복사!
  const data = imageData.data;
  
  // 전체 픽셀 배열을 4칸(RGBA)씩 묶어서 순회합니다.
  for (let i = 0; i < data.length; i += 4) {
    data[i] = 255 - data[i]; // 빨강(R) 반전
    data[i + 1] = 255 - data[i + 1]; // 초록(G) 반전
    data[i + 2] = 255 - data[i + 2]; // 파랑(B) 반전
    // data[i + 3] 인덱스인 투명도(A)는 건드리지 않습니다.
  }
  ctx.putImageData(imageData, 0, 0); // 가공된 픽셀 데이터를 캔버스에 덮어씌웁니다!
};

// 3. 흑백(Grayscale) 함수
const grayscale = () => {
  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  const data = imageData.data;
  for (let i = 0; i < data.length; i += 4) {
    // R, G, B 값의 평균을 구합니다.
    const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
    data[i] = avg; // 빨강
    data[i + 1] = avg; // 초록
    data[i + 2] = avg; // 파랑
  }
  ctx.putImageData(imageData, 0, 0);
};

// 4. 세피아(Sepia) 함수 (오래된 사진 느낌)
const sepia = () => {
  ctx.drawImage(img, 0, 0);
  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  const data = imageData.data;
  for (let i = 0; i < data.length; i += 4) {
    let r = data[i], // red
      g = data[i + 1], // green
      b = data[i + 2]; // blue

    // 세피아 톤을 만드는 공식 적용 (255를 넘지 않도록 Math.min 처리)
    data[i] = Math.min(Math.round(0.393 * r + 0.769 * g + 0.189 * b), 255);
    data[i + 1] = Math.min(Math.round(0.349 * r + 0.686 * g + 0.168 * b), 255);
    data[i + 2] = Math.min(Math.round(0.272 * r + 0.534 * g + 0.131 * b), 255);
  }
  ctx.putImageData(imageData, 0, 0);
};

// 라디오 버튼 이벤트 리스너 연결
const inputs = document.querySelectorAll("[name=color]");
for (const input of inputs) {
  input.addEventListener("change", (evt) => {
    switch (evt.target.value) {
      case "inverted":
        return invert();
      case "grayscale":
        return grayscale();
      case "sepia":
        return sepia();
      default:
        return original();
    }
  });
}

라디오 버튼을 하나씩 눌러보면 브라우저 내부에서 즉각적으로 수만 개의 픽셀 연산이 이루어지며 이미지가 변환되는 쾌감을 느끼실 수 있습니다!

캔버스 픽셀 조작하기 (Pixel manipulation with canvas)

이번 시간에는 캔버스의 진정한 강력함을 보여주는 픽셀 조작과 이미지 처리에 대해 알아보겠습니다. 이미지를 부드럽게 스케일링하거나, 픽셀 단위로 데이터를 뽑아내고, 최종적으로 우리가 만든 작품을 이미지 파일로 저장하는 방법까지 다뤄보죠!


줌과 안티앨리어싱 (Zooming and anti-aliasing)

drawImage() 메서드와 보조 캔버스(second canvas), 그리고 imageSmoothingEnabled 속성의 도움을 받으면, 원본 사진의 특정 부분을 돋보기처럼 확대(zoom)해서 픽셀 디테일을 관찰할 수 있습니다.

이 데모에서는 비교를 위해 imageSmoothingEnabled를 끈(false) 세 번째 캔버스도 나란히 배치해 보겠습니다. 이를 통해 브라우저가 이미지를 확대할 때 안티앨리어싱(스무딩 알고리즘)을 적용한 것과 안 한 것의 차이를 극명하게 볼 수 있죠.

HTML

<table>
  <thead>
    <tr>
      <th>Source (원본)</th>
      <th>Smoothing enabled = true (부드럽게)</th>
      <th>Smoothing enabled = false (픽셀 그대로)</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>
        <canvas id="canvas" width="300" height="227"></canvas>
      </td>
      <td>
        <canvas id="smoothed" width="200" height="200"></canvas>
      </td>
      <td>
        <canvas id="pixelated" width="200" height="200"></canvas>
      </td>
    </tr>
  </tbody>
</table>

CSS

body {
  font-family: monospace;
}

JavaScript

우선 마우스의 위치를 파악한 다음, 원본 이미지에서 마우스 커서를 중심으로 10x10 픽셀 크기의 아주 작은 영역을 가위로 오려냅니다(crop).
그러고 나서 이 오려낸 10픽셀짜리 조각을 다른 캔버스에 복사하되, 크기를 200x200 픽셀로 엄청나게 뻥튀기해서 그립니다. (무려 20배 확대!)

const img = new Image();
img.crossOrigin = "anonymous"; // 외부 이미지 사용 시 CORS 오염을 방지합니다.
img.src = "/shared-assets/images/examples/rhino.jpg";
img.onload = () => {
  draw(img);
};

function draw(image) {
  // 1. 원본 이미지를 그릴 첫 번째 캔버스
  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  ctx.drawImage(image, 0, 0);

  // 2. 부드럽게 확대될 두 번째 캔버스 (Smoothing 켜짐)
  const smoothCtx = document.getElementById("smoothed").getContext("2d");
  smoothCtx.imageSmoothingEnabled = true;

  // 3. 픽셀아트처럼 각지게 확대될 세 번째 캔버스 (Smoothing 꺼짐)
  const pixelatedCtx = document.getElementById("pixelated").getContext("2d");
  pixelatedCtx.imageSmoothingEnabled = false;

  // 돋보기 역할을 하는 줌(zoom) 함수 정의
  const zoom = (ctx, x, y) => {
    // drawImage의 9개짜리 파라미터를 사용해 원본에서 일부만 잘라내어 크게 그립니다!
    ctx.drawImage(
      canvas, // 소스는 첫 번째 캔버스입니다.
      Math.min(Math.max(0, x - 5), image.width - 10), // x 좌표에서 5만큼 뺀 위치부터 시작 (마우스를 중심으로)
      Math.min(Math.max(0, y - 5), image.height - 10),// y 좌표에서 5만큼 뺀 위치부터 시작
      10, // 원본에서 잘라낼 너비 (10px)
      10, // 원본에서 잘라낼 높이 (10px)
      0,  // 대상 캔버스의 0 좌표에
      0,  // 0 좌표부터
      200, // 너비를 200으로 뻥튀기!
      200, // 높이를 200으로 뻥튀기!
    );
  };

  // 원본 캔버스 위에서 마우스가 움직일 때마다 돋보기 캔버스들을 업데이트합니다.
  canvas.addEventListener("mousemove", (event) => {
    const x = event.layerX;
    const y = event.layerY;
    zoom(smoothCtx, x, y);
    zoom(pixelatedCtx, x, y);
  });
}

💡 강사의 팁: imageSmoothingEnabledfalse로 주면 우리가 흔히 아는 마인크래프트나 도트 게임(Pixel Art)의 그 깍둑깍둑한 질감을 그대로 유지하면서 이미지를 키울 수 있습니다. 도트 캐릭터를 캔버스에 그릴 땐 무조건 이걸 false로 끄고 시작하셔야 흐리멍덩해지지 않아요!

결과 (Result)

원본 이미지 위로 마우스를 올려보세요! (마우스 위치의 10x10 영역이 20배 확대되어 보입니다.)

(원본 코뿔소 사진과, 그 옆에 각각 부드럽게/거칠게 확대된 돋보기 뷰가 표시되는 데모 화면)


캔버스 이미지를 파일로 저장하기 (Saving images)

열심히 캔버스에 그림을 그렸다면, 이 결과물을 진짜 이미지 파일처럼 써먹거나 사용자에게 다운로드할 수 있게 해주고 싶겠죠? HTMLCanvasElement는 이럴 때 쓰라고 toDataURL()이라는 아주 고마운 메서드를 제공합니다.

이 메서드는 캔버스에 그려진 현재 상태의 이미지 데이터를, 우리가 type 매개변수로 지정한 포맷(기본값은 PNG)의 data URL(Base64 인코딩 문자열) 형태로 변환해서 반환해 줍니다. 참고로 반환된 이미지는 96 dpi의 해상도를 가집니다.

🚨 매우 중요한 보안 주의사항 (Note):
만약 캔버스 안에 그려진 픽셀들 중 단 하나라도 CORS 권한 승인 없이 다른 출처(origin)에서 몰래 가져온 이미지의 것이 섞여 있다면, 그 캔버스는 오염된(tainted) 상태가 됩니다. 오염된 캔버스에서는 데이터를 훔쳐 가는 것을 막기 위해 toDataURL()이나 getImageData() 같은 메서드 실행이 철저히 차단되고 보안 에러를 뿜어냅니다! 이에 대한 자세한 내용은 보안 및 오염된 캔버스 문서를 참고하세요.

<canvas.toDataURL('image/png')

아무것도 안 적었을 때의 기본 설정입니다. 무손실 압축인 PNG 이미지 문자열을 만들어냅니다.

canvas.toDataURL('image/jpeg', quality)

JPG 이미지 문자열을 만들어냅니다. 추가적으로 0부터 1 사이의 숫자(quality)를 두 번째 인자로 넘겨서 이미지 화질(압축률)을 조절할 수 있습니다. 1이 최고 화질(가장 무거움)이고, 0은 형체를 알아보기 힘들 정도로 깨지지만 파일 용량은 아주 작아집니다.

캔버스에서 이렇게 data URL을 성공적으로 뽑아냈다면, 이 긴 문자열을 아무 <img> 태그의 src 속성에 콱 박아 넣어서 화면에 띄울 수도 있고, <a> 하이퍼링크 태그의 href 속성에 넣은 뒤 download 속성을 달아서 사용자가 클릭하면 컴퓨터(디스크)에 파일로 쏙 다운로드되게 만들 수도 있습니다!

💡 강사의 팁 (다운로드 버튼 만들기):

const link = document.createElement('a');
link.download = 'my-awesome-drawing.png'; // 다운받을 파일명
link.href = canvas.toDataURL(); // 캔버스 데이터 URL 할당
link.click(); // 가상의 클릭을 발생시켜 다운로드 실행!

이 4줄의 코드만 있으면 사용자가 내가 만든 그림판 앱이나 차트를 이미지 파일로 다운받을 수 있는 버튼을 뚝딱 만들 수 있습니다.

또한 긴 문자열(Data URL) 대신, 메모리 효율이 훨씬 좋은 순수 바이너리 덩어리인 Blob 객체 형태로 캔버스 데이터를 뽑아낼 수도 있습니다.

canvas.toBlob(callback, type, encoderOptions)

캔버스 안에 들어있는 이미지를 비동기적으로(asynchronously) Blob 객체로 만들어줍니다. 작업이 끝나면 첫 번째 인자로 넘긴 콜백(callback) 함수를 부르면서 완성된 Blob 객체를 넘겨줍니다. 서버에 이미지 파일을 Ajax로 직접 업로드(Multipart Form-data 등)해야 할 때는 Data URL 대신 반드시 이 Blob을 사용하시는 것이 성능상 월등히 좋습니다.


같이 보기 (See also)


지금까지 캔버스에서 픽셀을 어떻게 떼어내고, 부드럽게 처리하고, 이미지로 구워내는지 그 원리를 샅샅이 파헤쳐 보았습니다! 이 기능들은 프론트엔드에서 '웹 기반 이미지 에디터'나 '필터 적용 앱'을 만들 때 가장 핵심이 되는 기술이랍니다. 다음 시간에는 캔버스 성능을 한계까지 끌어올리는 최적화 기법들에 대해 알아보겠습니다. 고생하셨습니다!

profile
프론트에_가까운_풀스택_개발자

0개의 댓글