Co je to nejjednodušší způsob, jak změnit velikost / optimalizovat velikost snímku pomocí iPhone SDK?

hlasů
107

Moje žádost stahuje soubor obrazových souborů ze sítě a jejich uložení na místní disk iPhone. Některé z těchto obrazů jsou dost velké rozměry (šířky větší než 500 pixelů, například). Vzhledem k tomu, iPhone nemá ani dost velký displej pro zobrazení obrázku v původní velikosti, Mám v plánu na změnu velikosti obrázku na něco trochu menší, aby ušetřili místo / výkon.

Také, některé z těchto obrázků jsou JPEG a nejsou uloženy jako obvyklé nastavení kvality 60%.

Jak mohu změnit velikost obrázku pomocí iPhone SDK, a jak mohu změnit nastavení kvality obrazu ve formátu JPEG?

Položena 04/03/2009 v 20:42
zdroj uživatelem
V jiných jazycích...                            


18 odpovědí

hlasů
240

Několik návrhů jsou poskytovány jako odpověď na tuto otázku . I navrhl techniku popsanou v tomto příspěvku , s příslušným kódem:

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

   return newImage;
}

Co se týče ukládání obrazu, nejrychlejší obrazový formát pro použití s ​​iPhone je PNG, protože má optimalizace pro daný formát. Nicméně, pokud chcete uložit tyto obrázky jako JPEG, můžete si vzít svůj UIImage a proveďte následující kroky:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

To vytváří NSData instanci obsahující syrové bajtů pro obraz ve formátu JPEG při nastavení kvality 60%. Obsah této instanci NSData pak lze zapsat na disk nebo uložené v paměti.

Odpovězeno 05/03/2009 v 03:20
zdroj uživatelem

hlasů
64

Nejjednodušší a nejpřímější způsob, jak změnit velikost obrázků by to

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();
Odpovězeno 05/03/2009 v 05:35
zdroj uživatelem

hlasů
23

Výše uvedené metody fungují dobře pro malé obrázky, ale při pokusu o změnu velikosti velmi velký obrázek, budete rychle k vyčerpání paměti a zhroucení aplikace. Mnohem lepší způsob, jak je použít CGImageSourceCreateThumbnailAtIndexpro změnu velikosti obrazu, aniž by ji úplně první dekódování.

Pokud máte cestu k obrazu, který chcete změnit velikost, můžete použít toto:

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

Více podrobností zde .

Odpovězeno 01/09/2014 v 12:03
zdroj uživatelem

hlasů
18

Nejlepší způsob, jak se velikost obrázků bez ztráty poměr stran (tedy bez roztahování imgage) je pro použití této metody:

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

}

Přidat tuto metodu ke svému Utility třídy, takže jej můžete použít v celém projektu, a přistupovat k němu jako tak:

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

Tato metoda se stará o měřítka při zachování poměru stran. To také přidává odsazení na snímku v případě, že zmenšen obraz má větší šířku než výšku (nebo naopak).

Odpovězeno 03/05/2013 v 09:40
zdroj uživatelem

hlasů
7

Pokud máte kontrolu nad serverem, tak bych důrazně doporučujeme velikosti stranu snímky serveru s imagemagick . Stahování velkých obrázků a velikosti je na telefonu je ztráta mnoha vzácných zdrojů - pásma, baterie a paměť. Z nichž všechny jsou vzácné v telefonech.

Odpovězeno 05/03/2009 v 10:23
zdroj uživatelem

hlasů
5

Vyvinul jsem je dokonalým řešením pro škálování obrazu v Swift.

Můžete ji použít pro změnu velikosti obrazu zaplnit, aspekt vyplnit nebo aspekt fit zadané velikosti.

Můžete zarovnat obraz na střed nebo některý ze čtyř rohů a koutů.

A také můžete zkrátit více prostoru, který se přidá, pokud poměry stran původního obrazu a velikost cíle nejsou stejné.

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

Existují příklady uplatnění tohoto řešení níže.

Šedý obdélník cílové místo obrázku bude změněna na. Modré kruhy světle modrým obdélníkem je obraz (použil jsem kruhy, protože to je snadné pochopit, když je zmenšen, aniž by zachování aspekt). Světle oranžová barva označuje oblasti, které budou ořezané pokud předat trim: true.

