Como redimensionar / otimizar facilmente o tamanho de uma imagem com iOS?

114

Meu aplicativo está baixando um conjunto de arquivos de imagem da rede e salvando-os no disco local do iPhone. Algumas dessas imagens são muito grandes (larguras maiores que 500 pixels, por exemplo). Como o iPhone nem mesmo tem uma tela grande o suficiente para mostrar a imagem em seu tamanho original, estou planejando redimensionar a imagem para algo um pouco menor para economizar espaço / desempenho.

Além disso, algumas dessas imagens são JPEGs e não são salvas com a configuração de qualidade normal de 60%.

Como posso redimensionar uma imagem com o iPhone SDK e como posso alterar a configuração de qualidade de uma imagem JPEG?

jpm
fonte

Respostas:

246

Algumas sugestões são fornecidas como respostas a esta pergunta . Eu havia sugerido a técnica descrita neste post , com o código relevante:

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

   return newImage;
}

No que diz respeito ao armazenamento da imagem, o formato de imagem mais rápido para usar com o iPhone é o PNG, pois possui otimizações para esse formato. No entanto, se quiser armazenar essas imagens como JPEGs, você pode pegar sua UIImage e fazer o seguinte:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Isso cria uma instância NSData contendo os bytes brutos para uma imagem JPEG em uma configuração de qualidade de 60%. O conteúdo dessa instância NSData pode ser gravado em disco ou armazenado em cache na memória.

Brad Larson
fonte
1
senhor ... eu escrevi a mesma lógica, mas uma linha reta branca aparecerá (retrato) no lado direito, por favor, dê-me a solução
Nag_iphone
1
Olá, como tratamos de manter a proporção e os clipes limitados durante o redimensionamento? No meu caso, quando redimensiono uma imagem que tem uma proporção diferente de "newsize", obtenho uma imagem redimensionada deformada. Obrigado!
Van Du Tran
1
Isso funcionou no passado, mas no iOS5.0.1 e posterior, isso está resultando em um vazamento de memória. Qualquer outra maneira de fazer isso?
Usman Nisar
Recomende o uso de [image drawInRect: rect blendMode: kCGBlendModeCopy alpha: 1.0] para melhorar o desempenho (portanto, o draw não precisa fazer cálculos de combinação durante o sorteio
cdemiris99
Você deve usar UIGraphicsBeginImageContextWithOptions (size, NO, 0.0); onde 0,0 usará a escala da tela principal para suportar a retina e acima. Apple declara "Você geralmente deve evitar chamar a função UIGraphicsBeginImageContext de nome semelhante (exceto como um fallback para compatibilidade com versões anteriores)".
Brad Goss
65

A maneira mais fácil e direta de redimensionar suas imagens seria esta

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();
perdido em trânsito
fonte
Isso é lindo. Consegui reduzir as imagens enviadas a um servidor de cerca de 1 MB a 100 k, mantendo a resolução do display retina (embora eu tenha alterado os valores 320,0 e 480,0 para 640,0 e 1136,0) e também fiz alguma compactação JPEG após o dimensionamento: UIImageJPEGRepresentation (img, 0.7f);
Keller
2
E se a proporção da imagem e a proporção máxima forem iguais? Por exemplo, se o tamanho da imagem for 3200 x 4800?
akshay1188
Isso funcionou no passado, mas no iOS5.0.1 e posterior, isso está resultando em um vazamento de memória. Qualquer outra maneira de fazer isso?
Usman Nisar
25

Os métodos acima funcionam bem para imagens pequenas, mas ao tentar redimensionar uma imagem muito grande, você rapidamente ficará sem memória e travará o aplicativo. Uma maneira muito melhor é CGImageSourceCreateThumbnailAtIndexredimensionar a imagem sem decodificá-la completamente primeiro.

Se você tiver o caminho para a imagem que deseja redimensionar, pode usar isto:

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

Mais detalhes aqui .

Pulkit Goyal
fonte
Obrigado, esta solução funciona como um encanto), Você conhece outros formatos de arquivo que suporta, CGImageSourcealém de imagens e PDFs?
sage444
Obrigado. Eu estava procurando um análogo do inSampleSizeque é usado pelo decodificador do Android. E esta é a única resposta que fornece uma maneira de reduzir uma imagem de maneira eficiente em termos de memória.
Stan Mots
Tive ótimos resultados trabalhando diretamente com arquivos no armazenamento, também funciona com imagens na memória, mas não tão rapidamente (para carregar a imagem grande para um UIImage e então dimensionar).
Kendall Helmstetter Gelner
Não funciona na extensão de compartilhamento. O aplicativo ainda está travando com uma imagem muito grande.
George
18

