Care este cel mai simplu mod de a redimensiona / optimiza o dimensiune a imaginii cu iPhone SDK-ul?

voturi
107

Cererea mea este descărcarea unui set de fișiere imagine din rețea, și salvarea lor pe disc iPhone locale. Unele dintre aceste imagini sunt destul de mari ca dimensiune (latime mai mare de 500 de pixeli, de exemplu). Deoarece iPhone-ul nu are nici măcar un ecran suficient de mare pentru a afișa imaginea în dimensiunea sa originală, eu sunt de planificare pe redimensionarea imaginii la ceva un pic mai mici pentru a economisi spațiu / performanță.

De asemenea, unele dintre aceste imagini sunt JPEG-uri și nu sunt salvate ca de obicei setarea de calitate 60%.

Cum pot redimensiona o imagine cu iPhone SDK-ul, si cum pot schimba setările de calitate a unei imagini JPEG?

Întrebat 04/03/2009 la 20:42
sursa de către utilizator
În alte limbi...                            


18 răspunsuri

voturi
240

Un cuplu de sugestii sunt furnizate ca răspuns la această întrebare . Am sugerat tehnica descrisă în acest post , cu codul corespunzător:

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

   return newImage;
}

În ceea ce privește stocarea imaginii, cel mai rapid formatul de imagine pentru a utiliza cu iPhone-ul este PNG, deoarece are optimizări pentru acest format. Cu toate acestea, dacă doriți să stocați aceste imagini ca JPEG-uri, puteți lua UIImage și efectuați următoarele:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Acest lucru creează o instanță NSData care conține octeții prime pentru o imagine JPEG la o setare de calitate de 60%. Conținutul care NSData exemplu poate fi scrisă pe disc sau în memoria cache.

Publicat 05/03/2009 la 03:20
sursa de către utilizator

voturi
64

Cel mai simplu și cel mai simplu mod de a redimensiona imaginile ar fi aceasta

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();
Publicat 05/03/2009 la 05:35
sursa de către utilizator

voturi
23

Metodele de mai sus funcționează bine pentru imagini mici, dar atunci când încercați să redimensionați o imagine foarte mare, va rula rapid din memorie și crash app. O modalitate mult mai bine este de a folosi CGImageSourceCreateThumbnailAtIndexpentru a redimensiona imaginea fără să o decodifica complet mai întâi.

Dacă aveți calea către imaginea pe care doriți să o redimensionați, puteți utiliza acest lucru:

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

Mai multe detalii aici .

Publicat 01/09/2014 la 12:03
sursa de către utilizator

voturi
18

Cel mai bun mod de a scala imagini fără a pierde raportul de aspect (de exemplu, fără a întinde imgage) este de a utiliza această metodă:

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

}

Adăugați această metodă pentru clasa propii, astfel încât să puteți folosi pe tot parcursul proiectului și accesați-l astfel:

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

Această metodă are grijă de scalare menținând în același timp raportul de aspect. De asemenea, adaugă liniuțele la imaginea în cazul în care imaginea micsorata are lățime mai mult decât înălțimea (sau invers).

Publicat 03/05/2013 la 09:40
sursa de către utilizator

voturi
7

Dacă aveți un control asupra server, aș recomanda cu fermitate redimensionarea partea imagini server cu ImageMagik . Descărcarea imagini mari și redimensionarea acestora pe telefon este o pierdere de multe resurse prețioase - lățime de bandă, memorie și un acumulator. Toate acestea sunt limitate pe telefoanele.

Publicat 05/03/2009 la 10:23
sursa de către utilizator

voturi
5

Am dezvoltat o soluție finală pentru scalare a imaginii în Swift.

Puteți să-l utilizați pentru a redimensiona imaginea pentru a umple, aspectul umple sau aspectul se potrivesc dimensiunea specificată.

Puteți alinia imaginea la centru sau la oricare dintre cele patru margini și patru colțuri.

Și, de asemenea, puteți decupa spațiu suplimentar care se adaugă, dacă rapoarte de aspect ale imaginii originale și dimensiunea țintă nu sunt egale.

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

Există exemple de aplicare a acestei soluții de mai jos.

Dreptunghi gri este imaginea site - ului țintă vor fi redimensionate la. Cercuri albastre în dreptunghi albastru deschis este imaginea (am folosit cercuri , pentru că este ușor pentru a vedea când este scalate fără a păstra aspectul). Culoarea portocalie Lumina marchează zonele care vor fi eliminate dacă treci trim: true.

