How to crop wide images in swift without stretching - ios

I am having trouble cropping pictures taken to be of an exact size that is in the wide format. For instance I take a picture with an iPad front camera, which has the resolution of 960w,1280h and I need to crop to be exactly 875w,570h. I tried some of the methods in here, but they all stretch the image or don't get the size I want.
Here is the first method that I tried:
func cropToBounds(image: UIImage, width: Double, height: Double) -> UIImage {
let cgimage = image.cgImage!
let contextImage: UIImage = UIImage(cgImage: cgimage)
guard let newCgImage = contextImage.cgImage else { return contextImage }
let contextSize: CGSize = contextImage.size
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
let cropAspect: CGFloat = CGFloat(width / height)
var cropWidth: CGFloat = CGFloat(width)
var cropHeight: CGFloat = CGFloat(height)
if width > height { //Landscape
cropWidth = contextSize.width
cropHeight = contextSize.width / cropAspect
posY = (contextSize.height - cropHeight) / 2
} else if width < height { //Portrait
cropHeight = contextSize.height
cropWidth = contextSize.height * cropAspect
posX = (contextSize.width - cropWidth) / 2
} else { //Square
if contextSize.width >= contextSize.height { //Square on landscape (or square)
cropHeight = contextSize.height
cropWidth = contextSize.height * cropAspect
posX = (contextSize.width - cropWidth) / 2
}else{ //Square on portrait
cropWidth = contextSize.width
cropHeight = contextSize.width / cropAspect
posY = (contextSize.height - cropHeight) / 2
}
}
let rect: CGRect = CGRect(x: posX, y: posY, width: cropWidth, height: cropHeight)
// Create bitmap image from context using the rect
guard let imageRef: CGImage = newCgImage.cropping(to: rect) else { return contextImage}
// Create a new image based on the imageRef and rotate back to the original orientation
let cropped: UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)
print(image.scale)
UIGraphicsBeginImageContextWithOptions(CGSize(width: width, height: height), false, 0.0)
cropped.draw(in: CGRect(x: 0, y: 0, width: width, height: height))
let resized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resized ?? image
}
This always stretches the image.
I thought about trying to cut the exact size I wanted, so I tried this:
func cropImage(image: UIImage, width: Double, height: Double)->UIImage{
let cgimage = image.cgImage!
let contextImage: UIImage = UIImage(cgImage: cgimage)
let contextSize: CGSize = contextImage.size
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
var recWidth : CGFloat = CGFloat(width)
var recHeight : CGFloat = CGFloat(height)
if width > height { //Landscape
posY = (contextSize.height - recHeight) / 2
}
else { //Square
posX = (contextSize.width - recWidth) / 2
}
let rect: CGRect = CGRect(x: posX, y: posY, width: recWidth, height: recHeight)
let imageRef:CGImage = cgimage.cropping(to: rect)!
print(imageRef.width)
print(imageRef.height)
let croppedimage:UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)
print(croppedimage.size)
return croppedimage
}
But this resulted in an image with the opposite of what I want, 570w,875h. So I thought about inverting the values, but if I do that I get 605w, 570h. Maybe the problem is in how I get the X and Y positions of the image?
EDIT
Here is what I am doing now after the help of Leo Dabus:
extension UIImage {
func cropped(to size: CGSize) -> UIImage? {
guard let cgImage = cgImage?
.cropping(to: .init(origin: .init(x: (self.size.width-size.width)/2,
y: (self.size.height-size.height)/2),
size: size)) else { return nil }
let format = imageRendererFormat
return UIGraphicsImageRenderer(size: size, format: format).image {
_ in
UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
.draw(in: .init(origin: .zero, size: size))
}
}
}
This is how I call it:
let foto = UIImage(data: imageData)!
let size = CGSize(width: 875.0, height: 570.0)
let cropedPhoto = foto.cropped(to: size)
The imageData comes from a capture of the front camera.
And this is my capture code:
#objc func takePhoto(_ sender: Any?) {
let videoOrientation = AVCaptureVideoOrientation.portrait
stillImageOutput!.connection(with: .video)?.videoOrientation = videoOrientation
let settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])
let gesture = previewView.gestureRecognizers
previewView.removeGestureRecognizer(gesture![0])
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
guard let imageData = photo.fileDataRepresentation()
else { return }
}

