사진 업로드 + 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 |