서버와 통신하는 작업중
서버에서 요구하는 조건중 이미지 데이터는 5mb 까지 제한이 있었다.
그걸 잊고 통신하던 중 형식에 맞지 않는다는 에러를 받게 되었는데…!
문제의 과정은 다음과 같다.
input.saveButtonTap
.withLatestFrom(tapValidConbine)
.throttle(.seconds(1), scheduler: MainScheduler.instance)
.filter({ $0.2 != nil })
.map({ content in
return (contents: content.0, datas: content.1, productId: content.2!)
})
.flatMap { content in
NetworkManager.uploadImages(model: ImageDataModel.self, router: .imageUpload, images: content.datas).map { result in
return (result, content.contents, content.productId)
}
}
.bind { result in
switch result.0 {
case .success(let imageModel):
imageUploadScueess.accept((imageModel: imageModel, content: result.1, productId: result.2.identi))
case .failure(let error):
networkError.accept(error)
}
}
.disposed(by: disposeBag)
위와 같은 코드에서 이미지의 데이터를 통해 서버와 통신 하는 과정이다.
문제는 다음과 같았는데
”ErrorCode: 400”
해당 코드는 문서에 의하면,
”파일의 제한 사항과 맞지 않습니다. ”
혹은
“파일을 보내지 않았지만 content-type을 application/json 으로 요청할 경우”
나같은 경우 이미지가 있어야 저로직이 들어가기에
”파일의 제한 사항과 맞지 않습니다.”
가 해당 되겠다고 판단했다.
파일의 제한 사항과 맞지 않을 경우를 알아보자면,
1. 확장자: jpg, jpeg, png, gif, pdf 로 제한
2. 용량: 5mb 제한
3. 파일갯수 : 5개
다음과 같은데 확장자는 jpeg로 통일하였었기 때문에 해당하지 않는 문제라 판단하였고,
파일 갯수 마저 최대 5개로 제한 하였기 해당 문제도 아니라고 판단하였다.그렇다면 남은 문제는 2. 용량 문제 인데
출력을 통해 판단해보면
// 각 데이터 용량 체크 data.count
[5903211 bytes, 3425951 bytes, 4395344 bytes, 2275097 bytes]
5903211 bytes
는 mb로 환산해보면5.903211 mb
가 나오게 되는데
해당하는 문제로 인해 문제가 발생 하였음을 추측 할수 있다.
그렇다면 압축을 진행해 보고자 한다.
이미지 리사이징을 통해 이미지 용량을 줄일수 있다고 한다
- 픽셀수 감소 효과 : 이미지의 해상도를 낮추는 방법이기에 픽셀수가 감소하게 됨으로 용량이 줄어든다.
예) 9000X9000 → 1920 x 1080
하지만 내가 원하는 바는 이미지 자체의 크기( W and H ) 은 유지하고 압축을 원하였기에
이번에는 이미지 리사이징 방법으로 접근을 하지 않았다.
JPEG 포멧으로 이미지를 압축시키는데
0.0 ~ 1.0 사이의 압축비율을 가지게 할수 있다.해당하는 방법으로 이미지 압축을 세밀하게 조절해 보고자 한다.
해당하는 메서드를 통해
간단하게 한다고 하면 퀄리티를 아주작게 1 ~ 4 사이 정도로 해서 5mb로 맞추어 줄순 있을것이다.
다….만….!
그렇게 접근 하게 된다면 이미지의 최적의 퀄리티가 아닌 모두 저퀄리티가 되어버리니
적절한 방법은 아니게 될것이라고 생각했다.그리하여 진행하는 방법은 다음과 같다.
private func imageZipLimit(image: UIImage, zipRate: Double) -> Data? {
let limitBytes = zipRate * 1024 * 1024
print("클라이언트가 원하는 크기",limitBytes)
var currentQuality: CGFloat = 0.95
var imageData = image.jpegData(compressionQuality: currentQuality)
while let data = imageData,
Double(imageData!.count) > limitBytes && currentQuality > 0{
print("현재 이미지 크기 :\(data.count)")
currentQuality -= 0.05
imageData = image.jpegData(compressionQuality: currentQuality)
print("현재 압축중인 이미지 크기 :\(imageData!.count)")
}
if let data = imageData,
Double(data.count) <= limitBytes {
print("압축 \(data.count) bytes, 압축률: \(currentQuality)")
return data
} else {
print("초과")
return nil
}
}
코드는 생각 보다 간단하다
zipRate
는 클라이언트가 정한 예를들어 5.0 이라고 하였을때
5mb → 5242880 bytes
가 나와야 한다.
1 mb = 1024 x 1024 이기에 다음과 같은 식이 나오게 된다.
그리고 점진적으로 0.5씩 퀄리티를 줄이며 압축하여 최적의 퀄리티를 찾아
해당하는 퀄리티를 적용해 방출하는 방법으로 해당하는 문제를 해결하였다.
사실 중간에 착각하여
1차 : [5093211 bytes, 3425951 bytes, 4395344 bytes, 2275097 bytes]
위와 같이 나왔을때 왜
5mb
를 초과했지 라고 착각하여
지연시간이 늘게 되었다.
후에 알고보니5,242,880 바이트
라는것을 알아챘고 이런 기본적인것을 까먹을 수도 있구나
까먹지 않게끔 계속해서 자신을 돌아보아야 겠다고 생각하게 되었다.