A melhor maneira de dimensionar imagens sem perder a proporção (ou seja, sem esticar a imagem) é usar este método:

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

}

Adicione este método à sua classe Utility para que você possa usá-lo em todo o seu projeto e acessá-lo desta forma:

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

Este método cuida do dimensionamento enquanto mantém a proporção da imagem. Também adiciona recuos à imagem caso a imagem reduzida tenha mais largura do que altura (ou vice-versa).

codeburn
fonte
8

Se você tiver controle sobre o servidor, recomendo fortemente redimensionar as imagens do lado do servidor com ImageMagik . Baixar imagens grandes e redimensioná-las no telefone é um desperdício de muitos recursos preciosos - largura de banda, bateria e memória. Todos os quais são escassos em telefones.

Rog
fonte
2
FTFQ: "Meu aplicativo está baixando um conjunto de arquivos de imagem da rede",
Rog
Esta pode ser uma resposta relevante. A pergunta indica que as imagens estão sendo baixadas da rede. Se o OP pode trabalhar com o lado do servidor de imagens, ele deve. Se ele não puder, a resposta ajudará mais.
Joshua Dance
6

Desenvolvi uma solução definitiva para dimensionamento de imagens em Swift.

Você pode usá-lo para redimensionar a imagem para preencher, preencher com aspecto ou ajustar o tamanho do tamanho especificado.

Você pode alinhar a imagem ao centro ou a qualquer uma das quatro bordas e quatro cantos.

E também você pode cortar o espaço extra que é adicionado se as proporções da imagem original e o tamanho do destino não forem iguais.

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

Existem exemplos de aplicação desta solução abaixo.

O retângulo cinza é a imagem do site de destino será redimensionada para. Círculos azuis em um retângulo azul claro são a imagem (usei círculos porque é fácil ver quando é redimensionado sem preservar o aspecto). A cor laranja clara marca as áreas que serão cortadas se você passar trim: true.

Aspecto se ajusta antes e depois da escala:

Aspecto ajuste 1 (antes) Aspecto ajuste 1 (depois)

Outro exemplo de ajuste de aspecto :

Aspecto ajuste 2 (antes) Aspecto ajuste 2 (depois)

Aspecto se ajusta ao alinhamento superior:

Aspecto ajuste 3 (antes) Aspecto ajuste 3 (depois)

Preenchimento de aspecto :

Preenchimento de aspecto (antes) Preenchimento de aspecto (depois)

Preencher :

Preencher (antes) Preencher (depois)

Usei upscaling em meus exemplos porque é mais simples de demonstrar, mas a solução também funciona para downscaling como em questão.

Para compressão JPEG, você deve usar isto:

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

Você pode verificar minha essência com o playground do Xcode.

mixel
fonte
3

Para Swift 3, o código abaixo dimensiona a imagem mantendo a proporção. Você pode ler mais sobre o ImageContext na documentação da 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!
    }
}

Para usá-lo, chame o resizeImage()método:

UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
Alexandre Lara
fonte
2

você pode usar este código para dimensionar a imagem no tamanho necessário.

+ (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;
}
Amit Shelgaonkar
fonte
1

Um problema que pode ocorrer em telas de retina é que a escala da imagem é definida por ImageCapture ou algo assim. As funções de redimensionamento acima não vão mudar isso. Nestes casos, o redimensionamento não funcionará corretamente.

No código abaixo, a escala é definida como 1 (não dimensionada) e a imagem retornada tem o tamanho que você esperaria. Isso é feito na UIGraphicsBeginImageContextWithOptionschamada.

-(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;
}
Vincent
fonte
1

Aumentando a quantidade de respostas aqui, mas eu escolhi uma solução que redimensiona por tamanho de arquivo, em vez de dimensões.

