Was ist der einfachste Weg, eine Bildgröße mit dem iPhone SDK, um die Größe / optimieren?

stimmen
107

Meine Anwendung ist das Herunterladen eines Satzes von Bilddateien aus dem Netzwerk, und sie an die lokalen iPhone Platte speichern. Einige dieser Bilder ziemlich groß in der Größe sind (Breiten größer als 500 Pixel, zum Beispiel). Da das iPhone nicht einmal groß genug Display hat das Bild in seiner ursprünglichen Größe zu zeigen, ich plane, um das Bild etwas ein bisschen kleiner zu sparen Platz / Leistung auf Größe ändern.

Außerdem sind einige dieser Bilder JPEGs und sie sind nicht wie die üblichen 60% Qualitätseinstellung gespeichert.

Wie kann ich ein Bild mit dem iPhone SDK Größe ändern, und wie kann ich die Qualität Einstellung eines JPEG-Bildes ändern?

Veröffentlicht am 04/03/2009 um 20:42
quelle vom benutzer
In anderen Sprachen...                            


18 antworten

stimmen
240

Ein paar Vorschläge sind als Antworten auf bereitgestellt dieser Frage . Ich hatte in beschrieben die Technik vorgeschlagen , diesen Beitrag mit dem entsprechenden Code,:

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

   return newImage;
}

Soweit Speicherung des Bildes, das schnellste Bildformat mit dem iPhone zu verwenden, ist PNG, weil es Optimierungen für dieses Format hat. Wenn Sie jedoch diese Bilder als JPEG-Dateien speichern möchten, können Sie Ihre UIImage nehmen und wie folgt vorgehen:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Dies schafft eine NSData Instanz das rohe Bytes für ein JPEG-Bild bei einer 60% igen Qualitätseinstellung enthält. Der Inhalt dieser NSData Instanz kann dann auf der Festplatte oder im Cache in den Speicher geschrieben werden.

Beantwortet am 05/03/2009 um 03:20
quelle vom benutzer

stimmen
64

Die einfachste und direkteste Weg, um Ihre Bilder, um die Größe wäre dies

float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;

if(imgRatio!=maxRatio){
    if(imgRatio < maxRatio){
        imgRatio = 480.0 / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = 480.0;
    }
    else{
        imgRatio = 320.0 / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = 320.0;
    }
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Beantwortet am 05/03/2009 um 05:35
quelle vom benutzer

stimmen
23

Die oben genannten Methoden funktionieren gut für kleine Bilder, aber wenn Sie versuchen , ein sehr großes Bild , um die Größe, Sie werden schnell aus dem Speicher und zum Absturz der App führen. Ein viel besserer Weg ist zu verwenden , um CGImageSourceCreateThumbnailAtIndexdas Bild zu skalieren , ohne vorher Decodierung es vollständig.

Wenn Sie den Pfad zu dem Bild haben Größe Sie ändern möchten, können Sie diese verwenden:

- (void)resizeImageAtPath:(NSString *)imagePath {
    // Create the image source (from path)
    CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);

    // To create image source from UIImage, use this
    // NSData* pngData =  UIImagePNGRepresentation(image);
    // CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);

    // Create thumbnail options
    CFDictionaryRef options = (__bridge CFDictionaryRef) @{
            (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
            (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
            (id) kCGImageSourceThumbnailMaxPixelSize : @(640)
    };
    // Generate the thumbnail
    CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options); 
    CFRelease(src);
    // Write the thumbnail at path
    CGImageWriteToFile(thumbnail, imagePath);
}

Weitere Details hier .

Beantwortet am 01/09/2014 um 12:03
quelle vom benutzer

stimmen
18

Der beste Weg, Bilder zu skalieren, ohne das Seitenverhältnis zu verlieren (dh ohne Strecken des imgage) wird diese Methode zu verwenden:

//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {

    float width = newSize.width;
    float height = newSize.height;

    UIGraphicsBeginImageContext(newSize);
    CGRect rect = CGRectMake(0, 0, width, height);

    float widthRatio = image.size.width / width;
    float heightRatio = image.size.height / height;
    float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;

    width = image.size.width / divisor;
    height = image.size.height / divisor;

    rect.size.width  = width;
    rect.size.height = height;

    //indent in case of width or height difference
    float offset = (width - height) / 2;
    if (offset > 0) {
        rect.origin.y = offset;
    }
    else {
        rect.origin.x = -offset;
    }

    [image drawInRect: rect];

    UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return smallImage;

}

