Der einfachste Weg, die Größe eines UIImage zu ändern?

397

In meiner iPhone-App mache ich ein Bild mit der Kamera und möchte es dann auf 290 * 390 Pixel verkleinern. Ich habe diese Methode verwendet, um die Größe des Bildes zu ändern:

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

Es funktioniert perfekt, ist aber eine undokumentierte Funktion, sodass ich es mit dem iPhone OS4 nicht mehr verwenden kann.

Also ... was ist der einfachste Weg, um die Größe eines UIImage zu ändern?

pimpampoum
quelle
Der Weg, es im Jahr 2019 zu tun, nshipster.com/image-resizing
dengST30

Antworten:

772

Der einfachste Weg ist, den Rahmen Ihres UIImageViewund das einzustellencontentMode eine der Größenänderungsoptionen festzulegen.

Oder Sie können diese Dienstprogrammmethode verwenden, wenn Sie die Größe eines Bildes tatsächlich ändern müssen:

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

Anwendungsbeispiel:

#import "MYUtil.h"

UIImage *myIcon = [MYUtil imageWithImage:myUIImageInstance scaledToSize:CGSizeMake(20, 20)];
Paul Lynch
quelle
11
Ich würde das Ergebnis hier NICHT behalten. newImagewird bereits automatisch freigegeben, und es sollte bis zu der Methode, die dies aufgerufen hat, sein, es beizubehalten oder nicht. Dieser Ansatz bittet nur um einen Speicherfehler, da er initnicht Teil des Methodennamens ist. Ich würde erwarten, dass eine Methode mit diesem Namen ein automatisch freigegebenes Objekt zurückgibt.
Alex Wayne
Gültiger Punkt und bearbeitet. Ich lasse nur die Vorsicht, dass mein Code, der dies verwendet, Malloc-Fehler an anderer Stelle ohne zusätzliche Beibehaltung erzeugt, was eindeutig irgendwie meine Schuld ist :-).
Paul Lynch
26
Ab iOS 4.0 sind alle UIGraphics * -Funktionen threadsicher.
BJ Homer
3
@ Paul Lynch: Bitte beachten Sie, dass diese Änderung der ursprünglichen Post-Mission bricht: Wie ein Bild zu einem gewissen genau , um der Größe Pixelgröße (im Gegensatz zu Punktgröße).
Nikolai Ruhe
8
Für diejenigen, die aufgrund der Einschränkung, auf die @NikolaiRuhe hingewiesen hat, Probleme haben, können Sie eine genaue Pixelgröße erzwingen, indem Sie im Aufruf vonUIGraphicsBeginImageContextWithOptions
Danny
84

Hier ist eine Swift-Version von Paul Lynchs Antwort

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
}

Und als Erweiterung:

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()
    }
}
Rogerio Chaves
quelle
2
Ich habe gerade bemerkt, dass unter iOS Ihre neue
Größe je
6
UIGraphicsBeginImageContextWithOptions (newSize, false, image.scale); für alle Geräte
phnmnn
Beachten Sie, dass dadurch die Größe des zugrunde liegenden CGImage nicht geändert wird (zumindest in iOS 12.1). Was aufgrund der Frage in Ordnung ist, aber wenn Sie das Bild ausschreiben, müssen Sie das cgImage verwenden, und Sie erhalten das Originalbild.
Prewett
72

Richtig Swift 3.0 für iOS 10+ -Lösung: Verwenden ImageRendererund Schließen der Syntax:

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

Und hier ist die Objective-C-Version:

@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
Jakub Průša
quelle
1
Sehr elegante Lösung, dies sollte die akzeptierte Antwort sein!
Appsunited
2
Das ist besser als elegant, es ist richtig. Apples API-Dokumente empfehlen neuen Code, um UIGraphicsRenderer wie diesen Code zu verwenden. Vielen Dank
Paul Bruneau
1
@appsunited Die Frage ist fast 8 Jahre alt. Und diese Methode funktioniert nur für iOS10 + wie angegeben.
Beim Kopieren des neuen Bildobjekts in die Zwischenablage wird ein weißer Block für mich erzeugt. Die Größe der Bildansicht wird nicht geändert?
Oliver Dixon
1
Diese Funktion gibt ein Bild mit 0 Höhe und 0 Breite zurück. Erwarten Sie, dass die Höhe 9000 Höhe und 9000 Breite beträgt.
krishan kumar
31

Trevor Howard hat einige UIImage-Kategorien , die die Größenänderung recht gut handhaben. Wenn nichts anderes, können Sie den Code als Beispiele verwenden.

Hinweis: Ab iOS 5.1 ist diese Antwort möglicherweise ungültig. Siehe Kommentar unten.

