업로드 이미지 크기를 줄이려면 UI 이미지 크기를 어떻게 조정해야 합니까?
구글을 검색해보니 높이/폭을 줄이거나 CoreImage를 통해 UI 이미지 모양을 편집하는 라이브러리만 발견되었습니다.하지만 저는 이미지 크기를 줄이는 방법을 설명하는 게시글인 라이브러리를 본 적이 없거나 발견하지 못해서 업로드할 때 전체 이미지 크기가 아닙니다.
지금까지 이것을 가지고 있습니다.
if image != nil {
//let data = NSData(data: UIImagePNGRepresentation(image))
let data = UIImagePNGRepresentation(image)
body.appendString("--\(boundary)\r\n")
body.appendString("Content-Disposition: form-data; name=\"image\"; filename=\"randomName\"\r\n")
body.appendString("Content-Type: image/png\r\n\r\n")
body.appendData(data)
body.appendString("\r\n")
}
12MB의 사진을 보내주고 있습니다.어떻게 하면 1mb로 줄일 수 있을까요? 감사합니다!
Xcode 9 • Swift 4 이상
편집/업데이트:iOS10+의 경우 UIGraphics ImageRender를 사용할 수 있습니다.이전 Swift 구문에 대해서는 편집 기록을 확인합니다.
extension UIImage {
func resized(withPercentage percentage: CGFloat, isOpaque: Bool = true) -> UIImage? {
let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: canvas, format: format).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
func resized(toWidth width: CGFloat, isOpaque: Bool = true) -> UIImage? {
let canvas = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: canvas, format: format).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
}
용도:
let image = UIImage(data: try! Data(contentsOf: URL(string:"https://i.stack.imgur.com/Xs4RX.jpg")!))!
let thumb1 = image.resized(withPercentage: 0.1)
let thumb2 = image.resized(toWidth: 72.0)
이미지 크기를 조정하기 위해 이 방법을 사용했습니다.
-(UIImage *)resizeImage:(UIImage *)image
{
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float maxHeight = 300.0;
float maxWidth = 400.0;
float imgRatio = actualWidth/actualHeight;
float maxRatio = maxWidth/maxHeight;
float compressionQuality = 0.5;//50 percent compression
if (actualHeight > maxHeight || actualWidth > maxWidth)
{
if(imgRatio < maxRatio)
{
//adjust width according to maxHeight
imgRatio = maxHeight / actualHeight;
actualWidth = imgRatio * actualWidth;
actualHeight = maxHeight;
}
else if(imgRatio > maxRatio)
{
//adjust height according to maxWidth
imgRatio = maxWidth / actualWidth;
actualHeight = imgRatio * actualHeight;
actualWidth = maxWidth;
}
else
{
actualHeight = maxHeight;
actualWidth = maxWidth;
}
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
NSData *imageData = UIImageJPEGRepresentation(img, compressionQuality);
UIGraphicsEndImageContext();
return [UIImage imageWithData:imageData];
}
이 방법을 사용하면 6.5MB의 이미지가 104KB로 줄어듭니다.
스위프트 4 코드:
func resize(_ image: UIImage) -> UIImage {
var actualHeight = Float(image.size.height)
var actualWidth = Float(image.size.width)
let maxHeight: Float = 300.0
let maxWidth: Float = 400.0
var imgRatio: Float = actualWidth / actualHeight
let maxRatio: Float = maxWidth / maxHeight
let compressionQuality: Float = 0.5
//50 percent compression
if actualHeight > maxHeight || actualWidth > maxWidth {
if imgRatio < maxRatio {
//adjust width according to maxHeight
imgRatio = maxHeight / actualHeight
actualWidth = imgRatio * actualWidth
actualHeight = maxHeight
}
else if imgRatio > maxRatio {
//adjust height according to maxWidth
imgRatio = maxWidth / actualWidth
actualHeight = imgRatio * actualHeight
actualWidth = maxWidth
}
else {
actualHeight = maxHeight
actualWidth = maxWidth
}
}
let rect = CGRect(x: 0.0, y: 0.0, width: CGFloat(actualWidth), height: CGFloat(actualHeight))
UIGraphicsBeginImageContext(rect.size)
image.draw(in: rect)
let img = UIGraphicsGetImageFromCurrentImageContext()
let imageData = img?.jpegData(compressionQuality: CGFloat(compressionQuality))
UIGraphicsEndImageContext()
return UIImage(data: imageData!) ?? UIImage()
}
스위프트 5 & Xcode 14
이 KB 를 사용했기 KB 를 생성하는..jpegData(compressionQuality: x)되므로 이 은 큰 를 들어 에서 생성된 1MB 압축 품질이 0.0으로 설정된 경우에도 큰 이미지가 유지되므로 이 방법은 큰 이미지에서는 작동하지 않습니다. 예를 들어 최신 아이폰의 세로 모드에서 생성된 10MB는 여전히 1MB 이상이고 압축 품질은 0.0으로 설정됩니다.
따라서 여기서 몇 가지 답변을 사용하여 배경 큐에서 이미지를 변환하는 도우미 구조를 다시 작성했습니다.
import UIKit
struct ImageCompressor {
static func compress(image: UIImage, maxByte: Int,
completion: @escaping (UIImage?) -> ()) {
DispatchQueue.global(qos: .userInitiated).async {
guard let currentImageSize = image.jpegData(compressionQuality: 1.0)?.count else {
return completion(nil)
}
var iterationImage: UIImage? = image
var iterationImageSize = currentImageSize
var iterationCompression: CGFloat = 1.0
while iterationImageSize > maxByte && iterationCompression > 0.01 {
let percentageDecrease = getPercentageToDecreaseTo(forDataCount: iterationImageSize)
let canvasSize = CGSize(width: image.size.width * iterationCompression,
height: image.size.height * iterationCompression)
UIGraphicsBeginImageContextWithOptions(canvasSize, false, image.scale)
defer { UIGraphicsEndImageContext() }
image.draw(in: CGRect(origin: .zero, size: canvasSize))
iterationImage = UIGraphicsGetImageFromCurrentImageContext()
guard let newImageSize = iterationImage?.jpegData(compressionQuality: 1.0)?.count else {
return completion(nil)
}
iterationImageSize = newImageSize
iterationCompression -= percentageDecrease
}
completion(iterationImage)
}
}
private static func getPercentageToDecreaseTo(forDataCount dataCount: Int) -> CGFloat {
switch dataCount {
case 0..<5000000: return 0.03
case 5000000..<10000000: return 0.1
default: return 0.2
}
}
}
이미지를 최대 2MB까지 압축합니다.
ImageCompressor.compress(image: image, maxByte: 2000000) { image in
guard let compressedImage = image else { return }
// Use compressedImage
}
}
스위프트 3 및 4로 이미지 크기를 1MB 미만으로 조정하려는 경우.
이 확장자를 복사하여 붙여넣기만 하면 됩니다.
extension UIImage {
func resized(withPercentage percentage: CGFloat) -> UIImage? {
let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: canvasSize))
return UIGraphicsGetImageFromCurrentImageContext()
}
func resizedTo1MB() -> UIImage? {
guard let imageData = UIImagePNGRepresentation(self) else { return nil }
var resizingImage = self
var imageSizeKB = Double(imageData.count) / 1000.0 // ! Or devide for 1024 if you need KB but not kB
while imageSizeKB > 1000 { // ! Or use 1024 if you need KB but not kB
guard let resizedImage = resizingImage.resized(withPercentage: 0.9),
let imageData = UIImagePNGRepresentation(resizedImage)
else { return nil }
resizingImage = resizedImage
imageSizeKB = Double(imageData.count) / 1000.0 // ! Or devide for 1024 if you need KB but not kB
}
return resizingImage
}
}
사용 방법:
let resizedImage = originalImage.resizedTo1MB()
편집: 차단 UI임을 유의하시기 바랍니다, 사용자의 경우에 맞는 방법이라고 판단되면 백그라운드 스레드로 이동하십시오.
Leo Answer와 동일하지만 SWIFT 2.0을 위한 약간의 편집
extension UIImage {
func resizeWithPercentage(percentage: CGFloat) -> UIImage? {
let imageView = UIImageView(frame: CGRect(origin: .zero, size: CGSize(width: size.width * percentage, height: size.height * percentage)))
imageView.contentMode = .ScaleAspectFit
imageView.image = self
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
imageView.layer.renderInContext(context)
guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
UIGraphicsEndImageContext()
return result
}
func resizeWithWidth(width: CGFloat) -> UIImage? {
let imageView = UIImageView(frame: CGRect(origin: .zero, size: CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))))
imageView.contentMode = .ScaleAspectFit
imageView.image = self
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
imageView.layer.renderInContext(context)
guard let result = UIGraphicsGetImageFromCurrentImageContext() else { return nil }
UIGraphicsEndImageContext()
return result
}
}
스위프트 4.2
let imagedata = yourImage.jpegData(compressionQuality: 0.1)!
다음은 user4261201의 답변이지만 제가 현재 사용하고 있는 답변입니다.
func compressImage (_ image: UIImage) -> UIImage {
let actualHeight:CGFloat = image.size.height
let actualWidth:CGFloat = image.size.width
let imgRatio:CGFloat = actualWidth/actualHeight
let maxWidth:CGFloat = 1024.0
let resizedHeight:CGFloat = maxWidth/imgRatio
let compressionQuality:CGFloat = 0.5
let rect:CGRect = CGRect(x: 0, y: 0, width: maxWidth, height: resizedHeight)
UIGraphicsBeginImageContext(rect.size)
image.draw(in: rect)
let img: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
let imageData:Data = UIImageJPEGRepresentation(img, compressionQuality)!
UIGraphicsEndImageContext()
return UIImage(data: imageData)!
}
여기서 질문의 핵심은 UII 이미지 자체를 축소하는 것이 아니라 서버에 업로드하기 전에 UII 이미지의 데이터를 어떻게 확실하게 일정 크기로 축소할 것인가 하는 것이라고 생각합니다.
으로.func jpegData(compressionQuality: CGFloat) -> Data?특정 크기로 압축할 필요가 없다면 잘 작동합니다.그러나 특정한 경우에는 특정 파일 크기 이하로 압축할 수 있는 것이 유용하다고 생각합니다. 땐에는.,.jpegData신뢰성이 떨어지고 이미지를 반복적으로 압축하면 파일 크기가 점점 커지게 됩니다(그리고 비용이 많이 들 수도 있습니다).대신 Leo의 답변처럼 UIImage 자체의 크기를 줄인 다음 jpegData로 변환하여 축소된 크기가 내가 선택한 값 아래에 있는지(내가 설정한 마진 내에서) 반복적으로 확인하는 것을 선호합니다.원하는 파일 크기에 대한 현재 파일 크기의 비율을 기준으로 압축 단계 곱셈기를 조정하여 가장 비용이 많이 드는 첫 번째 반복 속도를 높입니다(파일 크기가 가장 크기 때문에).
스위프트 5
extension UIImage {
func resized(withPercentage percentage: CGFloat, isOpaque: Bool = true) -> UIImage? {
let canvas = CGSize(width: size.width * percentage, height: size.height * percentage)
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: canvas, format: format).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
}
func compress(to kb: Int, allowedMargin: CGFloat = 0.2) -> Data {
guard kb > 10 else { return Data() } // Prevents user from compressing below a limit (10kb in this case).
let bytes = kb * 1024
var compression: CGFloat = 1.0
let step: CGFloat = 0.05
var holderImage = self
var complete = false
while(!complete) {
guard let data = holderImage.jpegData(compressionQuality: 1.0) else { break }
let ratio = data.count / bytes
if data.count < Int(CGFloat(bytes) * (1 + allowedMargin)) {
complete = true
return data
} else {
let multiplier:CGFloat = CGFloat((ratio / 5) + 1)
compression -= (step * multiplier)
}
guard let newImage = holderImage.resized(withPercentage: compression) else { break }
holderImage = newImage
}
return Data()
}
}
용도:
let data = image.compress(to: 1000)
에서의 이미지 시NSData식,법:
NSData *imageData = UIImageJPEGRepresentation(yourImage, floatValue);
yourImages입니다.UIImage.floatvalue ~ 값(0.0 ~ 1.0)
위는 이미지를 다음으로 변환하는 것입니다.JPEG.
위해서PNG : :UIImagePNGRepresentation
참고 : 위 코드는 Objective-C에 있습니다.스위프트에서 NSData를 어떻게 정의하는지 확인 부탁드립니다.
iOS 15+ 스위프트 5
백엔드에 업로드할 파일 크기가 더 작은 이미지를 생성하지 않기 때문에 여기에 있는 솔루션 중 일부는 질문에 답하지 않습니다.큰 이미지 파일이 꼭 필요하지 않을 때는 백엔드로 업로드하지 않는 것이 매우 중요합니다.훨씬 더 많은 공간이 필요하고 저장하는 데 비용이 많이 들며 다운로드하는 데 더 많은 시간이 소요되어 UI가 콘텐츠를 기다리게 됩니다.
많은 대답들이 둘 중 하나를 사용하고 있습니다.
UIGraphicsImageRenderer(size: canvas).image {
_ in draw(in: CGRect(origin: .zero, size: canvas))
}
나이가 많음
UIGraphicsGetImageFromCurrentImageContext()
이 솔루션의 문제는 더 작은 UI 이미지를 생성하지만 기본적인 CGI 이미지를 변경하지 않는다는 것입니다. 따라서 이미지를 DATA로 보내려고 할 때.jpegData(compressionQuality:)UIImage 업로드는 주목할 것이지만 크기가 조정되지 않고 파일 크기가 큰 기본 CGImage의 데이터입니다.
은 의 을 강요하는 입니다.jpedData매우 큰 압축 및 품질 손실을 발생시키는 사용 가능한 최소값까지.
하고 매우 의 jpeg 를 합니다.preparingThumbnail(of:)그리고 세트.jpegData(compressionQuality:)8시나 9시까지.
extension UIImage {
func thumbnail(width: CGFloat) -> UIImage? {
guard size.width > width else { return self }
let imageSize = CGSize(
width: width,
height: CGFloat(ceil(width/size.width * size.height))
)
return preparingThumbnail(of: imageSize)
}
}
Tung Fam의 답변을 바탕으로.특정 파일 크기로 크기를 조정합니다.0.7MB와 마찬가지로 이 코드를 사용할 수 있습니다.
extension UIImage {
func resize(withPercentage percentage: CGFloat) -> UIImage? {
var newRect = CGRect(origin: .zero, size: CGSize(width: size.width*percentage, height: size.height*percentage))
UIGraphicsBeginImageContextWithOptions(newRect.size, true, 1)
self.draw(in: newRect)
defer {UIGraphicsEndImageContext()}
return UIGraphicsGetImageFromCurrentImageContext()
}
func resizeTo(MB: Double) -> UIImage? {
guard let fileSize = self.pngData()?.count else {return nil}
let fileSizeInMB = CGFloat(fileSize)/(1024.0*1024.0)//form bytes to MB
let percentage = 1/fileSizeInMB
return resize(withPercentage: percentage)
}
}
이를 사용하여 원하는 크기를 제어할 수 있습니다.
func jpegImage(image: UIImage, maxSize: Int, minSize: Int, times: Int) -> Data? {
var maxQuality: CGFloat = 1.0
var minQuality: CGFloat = 0.0
var bestData: Data?
for _ in 1...times {
let thisQuality = (maxQuality + minQuality) / 2
guard let data = image.jpegData(compressionQuality: thisQuality) else { return nil }
let thisSize = data.count
if thisSize > maxSize {
maxQuality = thisQuality
} else {
minQuality = thisQuality
bestData = data
if thisSize > minSize {
return bestData
}
}
}
return bestData
}
메서드 호출 예제:
jpegImage(image: image, maxSize: 500000, minSize: 400000, times: 10)
maxSize와 minSize의 최대 크기와 최소 크기 사이의 파일을 가져오려고 시도하지만 횟수만 시도합니다.그 시간 내에 실패하면 0으로 반환됩니다.
아래 압축 데이터로 이미지를 압축하는 가장 쉬운 방법은 swift 4.2의 코드라고 생각합니다.
let imageData = yourImageTobeCompressed.jpegData(compressionQuality: 0.5)
서버에 업로드할 이 imageData를 전송할 수 있습니다.
이것은 UI 이미지 크기를 조정하기 위해 swift 3에서 수행한 작업입니다.이미지 크기를 100kb 이하로 줄입니다.비례적으로 효과가 있습니다!
extension UIImage {
class func scaleImageWithDivisor(img: UIImage, divisor: CGFloat) -> UIImage {
let size = CGSize(width: img.size.width/divisor, height: img.size.height/divisor)
UIGraphicsBeginImageContext(size)
img.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage!
}
}
용도:
let scaledImage = UIImage.scaleImageWithDivisor(img: capturedImage!, divisor: 3)
목표-C에서도 동일:
인터페이스:
@interface UIImage (Resize)
- (UIImage *)resizedWithPercentage:(CGFloat)percentage;
- (UIImage *)resizeTo:(CGFloat)weight isPng:(BOOL)isPng jpegCompressionQuality:(CGFloat)compressionQuality;
@end
구현:
#import "UIImage+Resize.h"
@implementation UIImage (Resize)
- (UIImage *)resizedWithPercentage:(CGFloat)percentage {
CGSize canvasSize = CGSizeMake(self.size.width * percentage, self.size.height * percentage);
UIGraphicsBeginImageContextWithOptions(canvasSize, false, self.scale);
[self drawInRect:CGRectMake(0, 0, canvasSize.width, canvasSize.height)];
UIImage *sizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return sizedImage;
}
- (UIImage *)resizeTo:(CGFloat)weight isPng:(BOOL)isPng jpegCompressionQuality:(CGFloat)compressionQuality {
NSData *imageData = isPng ? UIImagePNGRepresentation(self) : UIImageJPEGRepresentation(self, compressionQuality);
if (imageData && [imageData length] > 0) {
UIImage *resizingImage = self;
double imageSizeKB = [imageData length] / weight;
while (imageSizeKB > weight) {
UIImage *resizedImage = [resizingImage resizedWithPercentage:0.9];
imageData = isPng ? UIImagePNGRepresentation(resizedImage) : UIImageJPEGRepresentation(resizedImage, compressionQuality);
resizingImage = resizedImage;
imageSizeKB = (double)(imageData.length / weight);
}
return resizingImage;
}
return nil;
}
용도:
#import "UIImage+Resize.h"
UIImage *resizedImage = [self.picture resizeTo:2048 isPng:NO jpegCompressionQuality:1.0];
프로젝트에서 사용할 이미지의 크기를 조정하기 위해 승인된 답변을 사용하려고 하면 매우 픽셀화되고 흐릿하게 나타납니다.픽셀화나 흐림을 추가하지 않고 이미지 크기를 조정할 수 있는 코드 조각을 사용하게 되었습니다.
func scale(withPercentage percentage: CGFloat)-> UIImage? {
let cgSize = CGSize(width: size.width * percentage, height: size.height * percentage)
let hasAlpha = true
let scale: CGFloat = 0.0 // Use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(cgSize, !hasAlpha, scale)
self.draw(in: CGRect(origin: CGPoint.zero, size: cgSize))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
return scaledImage
}
스위프트에서 이미지 압축 및 수출을 조사하던 중 이 질문을 접하게 되었고, 문제를 더 잘 이해하고 더 나은 기술을 도출하기 위한 출발점으로 삼게 되었습니다.
UIGraphicsBeginImageContext(), UIGraphicsGetImageFromCurrentImageContext(), UIGraphicsEndImageContext() 프로세스는 iron_john_bonney 및 leo-dabus에서 사용되는 UIGraphicsImageRender에서 대체된 이전 기술입니다.그들의 예는 UIImage에 확장자로 작성된 반면, 저는 독립적인 기능을 작성하기로 선택했습니다.필요한 접근 방식의 차이는 비교(UIGraphics ImageRenderer 호출 참조)를 통해 식별할 수 있으며, UI 이미지 확장으로 쉽게 다시 포팅할 수 있습니다.
여기서 사용하는 압축 알고리즘에 대한 개선 가능성이 있다고 생각하여, 주어진 전체 픽셀 수를 갖도록 이미지를 조정한 후 jpeg 압축을 조정하여 지정된 최종 파일 크기를 달성하는 방식으로 시작하는 접근을 하였습니다.총 픽셀 수를 지정하는 목적은 이미지 가로 세로 비율 문제에 얽히지 않기 위함이었습니다.철저한 조사를 하지는 않았지만 지정된 총 픽셀 수로 이미지를 스케일링하면 최종 jpeg 이미지 파일 크기가 일반 범위에 들어갈 것으로 예상됩니다. 그러면 초기 픽셀 수가 너무 높지 않다면 파일 크기 제한을 허용 가능한 화질로 달성하도록 jpeg 압축을 사용할 수 있습니다.
UIGraphicsImageRender를 사용할 경우 CGRect는 호스트 Apple 장치의 논리적 픽셀로 지정되며, 이는 출력 jpeg의 실제 픽셀과 다릅니다.이를 이해하기 위해 장치 픽셀 비율을 찾습니다.장치 픽셀 비율을 얻기 위해 환경에서 추출하려고 했지만, 이러한 기술들은 운동장을 붕괴시키는 원인이 되어 효과가 떨어지는 기술을 사용했습니다.
이 코드를 Xcode playround에 붙여넣고 Resources 폴더에 적절한 .jpg 파일을 넣으면 출력 파일이 Playground 출력 폴더에 배치됩니다(Live View에서 Quick Look을 사용하여 이 위치를 찾으십시오).
import UIKit
func compressUIImage(_ image: UIImage?, numPixels: Int, fileSizeLimitKB: Double, exportImage: Bool) -> Data {
var returnData: Data
if let origWidth = image?.size.width,
let origHeight = image?.size.height {
print("Original image size =", origWidth, "*", origHeight, "pixels")
let imgMult = min(sqrt(CGFloat(numPixels)/(origWidth * origHeight)), 1) // This multiplier scales the image to have the desired number of pixels
print("imageMultiplier =", imgMult)
let cgRect = CGRect(origin: .zero, size: CGSize(width: origWidth * imgMult, height: origHeight * imgMult)) // This is in *logical* pixels
let renderer = UIGraphicsImageRenderer(size: cgRect.size)
let img = renderer.image { ctx in
image?.draw(in: cgRect)
}
// Now get the device pixel ratio if needed...
var img_scale: CGFloat = 1
if exportImage {
img_scale = img.scale
}
print("Image scaling factor =", img_scale)
// ...and use to ensure *output* image has desired number of pixels
let cgRect_scaled = CGRect(origin: .zero, size: CGSize(width: origWidth * imgMult/img_scale, height: origHeight * imgMult/img_scale)) // This is in *logical* pixels
print("New image size (in logical pixels) =", cgRect_scaled.width, "*", cgRect_scaled.height, "pixels") // Due to device pixel ratios, can have fractional pixel dimensions
let renderer_scaled = UIGraphicsImageRenderer(size: cgRect_scaled.size)
let img_scaled = renderer_scaled.image { ctx in
image?.draw(in: cgRect_scaled)
}
var compQual = CGFloat(1.0)
returnData = img_scaled.jpegData(compressionQuality: 1.0)!
var imageSizeKB = Double(returnData.count) / 1000.0
print("compressionQuality =", compQual, "=> imageSizeKB =", imageSizeKB, "KB")
while imageSizeKB > fileSizeLimitKB {
compQual *= 0.9
returnData = img_scaled.jpegData(compressionQuality: compQual)!
imageSizeKB = Double(returnData.count) / 1000.0
print("compressionQuality =", compQual, "=> imageSizeKB =", imageSizeKB, "KB")
}
} else {
returnData = Data()
}
return returnData
}
let image_orig = UIImage(named: "input.jpg")
let image_comp_data = compressUIImage(image_orig, numPixels: Int(4e6), fileSizeLimitKB: 1300, exportImage: true)
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
let filename = getDocumentsDirectory().appendingPathComponent("output.jpg")
try? image_comp_data.write(to: filename)
정보원으로는 조던 모건과 스위프트와의 해킹이 있었습니다.
누군가가 필요할 경우를 대비하여 Ali Pacman의 답변을 수정한 비동기 버전이 있습니다.
import UIKit
extension UIImage {
func compress(to maxByte: Int) async -> UIImage? {
let compressTask = Task(priority: .userInitiated) { () -> UIImage? in
guard let currentImageSize = jpegData(compressionQuality: 1.0)?.count else {
return nil
}
var iterationImage: UIImage? = self
var iterationImageSize = currentImageSize
var iterationCompression: CGFloat = 1.0
while iterationImageSize > maxByte && iterationCompression > 0.01 {
let percentageDecrease = getPercentageToDecreaseTo(forDataCount: iterationImageSize)
let canvasSize = CGSize(width: size.width * iterationCompression, height: size.height * iterationCompression)
UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
defer { UIGraphicsEndImageContext() }
draw(in: CGRect(origin: .zero, size: canvasSize))
iterationImage = UIGraphicsGetImageFromCurrentImageContext()
guard let newImageSize = iterationImage?.jpegData(compressionQuality: 1.0)?.count else {
return nil
}
iterationImageSize = newImageSize
iterationCompression -= percentageDecrease
}
return iterationImage
}
return await compressTask.value
}
private func getPercentageToDecreaseTo(forDataCount dataCount: Int) -> CGFloat {
switch dataCount {
case 0..<3000000: return 0.05
case 3000000..<10000000: return 0.1
default: return 0.2
}
}
}
sync/wait 및 image.pngData()를 사용하고 .jpegData(압축 품질: 1.0)가 아닌 Swift 5.5를 사용하면 이미지의 올바른 데이터 표현을 얻을 수 있습니다.
import UIKit
public struct ImageCompressor {
private static func getPercentageToDecreaseTo(forDataCount dataCount: Int) -> CGFloat {
switch dataCount {
case 0..<3000000: return 0.05
case 3000000..<10000000: return 0.1
default: return 0.2
}
}
static public func compressAsync(image: UIImage, maxByte: Int) async -> UIImage? {
guard let currentImageSize = image.pngData()?.count else { return nil }
var iterationImage: UIImage? = image
var iterationImageSize = currentImageSize
var iterationCompression: CGFloat = 1.0
while iterationImageSize > maxByte && iterationCompression > 0.01 {
let percentageDecrease = getPercentageToDecreaseTo(forDataCount: iterationImageSize)
let canvasSize = CGSize(width: image.size.width * iterationCompression,
height: image.size.height * iterationCompression)
/*
UIGraphicsBeginImageContextWithOptions(canvasSize, false, image.scale)
defer { UIGraphicsEndImageContext() }
image.draw(in: CGRect(origin: .zero, size: canvasSize))
iterationImage = UIGraphicsGetImageFromCurrentImageContext()
*/
iterationImage = await image.byPreparingThumbnail(ofSize: canvasSize)
guard let newImageSize = iterationImage?.pngData()?.count else {
return nil
}
iterationImageSize = newImageSize
iterationCompression -= percentageDecrease
}
return iterationImage
}
}
extension UIImage {
func resized(toValue value: CGFloat) -> UIImage {
if size.width > size.height {
return self.resize(toWidth: value)!
} else {
return self.resize(toHeight: value)!
}
}
.resizeToMaximumBytes를 사용하여 UI 이미지 크기 조정
언급URL : https://stackoverflow.com/questions/29137488/how-do-i-resize-the-uiimage-to-reduce-upload-image-size
'programing' 카테고리의 다른 글
| Google 차트에서 범례 숨기기 (0) | 2023.09.21 |
|---|---|
| Angular routing template url이 ASP에서 *.cshtml 파일을 지원합니까?순 MVC 5 프로젝트? (0) | 2023.09.21 |
| jQuery 슬라이드 왼쪽으로 이동하여 표시 (0) | 2023.09.21 |
| AndroidJUNit4.class는 더 이상 사용되지 않습니다.Androidx.test.ext 사용방법주닛. runners.안드로이드JUNIT4? (0) | 2023.09.21 |
| 앱포그 앱의 라이브 파일 시스템을 다운로드하려면 어떻게 해야 합니까? (0) | 2023.09.21 |

