如何在 Swift 中调整图像大小?

我正在使用 斯威夫特和 Parse.com 为 iOS 开发一个应用程序

我试图让用户从图像选择器中选择一张图片,然后在上传到我的后端之前将选定的图像调整到200x200像素。

Parse.com 有一个名为“ AnyPic”的 Instagram 复制应用程序教程,它提供了调整图像大小的代码,但是它是在 Objective-C..。

// Resize the image to be square (what is shown in the preview)
UIImage *resizedImage = [anImage resizedImageWithContentMode:UIViewContentModeScaleAspectFit
bounds:CGSizeMake(560.0f, 560.0f)
interpolationQuality:kCGInterpolationHigh];
// Create a thumbnail and add a corner radius for use in table views
UIImage *thumbnailImage = [anImage thumbnailImage:86.0f
transparentBorder:0.0f
cornerRadius:10.0f
interpolationQuality:kCGInterpolationDefault];

How would I create a 200x200px version of the selected picture (to then upload) in Swift?

那么,thumbnailImage 函数在做什么呢?

245744 次浏览

See my blog post, Resize image in swift and objective C, for further details.

图像调整功能迅速如下。

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage? {
let size = image.size
    

let widthRatio  = targetSize.width  / size.width
let heightRatio = targetSize.height / size.height
    

// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
    

// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(origin: .zero, size: newSize)
    

// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
    

return newImage
}

使用上面的函数,调整图像的大小为200 * 200,如下面的代码

self.resizeImage(UIImage(named: "yourImageName")!, targetSize: CGSizeMake(200.0, 200.0))

Swift 3更新

 func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
    

let widthRatio  = targetSize.width  / size.width
let heightRatio = targetSize.height / size.height
    

// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
}
    

// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
    

// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
    

return newImage!
}

既然@KiritModi 的回答来自2015年,这就是 Swift 3.0的版本:

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size


let widthRatio  = targetSize.width  / image.size.width
let heightRatio = targetSize.height / image.size.height


// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
}


// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)


// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


return newImage!
}

也可以使用 AlamofireImage (https://github.com/Alamofire/AlamofireImage)

let size = CGSize(width: 30.0, height: 30.0)
let aspectScaledToFitImage = image.af_imageAspectScaled(toFit: size)

上一篇文章中的函数给了我一个模糊的结果。

Swift 3 Version and Extension style

这个答案来自“ Kirit Modi”。

extension UIImage {


func resizeImage(targetSize: CGSize) -> UIImage {
let size = self.size


let widthRatio  = targetSize.width  / size.width
let heightRatio = targetSize.height / size.height


// Figure out what our orientation is, and use that to form the rectangle
var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
}


// This is the rect that we've calculated out and this is what is actually used below
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)


// Actually do the resizing to the rect using the ImageContext stuff
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


return newImage!
}
}

这里有两个简单的 UIImage扩展函数:

func scaledWithMaxWidthOrHeightValue(value: CGFloat) -> UIImage? {


let width = self.size.width
let height = self.size.height


let ratio = width/height


var newWidth = value
var newHeight = value


if ratio > 1 {
newWidth = width * (newHeight/height)
} else {
newHeight = height * (newWidth/width)
}


UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: newHeight), false, 0)


draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))


let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


return image
}


func scaled(withScale scale: CGFloat) -> UIImage? {


let size = CGSize(width: self.size.width * scale, height: self.size.height * scale)


UIGraphicsBeginImageContextWithOptions(size, false, 0)


draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))


let image = UIGraphicsGetImageFromCurrentImageContext()


UIGraphicsEndImageContext()


return image
}

例如,将图像最小化到1024或更小

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
}


}

适用于 Swift 4.0和 iOS 10

    extension UIImage {
func resizeImage(_ dimension: CGFloat, opaque: Bool, contentMode: UIViewContentMode = .scaleAspectFit) -> UIImage {
var width: CGFloat
var height: CGFloat
var newImage: UIImage


let size = self.size
let aspectRatio =  size.width/size.height


switch contentMode {
case .scaleAspectFit:
if aspectRatio > 1 {                            // Landscape image
width = dimension
height = dimension / aspectRatio
} else {                                        // Portrait image
height = dimension
width = dimension * aspectRatio
}


default:
fatalError("UIIMage.resizeToFit(): FATAL: Unimplemented ContentMode")
}


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


return newImage
}
}