TechZen
quelle
2
Ich musste auch die Größe einiger Bilder ändern und habe zuerst Trevors Ergänzungen zu UIImage ausprobiert, aber einige seltsame Fehler bei PNGs (etwas über den Alphakanal). Die akzeptierte Antwort auf diese Frage hat jedoch gut geklappt.
Sorig
1
Dies ist nicht mehr gültig (zumindest mit iOS5.1
Jann
@Jann, schau dir die Commits unter dem Beitrag an.
Vikingosegundo
@Jann Wenn Sie den in den Kommentaren vorgeschlagenen Korrekturen folgen, gehen Sie zu "Matt sagt: 22. November 2011 um 17:39 Uhr", weil er den Colorspaceref freigibt (im Gegensatz zu der ähnlichen Lösung von horseshoe7).
Ben Flynn
1
@sanmai mit einer dieser Größenänderungsmethoden verlieren die Bilder ihre Schärfe.
Gibt
31

Eine kompaktere Version für Swift 4 und iOS 10+:

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

Verwendungszweck:

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

Ich habe dies auch gesehen (was ich UIButtonsfür den normalen und den ausgewählten Status verwende, da Schaltflächen dies nicht tunresize passen). Der Kredit geht an den ursprünglichen Autor.

Erstellen Sie zuerst eine leere .h- und .m-Datei mit dem Namen UIImageResizing.hundUIImageResizing.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

Fügen Sie diese .h-Datei in die .m-Datei ein, in der Sie die Funktion verwenden möchten, und rufen Sie sie dann folgendermaßen auf:

UIImage* image = [UIImage imageNamed:@"largeImage.png"];
UIImage* smallImage = [image scaleToSize:CGSizeMake(100.0f,100.0f)];
Ich wurde ausgeraubt
quelle
Dies kopiert nicht über die Bildausrichtung.
Kevin
20

Diese Verbesserung des Paul-Codes liefert Ihnen ein scharfes hochauflösendes Bild auf einem iPhone mit Retina-Display. Andernfalls ist es beim Verkleinern verschwommen.

+ (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;
}
malhal
quelle
13
Nur zu Ihrer Information, die von Ihnen vorgenommenen Änderungen sind nicht erforderlich, da die Angabe eines Werts von 0,0 für die Skalierung in UIGraphicsBeginImageContextWithOptionsautomatisch die Skalierung des Hauptbildschirms verwendet (ab iOS 3.2).
Andrew R.
16

Hier ist ein einfacher Weg:

    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 ist ein neues Bild.

asmad
quelle
16

Schnelle Lösung für Stretch Fill, Aspect Fill und 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()
    }
}

und zur Verwendung können Sie Folgendes tun:

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

Vielen Dank an abdullahselek für seine ursprüngliche Lösung.

Josh Bernfeld
quelle
15

Hier ist eine Modifikation der Kategorie, die oben von iWasRobbed geschrieben wurde. Das Seitenverhältnis des Originalbilds bleibt erhalten, anstatt es zu verzerren.

- (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;
}
Scott bedeutet
quelle
11

Wenn Sie nur ein kleineres Bild wünschen und sich nicht für die genaue Größe interessieren:

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

Skalierung auf einstellen 0.25f einstellen, erhalten Sie ein 816 x 612-Bild von einer 8-Megapixel-Kamera.

Hier ist eine Kategorie UIImage + Scale für diejenigen, die eine benötigen.

Sanmai
quelle
10

Warum so kompliziert? Ich denke, mit der System-API kann das gleiche Ergebnis erzielt werden:

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.

Das einzige Problem ist, dass Sie als zweites Argument die Umkehrung des Zielverhältnisses übergeben sollten, da der zweite Parameter laut Dokument das Verhältnis des Originalbilds zum neuen skalierten angibt.

Chris
quelle
Weil Skalierung (%) nicht dasselbe ist wie Pixel (w / h).
Die Skala sollte groß sein. Bildgröße / Verhältnis nicht 1 / Verhältnis.
Marián Černý
9

Dies ist eine UIImage-Erweiterung, die mit Swift 3 und Swift 4 kompatibel ist und das Bild mit einem Seitenverhältnis auf die angegebene Größe skaliert

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

}

Anwendungsbeispiel

let image = UIImage(named: "apple")
let scaledImage = image.scaleImageToFitSize(size: CGSize(width: 45.0, height: 45.0))
abdullahselek
quelle
Ich würde empfehlen, die Funktion scaledImage(with size:)oder zu benennen scaledWithSize(_:). Auch UIGraphicsGetImageFromCurrentImageContextkann nicht wirklich zurückkehren nil, also !auch funktionieren würde. Sie können auch die direkte Erstellung vereinfachen CGRect(origin: .zero, size: size).
Sulthan
8

Ich habe in Apples eigenen Beispielen eine Kategorie für UIImage gefunden, die den gleichen Trick macht. Hier ist der Link: https://developer.apple.com/library/ios/samplecode/sc2273/Listings/AirDropSample_UIImage_Resize_m.html .

Sie müssen nur den Anruf ändern:

UIGraphicsBeginImageContextWithOptions(newSize, YES, 2.0);

in imageWithImage:scaledToSize:inRect:mit:

UIGraphicsBeginImageContextWithOptions(newSize, NO, 2.0);

