Il modo più semplice per ridimensionare un UIImage?


397

Nella mia app per iPhone, scatto una foto con la fotocamera, quindi voglio ridimensionarla a 290 * 390 pixel. Stavo usando questo metodo per ridimensionare l'immagine:

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

Funziona perfettamente, ma è una funzione non documentata, quindi non posso più usarlo con iPhone OS4.

Quindi ... qual è il modo più semplice per ridimensionare un UIImage?


Il modo di farlo nel 2019, nshipster.com/image-resizing
dengST30

Risposte:


772

Il modo più semplice è impostare la cornice del tuo UIImageViewe impostare contentModesu una delle opzioni di ridimensionamento.

In alternativa, è possibile utilizzare questo metodo di utilità, se in realtà è necessario ridimensionare un'immagine:

+ (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;
}

Esempio di utilizzo:

#import "MYUtil.h"

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

11
Non tratterrei il risultato qui. newImageverrà rilasciato automaticamente e dovrebbe essere fino al metodo che lo ha chiamato per mantenerlo o meno. Questo approccio richiede solo un bug di memoria poiché initnon fa parte del nome del metodo. Mi aspetterei che un metodo chiamato in questo modo restituisca un oggetto rilasciato automaticamente.
Alex Wayne,

Punto valido e modificato. Lascerò solo la cautela che il mio codice che utilizza questo genera errori malloc altrove senza una conservazione aggiuntiva, che è chiaramente colpa mia in qualche modo :-).
Paul Lynch,

26
A partire da iOS 4.0 , le funzioni di UIGraphics * sono tutte thread-safe.
BJ Homer,

3
@Paul Lynch: tieni presente che questa modifica interrompe la missione del post originale: come ridimensionare un'immagine a una dimensione esatta dei pixel (invece della dimensione del punto ).
Nikolai Ruhe,

8
Per coloro che lottano a causa della limitazione indicata da @NikolaiRuhe, puoi forzare la dimensione esatta dei pixel passando 1,0 anziché 0,0 nella chiamata aUIGraphicsBeginImageContextWithOptions
Danny

84

Ecco una versione rapida della risposta di Paul Lynch

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
}

E come estensione:

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
ho appena notato che, in iOS, la tua nuova dimensione si moltiplicherà per 2x, 3x in base al dispositivo
Sruit A.Suk

6
UIGraphicsBeginImageContextWithOptions (newSize, false, image.scale); per tutti i dispositivi
phnmnn,

Nota che questo non ridimensiona il CGImage sottostante (almeno in iOS 12.1). Il che va bene in base alla domanda, ma se stai scrivendo l'immagine, dovrai usare cgImage e otterrai l'immagine originale.
prewett

72

Soluzione corretta di Swift 3.0 per iOS 10+ : utilizzo ImageRenderere chiusura della sintassi:

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)
}

Ed ecco la versione di 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
Soluzione molto elegante, questa dovrebbe essere la risposta accettata!
Appsunited

2
È meglio che elegante, è corretto. I documenti API di Apple consigliano il nuovo codice di utilizzare UIGraphicsRenderer come fa questo codice. Grazie
Paul Bruneau,

1
@appsunited La domanda ha quasi 8 anni. E questo metodo funziona solo per iOS10 + come indicato.

Quando si copia il nuovo oggetto immagine negli Appunti, produce un blocco bianco per me. In realtà non sta ridimensionando la vista dell'immagine?
Oliver Dixon,

1
questa funzione restituisce un'immagine di 0 altezza e 0 larghezza, si prevede che l'altezza sia 9000 altezza e 9000 larghezza.
Krishan Kumar,

31

Trevor Howard ha alcune categorie di UIImage che gestiscono il ridimensionamento abbastanza bene. Se non altro è possibile utilizzare il codice come esempi.

Nota: a partire da iOS 5.1, questa risposta potrebbe non essere valida. Vedi il commento qui sotto.


2
Avevo bisogno di ridimensionare anche alcune immagini e per prima cosa ho provato le aggiunte di Trevor a UIImage, ma ho avuto alcuni strani bug su PNG (qualcosa sul canale alfa). La risposta accettata a questa domanda ha funzionato bene però.
Sorig,

1
Questo non è più valido (almeno con iOS5.1
Jann

@Jann, dai un'occhiata agli commit sotto il post.
vikingosegundo,

@Jann Se segui le correzioni suggerite nei commenti vai con "Matt dice: 22 novembre 2011 alle 17:39" perché rilascia il colorspaceref (a differenza della soluzione simile di Horseshoe7).
Ben Flynn,

1
@sanmai usando uno di questi metodi di ridimensionamento, le immagini perdono la nitidezza. c'è un modo per ottenere la nitidezza
vamsi575kg

31

Una versione più compatta per Swift 4 e iOS 10+:

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

Uso:

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

26

Ho visto anche questo fatto (che uso UIButtonsper lo stato Normale e Selezionato poiché i pulsanti non si resizeadattano). Il merito va a chiunque fosse l'autore originale.

Per prima cosa crea un file .h e .m vuoto chiamato UIImageResizing.heUIImageResizing.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

Includi quel file .h in qualunque file .m utilizzerai la funzione e chiamalo così:

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

Questo non copia sull'orientamento dell'immagine.
Kevin,

20

Questo miglioramento del codice di Paul ti darà un'immagine nitida ad alta risoluzione su un iPhone con un display retina. Altrimenti quando si ridimensiona è sfocato.

+ (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
Solo FYI, le modifiche apportate non sono necessarie, poiché fornendo un valore di 0,0 per la scala in UIGraphicsBeginImageContextWithOptionsverrà automaticamente utilizzata la scala della schermata principale (a partire da iOS 3.2).
Andrew R.,

16

Ecco un modo semplice:

    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 è una nuova immagine.


16

Soluzione rapida per Fill Fill, Aspect Fill e Aspect 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()
    }
}

