본문 바로가기
Rust

파일 업로드 & 흑백 필터 적용

by 쪼꼬에몽 2025. 11. 14.

사진 업로드 + canvas에 표시

const [image, setImage] = useState<HTMLImageElement | null>(null);
const canvasRef = useRef<HTMLCanvasElement | null>(null);
  • 이미지 저장 state와 canvas 요소를 관리하는 ref.

파일 업로드 핸들러

const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
  if (e.target.files && e.target?.files[0]) {
    const url = URL.createObjectURL(e.target?.files[0]);
    const img = new Image();
    img.src = url;
    img.onload = () => setImage(img);
  }
}

 

1. 파일 입력창에서 이미지를 선택

2. 브라우저가 임시 URL(blob:)을 생성

3. new Image()로 이미지 객체 생성

4. 이미지 로딩이 완료되면 setImage(img)로 state에 저장

  • 이미지를 메모리에 불러온 상태

왜 blob URL을 생성해야 할까?

  • <input type="file">로 선택된 파일은 브라우저 메모리 안에만 존재하는 로컬 파일 객체(File)
  • 직접 img.src에 넣지 못하기 때문에 렌더링 가능한 형태로 바꿔야 함

브라우저는 이미지의 src로 "URL"만 인식할 수 있음

  • HTML <img>의 src는 텍스트 URL 문자열이어야 함
  • 사용자가 업로드한 File은 바이너리 데이터라서 바로 넣을 수 없음
  • URL.createObjectURL()로 File 객체를 접근할 수 있는 URL로 바꿈
  • 실제 서버 URL이 아니라 로컬 브라우저 메모리 안에 있는 내용을 참조하는 특수 주소

이미지 로딩되는 구조

  • 브라우저는 blob URL을 읽고 그 URL이 가리키는 File 데이터(이미지)를 찾음
  • 이미지 디코딩을 하고
  • onload 이벤트가 발생해서 이미지가 준비됨

base64 방법

  • file을 base64로 변환하는 방법도 있음
  • 느리고 메모리를 많이 먹어서 성능이 떨어짐
  • blob URL 방식을 사용

이미지가 state에 들어오면 canvas에 그림

useEffect(() => {
  if (!image || !canvasRef.current) return;

  const canvas = canvasRef.current;
  const ctx = canvas?.getContext('2d');
  if (!ctx) return;

  canvas.width = image.width;
  canvas.height = image.height;
  ctx.drawImage(image, 0, 0);
}, [image]);
  • image가 state에 저장되는 순간 그림을 그리기 위해서 useEffect 사용

1. canvas 요소 가져오기

2. canvas 크기를 업로드한 이미지 크기와 동일하게 설정

3. ctx.drawImage(image, 0, 0)로 실제 출력

  • 업로드하면 바로 화면에 보임

canvas.getContext('2d')란?

  • <canvas>는 빈 도화지여서 그림 도구가 필요함
  • getContext('2d')를 이용해 2D 드로잉 도구를 요청하면 브라우저는 2D 렌더링 엔진 객체를 리턴

ctx가 하는 일

이미지 그리기

 -> ctx.drawImage(image, 0, 0);

 

도형 그리기

 -> ctx.fillRect(10, 10, 100, 100);

 

텍스트 그리기

 -> ctx.fillText("hello", 50, 50);

 

픽셀 접근

 -> const imageData = ctx.getImageData(...);

 

픽셀 수정 후 다시 넣기

 -> ctx.putImageData(imageData, 0, 0);

흑백 필터 적용

const applyGrayscale = () => {
  if (!wasm || !canvasRef.current || !image) return;

  const canvas = canvasRef.current;
  const ctx = canvas?.getContext('2d');
  if (!ctx) return;

  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  wasm.grayscale(imageData.data);

  ctx.putImageData(imageData, 0, 0);
};

현재 canvas의 픽셀 데이터 가져오기

const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  • canvas 전체의 픽셀 정보를 가져옴
  • 0, 0
  • imageData.data는 RGBA 값 배열

WASM 함수로 grayscale 변환

wasm.grayscale(imageData.data);
  • WASM 모듈이 실제 변환을 수행함
  • grayscale 알고리즘은 이렇게 적용됨
  • WASM은 JS보다 더 빠르게 수행됨

변환된 픽셀을 canvas에 다시 반영

ctx.putImageData(imageData, 0, 0);
  • WASM에서 변경된 pixel 배열을 다시 canvas에 그려서
  • 화면이 실시간으로 흑백으로 변환됨

 

 

 

 

'Rust' 카테고리의 다른 글

[트러블슈팅]next.js16과 tailwindcss v4 반응형 웹 오류  (3) 2025.11.22
트러블 슈팅  (1) 2025.11.21
이미지 다운로드하기  (0) 2025.11.20
대비 만들기  (0) 2025.11.18
밝기 조절하기  (0) 2025.11.18