Найпростіший спосіб змінити розмір UIImage?


397

У своєму додатку iPhone я знімаю фотокамеру, після чого хочу змінити розмір її до 290 * 390 пікселів. Я використовував цей метод, щоб змінити розмір зображення:

UIImage *newImage = [image _imageScaledToSize:CGSizeMake(290, 390)
                         interpolationQuality:1];    

Він прекрасно працює, але це незадокументована функція, тому я більше не можу його використовувати з iPhone OS4.

Отже ... який найпростіший спосіб змінити розмір UIImage?


Спосіб зробити це в 2019 році, nshipster.com/image-resizing
dengST30

Відповіді:


772

Найпростіший спосіб - встановити рамку вашого UIImageViewі встановити contentModeодин з варіантів зміни розміру.

Або ви можете використовувати цей утилітний метод, якщо вам дійсно потрібно змінити розмір зображення:

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
    //UIGraphicsBeginImageContext(newSize);
    // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
    // Pass 1.0 to force exact pixel size.
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();    
    UIGraphicsEndImageContext();
    return newImage;
}

Приклад використання:

#import "MYUtil.h"

UIImage *myIcon = [MYUtil imageWithImage:myUIImageInstance scaledToSize:CGSizeMake(20, 20)];

11
Я б НЕ зберігав результат тут. newImageбуде вже випущено автоматично, і це залежить від методу, який викликав це, щоб зберегти його чи ні. Цей підхід просто просить помилку пам'яті, оскільки initне є частиною назви методу. Я б очікував, що такий метод, як цей, повертає об'єкт, що вийшов автоматично.
Алекс Уейн

Дійсна точка та відредагована. Я просто застережу, що мій код, який використовує це, генерує помилки malloc в іншому місці без додаткового збереження, що явно я чомусь винен :-).
Пол Лінч

26
Як і в iOS 4.0 , всі функції UIGraphics * захищені потоками.
BJ Гомер

3
@Paul Lynch: Майте на увазі, що ця зміна порушує місію оригіналу публікації: Як змінити розмір зображення до точного розміру пікселя (на відміну від розміру точки ).
Микола Рухе

8
Тим, хто бореться через обмеження @NikolaiRuhe, ви можете примусити його до точного розміру пікселя, передавши 1,0 замість 0,0 у виклику доUIGraphicsBeginImageContextWithOptions
Денні

84

Ось швидка версія відповіді Пола Лінча

func imageWithImage(image:UIImage, scaledToSize newSize:CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
    image.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage
}

І як розширення:

public extension UIImage {
    func copy(newSize: CGSize, retina: Bool = true) -> UIImage? {
        // In next line, pass 0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
        // Pass 1 to force exact pixel size.
        UIGraphicsBeginImageContextWithOptions(
            /* size: */ newSize,
            /* opaque: */ false,
            /* scale: */ retina ? 0 : 1
        )
        defer { UIGraphicsEndImageContext() }

        self.draw(in: CGRect(origin: .zero, size: newSize))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

2
щойно зазначив, що в iOS ваш новий розмір збільшиться на 2x, 3x на базі пристрою
Sruit A.Suk

6
UIGraphicsBeginImageContextWithOptions (newSize, false, image.scale); для всіх пристроїв
phnmnn

Зауважте, що це не змінює розмір основного CGImage (принаймні, в iOS 12.1). Це добре в залежності від питання, але якщо ви виписуєте зображення, вам доведеться використовувати cgImage, і ви отримаєте оригінальне зображення.
prewett

72

Proper Swift 3.0 для iOS 10+ рішення: Використання ImageRendererта закриття синтаксису:

func imageWith(newSize: CGSize) -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: newSize)
    let image = renderer.image { _ in
        self.draw(in: CGRect.init(origin: CGPoint.zero, size: newSize))
    }

    return image.withRenderingMode(self.renderingMode)
}

А ось версія Objective-C:

@implementation UIImage (ResizeCategory)
- (UIImage *)imageWithSize:(CGSize)newSize
{
    UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:newSize];
    UIImage *image = [renderer imageWithActions:^(UIGraphicsImageRendererContext*_Nonnull myContext) {
        [self drawInRect:(CGRect) {.origin = CGPointZero, .size = newSize}];
    }];
    return [image imageWithRenderingMode:self.renderingMode];
}
@end

1
Дуже елегантне рішення, це повинна бути прийнята відповідь!
appsunited

2
Це краще, ніж елегантно, це правильно. Документи api Apple радять новий код використовувати UIGraphicsRenderer, як це робить. Дякую
Пол Бруно

1
@appsunited Питання майже 8 років. І цей метод працює лише для iOS10 +, як зазначено.

При копіюванні нового об’єкта зображення у буфер обміну він створює для мене білий блок. Це насправді не зміна розміру зображення?
Олівер Діксон

1
ця функція повертає зображення 0 висоти та 0 ширини, очікувана висота - 9000 висоти та 9000 ширини.
Кришан Кумар

31

Тревор Говард має декілька категорій UIImage, які досить добре змінюють розмір. Якщо нічого іншого, ви можете використовувати код як приклади.

Примітка. Відповідно до iOS 5.1, ця відповідь може бути недійсною. Дивіться коментар нижче.


2
Мені також потрібно було змінити розмір деяких зображень, і я спершу випробував доповнення Тревору до UIImage, але отримав кілька дивних помилок на PNG (щось про альфа-канал). Однак прийнята відповідь на це питання чудово опрацювала.
Соріг

1
Це вже не діє (по крайней мере , з iOS5.1
Янн

@Jann, подивіться на комітети нижче публікації.
vikingosegundo

@Jann Якщо ви дотримуєтесь виправлень, запропонованих у коментарях, перейдіть до "Метт каже: 22 листопада 2011 о 17:39", тому що він випускає colorpaceref (на відміну від подібного рішення підкова7).
Бен Флінн

1
@sanmai, використовуючи будь-який із цих методів зміни розміру, зображення втрачає свою гостроту. чи можна досягти різкості
vamsi575kg

31

Більш компактна версія для Swift 4 та iOS 10+:

extension UIImage {
    func resized(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
}

Використання:

let resizedImage = image.resized(to: CGSize(width: 50, height: 50))

26

Я також бачив це, як це зроблено (що я використовую UIButtonsдля нормального та вибраного стану, оскільки кнопки не resizeвміщуються). Заслуга належить тому, хто був оригінальним автором.

Спочатку зробіть порожній .h та .m файл, який називається UIImageResizing.hтаUIImageResizing.m

// Put this in UIImageResizing.h
@interface UIImage (Resize)
- (UIImage*)scaleToSize:(CGSize)size;
@end

// Put this in UIImageResizing.m
@implementation UIImage (Resize)

- (UIImage*)scaleToSize:(CGSize)size {
UIGraphicsBeginImageContext(size);

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, 0.0, size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), self.CGImage);

UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return scaledImage;
}

@end

Включіть цей .h файл у будь-який .m файл, у якому ви будете використовувати цю функцію, а потім назвіть його так:

UIImage* image = [UIImage imageNamed:@"largeImage.png"];
UIImage* smallImage = [image scaleToSize:CGSizeMake(100.0f,100.0f)];

Це не копіює над орієнтацією зображення.
Кевін

20

Це вдосконалення коду Пола дасть вам чітке зображення високої роздільної здатності на iPhone із сітківкою. Інакше при зменшенні розміру воно розмито.

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

13
Щойно FYI, внесені вами зміни не потрібні, оскільки подаючи значення 0,0 для шкали в UIGraphicsBeginImageContextWithOptionsавтоматично, буде використана шкала головного екрану (станом на iOS 3.2).
Ендрю Р.

16

Ось простий спосіб:

    UIImage * image = [UIImage imageNamed:@"image"];
    CGSize sacleSize = CGSizeMake(10, 10);
    UIGraphicsBeginImageContextWithOptions(sacleSize, NO, 0.0);
    [image drawInRect:CGRectMake(0, 0, sacleSize.width, sacleSize.height)];
    UIImage * resizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

