Ridimensiona UIImage mantenendo le proporzioni e la larghezza


136

Ho visto in molti post per ridimensionare l'immagine mantenendo le proporzioni. Queste funzioni utilizzano i punti fissi (Larghezza e Altezza) per RECT durante il ridimensionamento. Ma nel mio progetto, ho bisogno di ridimensionare la vista in base alla sola Larghezza, l'altezza dovrebbe essere presa automaticamente in base alle proporzioni. qualcuno mi aiuta a raggiungere questo obiettivo.

Risposte:


228

Il metodo di Srikar funziona molto bene, se conosci sia l'altezza che la larghezza della tua nuova dimensione. Se ad esempio conosci solo la larghezza su cui vuoi ridimensionare e non ti interessa l'altezza, devi prima calcolare il fattore di scala dell'altezza.

+(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
Non hai davvero bisogno della newWidthvariabile qui, è già i_width.
Matthew Quiros,

2
Devi anche dividere per altezza e confrontare i fattori di ridimensionamento usando il valore più vicino a 0. il codice sopra funzionerà solo con immagini più larghe di quanto siano alte
IceForge,

1
Avrei solo bisogno di dividere per altezza se volessi conoscere anche il mio rapporto di altezza e adattarmi scalando la larghezza o l'altezza. ma poiché il TO ha chiesto esplicitamente di mantenere il rapporto e la larghezza, e non la larghezza o l'altezza, la mia risposta è completamente corretta.
Maverick,

12
Ottima risposta, grazie. Ancora una cosa: se si riscontra una perdita di qualità dell'immagine usando questo metodo, utilizzare UIGraphicsBeginImageContextWithOptions(CGSizeMake(newWidth, newHeight), NO, 0);piuttosto quindiUIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
skornos

57

Se non ti capita di sapere se l'immagine sarà verticale o orizzontale (ad es. L'utente scatta una foto con la fotocamera), ho creato un altro metodo che accetta i parametri di larghezza e altezza massimi.

Supponiamo che tu abbia un UIImage *myLargeImagerapporto 4: 3.

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

Il UIImage ridimensionato sarà 1024x768 se orizzontale; 768x1024 se ritratto. Questo metodo genererà anche immagini ad alta risoluzione per la visualizzazione della retina.

+ (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
Questa è la cosa migliore, ma restituisce sempre il doppio della mia dimensione definita
Mashhadi,

2
Se vuoi solo ridimensionare, non ridimensionare, non dimenticare di avviare imageWithImage: scaledToMaxWidth: maxHeight: metodo con: if (image.size.width <larghezza && image.size.height <altezza) {return image; }
Arjan,

5
Per montare all'interno di una larghezza massima e l'altezza massima, è necessario il rapporto minimo come il fattore di scala: min(ratioX, ratioY). Altrimenti, se la larghezza è maggiore, potrebbe non adattarsi all'altezza massima.
Jason Sturges

ImageUtilities dove si trova?
tong

42

La migliore risposta Maverick 1st è correttamente tradotto in Swift (lavorando con l'ultimo 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

grazie @ Maverick1st l'algoritmo, l'ho implementato Swift, nel mio caso l'altezza è il parametro di input

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

Questo metodo è una categoria su UIImage. Ridimensiona per adattarsi a poche righe di codice usando AVFoundation. Non dimenticare di importare #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
Ho trovato questo per darmi i migliori risultati con il minimo ingombro di memoria. +1
Tommie C.,

11

Versione Swift 5 di aspetto adatto all'altezza , basata sulla risposta di @ János

Utilizza l' UIGraphicsImageRendererAPI moderna , quindi UIImageè garantito un reso valido per la restituzione.

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

Puoi usarlo insieme a un asset di immagini PDF (basato su vettori), per preservare la qualità a qualsiasi dimensione di rendering.


7

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

Il codice va così - Questo può essere usato come metodo di utilità -

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

Tieni presente che l'OP non ha menzionato UIImageView. Invece, presumibilmente voleva presumibilmente adattarsi direttamente a una [copia di un] UIImage, che è una cosa molto utile quando si esegue il lavoro CoreGraphics.
Womble,

6

livello di programmazione:

imageView.contentMode = UIViewContentModeScaleAspectFit;

storyboard:

inserisci qui la descrizione dell'immagine


funziona, MA riducendo le impronte di memoria, puoi far funzionare le app più velocemente, ad esempio caricando molte anteprime.
Ingconti,

Questo è un UIImageView, non un UIImage. A volte, devi fare un disegno senza UIImageView.
Womble,

5

Bene, abbiamo alcune buone risposte qui per il ridimensionamento dell'immagine, ma modifico solo secondo le mie necessità. spero che questo aiuti qualcuno come me.

Il mio requisito era

  1. Se la larghezza dell'immagine è superiore a 1920, ridimensionala con 1920 larghezza e mantenendo l'altezza con le proporzioni originali.
  2. Se l'altezza dell'immagine è superiore a 1080, ridimensionala con altezza 1080 e mantenendo la larghezza con le proporzioni originali.

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

Grazie a @ Srikar Appal , per il ridimensionamento ho usato il suo metodo.

Potresti controllare anche questo per il calcolo del ridimensionamento.


4

Importa e utilizza AVFoundation AVMakeRectWithAspectRatioInsideRect(CGRectCurrentSize, CGRectMake(0, 0, YOUR_WIDTH, CGFLOAT_MAX)


2

Per migliorare la risposta di 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
    }
}

Quando la scala è impostata su 0,0, viene utilizzato il fattore di scala della schermata principale, che per i display Retina è 2.0 o superiore (3.0 su iPhone 6 Plus).


1

Ryan's Solution @Ryan in codice rapido

uso:

 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

In Swift 3 ci sono alcune modifiche. Ecco un'estensione di 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 e Womble rispondono in Swift 5 con piccoli miglioramenti. Qui abbiamo l'estensione con 2 funzioni per ridimensionare l'immagine maxLengthdi qualsiasi dimensione e compressione jpeg.

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

Questo è stato perfetto per me. Mantiene le proporzioni e prende a maxLength. Larghezza o Altezza non sarà maggiore dimaxLength

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

Calcola l'altezza migliore dell'immagine per la larghezza disponibile.

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

L'ho risolto in un modo molto più semplice

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

il moltiplicatore della scala definirà lo scalling dell'immagine, più il moltiplicatore sarà più piccolo dell'immagine. così puoi controllare ciò che si adatta al tuo schermo.

Oppure puoi anche ottenere il multiplire dividendo imagewidth / screenwidth.

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.