Frage

Meine Anwendung ist eine Reihe von Bilddateien aus dem Netz herunterladen und sie auf der lokale 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 auf Ändern der Größe auf Platz / Leistung zu speichern.

Auch 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?

War es hilfreich?

Lösung

Ein paar Vorschläge sind als Antworten gegeben href="https://stackoverflow.com/questions/603907/uiimage-resize-then-crop"> diese Frage rel="noreferrer">, mit der ein entsprechender 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;
}

Was 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 gehen Sie wie folgt vor:

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.

Andere Tipps

Die einfachste und direkteste Weg, um Ihre Bilder, um die Größe sei 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();

Die oben genannten Methoden funktionieren gut für kleine Bilder, aber wenn man ein sehr großes Bild, um die Größe versuchen, werden Sie schnell aus dem Speicher und zum Absturz der App führen. Ein viel besserer Weg ist zu verwenden CGImageSourceCreateThumbnailAtIndexto die Größe des Bildes, ohne zuerst 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 .

Der beste Weg, Bilder zu skalieren, ohne das Seitenverhältnis zu verlieren (das heißt ohne Dehnung der imgage) ist 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 Sie wie folgt:

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

Diese Methode sorgt für 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) hat.

Wenn Sie die Kontrolle über den Server haben, würde ich empfehlen, die Bilder Serverseite Ändern der Größe mit 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.

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

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 Kanten und vier Ecken ausrichten.

Und auch können Sie 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 auf der Größe verändert werden. 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 trim: true passieren.

Aspect fit vor und nach der Skalierung:

 Aspect passen 1 (vorher)

Ein weiteres Beispiel für Aspekt fit :

 Aspect passen 2 (vor)

Aspect fit mit Top-Ausrichtung:

 Aspect passen 3 (vor)

Aspect füllen :

 Aspect Füllung (vor)

Füllen :

 Fill (vor)

Ich habe Upscaling in meinen Beispielen, weil es einfacher ist, zu zeigen, aber Lösung funktioniert auch für so in Frage Downscaling.

Für die JPEG-Komprimierung sollten Sie diese verwenden:

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

Sie können check out my Kern mit Xcode Spielplatz.

Für Swift 3 wird der Code unten skaliert das Bild, um das Seitenverhältnis zu halten. Sie können mehr über die Imagecontext in 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)

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

Das Hinzufügen der ganze Reihe von Antworten hier, aber ich habe eine Lösung gegangen, die nach Dateigröße skaliert, anstatt Dimensionen.

Dies wird sowohl die Dimensionen 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 Skalierung nach Größe Antwort

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 ändern arbeitet nicht richtig.

In dem folgenden Code wird die Skala auf 1 gesetzt ist (nicht skaliert) und das zurückgegebene Bild hat die Größe, die man erwarten würde. Dies wird in dem UIGraphicsBeginImageContextWithOptions Aufruf erfolgt.

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

ich am Ende mit Brads Technik eine scaleToFitWidth Methode in UIImage+Extensions zu erstellen, wenn das für jeden nützlich ist ...

-(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, wohin Sie mögen

#import "UIImage+Extensions.h"

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

Auch erwähnenswert Sie diese weiter nach unten in eine UIView+Extensions Klasse bewegen könnte, wenn Sie Bilder von einem UIView

machen möchten

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

}

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

Verbrauch:

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 mit Ihrem lokalen jpg Bildpfad

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
}

Wenn jemand noch für eine bessere Option sucht

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

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

Um ein Bild zu skalieren Ich habe besser (grafische) Ergebnisse durch diese Funktion anstelle von DrawInRect mit:

- (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 ist gesorgt für automatisch

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top