您可以使用此适合图像在 Swift 3;

extension UIImage {
func resizedImage(newSize: CGSize) -> UIImage {
// Guard newSize is different
guard self.size != newSize else { return self }


UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}


func resizedImageWithinRect(rectSize: CGSize) -> UIImage {
let widthFactor = size.width / rectSize.width
let heightFactor = size.height / rectSize.height


var resizeFactor = widthFactor
if size.height > size.width {
resizeFactor = heightFactor
}


let newSize = CGSize(width: size.width/resizeFactor, height: size.height/resizeFactor)
let resized = resizedImage(newSize: newSize)
return resized
}
}

用途;

let resizedImage = image.resizedImageWithinRect(rectSize: CGSize(width: 1900, height: 1900))

对于 Swift 4,我只是在 UIImage 上做一个引用 self 的扩展。

import UIKit
extension UIImage {
func resizeImage(targetSize: CGSize) -> UIImage {
let size = self.size
let widthRatio  = targetSize.width  / size.width
let heightRatio = targetSize.height / size.height
let newSize = widthRatio > heightRatio ?  CGSize(width: size.width * heightRatio, height: size.height * heightRatio) : CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)


UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


return newImage!
}
}

迅捷4版本

extension UIImage {
func resizeImage(_ newSize: CGSize) -> UIImage? {
func isSameSize(_ newSize: CGSize) -> Bool {
return size == newSize
}


func scaleImage(_ newSize: CGSize) -> UIImage? {
func getScaledRect(_ newSize: CGSize) -> CGRect {
let ratio   = max(newSize.width / size.width, newSize.height / size.height)
let width   = size.width * ratio
let height  = size.height * ratio
return CGRect(x: 0, y: 0, width: width, height: height)
}


func _scaleImage(_ scaledRect: CGRect) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(scaledRect.size, false, 0.0);
draw(in: scaledRect)
let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
UIGraphicsEndImageContext()
return image
}
return _scaleImage(getScaledRect(newSize))
}


return isSameSize(newSize) ? self : scaleImage(newSize)!
}
}

迅捷4,扩展版,边缘无白线。

似乎没有人提到,如果用非整数值调用 image.draw(),结果图像可能会在右边缘或底部边缘显示一个白线工件。

extension UIImage {


func scaled(with scale: CGFloat) -> UIImage? {
// size has to be integer, otherwise it could get white lines
let size = CGSize(width: floor(self.size.width * scale), height: floor(self.size.height * scale))
UIGraphicsBeginImageContext(size)
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}

Resizeimage 方法的调用

let image1 = resizeimage(image: myimage.image!, withSize: CGSize(width:200, height: 200))

调整图像大小的方法

func resizeimage(image:UIImage,withSize:CGSize) -> UIImage {
var actualHeight:CGFloat = image.size.height
var actualWidth:CGFloat = image.size.width
let maxHeight:CGFloat = withSize.height
let maxWidth:CGFloat = withSize.width
var imgRatio:CGFloat = actualWidth/actualHeight
let maxRatio:CGFloat = maxWidth/maxHeight
let compressionQuality = 0.5
if (actualHeight>maxHeight||actualWidth>maxWidth) {
if (imgRatio<maxRatio){
//adjust width according to maxHeight
imgRatio = maxHeight/actualHeight
actualWidth = imgRatio * actualWidth
actualHeight = maxHeight
}else if(imgRatio>maxRatio){
// adjust height according to maxWidth
imgRatio = maxWidth/actualWidth
actualHeight = imgRatio * actualHeight
actualWidth = maxWidth
}else{
actualHeight = maxHeight
actualWidth = maxWidth
}
}
let rec:CGRect = CGRect(x:0.0,y:0.0,width:actualWidth,height:actualHeight)
UIGraphicsBeginImageContext(rec.size)
image.draw(in: rec)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
let imageData = UIImageJPEGRepresentation(image, CGFloat(compressionQuality))
UIGraphicsEndImageContext()
let resizedimage = UIImage(data: imageData!)
return resizedimage!
}

迅捷4解决方案-

使用此函数

func image(with image: UIImage, scaledTo newSize: CGSize) -> UIImage {
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
drawingImageView.image = newImage
return newImage ?? UIImage()
}

调用函数:-

image(with: predictionImage, scaledTo: CGSize(width: 28.0, height: 28.0)

这里的28.0是要设置的像素大小

Swift 4.2版本的@KiritModi 问答

func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size


let widthRatio  = targetSize.width  / size.width
let heightRatio = targetSize.height / size.height


var newSize: CGSize
if(widthRatio > heightRatio) {
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
} else {
newSize = CGSize(width: size.width * widthRatio, height: size.height *      widthRatio)
}


let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)


UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()


return newImage!
}