resizedImage - це нове зображення.


16

Швидке рішення для розтягування, заповнення аспектів та аспекту Fit

extension UIImage {
    enum ContentMode {
        case contentFill
        case contentAspectFill
        case contentAspectFit
    }

    func resize(withSize size: CGSize, contentMode: ContentMode = .contentAspectFill) -> UIImage? {
        let aspectWidth = size.width / self.size.width
        let aspectHeight = size.height / self.size.height

        switch contentMode {
        case .contentFill:
            return resize(withSize: size)
        case .contentAspectFit:
            let aspectRatio = min(aspectWidth, aspectHeight)
            return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
        case .contentAspectFill:
            let aspectRatio = max(aspectWidth, aspectHeight)
            return resize(withSize: CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio))
        }
    }

    private func resize(withSize size: CGSize) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, self.scale)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

а для використання ви можете зробити наступне:

let image = UIImage(named: "image.png")!
let newImage = image.resize(withSize: CGSize(width: 200, height: 150), contentMode: .contentAspectFill)

Завдяки abdullahselek за його оригінальне рішення.


15

Ось модифікація категорії, написаної iWasRobbed вище. Він зберігає співвідношення сторін оригінального зображення, а не спотворює його.

- (UIImage*)scaleToSizeKeepAspect:(CGSize)size {
    UIGraphicsBeginImageContext(size);

    CGFloat ws = size.width/self.size.width;
    CGFloat hs = size.height/self.size.height;

    if (ws > hs) {
        ws = hs/ws;
        hs = 1.0;
    } else {
        hs = ws/hs;
        ws = 1.0;
    }

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0.0, size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    CGContextDrawImage(context, CGRectMake(size.width/2-(size.width*ws)/2,
        size.height/2-(size.height*hs)/2, size.width*ws,
        size.height*hs), self.CGImage);

    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}

11

Якщо ви просто хочете, щоб зображення було меншим розміром і не хвилювався точний розмір:

+ (UIImage *)imageWithImage:(UIImage *)image scaledToScale:(CGFloat)scale
{
    UIGraphicsBeginImageContextWithOptions(self.size, YES, scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

Налаштування шкали до 0.25f , ви отримаєте 816 на 612 зображення з 8MP камери.

Ось категорія UIImage + Scale для тих, хто її потребує.


10

Чому так складно? Я думаю, що за допомогою системного API можна досягти такого ж результату:

UIImage *largeImage;
CGFloat ratio = 0.4; // you want to get a new image that is 40% the size of large image.
UIImage *newImage = [UIImage imageWithCGImage:largeImage.CGImage
                                        scale:1/ratio
                                  orientation:largeImage.imageOrientation];
// notice the second argument, it is 1/ratio, not ratio.

Єдиний прийом полягає в тому, що ви повинні передати обернене цільове співвідношення як другий аргумент, оскільки згідно з документом другий параметр визначає відношення вихідного зображення порівняно з новим масштабним.


Тому що масштаб (%) - це не те саме, що пікселі (в / год).

Масштаб повинен бути великийImage.scale / співвідношення не 1 / ratio.
Marián Černý

9

Це розширення UIImage, сумісне зі Swift 3 та Swift 4, яке масштабує зображення до заданого розміру із співвідношенням сторін

extension UIImage {

    func scaledImage(withSize size: CGSize) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height))
        return UIGraphicsGetImageFromCurrentImageContext()!
    }

    func scaleImageToFitSize(size: CGSize) -> UIImage {
        let aspect = self.size.width / self.size.height
        if size.width / aspect <= size.height {
            return scaledImage(withSize: CGSize(width: size.width, height: size.width / aspect))
        } else {
            return scaledImage(withSize: CGSize(width: size.height * aspect, height: size.height))
        }
    }

}

Приклад використання

let image = UIImage(named: "apple")
let scaledImage = image.scaleImageToFitSize(size: CGSize(width: 45.0, height: 45.0))