Fügen Sie diese Methode, um Ihre Utility-Klasse, so dass Sie es in Ihrem Projekt verwenden können, und greifen es etwa so:

xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];

Dieses Verfahren sorgt für die Skalierung während Seitenverhältnis beibehalten wird. Es fügt auch Einzüge zu dem Bild, falls die verkleinerte Bild mehr Breite als Höhe (oder umgekehrt) aufweist.

Beantwortet am 03/05/2013 um 09:40
quelle vom benutzer

stimmen
7

Wenn Sie die Kontrolle über den Server haben, würde ich empfehlen , die Bilder Server - Seite mit Ändern der Größe ImageMagik . Herunterladen von großen Bilder und sie am Telefon Ändern der Größe ist eine Verschwendung von vielen wertvollen Ressourcen - Bandbreite, Batterie und Speicher. All das sind knapp an den Telefonen.

Beantwortet am 05/03/2009 um 10:23
quelle vom benutzer

stimmen
5

Ich entwickelte in Swift eine ultimative Lösung für Bildskalierung.

Sie können es verwenden Bild, um die Größe zu füllen, Aspekt angegebene Größe füllen oder Aspekt passen.

Sie können Bild-Center oder einer von vier Ecken und vier Ecken ausgerichtet sind.

Und auch Sie können zusätzlichen Platz trimmen, die, wenn Seitenverhältnisse von Originalbild und Zielgröße hinzugefügt wird, nicht gleich sind.

enum UIImageAlignment {
    case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}

enum UIImageScaleMode {
    case Fill,
    AspectFill,
    AspectFit(UIImageAlignment)
}

extension UIImage {
    func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
        let preWidthScale = width.map { $0 / size.width }
        let preHeightScale = height.map { $0 / size.height }
        var widthScale = preWidthScale ?? preHeightScale ?? 1
        var heightScale = preHeightScale ?? widthScale
        switch scaleMode {
        case .AspectFit(_):
            let scale = min(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        case .AspectFill:
            let scale = max(widthScale, heightScale)
            widthScale = scale
            heightScale = scale
        default:
            break
        }
        let newWidth = size.width * widthScale
        let newHeight = size.height * heightScale
        let canvasWidth = trim ? newWidth : (width ?? newWidth)
        let canvasHeight = trim ? newHeight : (height ?? newHeight)
        UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)

        var originX: CGFloat = 0
        var originY: CGFloat = 0
        switch scaleMode {
        case .AspectFit(let alignment):
            switch alignment {
            case .Center:
                originX = (canvasWidth - newWidth) / 2
                originY = (canvasHeight - newHeight) / 2
            case .Top:
                originX = (canvasWidth - newWidth) / 2
            case .Left:
                originY = (canvasHeight - newHeight) / 2
            case .Bottom:
                originX = (canvasWidth - newWidth) / 2
                originY = canvasHeight - newHeight
            case .Right:
                originX = canvasWidth - newWidth
                originY = (canvasHeight - newHeight) / 2
            case .TopLeft:
                break
            case .TopRight:
                originX = canvasWidth - newWidth
            case .BottomLeft:
                originY = canvasHeight - newHeight
            case .BottomRight:
                originX = canvasWidth - newWidth
                originY = canvasHeight - newHeight
            }
        default:
            break
        }
        self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
    }
}

Es gibt Beispiele für diese Lösung unter Anwendung.

Grau Rechteck ist Zielstelle Bild wird verkleinert. Blaue Kreise in hellblauem Rechteck ist das Bild (I Kreise verwendet , weil es einfach ist , zu sehen , wenn es ohne Konservierungs Aspekt skaliert wird ). Licht orange Farbe markiert Bereiche , die abgeschnitten werden, wenn Sie weitergeben trim: true.

Aspect passen vor und nach der Skalierung:

Aspect fit 1 (vor) Aspekt passen 1 (nach)

Ein weiteres Beispiel für Aspekt fit :

Aspect Sitz-2 (vor) Aspekt 2 passen (nach)

Aspekt passen mit Top Ausrichtung:

Aspect fit 3 (vor) Aspekt passen 3 (nach)

Aspect Füllung :