Um den Alphakanal im Bild zu betrachten.

aubykhan
quelle
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
}
Ashwini
quelle
Es ist eine gute Idee, einen beschreibenden Text zu Ihrem Code hinzuzufügen.
GMchris
6

Für meine Xamarians-Kollegen gibt es hier eine Xamarin.iOS C # -Version der Antwort von @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;
}
Martin Zikmund
quelle
5

Wenn Sie eine Miniaturansicht eines UIImage erstellen möchten (mit proportionaler Größenänderung oder möglicherweise etwas Zuschneiden), lesen Sie die Kategorie UIImage + Größe ändern , mit der Sie eine präzise , ImageMagick-ähnliche Syntax verwenden können:

UIImage* squareImage       = [image resizedImageByMagick: @"320x320#"];
Vlad Andersen
quelle
5

[vgl. Chris] So ändern Sie die Größe auf die gewünschte Größe:

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

oder gleichwertig ersetzen CGImageGetWidth(...)/DESIREDWIDTH

Tiritea
quelle
Beachten Sie, dass die Bilddaten selbst nicht in der Größe geändert werden, sondern ein Skalierungsfaktor angewendet wird, was bedeutet, dass das Bild im Speicher dieselbe Größe hat.
Inkredibl
5

Rogerio Chaves antwortet als schnelle Erweiterung

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
}

Und auch Bonus

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

Swift 3.0 mit ausfallsicherer Option (gibt im Fehlerfall das Originalbild zurück):

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
}
Rowel
quelle
5

(Swift 4-kompatibel) iOS 10+ und iOS <10-Lösung ( UIGraphicsImageRendererwenn möglich, UIGraphicsGetImageFromCurrentImageContextandernfalls verwenden)

/// 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!
    }
}
Nathan
quelle
5

Effektiver Ansatz ohne Bilddehnung 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!
                }

// Methode aufrufen

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

Die Antwort von @Paul Lynch ist großartig, würde aber das Bildverhältnis ändern. Wenn Sie das Bildverhältnis nicht ändern möchten und das neue Bild dennoch für eine neue Größe geeignet sein soll, versuchen Sie dies.

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

Verwenden Sie diese Erweiterung

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)
            })
        })
    }
}
Beslan Tularov
quelle
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()
Phil
quelle
2

Hier mein etwas ausführlicher Swift-Code

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
}
Dan Rosenstark
quelle
1
Das hat mir Zeit gespart. Vielen Dank!
Quy Nguyen
nützlich, aber nach dem Segue und dem Zurückkommen seltsam handeln, siehe hier plz: stackoverflow.com/questions/30978685/…
He Yifei
Bitte beachten Sie: Möglicherweise möchten Sie guardder aspectRatioAwareSizeFunktion eine Vorbedingung ( ) hinzufügen , damit keine Ausnahme durch eine Division durch Null ausgelöst wird, wenn die Eingabeparameter für imageSize oder boxSizeCGSize.zero
pkluz
@pkluz das ist ein guter Vorschlag, aber Sie würden sie überall in der Funktion brauchen, denke ich, da jede Variable der Teiler einer anderen Zeile ist ... Ich werde dies aus Gründen der Klarheit unverändert lassen. Für die Produktion oder eine Bibliothek für Github möchten Sie dies vielleicht verbessern ... Ich bin mehr als nur ein Wächter, ich befürchte, dass die Funktion kurze Variablennamen verwendet, die nicht viel aussagen. Ich würde das wahrscheinlich zuerst beheben und dann Wachen für andere Dinge hinzufügen und dann Komponententests hinzufügen.
Dan Rosenstark
2

Swift 4 Antwort:

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!
}
DanielEdrisian
quelle
Keine Notwendigkeit, die reale Skala 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.
festzulegen
1

Ich habe festgestellt, dass es schwierig ist, eine Antwort zu finden, die Sie sofort in Ihrem Swift 3- Projekt verwenden können. Das Hauptproblem anderer Antworten ist, dass sie den Alpha-Kanal des Bildes nicht berücksichtigen. Hier ist die Technik, die ich in meinen Projekten verwende.

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

Anwendungsbeispiel:

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

Dieser Code ist eine Neufassung der Apple-Erweiterung mit zusätzlicher Unterstützung für Bilder mit und ohne Alphakanal.

Als weitere Lektüre empfehle ich, diesen Artikel auf verschiedene Techniken zur Größenänderung von Bildern zu überprüfen . Der derzeitige Ansatz bietet eine anständige Leistung, arbeitet mit APIs auf hoher Ebene und ist leicht zu verstehen. Ich empfehle, daran festzuhalten, es sei denn, Sie stellen fest, dass die Größenänderung von Bildern einen Engpass in Ihrer Leistung darstellt.

Vadim Bulavin
quelle
1

Verwenden Sie diese Erweiterung, falls Sie die Größe von Breite / Höhe nur mit dem Seitenverhältnis ändern müssen.

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))
    }
}
Jeffrey Neo
quelle