이미지 선택 + 압축 + Base64 변환 (expo-image-picker)
개요
사용자 갤러리에서 이미지를 선택하고, 서버 전송을 위해 리사이즈/압축/Base64 변환하는 방법입니다.
설치
npx expo install expo-image-picker expo-image-manipulator
주의: 네이티브 모듈이므로 Development Build 재빌드 필요
전체 플로우
갤러리 열기 → 이미지 선택 → 크롭(선택) → 리사이즈 → 압축 → Base64 인코딩 → 서버 전송
구현 코드
// src/utils/image.ts
import * as ImagePicker from "expo-image-picker";
import * as ImageManipulator from "expo-image-manipulator";
interface ImageResult {
uri: string;
base64: string;
}
/**
* 프로필 이미지 선택 및 처리
* 1. 갤러리에서 이미지 선택 (1:1 비율 크롭)
* 2. 400x400으로 리사이즈
* 3. 70% 품질로 압축
* 4. Base64 인코딩
*/
export const pickProfileImage = async (): Promise<ImageResult | null> => {
// 1. 갤러리 권한 요청 및 이미지 선택
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaType.Images, // 이미지만 선택
allowsEditing: true, // 편집(크롭) 허용
aspect: [1, 1], // 1:1 비율 (정사각형)
quality: 1, // 원본 품질로 가져오기
});
// 취소한 경우
if (result.canceled || !result.assets[0]) {
return null;
}
const selectedImage = result.assets[0];
// 2. 이미지 리사이즈 + 압축 + Base64 변환
const manipulated = await ImageManipulator.manipulateAsync(
selectedImage.uri,
[{ resize: { width: 400, height: 400 } }], // 리사이즈
{
compress: 0.7, // 70% 품질로 압축
format: ImageManipulator.SaveFormat.JPEG, // JPEG 포맷
base64: true, // Base64 인코딩
}
);
return {
uri: manipulated.uri, // 로컬 파일 경로 (미리보기용)
base64: manipulated.base64 || "", // Base64 문자열 (서버 전송용)
};
};
컴포넌트에서 사용
// Step2ProfileScreen.tsx
import { pickProfileImage } from "../../../utils/image";
const Step2ProfileScreen = () => {
const [imageUri, setImageUri] = useState<string | null>(null);
const [imageBase64, setImageBase64] = useState<string | null>(null);
const handleImagePress = async () => {
const result = await pickProfileImage();
if (result) {
setImageUri(result.uri); // 미리보기용
setImageBase64(result.base64); // 서버 전송용
}
};
return (
<TouchableOpacity onPress={handleImagePress}>
{imageUri ? (
<Image source={{ uri: imageUri }} style={styles.image} />
) : (
<View style={styles.placeholder}>
<Text>이미지 선택</Text>
</View>
)}
</TouchableOpacity>
);
};
주요 옵션 설명
ImagePicker.launchImageLibraryAsync 옵션
| 옵션 | 설명 | 예시 |
|---|---|---|
| mediaTypes | 선택할 미디어 타입 | MediaType.Images, MediaType.Videos |
| allowsEditing | 크롭 편집 허용 | true / false |
| aspect | 크롭 비율 (allowsEditing=true일 때) | [1, 1], [4, 3], [16, 9] |
| quality | 이미지 품질 (0~1) | 1 (원본), 0.5 (50%) |
ImageManipulator.manipulateAsync 옵션
| 옵션 | 설명 | 예시 |
|---|---|---|
| resize | 리사이즈 크기 | { width: 400, height: 400 } |
| compress | 압축 품질 (0~1) | 0.7 (70%) |
| format | 출력 포맷 | SaveFormat.JPEG, SaveFormat.PNG |
| base64 | Base64 인코딩 여부 | true / false |
권한 처리
iOS에서는 Info.plist에 권한 설명이 필요하지만, Expo에서는 app.json에서 설정합니다.
// app.json
{
"expo": {
"plugins": [
[
"expo-image-picker",
{
"photosPermission": "프로필 사진을 설정하기 위해 갤러리 접근이 필요합니다."
}
]
]
}
}