[ios] iOS로 이미지 크기를 쉽게 조정 / 최적화하는 방법은 무엇입니까?

내 응용 프로그램이 네트워크에서 이미지 파일 세트를 다운로드하고 로컬 iPhone 디스크에 저장합니다. 이러한 이미지 중 일부는 크기가 상당히 큽니다 (예 : 500 픽셀보다 큰 너비). iPhone은 이미지를 원래 크기로 표시 할만큼 충분히 크지 않기 때문에 공간 / 성능을 절약하기 위해 이미지 크기를 조금 더 작게 조정할 계획입니다.

또한 이러한 이미지 중 일부는 JPEG이며 일반적인 60 % 품질 설정으로 저장되지 않습니다.

iPhone SDK로 사진의 크기를 조정하고 JPEG 이미지의 품질 설정을 어떻게 변경합니까?



답변

이 질문에 대한 답변으로 몇 가지 제안이 제공됩니다 . 관련 코드와 함께이 게시물에 설명 된 기술을 제안했습니다 .

+ (UIImage*)imageWithImage:(UIImage*)image
               scaledToSize:(CGSize)newSize;
{
   UIGraphicsBeginImageContext( newSize );
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();

   return newImage;
}

이미지 저장에 관한 한 iPhone에서 사용하는 가장 빠른 이미지 형식은 PNG입니다. 해당 형식에 최적화되어 있기 때문입니다. 그러나 이러한 이미지를 JPEG로 저장하려는 경우 UIImage를 가져와 다음을 수행 할 수 있습니다.

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

이렇게하면 60 % 품질 설정에서 JPEG 이미지에 대한 원시 바이트가 포함 된 NSData 인스턴스가 생성됩니다. 그런 다음 해당 NSData 인스턴스의 내용을 디스크에 쓰거나 메모리에 캐시 할 수 있습니다.


답변

이미지 크기를 조정하는 가장 쉽고 간단한 방법은 다음과 같습니다.

float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;

if(imgRatio!=maxRatio){
    if(imgRatio < maxRatio){
        imgRatio = 480.0 / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = 480.0;
    }
    else{
        imgRatio = 320.0 / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = 320.0;
    }
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();


답변

위의 방법은 작은 이미지에 잘 작동하지만 매우 큰 이미지의 크기를 조정하려고하면 메모리가 빨리 부족하여 앱이 충돌합니다. 훨씬 더 좋은 방법은 CGImageSourceCreateThumbnailAtIndex먼저 완전히 디코딩하지 않고 이미지 크기를 조정하는 데 사용 하는 것입니다.

크기를 조정하려는 이미지 경로가있는 경우 다음을 사용할 수 있습니다.

- (void)resizeImageAtPath:(NSString *)imagePath {
    // Create the image source (from path)
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);

    // To create image source from UIImage, use this
    // NSData* pngData =  UIImagePNGRepresentation(image);
    // CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);

    // Create thumbnail options
    CFDictionaryRef options = (__bridge CFDictionaryRef) @{
            (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
            (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
            (id) kCGImageSourceThumbnailMaxPixelSize : @(640)
    };
    // Generate the thumbnail
    CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
    CFRelease(src);
    // Write the thumbnail at path
    CGImageWriteToFile(thumbnail, imagePath);
}

자세한 내용은 여기를 참조 하세요 .


답변

가로 세로 비율을 잃지 않고 (즉, 이미지를 늘리지 않고) 이미지 크기를 조정하는 가장 좋은 방법은 다음 방법을 사용하는 것입니다.

//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {

    float width = newSize.width;
    float height = newSize.height;

    UIGraphicsBeginImageContext(newSize);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = image.size.width / width;
    float heightRatio = image.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = image.size.width / divisor;
    height = image.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.origin.y = offset;
    }
    else {
        rect.origin.x = -offset;
    }

    [image drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return smallImage;

}

이 메서드를 유틸리티 클래스에 추가하면 프로젝트 전체에서 사용할 수 있고 다음과 같이 액세스 할 수 있습니다.

xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];

이 방법은 종횡비를 유지하면서 크기 조정을 처리합니다. 또한 축소 된 이미지의 너비가 높이보다 더 큰 경우 (또는 그 반대의 경우) 이미지에 들여 쓰기를 추가합니다.


답변