You just need to get the original size width subtract the destination size width, divide by two and set the cropping origin x value. Next do the same with the height and set the y position. Then just initialize a new UIImage with the cropped cgImage:
extension UIImage {
func cropped(to size: CGSize) -> UIImage? {
guard let cgImage = cgImage?
.cropping(to: .init(origin: .init(x: (self.size.width - size.width) / 2,
y: (self.size.height - size.height) / 2),
size: size)) else { return nil }
return UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
}
}
let imageURL = URL(string: "https://www.comendochucruteesalsicha.com.br/wp-content/uploads/2016/09/IMG_5356-960x1280.jpg")!
let image = UIImage(data: try! Data(contentsOf: imageURL))!
let squared = image.cropped(to: .init(width: 875, height: 570))

Related

Profile tab bar image pixelated when set programatically on Swift

I am trying to set a profile image to the tab bar once downloaded from the user's db entry. To do so, I have to crop my image to 35x35 manually so that its not bigger than the bar using the following method:
func crop(to: CGSize) -> UIImage {
guard let cgimage = self.cgImage else { return self }
let contextImage: UIImage = UIImage(cgImage: cgimage)
guard let newCgImage = contextImage.cgImage else { return self }
let contextSize: CGSize = contextImage.size
//Set to square
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
let cropAspect: CGFloat = to.width / to.height
var cropWidth: CGFloat = to.width
var cropHeight: CGFloat = to.height
if to.width > to.height { //Landscape
cropWidth = contextSize.width
cropHeight = contextSize.width / cropAspect
posY = (contextSize.height - cropHeight) / 2
} else if to.width < to.height { //Portrait
cropHeight = contextSize.height
cropWidth = contextSize.height * cropAspect
posX = (contextSize.width - cropWidth) / 2
} else { //Square
if contextSize.width >= contextSize.height { //Square on landscape (or square)
cropHeight = contextSize.height
cropWidth = contextSize.height * cropAspect
posX = (contextSize.width - cropWidth) / 2
}else{ //Square on portrait
cropWidth = contextSize.width
cropHeight = contextSize.width / cropAspect
posY = (contextSize.height - cropHeight) / 2
}
}
let rect: CGRect = CGRect(x: posX, y: posY, width: cropWidth, height: cropHeight)
// Create bitmap image from context using the rect
guard let imageRef: CGImage = newCgImage.cropping(to: rect) else { return self}
// Create a new image based on the imageRef and rotate back to the original orientation
let cropped: UIImage = UIImage(cgImage: imageRef, scale: self.scale, orientation: self.imageOrientation)
UIGraphicsBeginImageContextWithOptions(to, false, self.scale)
cropped.draw(in: CGRect(x: 0, y: 0, width: to.width, height: to.height))
let resized = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return resized ?? self
}
Called on my "setViewControllers" method in the tab bar like so:
func setViewControllers() {
//.......
let profileImage: UIImage = (UserManager.current?.profileImage?.crop(to: CGSize(width: 35, height: 35)).roundedImage ?? #imageLiteral(resourceName: "profile_tab_bar_icon.png")).withRenderingMode(.alwaysOriginal)Ca
let profileNavBarController = createViewController(identifier: "ProfileNavigationController", storyboardName: "Profile", tabBarImage: profileImage)
profileNavBarController.tabBarItem.imageInsets = UIEdgeInsets(top: 9, left: 0, bottom: -9, right: 0)
self.viewControllers = [foo, bar, profileNavBarController]
}
Obviously, this does not manage for retina as I cannot set a #2X and #3X version. Hence, the image turns out to be pixelated in the tab bar:
I tried setting the image size to 70x70, which obviously returns an image that does not fit the tab bar. I also researched a way to create a UIImage object with #2X and #3X, but found nothing.
Any ideas on how I could solve this?
Add the following extension to your project, you can add after the ViewController.swift class ends.
extension UITabBarController {
func addSubviewToLastTabItem(_ imageName: String) {
if let lastTabBarButton = self.tabBar.subviews.last, let tabItemImageView = lastTabBarButton.subviews.first {
if let accountTabBarItem = self.tabBar.items?.last {
accountTabBarItem.selectedImage = nil
accountTabBarItem.image = nil
}
let imgView = UIImageView()
imgView.frame = tabItemImageView.frame
imgView.layer.cornerRadius = tabItemImageView.frame.height/2
imgView.layer.masksToBounds = true
imgView.contentMode = .scaleAspectFill
imgView.clipsToBounds = true
imgView.image = UIImage(named: imageName)
self.tabBar.subviews.last?.addSubview(imgView)
}
}
}
Now open ViewController.swift file add the following method:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.tabBarController?.addSubviewToLastTabItem("profile")
}
Reference Guide
I was having the same issue This one Worked!
extension UIImage {
func resize(targetSize: CGSize) -> UIImage {
return UIGraphicsImageRenderer(size:targetSize).image { _ in
self.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}
This is how to use it.
let profileImage: UIImage = (UserManager.current?.profileImage?..resize(targetSize: CGSize(width: 33, height: 33)).roundedImage ?? #imageLiteral(resourceName: "profile_tab_bar_icon.png")).withRenderingMode(.alwaysOriginal)
consider removing .roundedImage if it didint worked

How do change the size of an image (not the size of the file, not the size of an image view) in iOS? [duplicate]

I am making an app for iOS, using Swift and Parse.com
I am trying to let the user select a picture from an image picker and then resize the selected image to 200x200 pixels before uploading to my backend.
Parse.com have a tutorial for an Instagram copy app called "AnyPic" which gives this code for resizing images, but it is in 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?
And, what is the thumbnailImage function doing?
See my blog post, Resize image in swift and objective C, for further details.
Image resize function in swift as below.
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
}
Use the above function and resize image with 200*200 as below code
self.resizeImage(UIImage(named: "yourImageName")!, targetSize: CGSizeMake(200.0, 200.0))
swift3 updated
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!
}
Details
Xcode 10.2.1 (10E1001), Swift 5
Links
https://gist.github.com/eugenebokhan/5e62a0155754ae6aa6c3c13cf1744930
Image Resizing Techniques
Solution
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))
}
}
Test function
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)
}
Output
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
For Swift 4.0 and 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
}
}
Since #KiritModi 's answer is from 2015, this is the Swift 3.0's version:
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!
}
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))
}
}
}
use:
let image = #imageLiteral(resourceName: "ic_search")
cell!.search.image = image.imageResized(to: cell!.search.frame.size)
For Swift 4 I would just make an extension on UIImage with referencing to 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!
}
}
It's also possible to use AlamofireImage (https://github.com/Alamofire/AlamofireImage)
let size = CGSize(width: 30.0, height: 30.0)
let aspectScaledToFitImage = image.af_imageAspectScaled(toFit: size)
The function in the previous post gave me a blurry result.
Swift 3 Version and Extension style
This answer come from #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!
}
}
Updated Swift 5 version that uses the latest UIGraphicsImageRenderer API.
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))
}
}
}
Swift 4, extension version, NO WHITE LINE ON EDGES.
Nobody seems to be mentioning that if image.draw() is called with non-integer values, resulting image could show a white line artifact at the right or bottom edge.
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
}
Swift 5 version respecting ratio (scaleToFill) and centering image:
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 4 Version
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)!
}
}
UIImage Extension 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
}
}
Use :
UIImage().resize(200, 300)
All of the listed answers so far seem to result in an image of a reduced size, however the size isn't measured in pixels. Here's a Swift 5, pixel-based resize.
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
}
}
Usage:
image.resize(500)
Here's a general method (in Swift 5) for downscaling an image to fit a size. The resulting image can have the same aspect ratio as the original, or it can be the target size with the original image centered in it. If the image is smaller than the target size, it is not resized.
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))
}
}
}
Swift 4 Solution-
Use this function
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()
}
Calling a function:-
image(with: predictionImage, scaledTo: CGSize(width: 28.0, height: 28.0)
here 28.0 is the pixel size that you want to set
Swift 4.2 version of #KiritModi answer
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!
}
calling of resizeimage method
let image1 = resizeimage(image: myimage.image!, withSize: CGSize(width:200, height: 200))
method for resizeing image
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!
}
Here you have two simple functions of UIImage extension:
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
}
SWIFT 5 - XCODE 12 -- RESIZE IMAGE & No White line
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).
//method for resizing image
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!
}
//calling of resizeimage method:
let myimage = UIImage(named: "imagename")
let image1 = resizeimage(image: myimage!, withSize: CGSize(width:50, height: 50)).withRenderingMode(.alwaysOriginal)
Example is for image minimize to 1024 and less
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
}
}
You can use this for fit image at 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
}
}
Usage;
let resizedImage = image.resizedImageWithinRect(rectSize: CGSize(width: 1900, height: 1900))

