이미지 리사이징을 해야할 일이 생겨서 리사이징을 하는 방법을 찾던중 다양한 방법이 있는것을 알게 되었습니다.
하나는 공식적으로 메서드인 UIGraphicsImageRenderer 이고 다른 하나는 jpegData(compressionQuality:) 메서드를 사용하여 UIImage의 JPEG 압축하는 방식입니다.
UIGraphicsImageRenderer란?
Core Graphics 지원 이미지를 만들기 위한 그래픽 렌더러입니다.
UIGraphicsImageRenderer는 iOS 10.0 이후에 사용할 수 있는 API로, 그래픽스 및 이미지 렌더링에 최적화된 컨텍스트를 제공합니다. 이를 사용하면 Core Graphics의 복잡한 API를 사용하지 않고도 스위프트 코드로 간단하게 이미지를 그릴 수 있습니다.
도형 그리기 예시
import UIKit
func drawShapes() -> UIImage {
let size = CGSize(width: 300, height: 300)
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { ctx in
// Background color
UIColor.lightGray.setFill()
ctx.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
// Draw a red circle
UIColor.red.setFill()
let circleRect = CGRect(x: 50, y: 50, width: 100, height: 100)
ctx.cgContext.fillEllipse(in: circleRect)
// Draw a blue rectangle with a border
UIColor.blue.setFill()
UIColor.black.setStroke()
let rect = CGRect(x: 50, y: 150, width: 100, height: 50)
ctx.cgContext.fill(rect)
ctx.cgContext.stroke(rect, width: 2)
// Draw a line segment
ctx.cgContext.move(to: CGPoint(x: 200, y: 50))
ctx.cgContext.addLine(to: CGPoint(x: 250, y: 150))
UIColor.green.setStroke()
ctx.cgContext.setLineWidth(5)
ctx.cgContext.strokePath()
// Draw text
let textAttributes: [NSAttributedString.Key: Any] = [
.font: UIFont.boldSystemFont(ofSize: 20),
.foregroundColor: UIColor.white
]
let string = "Hello!"
string.draw(at: CGPoint(x: 200, y: 200), withAttributes: textAttributes)
}
return image
}
- UIGraphicsImageRenderer 생성:
- size는 그릴 이미지의 크기를 정의합니다.
- UIGraphicsImageRenderer(size: size)를 사용하여 renderer 객체를 생성합니다.
- 도형 및 텍스트 그리기:
- renderer.image { ctx in ... }는 그래픽스 컨텍스트를 제공하며, 이 컨텍스트를 사용하여 도형을 그립니다.
- 원, 사각형, 선 등을 그립니다
- 색상 설정:
- UIColor.setFill() 및 UIColor.setStroke() 메서드를 사용하여 채우기 및 테두리 색상을 설정합니다.
- 도형 그리기:
- ctx.cgContext.fillEllipse(in:)는 원을 그립니다.
- ctx.cgContext.fill(rect:)는 사각형을 채웁니다.
- ctx.cgContext.stroke(rect:, width:)는 사각형에 테두리를 그립니다.
- ctx.cgContext.move(to:) 및 ctx.cgContext.addLine(to:)를 사용하여 선을 그립니다.
- 텍스트 그리기:
- String.draw(at:withAttributes:)를 사용하여 텍스트를 그립니다.
즉, 이런식으로 이미지를 새로그려서 물리적인 크기를 줄이는데 목적을 두고 있습니다
→ 2000x2000의 이미지를 500x500으로 바꾸는 것
하지만 제가 하던 프로젝트에서는
[Body]: None
[Response]:
[Status Code]: 413
[Headers]:
Content-Length: 192
Content-Type: text/html
...
[Body]:
<html>
<head><title>413 Request Entity Too Large</title></head>
이런식으로 이미지의 크기가 커서 서버에 post하기 곤란한 것이였습니다.
또한, Post 하려는 부분이
이런식으로 개인의 프로필 부분이였기 때문에 이미지의 물리적인 크기가 줄어든다면 프로필에 표시되는 이미지의 크기가 어색하게 줄어드는 경우가 생기기 때문에 파일 크기 (데이터 크기)를 줄이는데 중점을 두어야 햇습니다.
따라서 JPEG 포맷의 압축률을 조절하는 방식으로 이미지의 크기를 줄엿습니다.
func compressImage(_ image: UIImage, toSizeInMB maxSizeInMB: Double) -> Data? {
let maxSizeInBytes = maxSizeInMB * 1024 * 1024
var compressionQuality: CGFloat = 1.0 // 1MB 될때까지 계속 while문 반복하기
var imageData: Data?
while compressionQuality > 0 {
imageData = image.jpegData(compressionQuality: compressionQuality)
if let imageData = imageData, Double(imageData.count) <= maxSizeInBytes {
print("Compressed image size: \\(Double(imageData.count) / 1024 / 1024) MB")
break
}
compressionQuality -= 0.1
}
return imageData
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.editedImage] as? UIImage {
ProfileImageView.image = image
if let compressedImageData = compressImage(image, toSizeInMB: 1.0) {
print("Compressed image data size: \\(Double(compressedImageData.count) / 1024 / 1024) MB")
picker.dismiss(animated: true, completion: nil)
}
}
}
이 방법은 원본 이미지의 픽셀 크기를 그대로 유지하면서도 이미지 데이터의 크기(바이트 단위)를 조절할수 있는 방식입니다.
이를 위해 UIImage의 jpegData(compressionQuality:) 메서드를 사용해 이미지를 JPEG 형식으로 압축합니다. compressionQuality 매개변수를 조절하면 이미지의 압축률을 조절할 수 있으며, 이런 방식으로 이미지 품질을 직접적으로 떨어뜨립니다.
제가 선택한 이유는 프로필 이미지의 모양이 깨지는것보다 프로필 이미지를 직접적으로 사용할 일이 없기 때문에 품질을 저하시키더라도 이러한 방식으로 파일 크기를 줄이는 방식이 좀더 나은 방식임을 알게 되어 적용하게 되었습니다.
'IOS - Swift' 카테고리의 다른 글
[iOS/Swift] Run Loop ( 2 / 2 ) (1) | 2023.08.27 |
---|---|
[iOS/Swift] Run Loop - (1 / 2) (0) | 2023.08.20 |
[iOS/Swift] Dependency Injection, 의존성 주입이란? (0) | 2023.07.30 |
Managing the view hierarchy 에 관하여 - 1 (0) | 2023.07.02 |
[WWDC 2022]Create parametric 3D room scans with RoomPlan (0) | 2023.06.11 |