Wat is de makkelijkste manier om het formaat / optimaliseren van een beeldgrootte met de iPhone SDK?

stemmen
107

Mijn toepassing is het downloaden van een set van beeldbestanden van het netwerk, en ze op te slaan naar de lokale iPhone schijf. Sommige van die beelden zijn vrij groot in omvang (breedtes die groter zijn dan 500 pixels, bijvoorbeeld). Omdat de iPhone heeft niet eens een groot genoeg scherm om het beeld in zijn oorspronkelijke grootte weer te geven, ik ben van plan om de grootte van het beeld om iets een beetje kleiner te besparen op ruimte / prestaties.

Ook zijn sommige van die beelden zijn JPEG's en ze worden niet opgeslagen als de gebruikelijke 60% kwaliteit setting.

Hoe kan ik de grootte van een foto met de iPhone SDK, en hoe kan ik veranderen instelling van de kwaliteit van een JPEG-afbeelding?

De vraag is gesteld op 04/03/2009 om 20:42
bron van user
In andere talen...                            


18 antwoorden

stemmen
240

Een paar suggesties worden als antwoord op deze vraag . Ik had de beschreven techniek voorgesteld deze post , met de desbetreffende 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;
}

Wat betreft de opslag van het beeld, de snelste beeldformaat te gebruiken met de iPhone is PNG, want het heeft optimalisaties voor dat formaat. Echter, als je wilt deze beelden als JPEG-bestanden op te slaan, kunt u uw UIImage nemen en doe het volgende:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Hierdoor ontstaat een NSData instantie die het ruwe bytes voor een JPEG bij 60% kwaliteitsinstelling. De inhoud van deze NSData bijvoorbeeld kunnen vervolgens worden weggeschreven of opgeslagen in het geheugen.

antwoordde op 05/03/2009 om 03:20
bron van user

stemmen
64

De eenvoudigste en meest eenvoudige manier om uw foto's verkleinen zou dit

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();
antwoordde op 05/03/2009 om 05:35
bron van user

stemmen
23

De bovenstaande methoden werken goed voor kleine afbeeldingen, maar wanneer u probeert om een zeer groot formaat te wijzigen, zult u snel opraken van het geheugen en crash van de app. Een veel betere manier is om te gebruiken CGImageSourceCreateThumbnailAtIndexom het beeld te vergroten of verkleinen zonder eerst volledig te decoderen.

Als u het pad naar de afbeelding die u wilt vergroten of verkleinen, kunt u dit gebruiken:

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

Meer details hier .

antwoordde op 01/09/2014 om 12:03
bron van user

stemmen
18

Beste manier om beelden te schalen zonder verlies van de aspect ratio (dwz zonder het uitrekken van de imgage) wordt deze methode te gebruiken:

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

}

Voeg deze methode om uw Utility klas, zodat je het kunt gebruiken in uw project, en toegang toe als volgt:

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

Deze methode verzorgt het schalen met behoud van beeldverhouding. Het voegt ook streepjes aan het beeld indien de verkleinde afbeelding meer breedte dan hoogte (of vice versa).

antwoordde op 03/05/2013 om 09:40
bron van user

stemmen
7

Als u controle over de server, ik beveel de grootte van het beelden server kant met Imagemagick . Het downloaden van grote afbeeldingen en verkleinen ze op de telefoon is een verspilling van veel kostbare middelen - bandbreedte, batterij en geheugen. Die allemaal zijn schaars op telefoons.

antwoordde op 05/03/2009 om 10:23
bron van user

stemmen
5

Ik ontwikkelde een ultieme oplossing voor het schalen in Swift.

U kunt het gebruiken resize beeld te vullen, aspect vullen of aspect past opgegeven grootte.

U kunt de afbeelding uitlijnen naar het centrum of een van de vier randen en vier hoeken.

En ook u kunt extra ruimte die wordt toegevoegd als aspect ratio van de oorspronkelijke beeld en beoogde omvang zijn niet gelijk trimmen.

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

Er zijn voorbeelden van het toepassen van onder deze oplossing.

Grijze rechthoek is het doel site zal worden aangepast aan. Blauwe cirkels in het licht blauwe rechthoek is het beeld (ik gebruikte kringen, want het is gemakkelijk om te zien wanneer het wordt geschaald zonder behoud van aspect). Licht oranje kleur markeert gebieden die worden bijgesneden wanneer u flauwvalt trim: true.