Aspect Füllung (vor) Aspect fill (nach)

füllen Sie :

Fill (vor) Füllen Sie (nach)

Früher habe ich Upscaling in meinen Beispielen weil es einfacher zu demonstrieren, aber Lösung funktioniert auch für so in Frage Downscaling.

Für JPEG-Komprimierung sollten Sie verwenden:

let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
  // ...
}

Sie können meine Besuche Kern mit Xcode Spielplatz.

Beantwortet am 23/03/2016 um 13:51
quelle vom benutzer

stimmen
3

Für Swift 3 skaliert der folgenden Code , um das Bild , um das Seitenverhältnis zu halten. Sie können mehr über die Imagecontext in lesen Apples Dokumentation :

extension UIImage {
    class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
        let scale = newHeight / image.size.height
        let newWidth = image.size.width * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage!
    }
}

Um es zu nutzen, ruft resizeImage()Methode:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
Beantwortet am 14/04/2017 um 03:50
quelle vom benutzer

stimmen
2

Sie können diesen Code verwenden Bild in erforderlicher Größe zu skalieren.

+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
    CGSize actSize = image.size;
    float scale = actSize.width/actSize.height;

    if (scale < 1) {
        newSize.height = newSize.width/scale;
    } 
    else {
        newSize.width = newSize.height*scale;
    }

    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}
Beantwortet am 30/09/2015 um 10:51
quelle vom benutzer

stimmen
1
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {
    let scale = newWidth / image.size.width
    let newHeight = CGFloat(200.0)
    UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
    image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))

    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}
Beantwortet am 12/04/2018 um 10:25
quelle vom benutzer

stimmen
1

Zusätzlich zu der Reihe von Antworten hier, aber ich habe eine Lösung gegangen, die nach Dateigröße skaliert, anstatt Dimensionen.

Dies wird sowohl die Abmessungen und die Qualität des Bildes reduzieren, bis sie von Ihnen angegebene Größe erreicht.

func compressTo(toSizeInMB size: Double) -> UIImage? {
    let bytes = size * 1024 * 1024
    let sizeInBytes = Int(bytes)
    var needCompress:Bool = true
    var imgData:Data?
    var compressingValue:CGFloat = 1.0

    while (needCompress) {

        if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {

            if data.count < sizeInBytes || compressingValue < 0.1 {
                needCompress = false
                imgData = data
            } else {
                compressingValue -= 0.1
            }
        }
    }

    if let data = imgData {
        print("Finished with compression value of: \(compressingValue)")
        return UIImage(data: data)
    }
    return nil
}

private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
    let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
    UIGraphicsBeginImageContext(size)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
        UIGraphicsEndImageContext()
        return newImage;
    }
    return nil
}

Kredit für die Skalierung von Größe Antwort

Beantwortet am 10/07/2017 um 11:24
quelle vom benutzer

stimmen
0

Wenn Sie Bild in Dokumentenverzeichnis ist, Fügen Sie diese URL - Erweiterung:

extension URL {
    func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
        let imageData = try Data(contentsOf: self)
        debugPrint("Image file size before compression: \(imageData.count) bytes")

        let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")

        guard let actualImage = UIImage(data: imageData) else { return nil }
        guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
            return nil
        }
        debugPrint("Image file size after compression: \(compressedImageData.count) bytes")

        do {
            try compressedImageData.write(to: compressedURL)
            return compressedURL
        } catch {
            return nil
        }
    }
}

Verwendung:

guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
    return
}

//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
    return
}

debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")

Hinweis: - Ändern <LocalImagePath.jpg> mit Ihrem lokalen jpg Bildpfad.

Beantwortet am 18/05/2018 um 10:02
quelle vom benutzer

stimmen
0
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
    CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
    CGImageRef imageRef = image.CGImage;

    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);

    CGContextConcatCTM(context, flipVertical);
    CGContextDrawImage(context, newRect, imageRef);

    CGImageRef newImageRef = CGBitmapContextCreateImage(context);
    UIImage *newImage = [UIImage imageWithCGImage:newImageRef];

    CGImageRelease(newImageRef);
    UIGraphicsEndImageContext();

    return newImage;
}
Beantwortet am 03/11/2016 um 08:37
quelle vom benutzer

stimmen
0

