SNS서비스를 만드는 프로젝트를 하면서, 이미지를 처리해야 하는 경우가 많았다. 이미지 용량을 줄이는 compressor라이브러리 사용법과 file input에 대한 유효성 검사 함수를 정리했다.
1) 이미지 크기 제한
1
2
3
4
5
6
7
8
9
10
11
// 정해진 파일 크기보다 큰 파일이라면 false를 반환한다. (max: 최대 이미지 mb, fileSize: 업로드한 이미지 용량)
function checkImageSize(fileData: { max: number; fileSize: number }): boolean {
const { max, fileSize } = fileData;
// 제한되는 사이즈
const maxSize = max * 1024 * 1024;
if (maxSize <= fileSize) {
return false;
}
return true;
}
2) 이미지 확장자 제한
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 정해진 파일 확장자가 아니라면 false를 반환한다. (fileName: 이미지 이름)
function checkImageExtension(fileName: string): boolean {
// 이미지 확장자
const imageExtensions = ["gif", "jpg", "jpeg", "png", "bmp", "ico", "apng"];
// 업로드한 파일 확장자 ('.'이후의 문자를 소문자로 변환)
const extension = fileName
.substring(fileName.lastIndexOf(".") + 1)
.toLocaleLowerCase();
// 업로드한 파일 확장자가 이미지 확장자인지 확인한다.
const result = imageExtensions.some((item) => item === extension);
return result;
}
3) 이미지 Compressor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import Compressor from "compressorjs";
// 이미지 compressor (file: 업로드한 파일 )
function compressorImage(file: File): Promise<File> {
// 프로미스 객체를 반환한다.
return new Promise((resolve, reject) => {
new Compressor(file, {
// compressor 옵션
checkOrientation: false,
quality: 0.8,
maxWidth: 1920,
maxHeight: 1920,
// compressor에 성공했을 경우, 파일로 저장하여 반환한다.
success(result: File) {
const compressorImage = new File([result], result.name, {
type: result.type,
});
resolve(compressorImage);
},
// compressor에 실패했을 경우,
error(error) {
reject(error);
},
});
});
}
4) 실제 적용 로직 (vue3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import {checkImageSize, compressorImage, checkImageExtension,} from "../../functions/image";
// fileInput의 change 이벤트가 발생할 때 실행한다.
const changeCustomCocktailImage = (event: Event) => {
let file = (event.target as HTMLInputElement).files![0];
// 파일을 업로드 하지 않고 취소 버튼을 누르는 경우
if (!file) {
return;
}
// 업로드한 파일이 이미지가 아닌경우
if (!checkImageExtension(file.name)) {
store.dispatch(
"modal/changeErrorModalMessage",
"올바른 이미지 파일을 업로드 하세요."
);
store.dispatch("modal/blinkErrorModalAppStatus", true);
return;
}
// 이미지 용량이 5mb초과면 compressor를 진행한다.
if (!checkImageSize({ max: 5, fileSize: file.size })) {
compressorImage(file).then((result) => {
// compressor를 진행해도 이미지 용량이 10mb 초과면 알림을 보낸다.
if (!checkImageSize({ max: 10, fileSize: result.size })) {
store.dispatch(
"modal/changeErrorModalMessage",
"이미지가 너무 큽니다."
);
store.dispatch("modal/blinkErrorModalAppStatus");
return;
// compressor를 진행 후, 이미지 용량이 10mb 이하면 업로드 한다.
} else {
const data = {
img: result,
};
store.dispatch("customCocktail/uploadImage", data);
emit("changeImage", data.img);
return;
}
});
// 이미지 용량이 5mb 이하면 compressor 없이 그냥 업로드 한다.
} else {
const data = {
img: file,
};
store.dispatch("customCocktail/uploadImage", data);
emit("changeImage", data.img);
return;
}
};
event.target.files[0]
을 통해 파일을 가져온다.- 만약 파일이 아니거나 이미지 파일이 아니면 바로 return 한다.
- 이미지 파일이 5mb 초과면 compressor를 진행한다.
- compressor를 진행해도 이미지가 10mb 초과이면 알림을 보내고 바로 return한다.
- compressor를 진행 후, 이미지가 10mb 이하이면 파일을 서버에 보낸다.
- 이미지 파일이 5mb 이하면 compressor 없이 바로 서버에 보낸다.