Permalink
259 lines (217 sloc) 9.74 KB
//
// UIImageExtensions.swift
// SwifterSwift
//
// Created by Omar Albeik on 8/6/16.
// Copyright © 2016 SwifterSwift
//
#if canImport(UIKit)
import UIKit
// MARK: - Properties
public extension UIImage {
/// SwifterSwift: Size in bytes of UIImage
public var bytesSize: Int {
return jpegData(compressionQuality: 1)?.count ?? 0
}
/// SwifterSwift: Size in kilo bytes of UIImage
public var kilobytesSize: Int {
return bytesSize / 1024
}
/// SwifterSwift: UIImage with .alwaysOriginal rendering mode.
public var original: UIImage {
return withRenderingMode(.alwaysOriginal)
}
/// SwifterSwift: UIImage with .alwaysTemplate rendering mode.
public var template: UIImage {
return withRenderingMode(.alwaysTemplate)
}
}
// MARK: - Methods
public extension UIImage {
/// SwifterSwift: Compressed UIImage from original UIImage.
///
/// - Parameter quality: The quality of the resulting JPEG image, expressed as a value from 0.0 to 1.0. The value 0.0 represents the maximum compression (or lowest quality) while the value 1.0 represents the least compression (or best quality), (default is 0.5).
/// - Returns: optional UIImage (if applicable).
public func compressed(quality: CGFloat = 0.5) -> UIImage? {
guard let data = compressedData(quality: quality) else { return nil }
return UIImage(data: data)
}
/// SwifterSwift: Compressed UIImage data from original UIImage.
///
/// - Parameter quality: The quality of the resulting JPEG image, expressed as a value from 0.0 to 1.0. The value 0.0 represents the maximum compression (or lowest quality) while the value 1.0 represents the least compression (or best quality), (default is 0.5).
/// - Returns: optional Data (if applicable).
public func compressedData(quality: CGFloat = 0.5) -> Data? {
return jpegData(compressionQuality: quality)
}
/// SwifterSwift: UIImage Cropped to CGRect.
///
/// - Parameter rect: CGRect to crop UIImage to.
/// - Returns: cropped UIImage
public func cropped(to rect: CGRect) -> UIImage {
guard rect.size.width < size.width && rect.size.height < size.height else { return self }
guard let image: CGImage = cgImage?.cropping(to: rect) else { return self }
return UIImage(cgImage: image)
}
/// SwifterSwift: UIImage scaled to height with respect to aspect ratio.
///
/// - Parameters:
/// - toHeight: new height.
/// - opaque: flag indicating whether the bitmap is opaque.
/// - Returns: optional scaled UIImage (if applicable).
public func scaled(toHeight: CGFloat, opaque: Bool = false) -> UIImage? {
let scale = toHeight / size.height
let newWidth = size.width * scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: toHeight), opaque, 0)
draw(in: CGRect(x: 0, y: 0, width: newWidth, height: toHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
/// SwifterSwift: UIImage scaled to width with respect to aspect ratio.
///
/// - Parameters:
/// - toWidth: new width.
/// - opaque: flag indicating whether the bitmap is opaque.
/// - Returns: optional scaled UIImage (if applicable).
public func scaled(toWidth: CGFloat, opaque: Bool = false) -> UIImage? {
let scale = toWidth / size.width
let newHeight = size.height * scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: toWidth, height: newHeight), opaque, 0)
draw(in: CGRect(x: 0, y: 0, width: toWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
/// SwifterSwift: Creates a copy of the receiver rotated by the given angle.
///
/// // Rotate the image by 180°
/// image.rotated(by: Measurement(value: 180, unit: .degrees))
///
/// - Parameter angle: The angle measurement by which to rotate the image.
/// - Returns: A new image rotated by the given angle.
@available(iOS 10.0, tvOS 10.0, watchOS 3.0, *)
public func rotated(by angle: Measurement<UnitAngle>) -> UIImage? {
let radians = CGFloat(angle.converted(to: .radians).value)
let destRect = CGRect(origin: .zero, size: size)
.applying(CGAffineTransform(rotationAngle: radians))
let roundedDestRect = CGRect(x: destRect.origin.x.rounded(),
y: destRect.origin.y.rounded(),
width: destRect.width.rounded(),
height: destRect.height.rounded())
UIGraphicsBeginImageContext(roundedDestRect.size)
guard let contextRef = UIGraphicsGetCurrentContext() else { return nil }
contextRef.translateBy(x: roundedDestRect.width / 2, y: roundedDestRect.height / 2)
contextRef.rotate(by: radians)
draw(in: CGRect(origin: CGPoint(x: -size.width / 2,
y: -size.height / 2),
size: size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
/// SwifterSwift: Creates a copy of the receiver rotated by the given angle (in radians).
///
/// // Rotate the image by 180°
/// image.rotated(by: .pi)
///
/// - Parameter radians: The angle, in radians, by which to rotate the image.
/// - Returns: A new image rotated by the given angle.
public func rotated(by radians: CGFloat) -> UIImage? {
let destRect = CGRect(origin: .zero, size: size)
.applying(CGAffineTransform(rotationAngle: radians))
let roundedDestRect = CGRect(x: destRect.origin.x.rounded(),
y: destRect.origin.y.rounded(),
width: destRect.width.rounded(),
height: destRect.height.rounded())
UIGraphicsBeginImageContext(roundedDestRect.size)
guard let contextRef = UIGraphicsGetCurrentContext() else { return nil }
contextRef.translateBy(x: roundedDestRect.width / 2, y: roundedDestRect.height / 2)
contextRef.rotate(by: radians)
draw(in: CGRect(origin: CGPoint(x: -size.width / 2,
y: -size.height / 2),
size: size))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
/// SwifterSwift: UIImage filled with color
///
/// - Parameter color: color to fill image with.
/// - Returns: UIImage filled with given color.
public func filled(withColor color: UIColor) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
color.setFill()
guard let context = UIGraphicsGetCurrentContext() else { return self }
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.setBlendMode(CGBlendMode.normal)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
guard let mask = cgImage else { return self }
context.clip(to: rect, mask: mask)
context.fill(rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
/// SwifterSwift: UIImage tinted with color
///
/// - Parameters:
/// - color: color to tint image with.
/// - blendMode: how to blend the tint
/// - Returns: UIImage tinted with given color.
public func tint(_ color: UIColor, blendMode: CGBlendMode) -> UIImage {
let drawRect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
context!.clip(to: drawRect, mask: cgImage!)
color.setFill()
UIRectFill(drawRect)
draw(in: drawRect, blendMode: blendMode, alpha: 1.0)
let tintedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return tintedImage!
}
/// SwifterSwift: UIImage with rounded corners
///
/// - Parameters:
/// - radius: corner radius (optional), resulting image will be round if unspecified
/// - Returns: UIImage with all corners rounded
public func withRoundedCorners(radius: CGFloat? = nil) -> UIImage? {
let maxRadius = min(size.width, size.height) / 2
let cornerRadius: CGFloat
if let radius = radius, radius > 0 && radius <= maxRadius {
cornerRadius = radius
} else {
cornerRadius = maxRadius
}
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let rect = CGRect(origin: .zero, size: size)
UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
draw(in: rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
// MARK: - Initializers
public extension UIImage {
/// SwifterSwift: Create UIImage from color and size.
///
/// - Parameters:
/// - color: image fill color.
/// - size: image size.
public convenience init(color: UIColor, size: CGSize) {
UIGraphicsBeginImageContextWithOptions(size, false, 1)
defer {
UIGraphicsEndImageContext()
}
color.setFill()
UIRectFill(CGRect(origin: .zero, size: size))
guard let aCgImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage else {
self.init()
return
}
self.init(cgImage: aCgImage)
}
}
#endif