¿Cómo redimensionar / optimizar fácilmente el tamaño de una imagen con iOS?

114

Mi aplicación descarga un conjunto de archivos de imagen de la red y los guarda en el disco local del iPhone. Algunas de esas imágenes tienen un tamaño bastante grande (anchos superiores a 500 píxeles, por ejemplo). Dado que el iPhone ni siquiera tiene una pantalla lo suficientemente grande para mostrar la imagen en su tamaño original, planeo cambiar el tamaño de la imagen a algo un poco más pequeño para ahorrar espacio / rendimiento.

Además, algunas de esas imágenes son JPEG y no se guardan como la configuración habitual de calidad del 60%.

¿Cómo puedo cambiar el tamaño de una imagen con el SDK de iPhone y cómo puedo cambiar la configuración de calidad de una imagen JPEG?

jpm
fuente

Respuestas:

246

Se proporcionan un par de sugerencias como respuestas a esta pregunta . Había sugerido la técnica descrita en esta publicación , con el 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;
}

En cuanto al almacenamiento de la imagen, el formato de imagen más rápido para usar con el iPhone es PNG, porque tiene optimizaciones para ese formato. Sin embargo, si desea almacenar estas imágenes como JPEG, puede tomar su UIImage y hacer lo siguiente:

NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);

Esto crea una instancia de NSData que contiene los bytes sin procesar para una imagen JPEG con una configuración de calidad del 60%. El contenido de esa instancia de NSData se puede escribir en el disco o en la memoria caché.

Brad Larson
fuente
1
señor ... escribí la misma lógica, pero aparecerá una línea recta blanca (retrato) en el lado derecho
favor,
1
Hola, ¿cómo nos ocupamos de mantener la relación de aspecto y los clips enlazados al cambiar el tamaño? En mi caso, cuando cambio el tamaño de una imagen que tiene una ración diferente a la de "tamaño noticioso", obtengo una imagen redimensionada deformada. ¡Gracias!
Van Du Tran
1
Esto ha funcionado en el pasado, pero en iOS5.0.1 y posteriores, esto resulta en una pérdida de memoria. ¿Alguna otra forma de lograr esto?
Usman Nisar
Se recomienda usar [image drawInRect: rect blendMode: kCGBlendModeCopy alpha: 1.0] para mejorar el rendimiento (para que el dibujo no tenga que hacer cálculos de combinación durante el dibujo)
cdemiris99
Debería usar UIGraphicsBeginImageContextWithOptions (tamaño, NO, 0.0); donde 0.0 usará la escala de la pantalla principal para apoyar la retina y superior. Apple dice "En general, debe evitar llamar a la función UIGraphicsBeginImageContext con un nombre similar (excepto como una alternativa para la compatibilidad con versiones anteriores)".
Brad Goss
65

La forma más fácil y sencilla de cambiar el tamaño de sus imágenes sería 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 en el transito
fuente
Esto es hermoso. Pude recortar las imágenes enviadas a un servidor de aproximadamente 1Mb a 100k mientras seguía manteniendo la resolución de pantalla retina (aunque cambié los valores de 320.0 y 480.0 a 640.0 y 1136.0) y también hice algo de compresión JPEG después de escalar: UIImageJPEGRepresentation (img, 0,7f);
Keller
2
¿Qué pasa si la relación de imagen y la relación máxima resultan ser iguales? Por ejemplo, si el tamaño de iamge es 3200x4800?
akshay1188
Esto ha funcionado en el pasado, pero en iOS5.0.1 y posteriores, esto resulta en una pérdida de memoria. ¿Alguna otra forma de lograr esto?
Usman Nisar
25

Los métodos anteriores funcionan bien para imágenes pequeñas, pero cuando intenta cambiar el tamaño de una imagen muy grande, rápidamente se quedará sin memoria y la aplicación se bloqueará. Una forma mucho mejor es usarCGImageSourceCreateThumbnailAtIndex para cambiar el tamaño de la imagen sin decodificarla completamente primero.

