import Foundation
import UIKit
import QuartzCore
import CoreGraphics
import Accelerate
public enum UIImageContentMode {
case scaleToFill, scaleAspectFit, scaleAspectFill
}
public extension UIImage {
/**
A singleton shared NSURL cache used for images from URL
*/
static var shared: NSCache<AnyObject, AnyObject>! {
struct StaticSharedCache {
static var shared: NSCache<AnyObject, AnyObject>? = NSCache()
}
return StaticSharedCache.shared!
}
// MARK: Image from solid color/**
Creates a new solid color image.
- Parameter color: The color to fill the image with.
- Parameter size: Image size (defaults: 10x10)
- Returns A new image
*/
convenience init?(color: UIColor, size: CGSize = CGSize(width: 10, height: 10)) {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(color.cgColor)
context?.fill(rect)
self.init(cgImage:(UIGraphicsGetImageFromCurrentImageContext()?.cgImage!)!)
UIGraphicsEndImageContext()
}
// MARK: Image from gradient colors/**
Creates a gradient color image.
- Parameter gradientColors: An array of colors to use for the gradient.
- Parameter size: Image size (defaults: 10x10)
- Returns A new image
*/
convenience init?(gradientColors:[UIColor], size:CGSize = CGSize(width: 10, height: 10), locations: [Float] = [] )
{
UIGraphicsBeginImageContextWithOptions(size, false, 0)
let context = UIGraphicsGetCurrentContext()
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colors = gradientColors.map {(color: UIColor) -> AnyObject! in return color.cgColor as AnyObject! } as NSArray
let gradient: CGGradient
if locations.count > 0 {
let cgLocations = locations.map { CGFloat($0) }
gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: cgLocations)!
} else {
gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: nil)!
}
context!.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: size.height), options: CGGradientDrawingOptions(rawValue: 0))
self.init(cgImage:(UIGraphicsGetImageFromCurrentImageContext()?.cgImage!)!)
UIGraphicsEndImageContext()
}
/**
Applies gradient color overlay to an image.
- Parameter gradientColors: An array of colors to use for the gradient.
- Parameter locations: An array of locations to use for the gradient.
- Parameter blendMode: The blending type to use.
- Returns A new image
*/
func apply(gradientColors: [UIColor], locations: [Float] = [], blendMode: CGBlendMode = CGBlendMode.normal) -> UIImage
{
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0, y: size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.setBlendMode(blendMode)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
context?.draw(self.cgImage!, in: rect)
// Create gradient
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colors = gradientColors.map {(color: UIColor) -> AnyObject! in return color.cgColor as AnyObject! } as NSArray
let gradient: CGGradient
if locations.count > 0 {
let cgLocations = locations.map { CGFloat($0) }
gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: cgLocations)!
} else {
gradient = CGGradient(colorsSpace: colorSpace, colors: colors, locations: nil)!
}
// Apply gradient
context?.clip(to: rect, mask: self.cgImage!)
context?.drawLinearGradient(gradient, start: CGPoint(x: 0, y: 0), end: CGPoint(x: 0, y: size.height), options: CGGradientDrawingOptions(rawValue: 0))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return image!;
}
// MARK: Image with Text/**
Creates a text label image.
- Parameter text: The text to use in the label.
- Parameter font: The font (default: System font of size 18)
- Parameter color: The text color (default: White)
- Parameter backgroundColor: The background color (default:Gray).
- Parameter size: Image size (default: 10x10)
- Parameter offset: Center offset (default: 0x0)
- Returns A new image
*/
convenience init?(text: String, font: UIFont = UIFont.systemFont(ofSize: 18), color: UIColor = UIColor.white, backgroundColor: UIColor = UIColor.gray, size: CGSize = CGSize(width: 100, height: 100), offset: CGPoint = CGPoint(x: 0, y: 0)) {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
label.font = font
label.text = text
label.textColor = color
label.textAlignment = .center
label.backgroundColor = backgroundColor
let image = UIImage(fromView: label)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
image?.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
self.init(cgImage:(UIGraphicsGetImageFromCurrentImageContext()?.cgImage!)!)
UIGraphicsEndImageContext()
}
// MARK: Image from UIView/**
Creates an image from a UIView.
- Parameter fromView: The source view.
- Returns A new image
*/
convenience init?(fromView view: UIView) {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0)
//view.drawViewHierarchyInRect(view.bounds, afterScreenUpdates: true)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
self.init(cgImage:(UIGraphicsGetImageFromCurrentImageContext()?.cgImage!)!)
UIGraphicsEndImageContext()
}
// MARK: Image with Radial Gradient// Radial background originally from: http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html/**
Creates a radial gradient.
- Parameter startColor: The start color
- Parameter endColor: The end color
- Parameter radialGradientCenter: The gradient center (default:0.5,0.5).
- Parameter radius: Radius size (default: 0.5)
- Parameter size: Image size (default: 100x100)
- Returns A new image
*/
convenience init?(startColor: UIColor, endColor: UIColor, radialGradientCenter: CGPoint = CGPoint(x: 0.5, y: 0.5), radius: Float = 0.5, size: CGSize = CGSize(width: 100, height: 100)) {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let num_locations: Int = 2
let locations: [CGFloat] = [0.0, 1.0] as [CGFloat]
let startComponents = startColor.cgColor.components!
let endComponents = endColor.cgColor.components!
let components: [CGFloat] = [startComponents[0], startComponents[1], startComponents[2], startComponents[3], endComponents[0], endComponents[1], endComponents[2], endComponents[3]]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorSpace: colorSpace, colorComponents: components, locations: locations, count: num_locations)
// Normalize the 0-1 ranged inputs to the width of the image
let aCenter = CGPoint(x: radialGradientCenter.x * size.width, y: radialGradientCenter.y * size.height)
let aRadius = CGFloat(min(size.width, size.height)) * CGFloat(radius)
// Draw it
UIGraphicsGetCurrentContext()?.drawRadialGradient(gradient!, startCenter: aCenter, startRadius: 0, endCenter: aCenter, endRadius: aRadius, options: CGGradientDrawingOptions.drawsAfterEndLocation)
self.init(cgImage:(UIGraphicsGetImageFromCurrentImageContext()?.cgImage!)!)
// Clean up
UIGraphicsEndImageContext()
}
// MARK: Alpha/**
Returns true if the image has an alpha layer.
*/var hasAlpha: Bool {
let alpha: CGImageAlphaInfo = self.cgImage!.alphaInfo
switch alpha {
case .first, .last, .premultipliedFirst, .premultipliedLast:
returntruedefault:
returnfalse
}
}
/**
Returns a copy of the given image, adding an alpha channel if it doesn't already have one.
*/
func applyAlpha() -> UIImage? {
if hasAlpha {
return self
}
let imageRef = self.cgImage;
let width = imageRef?.width;
let height = imageRef?.height;
let colorSpace = imageRef?.colorSpace
// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo().rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
let offscreenContext = CGContext(data: nil, width: width!, height: height!, bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace!, bitmapInfo: bitmapInfo.rawValue)
// Draw the image into the context and retrieve the new image, which will now have an alpha layer
let rect: CGRect = CGRect(x: 0, y: 0, width: CGFloat(width!), height: CGFloat(height!))
offscreenContext?.draw(imageRef!, in: rect)
let imageWithAlpha = UIImage(cgImage: (offscreenContext?.makeImage()!)!)
return imageWithAlpha
}
/**
Returns a copy of the image with a transparent border of the given size added around its edges. i.e. For rotating an image without getting jagged edges.
- Parameter padding: The padding amount.
- Returns A new image.
*/
func apply(padding: CGFloat) -> UIImage? {
// If the image does not have an alpha layer, add one
let image = self.applyAlpha()
if image == nil {
return nil
}
let rect = CGRect(x: 0, y: 0, width: size.width + padding * 2, height: size.height + padding * 2)
// Build a context that's the same dimensions as the new size
let colorSpace = self.cgImage?.colorSpace
let bitmapInfo = self.cgImage?.bitmapInfo
let bitsPerComponent = self.cgImage?.bitsPerComponent
let context = CGContext(data: nil, width: Int(rect.size.width), height: Int(rect.size.height), bitsPerComponent: bitsPerComponent!, bytesPerRow: 0, space: colorSpace!, bitmapInfo: (bitmapInfo?.rawValue)!)
// Draw the image in the center of the context, leaving a gap around the edges
let imageLocation = CGRect(x: padding, y: padding, width: image!.size.width, height: image!.size.height)
context?.draw(self.cgImage!, in: imageLocation)
// Create a mask to make the border transparent, and combine it with the imag