문제

내 응용 프로그램은 네트워크에서 일련의 이미지 파일을 다운로드하여 로컬 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);
}

자세한 내용은 여기.

종횡비를 잃지 않고 이미지를 확장하는 가장 좋은 방법 (즉, IMGAGE를 확장하지 않고) 은이 방법을 사용하는 것입니다.

//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.

측면 적합 스케일링 전후 :

Aspect fit 1 (before) Aspect fit 1 (after)

또 다른 예 측면 적합:

Aspect fit 2 (before) Aspect fit 2 (after)

측면 적합 최고 정렬 :

Aspect fit 3 (before) Aspect fit 3 (after)

측면 채우기:

Aspect fill (before) Aspect fill (after)

채우다:

Fill (before) Fill (after)

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

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

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

당신은 내 것을 확인할 수 있습니다 요점 Xcode Playground와 함께.

Swift 3의 경우 아래 코드는 측면 비율을 유지합니다. imageecontext에 대한 자세한 내용을 읽을 수 있습니다 애플의 문서:

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)

이 코드를 사용하여 이미지를 필요한 크기로 확장 할 수 있습니다.

+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
    CGSize actSize = image.size;
    float scale = actSize.width/actSize.height;

    if (scale < 1) {
        newSize.height = newSize.width/scale;
    } 
    else {
        newSize.width = newSize.height*scale;
    }

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

    return newImage;
}

여기에 많은 답변에 추가하지만, 치수가 아닌 파일 크기로 크기를 조정하는 솔루션을 찾았습니다.

이것은 주어진 크기에 도달 할 때까지 이미지의 크기와 품질을 줄입니다.

func compressTo(toSizeInMB size: Double) -> UIImage? {
    let bytes = size * 1024 * 1024
    let sizeInBytes = Int(bytes)
    var needCompress:Bool = true
    var imgData:Data?
    var compressingValue:CGFloat = 1.0

    while (needCompress) {

        if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {

            if data.count < sizeInBytes || compressingValue < 0.1 {
                needCompress = false
                imgData = data
            } else {
                compressingValue -= 0.1
            }
        }
    }

    if let data = imgData {
        print("Finished with compression value of: \(compressingValue)")
        return UIImage(data: data)
    }
    return nil
}

private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
    let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
    UIGraphicsBeginImageContext(size)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return newImage;
    }
    return nil
}

신용 크기에 따라 스케일링

Retina 디스플레이에서 발생할 수있는 문제는 이미지의 스케일이 imagecapture에 의해 설정된다는 것입니다. 위의 크기 조정 기능은이를 변경하지 않습니다. 이 경우 크기 조정은 제대로 작동하지 않습니다.

아래 코드에서 스케일은 1 (스케일링되지 않음)으로 설정되고 반환 된 이미지는 기대할 크기가 있습니다. 이것은 이루어집니다 UIGraphicsBeginImageContextWithOptions 전화.

-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
    UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
    [theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

나는 Brads 기술을 사용하여 a를 만들었습니다 scaleToFitWidth 방법 UIImage+Extensions 그것이 누구에게나 유용하다면 ...

-(UIImage *)scaleToFitWidth:(CGFloat)width
{
    CGFloat ratio = width / self.size.width;
    CGFloat height = self.size.height * ratio;

    NSLog(@"W:%f H:%f",width,height);

    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    [self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

그러면 당신이 좋아하는 곳

#import "UIImage+Extensions.h"

UIImage *newImage = [image scaleToFitWidth:100.0f];

또한 이것을 더 아래로 옮길 수 있다는 점에 주목할 가치가 있습니다. UIView+Extensions UIVIEW에서 이미지를 렌더링하려면 클래스

Cocoa Swift 프로그래머에게 그 질문에 답하고 싶었습니다. 이 함수는 새로운 크기로 nsimage를 반환합니다. 이 기능을 사용할 수 있습니다.

        let sizeChangedImage = changeImageSize(image, ratio: 2)






 // changes image size

    func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage   {

    // getting the current image size
    let w = image.size.width
    let h = image.size.height

    // calculating new size
    let w_new = w / ratio 
    let h_new = h / ratio 

    // creating size constant
    let newSize = CGSizeMake(w_new ,h_new)

    //creating rect
    let rect  = NSMakeRect(0, 0, w_new, h_new)

    // creating a image context with new size
    let newImage = NSImage.init(size:newSize)



    newImage.lockFocus()

        // drawing image with new size in context
        image.drawInRect(rect)

    newImage.unlockFocus()


    return newImage

}

이미지가 문서 디렉토리에 있으면 이것을 추가하십시오. URL 확대:

extension URL {
    func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
        let imageData = try Data(contentsOf: self)
        debugPrint("Image file size before compression: \(imageData.count) bytes")

        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")

        guard let actualImage = UIImage(data: imageData) else { return nil }
        guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
            return nil
        }
        debugPrint("Image file size after compression: \(compressedImageData.count) bytes")

        do {
            try compressedImageData.write(to: compressedURL)
            return compressedURL
        } catch {
            return nil
        }
    }
}

용법:

guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
    return
}

//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
    return
}

debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")

참고 :- 로컬 JPG 이미지 경로를 사용하여 <ColecimagePath.jpg>를 변경하십시오.

func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {

    let scale = newWidth / image.size.width
    let newHeight = CGFloat(200.0)
    UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
    image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

여전히 더 나은 옵션을 찾고 있다면

-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {


    UIImage *sourceImage = image;
    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor)
            scaleFactor = widthFactor;
        else
            scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image


        if (widthFactor < heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        } else if (widthFactor > heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }


    // this is actually the interesting part:

    UIGraphicsBeginImageContext(targetSize);

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    if(newImage == nil) NSLog(@"could not scale image");


    return newImage ;

}
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = image.CGImage;

    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);

    CGContextConcatCTM(context, flipVertical);
    CGContextDrawImage(context, newRect, imageRef);

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    CGImageRelease(newImageRef);
    UIGraphicsEndImageContext();

    return newImage;
}

이미지 크기를 조정하려면 DrawInrect의 Stead 에서이 함수를 사용하여 더 나은 (그래픽) 결과가 있습니다.

- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
    float lScale = pWidth / pImage.size.width;
    CGImageRef cgImage = pImage.CGImage;
    UIImage   *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
                            orientation:UIImageOrientationRight];
    return lResult;
}

종횡비는 자동으로 관리됩니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top