서버를 제어 할 수 있다면 ImageMagik로 이미지 서버 측의 크기를 조정하는 것이 좋습니다 . 큰 이미지를 다운로드하고 전화로 크기를 조정하는 것은 대역폭, 배터리 및 메모리와 같은 많은 귀중한 리소스를 낭비하는 것입니다. 이 모든 것이 휴대폰에서는 거의 없습니다.


답변

저는 Swift에서 이미지 스케일링을위한 최고의 솔루션을 개발했습니다.

이를 사용하여 이미지를 채우기, 가로 세로 채우기 또는 가로 세로 크기에 맞게 지정된 크기로 조정할 수 있습니다.

이미지를 중앙 또는 4 개의 모서리와 4 개의 모서리 중 하나에 정렬 할 수 있습니다.

또한 원본 이미지의 가로 세로 비율과 대상 크기가 같지 않을 경우 추가되는 추가 공간을 트리밍 할 수 있습니다.

enum UIImageAlignment {
    case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}

enum UIImageScaleMode {
    case Fill,
    AspectFill,
    AspectFit(UIImageAlignment)
}

extension UIImage {
    func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
        let preWidthScale = width.map { $0 / size.width }
        let preHeightScale = height.map { $0 / size.height }
        var widthScale = preWidthScale ?? preHeightScale ?? 1
        var heightScale = preHeightScale ?? widthScale
        switch scaleMode {
        case .AspectFit(_):
            let scale = min(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        case .AspectFill:
            let scale = max(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        default:
            break
        }
        let newWidth = size.width * widthScale
        let newHeight = size.height * heightScale
        let canvasWidth = trim ? newWidth : (width ?? newWidth)
        let canvasHeight = trim ? newHeight : (height ?? newHeight)
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)

        var originX: CGFloat = 0
        var originY: CGFloat = 0
        switch scaleMode {
        case .AspectFit(let alignment):
            switch alignment {
            case .Center:
                originX = (canvasWidth - newWidth) / 2
                originY = (canvasHeight - newHeight) / 2
            case .Top:
                originX = (canvasWidth - newWidth) / 2
            case .Left:
                originY = (canvasHeight - newHeight) / 2
            case .Bottom:
                originX = (canvasWidth - newWidth) / 2
                originY = canvasHeight - newHeight
            case .Right:
                originX = canvasWidth - newWidth
                originY = (canvasHeight - newHeight) / 2
            case .TopLeft:
                break
            case .TopRight:
                originX = canvasWidth - newWidth
            case .BottomLeft:
                originY = canvasHeight - newHeight
            case .BottomRight:
                originX = canvasWidth - newWidth
                originY = canvasHeight - newHeight
            }
        default:
            break
        }
        self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

아래에이 솔루션을 적용한 예가 있습니다.

회색 사각형은 대상 사이트 이미지 크기가 조정됩니다. 하늘색 직사각형의 파란색 원이 이미지입니다 (면을 유지하지 않고 크기를 조정하면보기 쉽기 때문에 원을 사용했습니다). 연한 주황색은 통과하면 잘릴 영역을 표시합니다 trim: true.

스케일링 전후의 가로 세로 맞춤 :

가로 세로 맞춤 1 (이전) 가로 세로 맞춤 1 (이후)

aspect fit 의 또 다른 예 :

Aspect fit 2 (이전) 가로 세로 맞춤 2 (이후)

상단 정렬로 가로 세로 맞춤 :

Aspect fit 3 (이전) 가로 세로 맞춤 3 (이후)

화면 채우기 :

화면 채우기 (이전) 화면 채우기 (이후)

채우기 :

채우기 (이전) 채우기 (이후)

설명하는 것이 더 간단하기 때문에 내 예제에서 업 스케일링을 사용했지만 솔루션은 문제에서와 같이 다운 스케일링에도 작동합니다.

JPEG 압축의 경우 다음을 사용해야합니다.

let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
  // ...
}

Xcode 플레이 그라운드로 나의 요점 을 확인할 수 있습니다 .


답변

Swift 3의 경우 아래 코드는 종횡비를 유지하면서 이미지 크기를 조정합니다. Apple의 문서 에서 ImageContext에 대해 자세히 읽을 수 있습니다 .

extension UIImage {
    class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
        let scale = newHeight / image.size.height
        let newWidth = image.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

그것을 사용하려면 resizeImage()메소드를 호출하십시오 .

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)