Cambiar el tamaño de UIImage a 200x200pt / px

82

He tenido problemas para cambiar el tamaño de una imagen. Básicamente he tropezado con: ¿Cómo reducir un UIImage y hacerlo crujiente / nítido al mismo tiempo en lugar de borroso?

Esta parece ser una solución legítima, pero de alguna manera no funciona correctamente.

Mi aplicación funciona con fotos de Camera Roll. Estas fotos deben cambiarse de tamaño a aproximadamente 200x200, mientras que el ancho es importante, no la altura.

Desafortunadamente, no tengo un código de muestra porque lo descarté en mi rabia por la solución que no funciona, lo siento.

swift_dan
fuente
¿Qué es exactamente lo que no funciona correctamente? ¿Qué resultado esperas y qué resultado obtuviste?
ifau
Espero una imagen con un ancho de 200 y en esta proporción una altura de x. Todavía obtengo la imagen original como 1920x .... lo que sea
swift_dan

Respuestas:

149

Aquí está mi código. La imagen tiene un ancho de 850 px y no 200 px:

 func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {

    let scale = newWidth / image.size.width
    let newHeight = image.size.height * scale
    UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight))
    image.drawInRect(CGRectMake(0, 0, newWidth, newHeight))
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()

    return newImage
}


@IBAction func chooseImage(sender: AnyObject) {


    var myPickerController = UIImagePickerController()
    myPickerController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
    myPickerController.delegate = self;
    self.presentViewController(myPickerController, animated: true, completion: nil)


}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject])

{
    var imagenow = info[UIImagePickerControllerOriginalImage] as? UIImage

    imageImage.image = resizeImage(imagenow!, newWidth: 200)



    pimg2 = imageImage.image!

    cidnew2 = textFieldCID!.text!
    pname2 = textFieldName!.text
    pmanu2 = textFieldMan!.text
    pnick2 = textFieldNick!.text
    podate2 = textFieldPODate!.text
    pno2 = textFieldArtNo!.text



    self.dismissViewControllerAnimated(true, completion: nil)

}
swift_dan
fuente
1
para deshacerse de los errores en swift 3, la información proporcionada en stackoverflow.com/a/37948158/1404324 podría ayudar
Faruk
3
trabajando en swift 4: func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage { let scale = newWidth / image.size.width let newHeight = image.size.height * 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! }
mikey9
65

Basado en la respuesta de swift_dan, una actualización para Swift 3

func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {

    let scale = newWidth / image.size.width
    let newHeight = image.size.height * 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
}
Christoph R
fuente
2
Si desea guardar calidad en pantallas retina y guardar transparente, use: UIGraphicsBeginImageContextWithOptions (CGSize (width: newWidth, height: newHeight), false, 0)
Evgeny Karev
¡Esto redujo mi imagen de 18 MB a <1 MB! Usé: resizeImage (image: (info [UIImagePickerControllerOriginalImage] as? UIImage) !, newWidth: 200) en un iPad 9.7 ". Imagen tomada de imagePickerController. Usando swift 3.0
Brian
43

Si está tratando con imágenes PNG que contienen transparencias, la función de respuesta aceptada realmente convertirá las áreas transparentes a negro.

Si desea escalar y mantener las transparencias en su lugar, pruebe esta función:

SWIFT 4

extension UIImage {
    func scaleImage(toSize newSize: CGSize) -> UIImage? {
        var newImage: UIImage?
        let newRect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height).integral
        UIGraphicsBeginImageContextWithOptions(newSize, false, 0)
        if let context = UIGraphicsGetCurrentContext(), let cgImage = self.cgImage {
            context.interpolationQuality = .high
            let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: newSize.height)
            context.concatenate(flipVertical)
            context.draw(cgImage, in: newRect)
            if let img = context.makeImage() {
                newImage = UIImage(cgImage: img)
            }
            UIGraphicsEndImageContext()
        }
        return newImage
    }
}
Travis M.
fuente
1
Increíble ... reducción de la huella de memoria de menos de 200 MB a 18: D
Tom
3
También debe tener en cuenta la escala de la pantalla reemplazando el UIImage init con:let scale = UIScreen.main.scale let newImage = UIImage(cgImage: context.makeImage()!, scale: scale, orientation: .up)
picciano
1
% 30 de los usuarios se bloquea en esta función ... en la línea context.draw (self.cgImage !, in: newRect) ... Crashed: com.apple.root.utility-qos 0x1001500a8 UIImage.scaleImage especializada (toSize: CGSize) - > UIImage?
Can Aksoy
1
Gracias, @CanAksoy, eliminé los opcionales forzados, esto debería ayudar.
Travis M.
21