细节

  • Xcode 10.2.1(10E1001) ,Swift 5

连结

解决方案

import UIKit
import CoreGraphics
import Accelerate


extension UIImage {


public enum ResizeFramework {
case uikit, coreImage, coreGraphics, imageIO, accelerate
}


/// Resize image with ScaleAspectFit mode and given size.
///
/// - Parameter dimension: width or length of the image output.
/// - Parameter resizeFramework: Technique for image resizing: UIKit / CoreImage / CoreGraphics / ImageIO / Accelerate.
/// - Returns: Resized image.


func resizeWithScaleAspectFitMode(to dimension: CGFloat, resizeFramework: ResizeFramework = .coreGraphics) -> UIImage? {


if max(size.width, size.height) <= dimension { return self }


var newSize: CGSize!
let aspectRatio = size.width/size.height


if aspectRatio > 1 {
// Landscape image
newSize = CGSize(width: dimension, height: dimension / aspectRatio)
} else {
// Portrait image
newSize = CGSize(width: dimension * aspectRatio, height: dimension)
}


return resize(to: newSize, with: resizeFramework)
}


/// Resize image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Parameter resizeFramework: Technique for image resizing: UIKit / CoreImage / CoreGraphics / ImageIO / Accelerate.
/// - Returns: Resized image.
public func resize(to newSize: CGSize, with resizeFramework: ResizeFramework = .coreGraphics) -> UIImage? {
switch resizeFramework {
case .uikit: return resizeWithUIKit(to: newSize)
case .coreGraphics: return resizeWithCoreGraphics(to: newSize)
case .coreImage: return resizeWithCoreImage(to: newSize)
case .imageIO: return resizeWithImageIO(to: newSize)
case .accelerate: return resizeWithAccelerate(to: newSize)
}
}


// MARK: - UIKit


/// Resize image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Returns: Resized image.
private func resizeWithUIKit(to newSize: CGSize) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(newSize, true, 1.0)
self.draw(in: CGRect(origin: .zero, size: newSize))
defer { UIGraphicsEndImageContext() }
return UIGraphicsGetImageFromCurrentImageContext()
}


// MARK: - CoreImage


/// Resize CI image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Returns: Resized image.
// https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html
private func resizeWithCoreImage(to newSize: CGSize) -> UIImage? {
guard let cgImage = cgImage, let filter = CIFilter(name: "CILanczosScaleTransform") else { return nil }


let ciImage = CIImage(cgImage: cgImage)
let scale = (Double)(newSize.width) / (Double)(ciImage.extent.size.width)


filter.setValue(ciImage, forKey: kCIInputImageKey)
filter.setValue(NSNumber(value:scale), forKey: kCIInputScaleKey)
filter.setValue(1.0, forKey: kCIInputAspectRatioKey)
guard let outputImage = filter.value(forKey: kCIOutputImageKey) as? CIImage else { return nil }
let context = CIContext(options: [.useSoftwareRenderer: false])
guard let resultCGImage = context.createCGImage(outputImage, from: outputImage.extent) else { return nil }
return UIImage(cgImage: resultCGImage)
}


// MARK: - CoreGraphics