Ich wollte nur diese Frage beantworten für Cocoa Swift Programmierer. Diese Funktion gibt NSImage mit neuer Größe. Sie können diese Funktion wie folgt verwenden.

        let sizeChangedImage = changeImageSize(image, ratio: 2)






 // changes image size

    func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage   {

    // getting the current image size
    let w = image.size.width
    let h = image.size.height

    // calculating new size
    let w_new = w / ratio 
    let h_new = h / ratio 

    // creating size constant
    let newSize = CGSizeMake(w_new ,h_new)

    //creating rect
    let rect  = NSMakeRect(0, 0, w_new, h_new)

    // creating a image context with new size
    let newImage = NSImage.init(size:newSize)



    newImage.lockFocus()

        // drawing image with new size in context
        image.drawInRect(rect)

    newImage.unlockFocus()


    return newImage

}
Beantwortet am 13/07/2016 um 09:00
quelle vom benutzer

stimmen
0

Versuchen Sie dieses, es für mich arbeiten,

       CGRect rect =CGRectMake (0, 0,1200,900);
       UIGraphicsBeginImageContext( rect.size );
       [image drawInRect:rect];
       UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
       NSData *imageData = UIImagePNGRepresentation(picture1);
       UIImage *img=[UIImage imageWithData:imageData];
      [imageArray addObject:img];
Beantwortet am 18/03/2016 um 11:48
quelle vom benutzer

stimmen
0

Ich landete mit Brads Technik zur Schaffung eines scaleToFitWidthVerfahrens , UIImage+Extensionswenn das ist nützlich für alle ...

-(UIImage *)scaleToFitWidth:(CGFloat)width
{
    CGFloat ratio = width / self.size.width;
    CGFloat height = self.size.height * ratio;

    NSLog(@"W:%f H:%f",width,height);

    UIGraphicsBeginImageContext(CGSizeMake(width, height));
    [self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

dann, wo Sie wollen

#import "UIImage+Extensions.h"

UIImage *newImage = [image scaleToFitWidth:100.0f];

Auch erwähnenswert Sie diese weiter nach unten in eine bewegen konnte UIView+ExtensionsKlasse , wenn Sie Bilder von einem UIView machen möchten

Beantwortet am 15/03/2016 um 14:49
quelle vom benutzer

stimmen
0

Wenn jemand noch auf der Suche für eine bessere Option

-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {


    UIImage *sourceImage = image;
    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;
    CGFloat width = imageSize.width;
    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;
    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor = 0.0;
    CGFloat scaledWidth = targetWidth;
    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

    if (CGSizeEqualToSize(imageSize, targetSize) == NO) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor)
            scaleFactor = widthFactor;
        else
            scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image


        if (widthFactor < heightFactor) {
            thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
        } else if (widthFactor > heightFactor) {
            thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
    }


    // this is actually the interesting part:

    UIGraphicsBeginImageContext(targetSize);

    CGRect thumbnailRect = CGRectZero;
    thumbnailRect.origin = thumbnailPoint;
    thumbnailRect.size.width  = scaledWidth;
    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect:thumbnailRect];

    newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    if(newImage == nil) NSLog(@"could not scale image");


    return newImage ;

}
Beantwortet am 23/06/2015 um 07:39
quelle vom benutzer

stimmen
0

Ein Problem, das auf Retina-Displays auftreten könnte, ist, dass das Ausmaß des Bildes durch Imagecapture gesetzt ist oder so. Die Resize-Funktionen werden über das nicht ändern. In diesen Fällen wird die Größe ändert nicht richtig funktionieren.

Im folgenden Code wird die Skala auf 1 (nicht skaliert) und das zurückgegebene Bild hat die Größe , die Sie erwarten. Dies wird in dem getan UIGraphicsBeginImageContextWithOptionsAnruf.

-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
    UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
    [theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}
Beantwortet am 06/04/2015 um 10:24
quelle vom benutzer

stimmen
-2

Zum Ändern der Größe eines Bildes I mit dieser Funktion anstelle von DrawInRect besser (grafische) Ergebnisse haben:

- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
    float lScale = pWidth / pImage.size.width;
    CGImageRef cgImage = pImage.CGImage;
    UIImage   *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
                            orientation:UIImageOrientationRight];
    return lResult;
}

Seitenverhältnis wird darauf geachtet, um automatisch

Beantwortet am 01/09/2013 um 15:46
quelle vom benutzer

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more