Я б рекомендував назвати функцію scaledImage(with size:)або scaledWithSize(_:). Також UIGraphicsGetImageFromCurrentImageContextреально не можуть повернутися nil, тому !працювали б також. Ви також можете спростити створення прямої камери до CGRect(origin: .zero, size: size).
Султан

8

Я знайшов категорію для UIImage у власних прикладах Apple, яка робить ту саму хитрість. Ось посилання: https://developer.apple.com/library/ios/samplecode/sc2273/Listings/AirDropSample_UIImage_Resize_m.html .

Вам потрібно буде просто змінити виклик:

UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);

в imageWithImage:scaledToSize:inRect:с:

UIGraphicsBeginImageContextWithOptions(newSize, NO, 2.0);

Для того, щоб розглянути альфа-канал на зображенні.


6
 func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage 
{
        let scale = newWidth / image.size.width
        let newHeight = image.size.height * scale
        UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
        image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
}

Це гарна ідея, щоб додати якийсь описовий текст, який відповідає вашому коду.
GMchris

6

Для моїх колег Xamarians, ось Xamarin.iOS C # версія відповіді @Paul Lynch.

private UIImage ResizeImage(UIImage image, CGSize newSize) 
{
    UIGraphics.BeginImageContextWithOptions(newSize, false, 0.0f);
    image.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));
    UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();
    UIGraphics.EndImageContext();
    return newImage;
}

5

Якщо ви хочете зробити мініатюру UIImage (з пропорційним розміром розміру або, можливо, задіяним обрізанням), перегляньте категорію UIImage + Змінити розмір, яка дозволяє використовувати стислий синтаксис, схожий на ImageMagick:

UIImage* squareImage       = [image resizedImageByMagick: @"320x320#"];

5

[cf Chris] Щоб змінити розмір до потрібного розміру:

UIImage *after = [UIImage imageWithCGImage:before.CGImage
                                     scale:CGImageGetHeight(before.CGImage)/DESIREDHEIGHT
                               orientation:UIImageOrientationUp];

або, що еквівалентно, замінити CGImageGetWidth(...)/DESIREDWIDTH


Зверніть увагу, що самі дані зображення не змінюються, але застосовується коефіцієнт масштабу, що означає, що зображення має однаковий розмір в пам'яті.
inkredibl

5

Роджеріо Чавес відповідає як швидке розширення

func scaledTo(size: CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(size, false, 0.0);
    self.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
    UIGraphicsEndImageContext()
    return newImage
}

А також бонус

func scaledTo(height: CGFloat) -> UIImage{
    let width = height*self.size.width/self.size.height
    return scaledTo(size: CGSize(width: width, height: height))
}

5

Swift 3.0 з можливістю помилки (повертає початкове зображення у разі помилки):

func resize(image: UIImage, toSize size: CGSize) -> UIImage{
    UIGraphicsBeginImageContextWithOptions(size,false,1.0)
    image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let resizedImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return resizedImage
    }
    UIGraphicsEndImageContext()
    return image
}

5

(Сумісний Swift 4) iOS 10+ та iOS <10 (використовуючи, UIGraphicsImageRendererякщо можливо, UIGraphicsGetImageFromCurrentImageContextінакше)