Isso reduzirá as dimensões e a qualidade da imagem até que ela atinja o tamanho determinado.

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
}

Crédito para resposta de escala por tamanho

Harry Bloom
fonte
1

Versão Swift

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
}
Softlabsindia
fonte
1

De acordo com esta sessão, iOS Memory Deep Dive , é melhor usarmos ImageIOpara reduzir as imagens.

O mal de usar UIImageimagens em escala reduzida.

  • Descomprimirá a imagem original na memória
  • As transformações do espaço de coordenadas internas são caras

Usar ImageIO

  • ImageIO pode ler tamanhos de imagem e informações de metadados sem sujar a memória.

  • ImageIO pode redimensionar imagens ao custo da imagem redimensionada apenas.

Sobre a imagem na memória

  • O uso da memória está relacionado às dimensões das imagens, não ao tamanho do arquivo.
  • UIGraphicsBeginImageContextWithOptionssempre usa o SRGBformato de renderização, que usa 4 bytes por pixel.
  • Uma imagem tem load -> decode -> render3 fases.
  • UIImage é caro para dimensionar e redimensionar

Para a imagem a seguir, se você usar UIGraphicsBeginImageContextWithOptions , precisamos apenas de 590 KB para carregar uma imagem, enquanto precisamos de 2048 pixels x 1536 pixels x 4 bytes per pixel= 10 MB ao decodificar insira a descrição da imagem aqui

enquanto UIGraphicsImageRenderer, introduzido no iOS 10, escolherá automaticamente o melhor formato gráfico no iOS12. Isso significa que você pode economizar 75% da memória substituindo UIGraphicsBeginImageContextWithOptionspor UIGraphicsImageRendererse não precisar de SRGB.

Este é o meu artigo sobre imagens iOS na memória

func resize(url: NSURL, maxPixelSize: Int) -> CGImage? {
    let imgSource = CGImageSourceCreateWithURL(url, nil)
    guard let imageSource = imgSource else {
        return nil
    }

    var scaledImage: CGImage?
    let options: [NSString: Any] = [
            // The maximum width and height in pixels of a thumbnail.
            kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
            kCGImageSourceCreateThumbnailFromImageAlways: true,
            // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
            kCGImageSourceCreateThumbnailWithTransform: true
    ]
    scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)

    return scaledImage
}


let filePath = Bundle.main.path(forResource:"large_leaves_70mp", ofType: "jpg")

let url = NSURL(fileURLWithPath: filePath ?? "")

let image = resize(url: url, maxPixelSize: 600)

ou

// Downsampling large images for display at smaller size
func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
    let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
    let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
    let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
    let downsampleOptions =
        [kCGImageSourceCreateThumbnailFromImageAlways: true,
        kCGImageSourceShouldCacheImmediately: true,
        // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
        kCGImageSourceCreateThumbnailWithTransform: true,
        kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
    let downsampledImage =
        CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
    return UIImage(cgImage: downsampledImage)
}
RY Zheng
fonte
0

Acabei usando a técnica de Brad para criar um scaleToFitWidthmétodo em UIImage+Extensionsse isso é útil para alguém ...

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

então onde você quiser

#import "UIImage+Extensions.h"

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

Também vale a pena notar que você pode mover isso mais para baixo em uma UIView+Extensionsclasse se quiser renderizar imagens de um UIView

Magoo
fonte
0

Eu só queria responder a essa pergunta para os programadores Cocoa Swift. Esta função retorna NSImage com novo tamanho. Você pode usar essa função assim.

        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

}
Esperança
fonte
0

Se sua imagem estiver no diretório de documentos, adicione esta extensão de URL :

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

Uso:

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

Nota: - Altere <LocalImagePath.jpg> com o caminho da imagem jpg local.

Mohammad Zaid Pathan
fonte
-1

Se alguém ainda está procurando a melhor opção

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

}
Seema Sharma
fonte
-1
- (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;
}
backbencher
fonte
Por favor, forneça pelo menos alguma explicação sobre o código em sua resposta. E também formate o código usando o editor de respostas para torná-lo legível.
xpereta
-2

Para redimensionar uma imagem, tenho melhores resultados (gráficos) usando esta função em vez de 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;
}

A proporção é cuidada automaticamente

Jebu
fonte