Aspect passen vóór en na schaling:

Aspect fit 1 (vóór) Aspect fit 1 (na)

Een ander voorbeeld van aspect fit :

Aspect fit 2 (vóór) Aspect fit 2 (na)

Aspect passen met top alignment:

Aspect fit 3 (vóór) Aspect fit 3 (na)

Aspect vullen :

Aspect vulling (vóór) Aspect fill (na)

Vul :

Fill (vóór) Fill (na)

Ik gebruikte schaalvergroting in mijn voorbeelden, want het is eenvoudiger om aan te tonen, maar oplossing werkt ook voor omlaagscaleringsfactor als in kwestie.

Voor JPEG-compressie moet u dit gebruiken:

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

Je kunt mijn kern met Xcode speeltuin.

antwoordde op 23/03/2016 om 13:51
bron van user

stemmen
3

Swift 3, de volgende code schaalt het beeld behoud van verhoudingen. U kunt meer informatie over de ImageContext in te lezen documentatie van 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!
    }
}

Om het te gebruiken, noemen resizeImage()methode:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
antwoordde op 14/04/2017 om 03:50
bron van user

stemmen
2

U kunt deze code gebruiken afbeelding op schaal in de gewenste grootte.

+ (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;
}
antwoordde op 30/09/2015 om 10:51
bron van user

stemmen
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
}
antwoordde op 12/04/2018 om 10:25
bron van user

stemmen
1

Toe te voegen aan de hoop antwoorden hier, maar ik heb gekozen voor een oplossing die resizes op bestandsgrootte, in plaats van dimensies.

Dit zal zorgen voor een daling van de afmetingen en de kwaliteit van het beeld tot het door u opgegeven grootte bereikt.

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
}

Krediet voor het schalen op grootte antwoord

antwoordde op 10/07/2017 om 11:24
bron van user

stemmen
0

Als je afbeelding in document directory, Voeg deze 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
        }
    }
}

Gebruik:

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

Opmerking: - Change <LocalImagePath.jpg> met uw lokale afbeelding jpg pad.

antwoordde op 18/05/2018 om 10:02
bron van user

stemmen
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;
}
antwoordde op 03/11/2016 om 08:37
bron van user

stemmen
0

Ik wilde alleen maar op die vraag voor Cocoa Swift programmeurs beantwoorden. Deze functie geeft NSImage met nieuwe grootte. U kunt deze functie gebruiken als dit.

        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

}
antwoordde op 13/07/2016 om 09:00
bron van user

stemmen
0

Probeer deze, het werk voor mij,

       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];
antwoordde op 18/03/2016 om 11:48
bron van user

stemmen
0

Uiteindelijk heb ik met behulp van Brads techniek om het creëren van een scaleToFitWidthmethode in UIImage+Extensionsals dat is handig voor iedereen ...

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

dan waar u maar wilt

#import "UIImage+Extensions.h"

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

Ook vermeldenswaard kon je dit verder naar beneden in een te verplaatsen UIView+Extensionsklasse als u beelden van een UIView maken

antwoordde op 15/03/2016 om 14:49
bron van user

stemmen
0

Als iemand nog op zoek naar betere optie

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

}
antwoordde op 23/06/2015 om 07:39
bron van user

stemmen
0

Een probleem dat kan ontstaan ​​op retina displays is dat de schaal van de afbeelding door ImageCapture of zo wordt ingesteld. De resize bovenstaande functies zullen niet veranderen. In deze gevallen zal de resize niet goed werken.

In de onderstaande code, wordt de schaal ingesteld op 1 (niet geschaald) en de geretourneerde afbeelding heeft de grootte die je zou verwachten. Dit gebeurt in het UIGraphicsBeginImageContextWithOptionsgesprek.

-(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;
}
antwoordde op 06/04/2015 om 10:24
bron van user

stemmen
-2

De grootte van een afbeelding heb ik beter (grafisch) resultaten door het gebruik van deze functie in plaats van 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;
}

Beeldverhouding wordt verzorgd voor het automatisch

antwoordde op 01/09/2013 om 15:46
bron van user

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