Si tiene la ruta a la imagen que desea cambiar de tamaño, puede usar esto:

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

Más detalles aquí .

Pulkit Goyal
fuente
Gracias, esta solución funciona a las mil maravillas), ¿Conoces otros formatos de archivo que admita por CGImageSourceademás de imágenes y pdfs?
sage444
Gracias. Estaba buscando un análogo inSampleSizeque sea utilizado por el decodificador de Android. Y esta es la única respuesta que proporciona una forma de reducir una imagen de una manera eficiente en la memoria.
Stan Mots
Tuve excelentes resultados con esto trabajando directamente con archivos almacenados, también funciona con imágenes en memoria pero no tan rápido (para cargar la imagen grande en un UIImage y luego escalar).
Kendall Helmstetter Gelner
No funciona en la extensión compartida. La aplicación aún se bloquea con una imagen muy grande.
George
18

La mejor manera de escalar imágenes sin perder la relación de aspecto (es decir, sin estirar la imagen) es 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;

}

Agregue este método a su clase de utilidad para que pueda usarlo en todo su proyecto y acceda a él así:

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

Este método se encarga de escalar mientras mantiene la relación de aspecto. También agrega sangrías a la imagen en caso de que la imagen reducida tenga más ancho que alto (o viceversa).

codeburn
fuente
8

Si tiene control sobre el servidor, le recomiendo encarecidamente cambiar el tamaño del lado del servidor de imágenes con ImageMagik . Descargar imágenes grandes y cambiar su tamaño en el teléfono es un desperdicio de muchos recursos valiosos: ancho de banda, batería y memoria. Todos los cuales son escasos en los teléfonos.

Rog
fuente
2
FTFQ: "Mi aplicación está descargando un conjunto de archivos de imagen de la red"
Rog
Esta podría ser una respuesta relevante. La pregunta indica que las imágenes se están descargando de la red. Si el OP puede trabajar con el lado del servidor de imágenes, debería hacerlo. Si no puede, responder le ayudará más.
Joshua Dance
6

Desarrollé una solución definitiva para el escalado de imágenes en Swift.

Puede usarlo para cambiar el tamaño de la imagen para rellenar, rellenar de aspecto o ajustar el aspecto al tamaño especificado.

Puede alinear la imagen al centro o cualquiera de los cuatro bordes y las cuatro esquinas.

Y también puede recortar el espacio adicional que se agrega si las relaciones de aspecto de la imagen original y el tamaño del objetivo no son iguales.

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

Hay ejemplos de cómo aplicar esta solución a continuación.

El rectángulo gris es el tamaño de la imagen del sitio de destino. Círculos azules en un rectángulo azul claro es la imagen (usé círculos porque es fácil de ver cuando está escalado sin preservar el aspecto). El color naranja claro marca las áreas que se recortarán si pasa trim: true.

Ajuste de aspecto antes y después del escalado:

Ajuste de aspecto 1 (antes) Ajuste de aspecto 1 (después)

Otro ejemplo de ajuste de aspecto :

Ajuste de aspecto 2 (antes) Ajuste de aspecto 2 (después)

Ajuste de aspecto con alineación superior:

Ajuste de aspecto 3 (antes) Ajuste de aspecto 3 (después)

Relleno de aspecto :

Relleno de aspecto (antes) Relleno de aspecto (después)

Llenar :

Llenar (antes) Llenar (después)

Utilicé la ampliación en mis ejemplos porque es más fácil de demostrar, pero la solución también funciona para la reducción como en la pregunta.

Para la compresión JPEG, debe usar esto:

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

Puedes ver mi esencia con Xcode playground.

mixel
fuente
3

Para Swift 3, el siguiente código escala la imagen manteniendo la relación de aspecto. Puede leer más sobre ImageContext en la documentación de 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 usarlo, llame al resizeImage()método:

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