/// Resize image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Returns: Resized image.
private func resizeWithCoreGraphics(to newSize: CGSize) -> UIImage? {
guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else { return nil }


let width = Int(newSize.width)
let height = Int(newSize.height)
let bitsPerComponent = cgImage.bitsPerComponent
let bytesPerRow = cgImage.bytesPerRow
let bitmapInfo = cgImage.bitmapInfo


guard let context = CGContext(data: nil, width: width, height: height,
bitsPerComponent: bitsPerComponent,
bytesPerRow: bytesPerRow, space: colorSpace,
bitmapInfo: bitmapInfo.rawValue) else { return nil }
context.interpolationQuality = .high
let rect = CGRect(origin: CGPoint.zero, size: newSize)
context.draw(cgImage, in: rect)


return context.makeImage().flatMap { UIImage(cgImage: $0) }
}


// MARK: - ImageIO


/// Resize image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Returns: Resized image.
private func resizeWithImageIO(to newSize: CGSize) -> UIImage? {
var resultImage = self


guard let data = jpegData(compressionQuality: 1.0) else { return resultImage }
let imageCFData = NSData(data: data) as CFData
let options = [
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceThumbnailMaxPixelSize: max(newSize.width, newSize.height)
] as CFDictionary
guard   let source = CGImageSourceCreateWithData(imageCFData, nil),
let imageReference = CGImageSourceCreateThumbnailAtIndex(source, 0, options) else { return resultImage }
resultImage = UIImage(cgImage: imageReference)


return resultImage
}


// MARK: - Accelerate


/// Resize image from given size.
///
/// - Parameter newSize: Size of the image output.
/// - Returns: Resized image.
private func resizeWithAccelerate(to newSize: CGSize) -> UIImage? {
var resultImage = self


guard let cgImage = cgImage, let colorSpace = cgImage.colorSpace else { return nil }


// create a source buffer
var format = vImage_CGImageFormat(bitsPerComponent: numericCast(cgImage.bitsPerComponent),
bitsPerPixel: numericCast(cgImage.bitsPerPixel),
colorSpace: Unmanaged.passUnretained(colorSpace),
bitmapInfo: cgImage.bitmapInfo,
version: 0,
decode: nil,
renderingIntent: .absoluteColorimetric)
var sourceBuffer = vImage_Buffer()
defer {
sourceBuffer.data.deallocate()
}


var error = vImageBuffer_InitWithCGImage(&sourceBuffer, &format, nil, cgImage, numericCast(kvImageNoFlags))
guard error == kvImageNoError else { return resultImage }


// create a destination buffer
let destWidth = Int(newSize.width)
let destHeight = Int(newSize.height)
let bytesPerPixel = cgImage.bitsPerPixel
let destBytesPerRow = destWidth * bytesPerPixel
let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: destHeight * destBytesPerRow)
defer {
destData.deallocate()
}
var destBuffer = vImage_Buffer(data: destData, height: vImagePixelCount(destHeight), width: vImagePixelCount(destWidth), rowBytes: destBytesPerRow)


// scale the image
error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, numericCast(kvImageHighQualityResampling))
guard error == kvImageNoError else { return resultImage }


// create a CGImage from vImage_Buffer
let destCGImage = vImageCreateCGImageFromBuffer(&destBuffer, &format, nil, nil, numericCast(kvImageNoFlags), &error)?.takeRetainedValue()
guard error == kvImageNoError else { return resultImage }


// create a UIImage
if let scaledImage = destCGImage.flatMap({ UIImage(cgImage: $0) }) {
resultImage = scaledImage
}


return resultImage
}
}

Usage

Get image size

import UIKit


// https://stackoverflow.com/a/55765409/4488252
extension UIImage {
func getFileSizeInfo(allowedUnits: ByteCountFormatter.Units = .useMB,
countStyle: ByteCountFormatter.CountStyle = .memory,
compressionQuality: CGFloat = 1.0) -> String? {
// https://developer.apple.com/documentation/foundation/bytecountformatter
let formatter = ByteCountFormatter()
formatter.allowedUnits = allowedUnits
formatter.countStyle = countStyle
return getSizeInfo(formatter: formatter, compressionQuality: compressionQuality)
}


func getSizeInfo(formatter: ByteCountFormatter, compressionQuality: CGFloat = 1.0) -> String? {
guard let imageData = jpegData(compressionQuality: compressionQuality) else { return nil }
return formatter.string(fromByteCount: Int64(imageData.count))
}
}