Para Swift 3.0

simplemente agregue este fragmento como extensión a UIImage. Sin embargo, recuerde que no va a hacer la imagen en forma cuadrada pero si estuviera en esa forma, el resultado será cuadrado.

extension UIImage {
    func resizeImage(newWidth: CGFloat) -> UIImage {

        let scale = newWidth / self.size.width
        let newHeight = self.size.height * scale
        UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
        self.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage!
    } }
Faruk
fuente
Probé este código. Produce una imagen pequeña ;; er, pero deja una impresión de memoria enorme: asigna unos 100-200 MB adicionales en el montón ((
rommex
10

Swift 4.0 -

Si está tratando con imágenes que contienen transparencias, entonces la función de respuesta aceptada realmente convertirá las áreas transparentes en negro.

Si desea escalar y mantener las transparencias en su lugar, pruebe esta función:

func resizeImageWith(image: UIImage, newSize: CGSize) -> UIImage {

    let horizontalRatio = newSize.width / image.size.width
    let verticalRatio = newSize.height / image.size.height

    let ratio = max(horizontalRatio, verticalRatio)
    let newSize = CGSize(width: image.size.width * ratio, height: image.size.height * ratio)
    var newImage: UIImage

    if #available(iOS 10.0, *) {
        let renderFormat = UIGraphicsImageRendererFormat.default()
        renderFormat.opaque = false
        let renderer = UIGraphicsImageRenderer(size: CGSize(width: newSize.width, height: newSize.height), format: renderFormat)
        newImage = renderer.image {
            (context) in
            image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        }
    } else {
        UIGraphicsBeginImageContextWithOptions(CGSize(width: newSize.width, height: newSize.height), isOpaque, 0)
        image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
        newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
    }

    return newImage
}
abhimanyu jindal
fuente
8

Este código usa UIGraphicsImageRenderer introducido en iOS 10: en mis pruebas, fue un 10-40% más rápido que las muestras anteriores con UIGraphicsBeginImageContext (Swift 4 / Xcode 9):

extension UIImage {
        func renderResizedImage (newWidth: CGFloat) -> UIImage {
            let scale = newWidth / self.size.width
            let newHeight = self.size.height * scale
            let newSize = CGSize(width: newWidth, height: newHeight)

            let renderer = UIGraphicsImageRenderer(size: newSize)

            let image = renderer.image { (context) in
                self.draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
            }
            return image
        }
    }
rommex
fuente
Ya hay una respuesta que cubre esto: stackoverflow.com/a/45936836/1489885
TIENE el
1
@ TIENE mi código es más corto, está hecho con extensión y tiene mis datos de rendimiento.
rommex
Aunque realmente me encantó esta respuesta (por usar herramientas modernas, codificación rápida y concisa), debo señalar el comportamiento inesperado que experimenté con ella. Si el UIImage original se recorta de la cámara y tiene algún tamaño (por ejemplo, 1180x850) y le estaba pidiendo al código que lo "redujera" a newWidth: 800, en realidad TRIPPLICÓ el tamaño de la imagen, ¡porque mi dispositivo era retina 3x! ! ¡Uno DEBE proporcionar un formato UIGraphicsImageRendererFormat con la escala deseada! Tener cuidado. Obtuvimos una imagen enorme en lugar de más pequeña.
Motti Shneor
7

Esta función devolverá una imagen con el ancho que especificó:

func scaleImage(image: UIImage, maximumWidth: CGFloat) -> UIImage {
    let rect: CGRect = CGRectMake(0, 0, image.size.width, image.size.height)
    let cgImage: CGImageRef = CGImageCreateWithImageInRect(image.CGImage!, rect)!
    return UIImage(CGImage: cgImage, scale: image.size.width / maximumWidth, orientation: image.imageOrientation)
}

Swift 3.0

func scaledImage(_ image: UIImage, maximumWidth: CGFloat) -> UIImage {
    let rect: CGRect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
    let cgImage: CGImage = image.cgImage!.cropping(to: rect)!
    return UIImage(cgImage: cgImage, scale: image.size.width / maximumWidth, orientation: image.imageOrientation)
}
Rashid
fuente
4

Mejorando aún más la respuesta de @rommex usando un tamaño máximo, en Swift 4.2:

private extension UIImage {
    func scaled(to maxSize: CGFloat) -> UIImage? {
        let aspectRatio: CGFloat = min(maxSize / size.width, maxSize / size.height)
        let newSize = CGSize(width: size.width * aspectRatio, height: size.height * aspectRatio)
        let renderer = UIGraphicsImageRenderer(size: newSize)
        return renderer.image { context in
            draw(in: CGRect(origin: CGPoint(x: 0, y: 0), size: newSize))
        }
    }
}
Balázs Vincze
fuente
3

Este código funciona excelentemente en imágenes cuadradas y no perderá la calidad.

extension UIImage {

func resize(targetSize: CGSize) -> UIImage {
    return UIGraphicsImageRenderer(size:targetSize).image { _ in
        self.draw(in: CGRect(origin: .zero, size: targetSize))
    }
}

}

Respuesta de: Cambiar el tamaño de la imagen sin perder calidad

ninahadi
fuente
2

Si está utilizando kingfisher lib para cargar imágenes en su proyecto y desea cambiar su tamaño, esta es la forma:

  • Xcode 8
  • Rápido 3x

    let imageUrl = URL(string: "your image url")
     //Size refer to the size which you want to resize your original image
     let size = CGSize(width: 60, height: 60)
     let processImage = ResizingImageProcessor(targetSize: size, contentMode: .aspectFit)
     cell.courseTitleImage.kf.setImage(with: imageUrl! , placeholder: UIImage(named: "placeholder"), options: [.transition(ImageTransition.fade(1)), .processor(processImage)], progressBlock: nil, completionHandler: nil)
    

    O

    Cambiar el tamaño de la imagen local: - puede consultar la respuesta de @Christoph R

  • Abdul Karim
    fuente
    1
    func getScaledDimension(width: CGFloat, height: CGFloat,new_width: CGFloat, new_height: CGFloat)->CGPoint {
    
            let widthAspect =  (width / new_width)
            let heightAspect = (height / new_height)
            if widthAspect == 0 || heightAspect == 0 {
                return CGPoint(x: width, y: height)
            }
            var width1 : CGFloat = 0
            var height1 : CGFloat =  0
            if widthAspect > heightAspect {
                width1 = (width) / heightAspect
                height1 = (height) / heightAspect
            } else {
                width1 = (width) / widthAspect
                height1 = (height) / widthAspect
            }
    
            return CGPoint(x: width1, y: height1 )
        }
    
    
    
        func ResizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
    
            let rect = CGRectMake(0, 0, targetSize.width, targetSize.height)
    
            UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0)
            image.drawInRect(rect)
            let newImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            return newImage
        }
    
    
     let imagesize =  getScaledDimension(image.size.width, height: image.size.height , new_width: Width, new_height: Hieght)
    
            print("Image Size Scaled Dimension -> H:\(imagesize.x) W:\(imagesize.y)")
    
            let newImage = ResizeImage(image, targetSize: CGSizeMake(imagesize.x,imagesize.y))
            print("Resize Image Size -> H\(newImage.size.height) W\(newImage.size.width) ")
    
    Mohammad Razipour
    fuente
    1

    Esta es una continuación de la respuesta de @Christoph R publicada para Swift 3.0. Este código funciona para Swift 5.0.1.

    static func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage {
    
        let scale = newWidth / image.size.width
        let newHeight = image.size.height * 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!
    }
    

    en el sitio de las personas que llaman

    TaskUtilties.resizeImage(image: rawImage!, newWidth: CGFloat(50))
    
    vikas kumar
    fuente
    0

    Reduzca el tamaño de la imagen en 1024, siempre puede convertir según la capacidad del servidor

    func resizeImage(image: UIImage) -> UIImage {
    
            if image.size.height >= 1024 && image.size.width >= 1024 {
    
                UIGraphicsBeginImageContext(CGSize(width:1024, height:1024))
                image.draw(in: CGRect(x:0, y:0, width:1024, height:1024))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else if image.size.height >= 1024 && image.size.width < 1024
            {
    
                UIGraphicsBeginImageContext(CGSize(width:image.size.width, height:1024))
                image.draw(in: CGRect(x:0, y:0, width:image.size.width, height:1024))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else if image.size.width >= 1024 && image.size.height < 1024
            {
    
                UIGraphicsBeginImageContext(CGSize(width:1024, height:image.size.height))
                image.draw(in: CGRect(x:0, y:0, width:1024, height:image.size.height))
    
                let newImage = UIGraphicsGetImageFromCurrentImageContext()
                UIGraphicsEndImageContext()
    
                return newImage!
    
            }
            else
            {
                return image
            }
    
        }
    
    Urvish Modi
    fuente