puede usar este código para escalar la imagen en el tamaño requerido.

+ (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
fuente
2

Según esta sesión, iOS Memory Deep Dive , es mejor que usemosImageIO para reducir la escala de imágenes.

Lo malo de usar UIImageimágenes a escala reducida.

  • Descomprimirá la imagen original en la memoria.
  • Las transformaciones del espacio de coordenadas internas son caras

Utilizar ImageIO

  • ImageIO puede leer tamaños de imagen e información de metadatos sin ensuciar la memoria.

  • ImageIO puede cambiar el tamaño de las imágenes a costa de solo cambiar el tamaño de la imagen.

Acerca de la imagen en la memoria

  • El uso de memoria está relacionado con las dimensiones de las imágenes, no con el tamaño del archivo.
  • UIGraphicsBeginImageContextWithOptionssiempre usa SRGBformato de renderizado, que usa 4 bytes por píxel.
  • Una imagen tiene load -> decode -> render3 fases.
  • UIImage es caro para el tamaño y el cambio de tamaño

Para la siguiente imagen, si usa UIGraphicsBeginImageContextWithOptions , solo necesitamos 590KB para cargar una imagen, mientras que necesitamos 2048 pixels x 1536 pixels x 4 bytes per pixel= 10MB al decodificar ingrese la descripción de la imagen aquí

mientras que UIGraphicsImageRenderer, introducido en iOS 10, seleccionará automáticamente el mejor formato gráfico en iOS12. Significa que puede ahorrar el 75% de la memoria reemplazando UIGraphicsBeginImageContextWithOptionsconUIGraphicsImageRenderer si no necesita SRGB.

Este es mi artículo sobre imágenes de iOS en la memoria.

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)

o

// 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
fuente
1

Un problema que puede ocurrir en las pantallas retina es que ImageCapture o algo así establece la escala de la imagen. Las funciones de cambio de tamaño anteriores no cambiarán eso. En estos casos, el cambio de tamaño no funcionará correctamente.

En el siguiente código, la escala se establece en 1 (no escalada) y la imagen devuelta tiene el tamaño esperado. Esto se hace en la UIGraphicsBeginImageContextWithOptionsllamada.

-(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
fuente
1

Agregando a la gran cantidad de respuestas aquí, pero he optado por una solución que cambia el tamaño por tamaño de archivo, en lugar de dimensiones.

Esto reducirá las dimensiones y la calidad de la imagen hasta que alcance el tamaño indicado.

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 por escalar por respuesta de tamaño

Harry Bloom
fuente
1

Versión rápida

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
fuente
0

Terminé usando la técnica de Brads para crear un scaleToFitWidthmétodo UIImage+Extensionssi eso es útil para alguien ...

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

entonces donde quieras

#import "UIImage+Extensions.h"

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

También vale la pena señalar que puede mover esto más abajo en una UIView+Extensionsclase si desea renderizar imágenes desde una UIView

Magoo
fuente
0

Solo quería responder esa pregunta para los programadores de Cocoa Swift. Esta función devuelve NSImage con un nuevo tamaño. Puedes usar esa función así.

        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

}
Esperanza
fuente
0

Si su imagen está en el directorio de documentos, agregue esta extensión 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: - Cambie <LocalImagePath.jpg> con su ruta de imagen jpg local.

Mohammad Zaid Pathan
fuente
-1

Si alguien sigue buscando una mejor opción

-(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
fuente
-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;
}
diputado sin cartera
fuente
Por favor, proporcione al menos alguna explicación del código en su respuesta. Y también formatee el código usando el editor de respuestas para hacerlo legible.
xpereta
-2

Para cambiar el tamaño de una imagen, tengo mejores resultados (gráficos) al usar esta función en lugar 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;
}

La relación de aspecto se cuida automáticamente

Jebu
fuente