测试功能

private func test() {
guard let img = UIImage(named: "img") else { return }
printInfo(of: img, title: "original image |")
let dimension: CGFloat = 2000


var framework: UIImage.ResizeFramework = .accelerate
var startTime = Date()
if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
}


framework = .coreGraphics
startTime = Date()
if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
}


framework = .coreImage
startTime = Date()
if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
}


framework = .imageIO
startTime = Date()
if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
}


framework = .uikit
startTime = Date()
if let img = img.resizeWithScaleAspectFitMode(to: dimension, resizeFramework: framework) {
printInfo(of: img, title: "resized image |", with: framework, startedTime: startTime)
}
}


private func printInfo(of image: UIImage, title: String, with resizeFramework: UIImage.ResizeFramework? = nil, startedTime: Date? = nil) {
var description = "\(title) \(image.size)"
if let startedTime = startedTime { description += ", execution time: \(Date().timeIntervalSince(startedTime))" }
if let fileSize = image.getFileSizeInfo(compressionQuality: 0.9) { description += ", size: \(fileSize)" }
if let resizeFramework = resizeFramework { description += ", framework: \(resizeFramework)" }
print(description)
}

输出

original image | (5790.0, 8687.0), size: 17.1 MB
resized image | (1333.0, 2000.0), execution time: 0.8192930221557617, size: 1.1 MB, framework: accelerate
resized image | (1333.0, 2000.0), execution time: 0.44696998596191406, size: 1 MB, framework: coreGraphics
resized image | (1334.0, 2000.0), execution time: 54.172922015190125, size: 1.1 MB, framework: coreImage
resized image | (1333.0, 2000.0), execution time: 1.8765920400619507, size: 1.1 MB, framework: imageIO
resized image | (1334.0, 2000.0), execution time: 0.4638739824295044, size: 1 MB, framework: uikit

这里有一个通用的方法(在 Swift 5中)来缩放图像以适应尺寸。得到的图像可以具有与原始图像相同的纵横比,也可以是以原始图像为中心的目标大小。如果图像小于目标大小,则不调整其大小。

extension UIImage {
func scaledDown(into size:CGSize, centered:Bool = false) -> UIImage {
var (targetWidth, targetHeight) = (self.size.width, self.size.height)
var (scaleW, scaleH) = (1 as CGFloat, 1 as CGFloat)
if targetWidth > size.width {
scaleW = size.width/targetWidth
}
if targetHeight > size.height {
scaleH = size.height/targetHeight
}
let scale = min(scaleW,scaleH)
targetWidth *= scale; targetHeight *= scale
let sz = CGSize(width:targetWidth, height:targetHeight)
if !centered {
return UIGraphicsImageRenderer(size:sz).image { _ in
self.draw(in:CGRect(origin:.zero, size:sz))
}
}
let x = (size.width - targetWidth)/2
let y = (size.height - targetHeight)/2
let origin = CGPoint(x:x,y:y)
return UIGraphicsImageRenderer(size:size).image { _ in
self.draw(in:CGRect(origin:origin, size:sz))
}
}
}

更新了使用最新 UIGraphicsImageRenderer API 的 Swift 5版本。

extension UIImage {
public func resized(to target: CGSize) -> UIImage {
let ratio = min(
target.height / size.height, target.width / size.width
)
let new = CGSize(
width: size.width * ratio, height: size.height * ratio
)
let renderer = UIGraphicsImageRenderer(size: new)
return renderer.image { _ in
self.draw(in: CGRect(origin: .zero, size: new))
}
}
}

UIImage 扩展 Swift 5

