종횡비와 너비를 유지하여 UIImage 크기 조정


136

종횡비를 유지하여 이미지 크기를 조정하는 많은 게시물에서 보았습니다. 이 함수는 크기를 조정하는 동안 RECT에 고정 소수점 (폭 및 높이)을 사용합니다. 그러나 프로젝트에서 너비 만 기준으로 뷰의 크기를 조정해야하며 가로 세로 비율을 기준으로 높이를 자동으로 가져와야합니다. 누구나 내가 이것을 달성하도록 도와줍니다.

답변:


228

새 크기의 높이 너비를 모두 알고 있다면 Srikar의 방법이 매우 효과적 입니다. 예를 들어 크기를 조정할 너비 만 알고 높이에 신경 쓰지 않으면 먼저 높이의 배율을 계산해야합니다.

+(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
{
    float oldWidth = sourceImage.size.width;
    float scaleFactor = i_width / oldWidth;

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = oldWidth * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

22
newWidth여기서 변수가 실제로 필요하지는 않지만 이미 i_width있습니다.
Matthew Quiros

2
높이로 나눠서 0에 가까운 것을 사용하여 스케일링 계수를 비교해야합니다. 위의 코드는 더 큰 이미지에서만 작동합니다
IceForge

1
높이 비율도 알고 너비 또는 높이를 조정하여 높이를 맞추려면 높이로 나눠야합니다. 그러나 TO가 너비 또는 높이가 아닌 비율과 너비를 명시 적으로 요구했기 때문에 내 대답은 완전히 정확합니다.
Maverick1st

12
좋은 답변, 감사합니다. 한가지 더 :이 방법을 사용하여 이미지 품질의 손실이 발생한 경우, 다음 사용 UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);보다는UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

이미지가 세로 또는 가로인지 여부를 모르는 경우 (예 : 사용자가 카메라로 사진을 찍는 경우) 최대 너비 및 높이 매개 변수를 사용하는 다른 방법을 만들었습니다.

UIImage *myLargeImage4 : 3의 비율 을 가지고 있다고 가정 해 봅시다 .

UIImage *myResizedImage = [ImageUtilities imageWithImage:myLargeImage 
                                        scaledToMaxWidth:1024 
                                               maxHeight:1024];

가로 방향 인 경우 크기가 조정 된 UIImage는 1024x768입니다. 세로 인 경우 768x1024 이 방법은 또한 망막 디스플레이를 위해 더 높은 해상도 이미지를 생성합니다.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
    if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
        UIGraphicsBeginImageContextWithOptions(size, NO, [[UIScreen mainScreen] scale]);
    } else {
        UIGraphicsBeginImageContext(size);
    }
    [image drawInRect:CGRectMake(0, 0, size.width, size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();

    return newImage;
}

+ (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
    CGFloat oldWidth = image.size.width;
    CGFloat oldHeight = image.size.height;

    CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    CGFloat newHeight = oldHeight * scaleFactor;
    CGFloat newWidth = oldWidth * scaleFactor;
    CGSize newSize = CGSizeMake(newWidth, newHeight);

    return [ImageUtilities imageWithImage:image scaledToSize:newSize];
}

1
이것이 가장 좋은 방법이지만 항상 정의 된 크기의 두 배를 반환합니다.
Mashhadi

2
업 사이징이 아닌 다운 사이징 만하려면 imageWithImage : scaledToMaxWidth : maxHeight : 메소드를 시작하는 것을 잊지 마십시오. if (image.size.width <width && image.size.height <height) {return image; }
Arjan

5
최대 너비와 최대 높이에 맞추려면 배율 비율로 최소 비율이 필요합니다 min(ratioX, ratioY). 그렇지 않으면 너비가 더 크면 최대 높이에 맞지 않을 수 있습니다.
Jason Sturges

ImageUtilities는 어디에 있습니까?
tong

42

최고의 답변 Maverick 1st가 Swift로 올바르게 번역되었습니다 (최신 swift 3 사용 ).

func imageWithImage (sourceImage:UIImage, scaledToWidth: CGFloat) -> UIImage {
    let oldWidth = sourceImage.size.width
    let scaleFactor = scaledToWidth / oldWidth

    let newHeight = sourceImage.size.height * scaleFactor
    let newWidth = oldWidth * scaleFactor

    UIGraphicsBeginImageContext(CGSize(width:newWidth, height:newHeight))
    sourceImage.draw(in: CGRect(x:0, y:0, width:newWidth, height:newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
}

38

@ Maverick1st 덕분에 알고리즘을 구현했습니다 Swift. 제 경우에는 높이가 입력 매개 변수입니다.

class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {

    let scale = newHeight / image.size.height
    let newWidth = image.size.width * scale
    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
    image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}

18

이 메소드는 UIImage의 카테고리입니다. AVFoundation을 사용하여 몇 줄의 코드에 맞게 확장 할 수 있습니다. 가져 오는 것을 잊지 마십시오 #import <AVFoundation/AVFoundation.h>.

@implementation UIImage (Helper)

- (UIImage *)imageScaledToFitToSize:(CGSize)size
{
    CGRect scaledRect = AVMakeRectWithAspectRatioInsideRect(self.size, CGRectMake(0, 0, size.width, size.height));
    UIGraphicsBeginImageContextWithOptions(size, NO, 0);
    [self drawInRect:scaledRect];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

@end

2
메모리 사용량이 가장 적은 최상의 결과를 얻을 수있는 것으로 나타났습니다. +1
Tommie C.

11

@ János의 답변을 기반으로 한 가로 세로 높이스위프트 5 버전

최신 UIGraphicsImageRendererAPI를 사용 하므로 유효한 UIImage반환이 보장됩니다.

extension UIImage
{
    /// Given a required height, returns a (rasterised) copy
    /// of the image, aspect-fitted to that height.

    func aspectFittedToHeight(_ newHeight: CGFloat) -> UIImage
    {
        let scale = newHeight / self.size.height
        let newWidth = self.size.width * scale
        let newSize = CGSize(width: newWidth, height: newHeight)
        let renderer = UIGraphicsImageRenderer(size: newSize)

        return renderer.image { _ in
            self.draw(in: CGRect(origin: .zero, size: newSize))
        }
    }
}

이를 벡터 기반의 PDF 이미지 자산과 함께 사용하면 모든 렌더링 크기에서 품질을 유지할 수 있습니다.


7

가장 간단한 방법은 프레임을 UIImageView설정 contentMode하고 크기 조정 옵션 중 하나로 설정하는 것입니다.

코드는 다음과 같습니다-유틸리티 방법으로 사용할 수 있습니다-

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

OP는 UIImageView를 언급하지 않았습니다. 대신, 그는 아마도 UIImage의 [사본]을 직접 가로 세로 맞추기를 원했을 것입니다. CoreGraphics 작업을 할 때 매우 편리합니다.
울림

6

프로그래밍 방식으로 :

imageView.contentMode = UIViewContentModeScaleAspectFit;

스토리 보드 :

여기에 이미지 설명을 입력하십시오


작동하지만 메모리 풋 프린트를 줄이면 많은 썸네일을로드하는 등의 앱 작동 속도를 높일 수 있습니다.
ingconti

UIImage가 아니라 UIImageView입니다. 때때로 UIImageView없이 그리기를해야합니다.
Womble

5

글쎄, 우리는 이미지 크기 조정에 대한 좋은 대답이 거의 없지만 필요에 따라 수정합니다. 이것이 나와 같은 누군가를 돕기를 바랍니다.

내 요구 사항은

  1. 이미지 너비가 1920보다 큰 경우 1920 너비로 크기를 조정하고 원래 종횡비로 높이를 유지하십시오.
  2. 이미지 높이가 1080보다 큰 경우 1080 높이로 크기를 조정하고 원래 종횡비로 너비를 유지하십시오.

 if (originalImage.size.width > 1920)
 {
        CGSize newSize;
        newSize.width = 1920;
        newSize.height = (1920 * originalImage.size.height) / originalImage.size.width;
        originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];        
 }

 if (originalImage.size.height > 1080)
 {
            CGSize newSize;
            newSize.width = (1080 * originalImage.size.width) / originalImage.size.height;
            newSize.height = 1080;
            originalImage = [ProfileEditExperienceViewController imageWithImage:originalImage scaledToSize:newSize];

 }

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

@ Srikar Appal 덕분 에 크기 조정을 위해 그의 방법을 사용했습니다.

크기 조정 계산을 위해 이것을 확인 하고 싶을 수도 있습니다 .


4

AVFoundation을 가져 와서 사용하십시오. AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

Ryan의 답변을 개선하려면 다음을 수행하십시오.

   + (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size {
CGFloat oldWidth = image.size.width;
        CGFloat oldHeight = image.size.height;

//You may need to take some retina adjustments into consideration here
        CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

return [UIImage imageWithCGImage:image.CGImage scale:scaleFactor orientation:UIImageOrientationUp];
    }

2
extension UIImage {

    /// Returns a image that fills in newSize
    func resizedImage(newSize: CGSize) -> UIImage? {
        guard size != newSize else { return self }

    let hasAlpha = false
    let scale: CGFloat = 0.0
    UIGraphicsBeginImageContextWithOptions(newSize, !hasAlpha, scale)
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)

        draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        let newImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }

    /// Returns a resized image that fits in rectSize, keeping it's aspect ratio
    /// Note that the new image size is not rectSize, but within it.
    func resizedImageWithinRect(rectSize: CGSize) -> UIImage? {
        let widthFactor = size.width / rectSize.width
        let heightFactor = size.height / rectSize.height

        var resizeFactor = widthFactor
        if size.height > size.width {
            resizeFactor = heightFactor
        }

        let newSize = CGSize(width: size.width / resizeFactor, height: size.height / resizeFactor)
        let resized = resizedImage(newSize: newSize)

        return resized
    }
}

배율이 0.0으로 설정되면 메인 화면의 배율이 사용되며 Retina 디스플레이의 경우 배율이 2.0 이상 (iPhone 6 Plus의 경우 3.0)입니다.


1

신속한 코드에서 Ryan의 솔루션 @Ryan

사용하다:

 func imageWithSize(image: UIImage,size: CGSize)->UIImage{
    if UIScreen.mainScreen().respondsToSelector("scale"){
        UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.mainScreen().scale);
    }
    else
    {
         UIGraphicsBeginImageContext(size);
    }

    image.drawInRect(CGRectMake(0, 0, size.width, size.height));
    var newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

//Summon this function VVV
func resizeImageWithAspect(image: UIImage,scaledToMaxWidth width:CGFloat,maxHeight height :CGFloat)->UIImage
{
    let oldWidth = image.size.width;
    let oldHeight = image.size.height;

    let scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;

    let newHeight = oldHeight * scaleFactor;
    let newWidth = oldWidth * scaleFactor;
    let newSize = CGSizeMake(newWidth, newHeight);

    return imageWithSize(image, size: newSize);
}

1

에서 스위프트 3 약간의 변화가있다. UIImage의 확장은 다음과 같습니다.

public extension UIImage {
    public func resize(height: CGFloat) -> UIImage? {
        let scale = height / self.size.height
        let width = self.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: width, height: height))
        self.draw(in: CGRect(x:0, y:0, width:width, height:height))
        let resultImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return resultImage
    }
}

1

Zeeshan Tufail 및 Womble은 Swift 5 에서 약간 개선되었습니다. 여기에는 이미지를 maxLength모든 크기 및 jpeg 압축으로 확장하는 2 개의 기능이있는 확장 기능이 있습니다.

extension UIImage {
    func aspectFittedToMaxLengthData(maxLength: CGFloat, compressionQuality: CGFloat) -> Data {
        let scale = maxLength / max(self.size.height, self.size.width)
        let format = UIGraphicsImageRendererFormat()
        format.scale = scale
        let renderer = UIGraphicsImageRenderer(size: self.size, format: format)
        return renderer.jpegData(withCompressionQuality: compressionQuality) { context in
            self.draw(in: CGRect(origin: .zero, size: self.size))
        }
    }
    func aspectFittedToMaxLengthImage(maxLength: CGFloat, compressionQuality: CGFloat) -> UIImage? {
        let newImageData = aspectFittedToMaxLengthData(maxLength: maxLength, compressionQuality: compressionQuality)
        return UIImage(data: newImageData)
    }
}

0

이것은 나에게 완벽했습니다. 종횡비를 유지하고을 사용합니다 maxLength. 너비 또는 높이는maxLength

-(UIImage*)imageWithImage: (UIImage*) sourceImage maxLength: (float) maxLength
{
    CGFloat scaleFactor = maxLength / MAX(sourceImage.size.width, sourceImage.size.height);

    float newHeight = sourceImage.size.height * scaleFactor;
    float newWidth = sourceImage.size.width * scaleFactor;

    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
    [sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

0

사용 가능한 너비에 대한 이미지의 최적 높이를 계산합니다.

import Foundation

public extension UIImage {
    public func height(forWidth width: CGFloat) -> CGFloat {
        let boundingRect = CGRect(
            x: 0,
            y: 0,
            width: width,
            height: CGFloat(MAXFLOAT)
        )
        let rect = AVMakeRect(
            aspectRatio: size,
            insideRect: boundingRect
        )
        return rect.size.height
    }
}

-1

훨씬 간단한 방법으로 해결했습니다.

UIImage *placeholder = [UIImage imageNamed:@"OriginalImage.png"];
self.yourImageview.image = [UIImage imageWithCGImage:[placeholder CGImage] scale:(placeholder.scale * 1.5)
                                  orientation:(placeholder.imageOrientation)];

배율 승수는 이미지의 호출을 정의하며, 승수는 이미지를 작게합니다. 화면에 맞는 것을 확인할 수 있습니다.

또는 이미지 너비 / 화면 너비를 나누어 다중 배수를 얻을 수도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.