Crop UIImage to center square

I get images that are in 1920x1080 resolution. I am attempting to crop them to the center square area (ie 1080x1080 square in the center). The resolution may change in the future. Would it be possible to crop the image this way? I have tried a couple things posted on SO, but I always get an image that is 660x1080 if I try to crop then center. Here is an image depicting what I want to achieve.
Basically the red is original, green is what I want, and yellow is just showing mixX and midY lines.
The code I tried.
func imageByCroppingImage(image: UIImage, toSize size: CGSize) -> UIImage{
let newCropWidth: CGFloat?
let newCropHeight: CGFloat?
if image.size.width < image.size.height {
if image.size.width < size.width {
newCropWidth = size.width
} else {
newCropWidth = image.size.width
}
newCropHeight = (newCropWidth! * size.height) / size.width
} else {
if image.size.height < size.height {
newCropHeight = size.height
} else {
newCropHeight = image.size.height
}
newCropWidth = (newCropHeight! * size.width) / size.height
}
let x = image.size.width / 2.0 - newCropWidth! / 2.0
let y = image.size.height / 2.0 - newCropHeight! / 2.0
let cropRect = CGRect(x: x, y: y, width: newCropWidth!, height: newCropHeight!)
let imageRef = image.cgImage!.cropping(to: cropRect)
let cropped = UIImage(cgImage: imageRef!, scale: 1.0, orientation: .right)
return cropped
}
And then I pass that method a CGSize(1080, 1080). I get an image that is 660, 1080. Any thoughts?
The intent is to crop the image, not to just display it centered.
You can use the same approach I used in this answer without the line UIBezierPath(ovalIn: breadthRect).addClip()
extension UIImage {
var isPortrait: Bool { size.height > size.width }
var isLandscape: Bool { size.width > size.height }
var breadth: CGFloat { min(size.width, size.height) }
var breadthSize: CGSize { .init(width: breadth, height: breadth) }
func squared(isOpaque: Bool = false) -> UIImage? {
guard let cgImage = cgImage?
.cropping(to: .init(origin: .init(x: isLandscape ? ((size.width-size.height)/2).rounded(.down) : 0,
y: isPortrait ? ((size.height-size.width)/2).rounded(.down) : 0),
size: breadthSize)) else { return nil }
let format = imageRendererFormat
format.opaque = isOpaque
return UIGraphicsImageRenderer(size: breadthSize, format: format).image { _ in
UIImage(cgImage: cgImage, scale: 1, orientation: imageOrientation)
.draw(in: .init(origin: .zero, size: breadthSize))
}
}
}
let imageURL = URL(string: "http://i.stack.imgur.com/Xs4RX.jpg")!
let image = UIImage(data: try! Data(contentsOf: imageURL))!
let squared = image.squared()