/// Resizes an image
///
/// - Parameter newSize: New size
/// - Returns: Resized image
func scaled(to newSize: CGSize) -> UIImage {
    let rect = CGRect(origin: .zero, size: newSize)

    if #available(iOS 10, *) {
        let renderer = UIGraphicsImageRenderer(size: newSize)
        return renderer.image { _ in
            self.draw(in: rect)
        }
    } else {
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
        self.draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

5

Ефективний підхід без розтягування зображення Swift 4

// Method to resize image
func resize(image: UIImage, toScaleSize:CGSize) -> UIImage {
                UIGraphicsBeginImageContextWithOptions(toScaleSize, true, image.scale)
                        image.draw(in: CGRect(x: 0, y: 0, width: toScaleSize.width, height: toScaleSize.height))
                        let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
                        UIGraphicsEndImageContext()
                        return scaledImage!
                }

// Метод виклику

    let resizedImage = self.resize(image: UIImage(named: "YourImageName")!, toScaleSize: CGSize(width: 290, height: 390))

3

Відповідь @Paul Lynch чудова, але це змінило б співвідношення зображень. якщо ви не хочете змінювати співвідношення зображень і все ще хочете, щоб нове зображення підходило для нового розміру, спробуйте це.

+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {

// calculate a new size which ratio is same to original image
CGFloat ratioW = image.size.width / newSize.width;
CGFloat ratioH = image.size.height / newSize.height;

CGFloat ratio = image.size.width / image.size.height;

CGSize showSize = CGSizeZero;
if (ratioW > 1 && ratioH > 1) { 

    if (ratioW > ratioH) { 
        showSize.width = newSize.width;
        showSize.height = showSize.width / ratio;
    } else {
        showSize.height = newSize.height;
        showSize.width = showSize.height * ratio;
    }

} else if (ratioW > 1) {

    showSize.width = showSize.width;
    showSize.height = showSize.width / ratio;

} else if (ratioH > 1) {

    showSize.height = showSize.height;
    showSize.width = showSize.height * ratio;

}

//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(showSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, showSize.width, showSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;}

3

використовувати це розширення

extension UIImage {
    public func resize(size:CGSize, completionHandler:(resizedImage:UIImage, data:NSData?)->()) {
        dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), { () -> Void in
            let newSize:CGSize = size
            let rect = CGRectMake(0, 0, newSize.width, newSize.height)
            UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
            self.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            let imageData = UIImageJPEGRepresentation(newImage, 0.5)
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completionHandler(resizedImage: newImage, data:imageData)
            })
        })
    }
}

2

Swift 2.0:

let image = UIImage(named: "imageName")
let newSize = CGSize(width: 10, height: 10)

UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
image?.drawInRect(CGRectMake(0, 0, newSize.width, newSize.height))
let imageResized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()

2

Ось мій дещослівний код Свіфта

func scaleImage(image:UIImage,  toSize:CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(toSize, false, 0.0);

    let aspectRatioAwareSize = self.aspectRatioAwareSize(image.size, boxSize: toSize, useLetterBox: false)


    let leftMargin = (toSize.width - aspectRatioAwareSize.width) * 0.5
    let topMargin = (toSize.height - aspectRatioAwareSize.height) * 0.5


    image.drawInRect(CGRectMake(leftMargin, topMargin, aspectRatioAwareSize.width , aspectRatioAwareSize.height))
    let retVal = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return retVal
}

func aspectRatioAwareSize(imageSize: CGSize, boxSize: CGSize, useLetterBox: Bool) -> CGSize {
    // aspect ratio aware size
    // http://stackoverflow.com/a/6565988/8047
    let imageWidth = imageSize.width
    let imageHeight = imageSize.height
    let containerWidth = boxSize.width
    let containerHeight = boxSize.height

    let imageAspectRatio = imageWidth/imageHeight
    let containerAspectRatio = containerWidth/containerHeight

    let retVal : CGSize
    // use the else at your own risk: it seems to work, but I don't know 
    // the math
    if (useLetterBox) {
        retVal = containerAspectRatio > imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
    } else {
        retVal = containerAspectRatio < imageAspectRatio ? CGSizeMake(imageWidth * containerHeight / imageHeight, containerHeight) : CGSizeMake(containerWidth, imageHeight * containerWidth / imageWidth)
    }

    return retVal
}

1
Це заощадило мій час. Дякую!
Quy Nguyen

корисно, але дійте дивно після подій та повернення, дивіться тут plz: stackoverflow.com/questions/30978685/…
Він Yifei 何 一 非

Зверніть увагу: Ви можете додати умову guardдо aspectRatioAwareSizeфункції ( ), щоб вона не кинула ділення на нуль винятком, якщо вхідними параметрами або imageSize, або boxSize єCGSize.zero
pkluz

