将UIImage调整为200x200pt/px大小

90

我一直在努力调整图像大小。基本上,我遇到了以下问题: 如何缩小UIImage并使其同时变得清晰 / 锐利而不是模糊的?

这似乎是一个合适的解决方案,但不知何故它无法正常工作。

我的应用程序使用来自相机胶卷的照片。 这些照片应该调整为约200x200的尺寸,其中宽度很重要,而高度不重要。

不幸的是,由于我的愤怒导致无法工作的解决方案,我没有示例代码,抱歉。


什么东西出了问题?你期望得到什么结果,实际得到了什么结果? - ifau
我希望得到一张宽度为200像素的图片,并且按照比例计算高度。但是我仍然得到了原始图像,例如1920x...任何尺寸。 - swift_dan
13个回答

156

这是我的代码。图片宽度为850像素而不是200像素:

 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)

}

1
为了消除Swift 3中的错误,可以参考https://dev59.com/tVoT5IYBdhLWcg3w-TVV#37948158提供的信息。 - Faruk
5
在 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! }`该函数可以调整图像的大小,并返回一个新的 UIImage 对象。新的宽度是通过传入参数中的 newWidth 指定的,而高度将根据比例自动计算。函数使用了 UIKit 框架中的 UIGraphicsBeginImageContext 函数来创建一个基于位图的上下文,然后在此上下文中绘制图像并生成新的图像。最后,用 UIGraphicsEndImageContext 函数结束上下文并返回新的图像对象。 - mikey9

68

基于swift_dan的答案,这是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
}

2
如果您想在Retina显示器中保存质量并保存透明度,请使用:UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: newHeight), false, 0)。 - Evgeny Karev
这将我的图像从18MB减小到不到1MB!我使用了:resizeImage(image:(info [UIImagePickerControllerOriginalImage] as?UIImage)!,newWidth:200),在iPad 9.7“上。图像来自imagePickerController。使用swift 3.0。 - Brian Bird

45

如果你处理的是包含透明度的PNG图像,那么接受的答案函数实际上会将透明区域转换为黑色。

如果你希望在缩放图像的同时保留透明度,请尝试使用这个函数:

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

1
太棒了!内存占用从不到200MB降至18MB :D - Tom
4
你还应该考虑屏幕比例,将UIImage的初始化替换为:let scale = UIScreen.main.scale let newImage = UIImage(cgImage: context.makeImage()!, scale: scale, orientation: .up) - picciano
1
30%的用户在此函数上崩溃。 在行上context.draw(self.cgImage!,in:newRect)... 崩溃:com.apple.root.utility-qos 0x1001500a8 specialized UIImage.scaleImage(toSize : CGSize) -> UIImage? - Can Aksoy
1
谢谢,@CanAksoy,我去掉了强制可选项,这应该会有所帮助。 - Travis M.

25

适用于Swift 3.0

只需将此代码片段作为扩展添加到UIImage即可。但是,请记住,这不会使图像成为正方形,而是如果它本来就是正方形,则结果将是正方形。

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

尝试了这段代码。它确实生成了一个较小的图像,但是它留下了巨大的内存印记——在堆上分配了额外的100-200MB。 - rommex

11

Swift 4.0 -

如果您处理的图像包含透明度,则接受的答案函数实际上将透明区域转换为黑色。

如果您希望缩放并保留透明度,请尝试使用此函数:

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
}

10

这段代码使用了 iOS 10 引入的 UIGraphicsImageRenderer:在我的测试中,它比先前使用 UIGraphicsBeginImageContext(Swift 4 / Xcode 9)的示例快 10-40%:

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

已经有一个覆盖此内容的答案:https://dev59.com/ZVwY5IYBdhLWcg3w_cJH#45936836 - HAS
1
@HAS 我的代码更短,使用扩展完成,并且包含了我的性能数据。 - rommex
1
虽然我非常喜欢这个答案(使用现代工具,快速和简洁的编码),但我必须指出我遇到的意外行为。如果原始UIImage是从摄像机裁剪并具有某些大小(例如1180x850),我要求代码将其“缩小”到newWidth:800,它实际上会将图像大小增加三倍 - 因为我的设备是3倍视网膜! 必须提供具有所需比例的UIGraphicsImageRendererFormat !!! 小心。我们得到了巨大的图像而不是更小的。 - Motti Shneor

8

这个函数会返回一个宽度为您指定值的图片:

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

6

这段代码在正方形图片上表现出色,并且不会失去质量。

extension UIImage {

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

}

来源回答: 如何在不损失质量的情况下调整图像大小?


4

在 Swift 4.2 中,进一步改进 @rommex 的答案,使用最大尺寸:

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接