Aspekt fit před a po změně měřítka:

Poměr stran zapadají 1 (před) Aspekt fit 1 (po)

Dalším příkladem stran fit :

Aspekt fit 2 (před) Poměr fit 2 (po)

Aspekt fit s horní zarovnání:

Aspect fit 3 (před) Poměr fit 3 (po)

Aspekt výplň :

Aspekt fill (před) Aspekt fill (po)

Výplň :

Fill (před) Fill (po)

Použil jsem upscaling ve svých příkladech, protože je to jednodušší prokázat, ale řešení funguje i pro zmenšování jako v otázce.

Pro kompresi JPEG byste měli používat toto:

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

Můžete se podívat na mou podstatu s Xcode hřištěm.

Odpovězeno 23/03/2016 v 13:51
zdroj uživatelem

hlasů
3

Pro Swift 3, níže kód změní velikost obrazu při zachování poměru stran. Si můžete přečíst více o ImageContext v dokumentaci společnosti 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!
    }
}

Pokud jej chcete použít, volejte resizeImage()metodu:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
Odpovězeno 14/04/2017 v 03:50
zdroj uživatelem

hlasů
2

můžete použít tento kód měřítko obrazu v požadované velikosti.

+ (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;
}
Odpovězeno 30/09/2015 v 10:51
zdroj uživatelem

hlasů
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
}
Odpovězeno 12/04/2018 v 10:25
zdroj uživatelem

hlasů
1

Přidávat se k zabil odpovědi tady, ale já jsem šel za řešení, které změní velikost podle velikosti souboru, spíše než rozměry.

To bude i zmenšení rozměrů a kvalitu obrazu, dokud nedosáhne svou danou velikost.

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
}

Zásluhu na škálování podle velikosti odpovědi

Odpovězeno 10/07/2017 v 11:24
zdroj uživatelem

hlasů
0

Máte-li obrázek v adresáři dokumentů, Přidat URL rozšíření:

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

Používání:

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

Poznámka: - změna <LocalImagePath.jpg> s místní dráhy jpg obrazu.

Odpovězeno 18/05/2018 v 10:02
zdroj uživatelem

hlasů
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;
}
Odpovězeno 03/11/2016 v 08:37
zdroj uživatelem

hlasů
0

Jen jsem chtěl odpovědět na tuto otázku pro Cocoa Swift programátory. Tato funkce vrací NSImage s novou velikostí. Můžete použít tuto funkci, jako je tento.

        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

}
Odpovězeno 13/07/2016 v 09:00
zdroj uživatelem

hlasů
0

Zkuste to, je to práce pro mě,

       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];
Odpovězeno 18/03/2016 v 11:48
zdroj uživatelem

hlasů
0

Skončil jsem s použitím drátěnky technikou vytvořit scaleToFitWidthmetodu v UIImage+Extensionspřípadě, že je užitečné pro každého ...

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

pak tam, kde se vám líbí

#import "UIImage+Extensions.h"

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

Stojí také za zmínku byste mohli posunout dál do UIView+Extensionsskupiny Chcete-li vykreslit obrázky z UIView

Odpovězeno 15/03/2016 v 14:49
zdroj uživatelem

hlasů
0

Pokud má někdo stále hledá lepší volba

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

}
Odpovězeno 23/06/2015 v 07:39
zdroj uživatelem

hlasů
0

Problém, který může nastat na sítnice displejů je, že měřítko obrazu je dána ImageCapture nebo tak nějak. Funkce změny velikosti se nad to nezmění. V těchto případech bude změna velikosti nepracují správně.

V níže uvedeném kódu, váha je nastavena na hodnotu 1 (není měřítko) a vrátila obraz má velikost, která byste očekávali. To se provádí ve UIGraphicsBeginImageContextWithOptionsvýzvě.

-(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;
}
Odpovězeno 06/04/2015 v 10:24
zdroj uživatelem

hlasů
-2

Chcete-li změnit velikost obrazu mám lepší (grafické) výsledků pomocí této funkce namísto 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;
}

Poměr stran je postaráno automaticky

Odpovězeno 01/09/2013 v 15:46
zdroj uživatelem

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