Aspect potrivesc înainte și după scalarea:

Aspect fit 1 (înainte) Aspect potrivi 1 (după)

Un alt exemplu de fit aspect :

Aspect fit 2 (înainte) Aspect potrivi 2 (după)

Aspect potrivesc cu aliniere sus:

fit Aspect 3 (înainte) Aspect potrivi 3 (după)

Aspect de umplere :

Aspect de umplere (înainte) Aspect de umplere (după)

Umple :

Se umple (înainte) Se umple (după)

Am folosit Upscaling în exemplele mele pentru că este mai simplu de a demonstra, dar soluția funcționează și pentru ca în cauză downscaling.

Pentru compresia JPEG ar trebui să utilizați acest lucru:

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

Puteți verifica afară meu GIST cu Xcode un loc de joacă.

Publicat 23/03/2016 la 13:51
sursa de către utilizator

voturi
3

Pentru Swift 3, codul de mai jos scalează imaginea păstrând raportul de aspect. Puteți citi mai multe despre ImageContext în documentația Apple :

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

Pentru a- l utiliza, apelați resizeImage()metoda:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
Publicat 14/04/2017 la 03:50
sursa de către utilizator

voturi
2

puteți utiliza acest cod pentru a scala imaginea în dimensiune necesară.

+ (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;
}
Publicat 30/09/2015 la 10:51
sursa de către utilizator

voturi
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
}
Publicat 12/04/2018 la 10:25
sursa de către utilizator

voturi
1

Adăugarea la ucis de răspunsuri aici, dar am plecat pentru o soluție care redimensionează de mărime fișier, mai degrabă decât dimensiunile.

Acest lucru va reduce si dimensiunile și calitatea imaginii, până când ajunge la dimensiunea dată.

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
}

Credit pentru scalarea de răspuns mărime

Publicat 10/07/2017 la 11:24
sursa de către utilizator

voturi
0

Dacă imaginea este în directorul de document, Adăugați această adresă URL extensie:

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

utilizare:

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

Notă: - Schimbare <LocalImagePath.jpg> cu calea locală de imagine jpg.

Publicat 18/05/2018 la 10:02
sursa de către utilizator

voturi
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;
}
Publicat 03/11/2016 la 08:37
sursa de către utilizator

voturi
0

Am vrut doar să răspundă la această întrebare pentru programatori cacao Swift. Această funcție returnează NSImage cu noua dimensiune. Puteți utiliza această funcție ca aceasta.

        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

}
Publicat 13/07/2016 la 09:00
sursa de către utilizator

voturi
0

Încercați acest lucru, lucru pentru mine,

       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];
Publicat 18/03/2016 la 11:48
sursa de către utilizator

voturi
0

Am ajuns folosind tehnica Brads pentru a crea o scaleToFitWidthmetodă în UIImage+Extensionscazul în care este util pentru oricine ...

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

apoi ori de câte ori doriți

#import "UIImage+Extensions.h"

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

De asemenea , demn de remarcat ai putea muta această continuare în jos într - o UIView+Extensionsclasă , dacă doriți să facă imagini de la un UIView

Publicat 15/03/2016 la 14:49
sursa de către utilizator

voturi
0

Dacă cineva caută încă o mai bună opțiune

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

}
Publicat 23/06/2015 la 07:39
sursa de către utilizator

voturi
0

O problemă care ar putea apărea pe ecranele Retina este că scara imaginii este stabilită de ImageCapture sau cam asa ceva. Funcțiile de redimensionare de mai sus nu se va schimba asta. În aceste cazuri, redimensionare va funcționa în mod corespunzător, nu.

În codul de mai jos, scara este setat la 1 (nu scalate) și imaginea returnat are dimensiunea pe care v - ați aștepta. Acest lucru se face în UIGraphicsBeginImageContextWithOptionsapel.

-(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;
}
Publicat 06/04/2015 la 10:24
sursa de către utilizator

voturi
-2

Pentru a redimensiona o imagine am avea rezultate mai bune (grafice) prin utilizarea acestei funcții în locul lui DrawInRect:

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

Raportul de aspect este avut grijă pentru automat

Publicat 01/09/2013 la 15:46
sursa de către utilizator

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