@pkluz, це гарна пропозиція, але вам знадобиться їх у всій функції, я думаю, оскільки кожна змінна є дільником іншого рядка ... Я покину це як для наочності. Для виробництва або бібліотеки для github, ви, можливо, захочете поповнити це ... Більше ніж охорону, я переживаю, що ця функція використовує короткі імена змінних, які не говорять багато. Я, мабуть, спершу це виправлюю, а потім додаю охорону для інших речей, а потім додаю тестові одиниці.
Дан Розенстарк

2

Відповідь Swift 4:

func scaleDown(image: UIImage, withSize: CGSize) -> UIImage {
    let scale = UIScreen.main.scale
    UIGraphicsBeginImageContextWithOptions(withSize, false, scale)
    image.draw(in: CGRect(x: 0, y: 0, width: withSize.width, height: withSize.height))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return newImage!
}

Не потрібно встановлювати реальну шкалу:The scale factor to apply to the bitmap. If you specify a value of 0.0, the scale factor is set to the scale factor of the device’s main screen.
Натан

1

Я виявив, що важко знайти відповідь, що ви можете використовувати нестандартно у своєму проекті Swift 3 . Основна проблема інших відповідей полягає в тому, що вони не шанують альфа-канал зображення. Ось техніка, яку я використовую у своїх проектах.

extension UIImage {

    func scaledToFit(toSize newSize: CGSize) -> UIImage {
        if (size.width < newSize.width && size.height < newSize.height) {
            return copy() as! UIImage
        }

        let widthScale = newSize.width / size.width
        let heightScale = newSize.height / size.height

        let scaleFactor = widthScale < heightScale ? widthScale : heightScale
        let scaledSize = CGSize(width: size.width * scaleFactor, height: size.height * scaleFactor)

        return self.scaled(toSize: scaledSize, in: CGRect(x: 0.0, y: 0.0, width: scaledSize.width, height: scaledSize.height))
    }

    func scaled(toSize newSize: CGSize, in rect: CGRect) -> UIImage {
        if UIScreen.main.scale == 2.0 {
            UIGraphicsBeginImageContextWithOptions(newSize, !hasAlphaChannel, 2.0)
        }
        else {
            UIGraphicsBeginImageContext(newSize)
        }

        draw(in: rect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage ?? UIImage()
    }

    var hasAlphaChannel: Bool {
        guard let alpha = cgImage?.alphaInfo else {
            return false
        }
        return alpha == CGImageAlphaInfo.first ||
            alpha == CGImageAlphaInfo.last ||
            alpha == CGImageAlphaInfo.premultipliedFirst ||
            alpha == CGImageAlphaInfo.premultipliedLast
    }
}

Приклад використання:

override func viewDidLoad() {
    super.viewDidLoad()

    let size = CGSize(width: 14.0, height: 14.0)
    if let image = UIImage(named: "barbell")?.scaledToFit(toSize: size) {
        let imageView = UIImageView(image: image)
        imageView.center = CGPoint(x: 100, y: 100)
        view.addSubview(imageView)
    }
}

Цей код є переписанням розширення Apple з додатковою підтримкою зображень з альфа-каналом і без нього.

Для подальшого читання рекомендую перевірити цю статтю на наявність різних методик зміни розміру зображення. Сучасний підхід пропонує гідну продуктивність, він працює API високого рівня та простий у розумінні. Я рекомендую дотримуватися цього, якщо ви не виявите, що зміна розміру зображення є вузьким місцем у вашій роботі.


1

Використовуйте це розширення, якщо вам потрібно змінити розмір ширини / висоти лише за пропорцією.

extension UIImage {
    func resize(to size: CGSize) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(in: CGRect(origin: .zero, size: size))
        }
    }
    func resize(width: CGFloat) -> UIImage {
        return resize(to: CGSize(width: width, height: width / (size.width / size.height)))
    }
    func resize(height: CGFloat) -> UIImage {
        return resize(to: CGSize(width: height * (size.width / size.height), height: height))
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.