대비(Constrast) 필터 공식
new = (old - 128) * contrast + 128
- 1.0은 원본
- 1.0보다 크면 대비 증가
- 1.0보다 작으면 대비 감소
UI에서는 보통 0~200 값을 slider로 주기 때문에 WASM에서는 다음과 같이 변환
contrastFactor = contrastValue / 100
contrast.rs
- 브라우저에서 전달된 이미지 픽셀 배열을 WASM로 가져옴
- 각 픽셀의 대비를 조절
- 조절은 RGB 값에 ((value - 128) * factor + 128)로 수행됨
- 변경된 값을 다시 같은 메모리에 써 넣기 때문에 JS에서 바로 반영됨
#[no_mangle]
pub extern "C" fn contrast(ptr: *mut u8, length: usize, contrast_value: f32) {
let pixels = unsafe { core::slice::from_raw_parts_mut(ptr, length) };
let factor = contrast_value / 100.0;
for i in (0..length).step_by(4) {
let r = pixels[i] as f32;
let g = pixels[i + 1] as f32;
let b = pixels[i + 2] as f32;
let nr = ((r - 128.0) * factor + 128.0).clamp(0.0, 255.0);
let ng = ((g - 128.0) * factor + 128.0).clamp(0.0, 255.0);
let nb = ((b - 128.0) * factor + 128.0).clamp(0.0, 255.0);
pixels[i] = nr as u8;
pixels[i + 1] = ng as u8;
pixels[i + 2] = nb as u8;
}
}
#[no_mangle]
- 함수 이름이 WASM에서 그대로 유지되도록 설정
#[wasm_bindgen]과 #[no_mangle] extern "C" 차이
| #[wasm_bindgen] | #[no_mangle] extern "C" | |
| JS와의 연결 방식 | wasm-bindgen이 자동으로 JS wrapper 생성 | 직접 메모리 주소로 접근하는 raw C 스타일 |
| 사용 난이도 | 매우 쉬움 | 매우 어려움 (메모리 직접 관리) |
| 안전성 | 안전하고 편리 | unsafe 많이 필요 |
| 데이터 전달 방식 | 슬라이스 & 구조체 등 Rust 타입 그대로 사용 가능 | ptr + length 조합으로 직접 메모리 처리 |
| 빌드 툴 요구 | wasm-bindgen / wasm-pack 필요 | wasm-bindgen 없이 standalone wasm 가능 |
| 속도 | 약간 느릴 수 있음 (wrapper overhead) | 가장 빠름 (100% raw 호출) |
| 언제 쓰나? | 일반적인 웹앱 개발 | 고성능 필터, 이미지 처리 같은 로우레벨 연산 |
#[wasm_bindgen]
- wasm_bindgen이 자동으로 변환해 줘서 Rust 함수가 JS에서 바로 사용 가능
- JS -> WASM, WASM -> JS 타입 변환도 자동 처리
- &mut [u8] 같은 슬라이스도 wrapper가 알아서 JS TypedArray와 연결해줌
#[no_mangle] extern "C"
- 순수 C ABI (가장 로우 레벨)
- wasm-bindgen 없이도 build 및 실행 가능
- JS에서 메모리(buffer)를 직접 할당하고 포인터를 Rust에 전달해야 함
// JS에서 사용하는 법
const ptr = imgData.data.byteOffset;
wasmInstance.exports.contrast(ptr, imgData.data.length, 120.0);
편하고 쉬운 함수는 wasm_bindgen
- brightness와 grayscale
- 쉽게 개발 가능하고 속도도 충분
매우 고성능이 필요한 함수는 no_mangle + raw pointer
- contrast, convolution, sharpen, gaussian blur
- 반복 연산이 너무 많아서 wrapper 비용까지 제거해야 함
extern "C"
- JS에서 호출할 수 있는 C ABI 형태
ptr
- JS에서 넘긴 imageData.data의 포인터(메모리 주소)
length
- 픽셀 배열 길이
contrast_value
- 대비 값
let pixels = unsafe { core::slice::from_raw_parts_mut(ptr, length) };
- 픽셀 배열 가져오기
- JS로부터 받은 메모리 주소(ptr)를 Rust 슬라이스로 변환
- unsafe인 이유는 메모리 주소를 직접 다뤄서 Rust가 안정성 보장을 못 함
- 이 배열은 RGBA 단위이므로 4바이트씩 하나의 픽셀
let factor = contrast_value / 100.0;
- 대비 비율 계산
- JS에서 constrast_value를 예를 들어 120으로 보내면 1.2가 됨
let r = pixels[i] as f32;
let g = pixels[i + 1] as f32;
let b = pixels[i + 2] as f32;
- 현재 RGB 값을 f32로 변환
let nr = ((r - 128.0) * factor + 128.0).clamp(0.0, 255.0);
- 대비 = 원본 값에서 128(중간값)을 기준으로 멀리 보내거나 가까이 보냄
- 대비를 높이면 어두운 부분은 더 어둡게, 밝은 부분은 더 밝게
- 대비를 낮추면 전체가 플랫해짐
- 픽셀 값이 0 ~ 255를 넘지 않도록 제한
pixels[i] = nr as u8;
pixels[i + 1] = ng as u8;
pixels[i + 2] = nb as u8;
- 계산된 RGB 값을 다시 메모리에 넣기
- 알파 값은 유지
하지만 본 프로젝트에서는
[wasm_bindgen]을 이용할 것이다.
이전 밝기와 흑백에서 [wasm_bindgen]을 이용하였고,
유지 보수에 있어 [wasm_bindgen]이 더 유리하기 때문
export default function useFilterContrast() {
const { prepareFilter } = useFilterBase();
const applyContrast = (
wasm: WasmModule | null,
getCanvasImageData: GetCanvasImageData,
newValue: number,
) => {
const info = prepareFilter(wasm, getCanvasImageData);
if (!info) return;
const { ctx, imageData } = info;
wasm?.contrast(imageData.data, newValue);
ctx.putImageData(imageData, 0, 0);
};
return { applyContrast };
}
- 대비 필터를 적용하는 함수
export default function useFilterContrast() {
const { prepareFilter } = useFilterBase();
- WASM 기능 + canvas 픽셀 저장을 위한 공통 로직
- 여러 필터에서 공유하는 base 로직
- 필터 적용하기 전에 이미지 편집 준비를 자동으로 해주는 함수
const info = prepareFilter(wasm, getCanvasImageData);
if (!info) return;
- wasm 모듈이 있는지 확인
- canvas가 있는지 확인
- 이미지 픽셀을 읽어오기
- 필요한 렌더링 context 가져오기
- 필터 적용하기 전에 이미지 편집 준비를 자동으로 해주는 함수
const { ctx, imageData } = info;
- ctx : canvas의 2D rendering context
- imageData : 현재 Canvas의 RGBA 픽셀 배열
wasm?.contrast(imageData.data, newValue);
- Rust(WASM) contrast 함수 호출
ctx.putImageData(imageData, 0, 0);
- 변경된 픽셀을 canvas에 다시 반영
- WASM이 pixel 배열을 직접 수정 -> canvas에 반영 -> 즉시 UI에 표시
'Rust' 카테고리의 다른 글
| [트러블슈팅]next.js16과 tailwindcss v4 반응형 웹 오류 (3) | 2025.11.22 |
|---|---|
| 트러블 슈팅 (1) | 2025.11.21 |
| 이미지 다운로드하기 (0) | 2025.11.20 |
| 밝기 조절하기 (0) | 2025.11.18 |
| 파일 업로드 & 흑백 필터 적용 (0) | 2025.11.14 |