extension UIImage {
func resize(_ width: CGFloat, _ height:CGFloat) -> UIImage? {
let widthRatio  = width / size.width
let heightRatio = height / size.height
let ratio = widthRatio > heightRatio ? heightRatio : widthRatio
let newSize = CGSize(width: size.width * ratio, height: size.height * ratio)
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
self.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}



用途: UIImage () . resize (200,300)

到目前为止,所有列出的答案似乎都导致图像尺寸缩小,但是尺寸并不是以像素来衡量的。这是 Swift 5,基于像素的调整大小

extension UIImage {
func resize(_ max_size: CGFloat) -> UIImage {
// adjust for device pixel density
let max_size_pixels = max_size / UIScreen.main.scale
// work out aspect ratio
let aspectRatio =  size.width/size.height
// variables for storing calculated data
var width: CGFloat
var height: CGFloat
var newImage: UIImage
if aspectRatio > 1 {
// landscape
width = max_size_pixels
height = max_size_pixels / aspectRatio
} else {
// portrait
height = max_size_pixels
width = max_size_pixels * aspectRatio
}
// create an image renderer of the correct size
let renderer = UIGraphicsImageRenderer(size: CGSize(width: width, height: height), format: UIGraphicsImageRendererFormat.default())
// render the image
newImage = renderer.image {
(context) in
self.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
}
// return the image
return newImage
}
}

用法:

image.resize(500)

For Swift 5.0 and iOS 12

extension UIImage {
func imageResized(to size: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size: size).image { _ in
draw(in: CGRect(origin: .zero, size: size))
}
}
}

用途:

let image = #imageLiteral(resourceName: "ic_search")
cell!.search.image = image.imageResized(to: cell!.search.frame.size)

Swift 5版本的比例(scaleTofill)和居中图像:

extension UIImage {
func resized(to newSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size: newSize).image { _ in
let hScale = newSize.height / size.height
let vScale = newSize.width / size.width
let scale = max(hScale, vScale) // scaleToFill
let resizeSize = CGSize(width: size.width*scale, height: size.height*scale)
var middle = CGPoint.zero
if resizeSize.width > newSize.width {
middle.x -= (resizeSize.width-newSize.width)/2.0
}
if resizeSize.height > newSize.height {
middle.y -= (resizeSize.height-newSize.height)/2.0
}
            

draw(in: CGRect(origin: middle, size: resizeSize))
}
}
}

SWIFT 5-XCODE 12——调整图像大小和无白线

I used a wonderful solution above for Swift 5. And I changed one bit to include the term "floor" as I was getting a white line around my resized images. This rounds it to the nearest pixel or something so it looks great! I also had to change the syntax around the image name when the function is called (last line).

//调整图像大小的方法

func resizeimage(image:UIImage,withSize:CGSize) -> UIImage {
var actualHeight:CGFloat = image.size.height
var actualWidth:CGFloat = image.size.width
let maxHeight:CGFloat = withSize.height
let maxWidth:CGFloat = withSize.width
var imgRatio:CGFloat = actualWidth/actualHeight
let maxRatio:CGFloat = maxWidth/maxHeight
let compressionQuality = 0.5
if (actualHeight>maxHeight||actualWidth>maxWidth) {
if (imgRatio<maxRatio){
//adjust width according to maxHeight
imgRatio = maxHeight/actualHeight
actualWidth = floor(imgRatio * actualWidth)
actualHeight = maxHeight
}else if(imgRatio>maxRatio){
// adjust height according to maxWidth
imgRatio = maxWidth/actualWidth
actualHeight = imgRatio * actualHeight
actualWidth = maxWidth
}else{
actualHeight = maxHeight
actualWidth = maxWidth
}
}
let rec:CGRect = CGRect(x:0.0,y:0.0,width:actualWidth,height:actualHeight)
UIGraphicsBeginImageContext(rec.size)
image.draw(in: rec)
let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
let imageData = UIImageJPEGRepresentation(image, CGFloat(compressionQuality))
UIGraphicsEndImageContext()
let resizedimage = UIImage(data: imageData!)
return resizedimage!
}

//调用 resizeimage 方法:

Let myimage = UIImage (命名为: “ imagename”)

let image1 = resizeimage(image: myimage!, withSize: CGSize(width:50, height: 50)).withRenderingMode(.alwaysOriginal)