Add Tabbar Item Image from one UIImage issue - ios

I'm Newbie in Swift.
I have a question.
When I add Tabbar Item image from one UIImage, then Nothing show up.
Although, Not in Tabbar Item, Image appear well and image that load from asset to tab bar item works well.
I already resize that thing, and not in tab bar, that resized image load well.
So, I'm so confused how to do that.
Here is my codes
This is load from Facebook profile picture
FBSDKGraphRequest(graphPath: "/me", parameters: ["fields": "email, id, name, picture"]).start { (connection, result, err) in
if err != nil {
print("FBLogin Error: \(err)")
return
}
print(result!)
let dd = result as! [String : AnyObject]
let test = (dd["picture"]!["data"]!! as! [String: AnyObject])["url"]
let url = URL(string: test as! String)
let data_picture = try? Data(contentsOf: url!)
var temp_img = UIImage()
temp_img = UIImage(data: data_picture!)!
temp_tabbar_profile = self.resizeImage(image: temp_img, targetSize: CGSize(width: 30, height: 30))
temp_tabbar_profile is UIImage
And This is resize code.
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!
}
This is set tab bar image code
override func viewDidLoad() {
super.viewDidLoad()
let tabBarItems = tabBar.items! as [UITabBarItem]
tabBarItems[0].selectedImage = temp_tabbar_profile
tabBarItems[0].image = temp_tabbar_profile
tabBarItems[0].title = ""
}
When I run app, then just gray picture appeared.
When I load this temp_tabbar_profile in other view's image view.image,
loaded well!!!
I don't know what is wrong.
Thank you for reading my problem.

You should use tabBarItems[0].image = temp_tabbar_profile.withRenderingMode(.alwaysOriginal). Or the UITabBar will display your image in a abstract way.

Related

Load image to Tab Bar Item from server

I loaded an image from the server and tried to put it on a UITabBarItem, but it just shows a grey square. I already set image render mode to original but does not work...
thank you for your help
downloader.imageDownloader?.downloadImage(with: URL(string: GlobalSetting().initUser().photoPath)!, options: .highPriority, progress: { (receivedSize, expectedSize, url) in
print(receivedSize as Int)
}, completed: { (image, data, error, success) in
let newImage = image?.resizeImageWith(newSize: CGSize(width: 20, height: 20))
newImage?.withRenderingMode(.alwaysOriginal)
self.tabBar.items![1].image = newImage
})
GlobalSetting is where I'm saving URL photo "http://api.humancloudz.com/photo/comp_abc/avatar-A18002.png"
I don't know where is the problem in your code as I see only part of it. I tried to create TabBarController, tried to load image in viewDidAppear and everything works fine. Try my code
class TabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard let url = URL(string: "https://homepages.cae.wisc.edu/~ece533/images/airplane.png") else { return }
let data = try! Data(contentsOf: url)
let image = UIImage(data: data)!
let resized = resizeImage(image: image, targetSize: CGSize(width: 20, height: 20))?.withRenderingMode(.alwaysOriginal)
tabBar.items![0].image = resized
tabBar.items![1].image = resized
}
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
}
}
Hope it will be helpful
Can you try adding DispatchQueue.main.async when you set the image, like:
downloader.imageDownloader?.downloadImage(with: URL(string: GlobalSetting().initUser().photoPath)!, options: .highPriority, progress: { (receivedSize, expectedSize, url) in
print(receivedSize as Int)
}, completed: { (image, data, error, success) in
let newImage = image?.resizeImageWith(newSize: CGSize(width: 20, height: 20))
newImage?.withRenderingMode(.alwaysOriginal)
DispatchQueue.main.async {
self.tabBar.items![1].image = newImage
}
})

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

Quality of photo being lost when Uploading to Firebase Swift 4

I have tried
if let uploadData = UIImageJPEGRepresentation(uploadImage, 0.9){
let subFileName = NSUUID().uuidString
storageRef.child("\(subFileName)").putData(uploadData, metadata: nil, completion: { (data , error) in
if error != nil{
print(error!)
}
})
I have also tried
UIImagePNGRepresentation(uploadImage)
both of which do not produce the original quality image , the only thing that changes is the size in firebase storage... I have also tried changing the image with a cgSize change
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
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!
}
yet none of this has helped :( how can I fix this?
I know the image quality is bad because when I load it from download url in firebase console the quality is bad.. Thanks for the help!!

UIImage resizing via an extension

I have this UIImage resizing extension
extension UIImage {
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!
}
}
I tried to resize an image by calling the extension like below
let logoView: UIImageView = {
let LV = UIImageView()
let thumbnail = resizeImage(image: "DN", CGSize.init(width:70, height:70))
LV.image = thumbnail
LV.contentMode = .scaleAspectFill
LV.layer.masksToBounds = true
return LV
}()
However the Xcode is not allowing me to call the resizing function extension. How can I properly resize the image?
func setupViews() {
addSubview(logoView)
}
Functions in extensions are not standalone functions but tied to the thing they extend. In your case, you're adding a function to UIImage but you are calling it like a standalone function.
To fix, your function should be like this:
extension UIImage {
func resizeImage(targetSize: CGSize) -> UIImage {
// the image is now “self” and not “image” as you original wrote
...
}
}
and you would call it like:
let logoView: UIImageView = {
let LV = UIImageView()
let image = UIImage(named: "DN")
if let image = image {
let thumbnail = image.resizeImage(CGSize.init(width:70, height:70))
LV.image = thumbnail
LV.contentMode = .scaleAspectFill
LV.layer.masksToBounds = true
}
return LV
}()

iOS: Get displayed image size in pixels

In my app, I'm displaying an image of a rectangle from the assets library. The image is 100x100 pixels. I'm only using the 1x slot for this asset.
I want to display this image at 300x300 pixels. Doing this using points is quite simple but I can't figure out how to get UIImageView to set the size in pixels.
Alternatively, if I can't set the size in pixels to display, I'd like to get the size in pixels that the image is being displayed.
I have tried using .scale on the UIImageView and UIImage instances, but it's always 1. Even though I have set constraints to 150 and 300.
To get size in pixels of UIImageView:
let widthInPixels = imageView.frame.width * UIScreen.mainScreen().scale
let heightInPixels = imageView.frame.height * UIScreen.mainScreen().scale
To get size in pixels of UIImage:
let widthInPixels = image.size.width * image.scale
let heightInPixels = image.size.height * image.scale
Swift 5
Take a Look here
// This extension to save ImageView as UImage
extension UIView {
func asImage() -> UIImage {
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { rendererContext in
layer.render(in: rendererContext.cgContext)
}
}
}
// this extension to resize image
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!
}
}
// This extension will display image with 300X300 pixels
extension UIImage {
func Size300X300() -> UIImage? {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
let image = imageView.asImage()
let newImage = image.resizeImage(targetSize: CGSize(width:300, height: 300))
return newImage
}
}
let image = YOURIMAGE.Size300X300()
imageView.image = image!

Resources