Swift 3: crop image

I want to crop images from the center with a specific width and height. I found this code in a SO issue but this method resize the image then it crop it. I want to only get my image cropped and not resized. I tried modifying this code but I can't get the result that I want.
//cropImage
func cropToBounds(image: UIImage, width: Double, height: Double) -> UIImage {
let contextImage: UIImage = UIImage(cgImage: image.cgImage!)
let contextSize: CGSize = contextImage.size
var posX: CGFloat = 0.0
var posY: CGFloat = 0.0
var cgwidth: CGFloat = CGFloat(width)
var cgheight: CGFloat = CGFloat(height)
// See what size is longer and create the center off of that
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
posY = 0
cgwidth = contextSize.height
cgheight = contextSize.height
} else {
posX = 0
posY = ((contextSize.height - contextSize.width) / 2)
cgwidth = contextSize.width
cgheight = contextSize.width
}
let rect: CGRect = CGRect(x: posX, y: posY, width: cgwidth, height: cgheight)
// Create bitmap image from context using the rect
let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!
// Create a new image based on the imageRef and rotate back to the original orientation
let image: UIImage = UIImage(cgImage: imageRef, scale: image.scale, orientation: image.imageOrientation)
return image
}
How can I do that?
It should be:
func cropImage(toRect rect:CGRect) -> UIImage? {
var rect = rect
rect.origin.y = rect.origin.y * self.scale
rect.origin.x = rect.origin.x * self.scale
rect.size.width = rect.width * self.scale
rect.size.height = rect.height * self.scale
guard let imageRef = self.cgImage?.cropping(to: rect) else {
return nil
}
let croppedImage = UIImage(cgImage:imageRef)
return croppedImage
}
Make sure image will be cropped in the center.
Include largest crop zone possible given by the width and height.
extension UIImage {
func crop(width: CGFloat = 60, height: CGFloat = 60) -> UIImage {
let scale = min(self.size.width / width, self.size.height / height)
let x = self.size.width > self.size.height
? (self.size.width - width * scale) / 2
: 0
let y = self.size.width > self.size.height
? 0
: (self.size.height - height * scale) / 2
let cropZone = CGRect(x: x, y: y, width: width * scale, height: height * scale)
guard let image: CGImage = self.cgImage?.cropping(to: cropZone) else { return UIImage() }
return UIImage(cgImage: image)
}
I am using this to display image which ratio is different from my frame, so I center it and crop the sides.
extension UIImage {
func cropTo(size: CGSize) -> UIImage {
guard let cgimage = self.cgImage else { return self }
let contextImage: UIImage = UIImage(cgImage: cgimage)
var cropWidth: CGFloat = size.width
var cropHeight: CGFloat = size.height
if (self.size.height < size.height || self.size.width < size.width){
return self
}
let heightPercentage = self.size.height/size.height
let widthPercentage = self.size.width/size.width
if (heightPercentage < widthPercentage) {
cropHeight = size.height*heightPercentage
cropWidth = size.width*heightPercentage
} else {
cropHeight = size.height*widthPercentage
cropWidth = size.width*widthPercentage
}
let posX: CGFloat = (self.size.width - cropWidth)/2
let posY: CGFloat = (self.size.height - cropHeight)/2
let rect: CGRect = CGRect(x: posX, y: posY, width: cropWidth, height: cropHeight)
// Create bitmap image from context using the rect
let imageRef: CGImage = contextImage.cgImage!.cropping(to: rect)!
// Create a new image based on the imageRef and rotate back to the original orientation
let cropped: UIImage = UIImage(cgImage: imageRef, scale: self.scale, orientation: self.imageOrientation)
return cropped
}
}

How to Resize image in Swift?

I am making an app for iOS, using Swift and Parse.com
I am trying to let the user select a picture from an image picker and then resize the selected image to 200x200 pixels before uploading to my backend.
Parse.com have a tutorial for an Instagram copy app called "AnyPic" which gives this code for resizing images, but it is in 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?
And, what is the thumbnailImage function doing?
See my blog post, Resize image in swift and objective C, for further details.
Image resize function in swift as below.
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
}
Use the above function and resize image with 200*200 as below code
self.resizeImage(UIImage(named: "yourImageName")!, targetSize: CGSizeMake(200.0, 200.0))
swift3 updated
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!
}
Details
Xcode 10.2.1 (10E1001), Swift 5
Links
https://gist.github.com/eugenebokhan/5e62a0155754ae6aa6c3c13cf1744930
Image Resizing Techniques
Solution
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))
}
}
Test function
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)
}
Output
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
For Swift 4.0 and 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
}
}
Since #KiritModi 's answer is from 2015, this is the Swift 3.0's version:
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!
}
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))
}
}
}
use:
let image = #imageLiteral(resourceName: "ic_search")
cell!.search.image = image.imageResized(to: cell!.search.frame.size)
For Swift 4 I would just make an extension on UIImage with referencing to 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!
}
}
It's also possible to use AlamofireImage (https://github.com/Alamofire/AlamofireImage)
let size = CGSize(width: 30.0, height: 30.0)
let aspectScaledToFitImage = image.af_imageAspectScaled(toFit: size)
The function in the previous post gave me a blurry result.
Swift 3 Version and Extension style
This answer come from #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!
}
}
Updated Swift 5 version that uses the latest UIGraphicsImageRenderer API.
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))
}
}
}
Swift 4, extension version, NO WHITE LINE ON EDGES.
Nobody seems to be mentioning that if image.draw() is called with non-integer values, resulting image could show a white line artifact at the right or bottom edge.
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
}
Swift 5 version respecting ratio (scaleToFill) and centering image:
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 4 Version
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)!
}
}
UIImage Extension 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
}
}
Use :
UIImage().resize(200, 300)
All of the listed answers so far seem to result in an image of a reduced size, however the size isn't measured in pixels. Here's a Swift 5, pixel-based resize.
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
}
}
Usage:
image.resize(500)
Here's a general method (in Swift 5) for downscaling an image to fit a size. The resulting image can have the same aspect ratio as the original, or it can be the target size with the original image centered in it. If the image is smaller than the target size, it is not resized.
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))
}
}
}
Swift 4 Solution-
Use this function
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()
}
Calling a function:-
image(with: predictionImage, scaledTo: CGSize(width: 28.0, height: 28.0)
here 28.0 is the pixel size that you want to set
Swift 4.2 version of #KiritModi answer
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!
}
calling of resizeimage method
let image1 = resizeimage(image: myimage.image!, withSize: CGSize(width:200, height: 200))
method for resizeing image
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!
}
Here you have two simple functions of UIImage extension:
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
}
SWIFT 5 - XCODE 12 -- RESIZE IMAGE & No White line
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).
//method for resizing image
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!
}
//calling of resizeimage method:
let myimage = UIImage(named: "imagename")
let image1 = resizeimage(image: myimage!, withSize: CGSize(width:50, height: 50)).withRenderingMode(.alwaysOriginal)
Example is for image minimize to 1024 and less
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
}
}
You can use this for fit image at 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
}
}
Usage;
let resizedImage = image.resizedImageWithinRect(rectSize: CGSize(width: 1900, height: 1900))

Resources