e per usare puoi fare quanto segue:

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

Grazie ad abdullahselek per la sua soluzione originale.


15

Ecco una modifica della categoria scritta da iWasRobbed sopra. Mantiene le proporzioni dell'immagine originale invece di distorcerla.

- (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

Se vuoi solo un'immagine più piccola e non ti interessa la dimensione esatta:

+ (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;
}

Impostare la scala su 0.25f ti darà un'immagine 816 per 612 da una fotocamera da 8 MP.

Ecco una categoria UIImage + Scala per chi ne ha bisogno.


10

Perché così complicato? Penso che l'utilizzo dell'API di sistema possa ottenere lo stesso risultato:

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.

L'unico problema è che dovresti passare l'inverso del rapporto target come secondo argomento, poiché secondo il documento il secondo parametro specifica il rapporto dell'immagine originale rispetto al nuovo ridimensionato.


Perché la scala (%) non è la stessa cosa dei pixel (w / h).

La scala deve essere largeImage.scale / ratio non 1 / ratio.
Marián Černý,

9

Questa è un'estensione UIImage compatibile con Swift 3 e Swift 4 che ridimensiona l'immagine in base alle dimensioni con proporzioni

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))
        }
    }

}

Esempio di utilizzo

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

Consiglierei di nominare la funzione scaledImage(with size:)o scaledWithSize(_:). Inoltre UIGraphicsGetImageFromCurrentImageContextnon può davvero tornare nil, quindi !funzionerebbe anche. Puoi anche semplificare la creazione di rect a CGRect(origin: .zero, size: size).
Sulthan,


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
}

È una buona idea aggiungere del testo descrittivo da associare al codice.
GMchris,

6

Per i miei compagni di Xamarians, ecco una Xamarin.iOS # versione C @ Paolo Lynch risposta.

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

Se vuoi creare un'anteprima di un UIImage (con ridimensionamento proporzionale o forse qualche ritaglio coinvolto), dai un'occhiata alla categoria UIImage + Resize che ti consente di usare una sintassi concisa, simile a ImageMagick:

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

5

[cf Chris] Per ridimensionare alla dimensione desiderata:

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

o, equivalentemente, sostituto CGImageGetWidth(...)/DESIREDWIDTH


Si noti che i dati dell'immagine stessa non vengono ridimensionati ma viene applicato un fattore di scala che significa che l'immagine ha le stesse dimensioni in memoria.
Inkredibl,

5

Rogerio Chaves risponde come una rapida estensione

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
}

E anche bonus

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 con opzione fail-safe (restituisce l'immagine originale in caso di errore):

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

(Compatibile con Swift 4) Soluzione iOS 10+ e iOS <10 (utilizzando UIGraphicsImageRendererse possibile, UIGraphicsGetImageFromCurrentImageContextaltrimenti)

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

Approccio efficace senza allungare l'immagine 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!
                }

// Metodo di chiamata

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

3

La risposta di Paul Lynch è ottima, ma cambierebbe il rapporto dell'immagine. se non si desidera modificare il rapporto dell'immagine e si desidera che la nuova immagine sia adatta a nuove dimensioni, provare questo.

+ (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

usa questa estensione

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

Ecco il mio codice Swift piuttosto dettagliato

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
Questo mi ha risparmiato tempo. Grazie!
Quy Nguyen il

utile, ma comportati in modo strano dopo le attività di seguito e di ritorno, vedi qui plz: stackoverflow.com/questions/30978685/…
He Yifei 何 一 非

Nota: potresti voler aggiungere un prerequisito ( guard) alla aspectRatioAwareSizefunzione in modo tale da non generare una divisione per zero eccezione se i parametri di input per imageSize o boxSize sonoCGSize.zero
pkluz,

@pkluz questo è un buon suggerimento, ma ne avresti bisogno in tutta la funzione, credo, dato che ogni variabile è il divisore di un'altra riga ... Lascio questo come è per chiarezza. Per la produzione o una libreria per github, potresti voler rinforzare questo ... Più che una guardia, sono preoccupato che la funzione usi nomi di variabili brevi che non dicono molto. Probabilmente lo risolverei prima, quindi aggiungere le protezioni per altre cose e quindi aggiungere i test unitari.
Dan Rosenstark,

2

Swift 4 risponde:

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!
}

Non è necessario impostare la scala reale: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.
nathan,

1

Ho scoperto che è difficile trovare una risposta che puoi usare immediatamente nel tuo progetto Swift 3 . Il problema principale di altre risposte è che non onorano il canale alfa dell'immagine. Ecco la tecnica che sto usando nei miei progetti.

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
    }
}

Esempio di utilizzo:

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)
    }
}

Questo codice è una riscrittura dell'estensione di Apple con l'aggiunta del supporto per le immagini con e senza canale alfa.

Come ulteriore lettura, consiglio di consultare questo articolo per diverse tecniche di ridimensionamento delle immagini. L'approccio attuale offre prestazioni decenti, gestisce API di alto livello e di facile comprensione. Ti consiglio di attenerci a meno che non trovi che il ridimensionamento delle immagini è un collo di bottiglia nelle tue prestazioni.


1

Utilizzare questa estensione, nel caso in cui sia necessario ridimensionare larghezza / altezza solo con le proporzioni.

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))
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.