Merge pull request #19 from TouchInstinct/image/roundcorners

image extension added
This commit is contained in:
Nikolai Ashanin 2016-09-29 18:13:02 +03:00 committed by GitHub
commit 823bbd54fe
17 changed files with 720 additions and 26 deletions

BIN
LeadKit/.DS_Store vendored

Binary file not shown.

View File

@ -51,6 +51,13 @@
78CFEE5B1C5C45E500F50370 /* ViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78CFEE501C5C45E500F50370 /* ViewModelProtocol.swift */; };
78E59B191C773EE600C6BFE9 /* ObjectsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B181C773EE600C6BFE9 /* ObjectsGenerator.swift */; };
78E59B1B1C77470A00C6BFE9 /* ViewsGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78E59B1A1C77470A00C6BFE9 /* ViewsGenerator.swift */; };
95B39A781D9BFCC30057BD54 /* UIImageView+LoadingImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A771D9BFCC30057BD54 /* UIImageView+LoadingImage.swift */; };
95B39A7A1D9BFD550057BD54 /* UIImage+Loading.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A791D9BFD550057BD54 /* UIImage+Loading.swift */; };
95B39A7C1D9C05260057BD54 /* UIImage+Gradients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A7B1D9C05260057BD54 /* UIImage+Gradients.swift */; };
95B39A7E1D9C069B0057BD54 /* UIImage+Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A7D1D9C069B0057BD54 /* UIImage+Text.swift */; };
95B39A801D9C09440057BD54 /* UIImage+Cropping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A7F1D9C09440057BD54 /* UIImage+Cropping.swift */; };
95B39A841D9C0C3E0057BD54 /* UIImage+Alpha.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A831D9C0C3E0057BD54 /* UIImage+Alpha.swift */; };
95B39A861D9D51250057BD54 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B39A851D9D51250057BD54 /* String+Localization.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -111,6 +118,13 @@
78CFEE501C5C45E500F50370 /* ViewModelProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewModelProtocol.swift; sourceTree = "<group>"; };
78E59B181C773EE600C6BFE9 /* ObjectsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjectsGenerator.swift; sourceTree = "<group>"; };
78E59B1A1C77470A00C6BFE9 /* ViewsGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewsGenerator.swift; sourceTree = "<group>"; };
95B39A771D9BFCC30057BD54 /* UIImageView+LoadingImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImageView+LoadingImage.swift"; path = "UIImageView/UIImageView+LoadingImage.swift"; sourceTree = "<group>"; };
95B39A791D9BFD550057BD54 /* UIImage+Loading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Loading.swift"; sourceTree = "<group>"; };
95B39A7B1D9C05260057BD54 /* UIImage+Gradients.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Gradients.swift"; sourceTree = "<group>"; };
95B39A7D1D9C069B0057BD54 /* UIImage+Text.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Text.swift"; sourceTree = "<group>"; };
95B39A7F1D9C09440057BD54 /* UIImage+Cropping.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Cropping.swift"; sourceTree = "<group>"; };
95B39A831D9C0C3E0057BD54 /* UIImage+Alpha.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Alpha.swift"; sourceTree = "<group>"; };
95B39A851D9D51250057BD54 /* String+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -204,6 +218,7 @@
isa = PBXGroup;
children = (
787783661CA04D4A001CDC9B /* String+SizeCalculation.swift */,
95B39A851D9D51250057BD54 /* String+Localization.swift */,
);
path = String;
sourceTree = "<group>";
@ -289,6 +304,7 @@
78CFEE441C5C45E500F50370 /* Extensions */ = {
isa = PBXGroup;
children = (
95B39A761D9BFC930057BD54 /* UIImageView */,
78C36F7F1D8021D100E7EBEA /* UIColor */,
78C36F7C1D801E2F00E7EBEA /* Double */,
787783651CA04D14001CDC9B /* String */,
@ -347,6 +363,14 @@
path = UIView;
sourceTree = "<group>";
};
95B39A761D9BFC930057BD54 /* UIImageView */ = {
isa = PBXGroup;
children = (
95B39A771D9BFCC30057BD54 /* UIImageView+LoadingImage.swift */,
);
name = UIImageView;
sourceTree = "<group>";
};
C37210711ACDF1042F70C2EB /* UIImage */ = {
isa = PBXGroup;
children = (
@ -355,6 +379,11 @@
78C36F761D80117D00E7EBEA /* UIImage+Transformations.swift */,
78C36F781D8011FA00E7EBEA /* UIImage+Resize.swift */,
78C36F7A1D8015ED00E7EBEA /* UIImage+Creation.swift */,
95B39A791D9BFD550057BD54 /* UIImage+Loading.swift */,
95B39A7B1D9C05260057BD54 /* UIImage+Gradients.swift */,
95B39A7D1D9C069B0057BD54 /* UIImage+Text.swift */,
95B39A7F1D9C09440057BD54 /* UIImage+Cropping.swift */,
95B39A831D9C0C3E0057BD54 /* UIImage+Alpha.swift */,
);
path = UIImage;
sourceTree = "<group>";
@ -385,13 +414,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 78CFEE3E1C5C456B00F50370 /* Build configuration list for PBXNativeTarget "LeadKit" */;
buildPhases = (
782B1B3D1C7343CD003F8A95 /* Tailor */,
782B1B3E1C7343E0003F8A95 /* SwiftLint */,
78CFEE251C5C456B00F50370 /* Sources */,
78CFEE261C5C456B00F50370 /* Frameworks */,
78CFEE271C5C456B00F50370 /* Headers */,
78CFEE281C5C456B00F50370 /* Resources */,
78B0FC871C6B314B00358B64 /* Carthage copy-frameworks */,
782B1B3D1C7343CD003F8A95 /* Tailor */,
782B1B3E1C7343E0003F8A95 /* SwiftLint */,
);
buildRules = (
);
@ -540,12 +569,16 @@
787783671CA04D4A001CDC9B /* String+SizeCalculation.swift in Sources */,
78011A641D47ABC500EA16A2 /* UIView+DefaultReuseIdentifier.swift in Sources */,
78CFEE531C5C45E500F50370 /* UITableView+DequeueCustomCell.swift in Sources */,
95B39A781D9BFCC30057BD54 /* UIImageView+LoadingImage.swift in Sources */,
786D78EC1D53C46E006B2CEA /* AlamofireManager+Extensions.swift in Sources */,
95B39A841D9C0C3E0057BD54 /* UIImage+Alpha.swift in Sources */,
95B39A801D9C09440057BD54 /* UIImage+Cropping.swift in Sources */,
78E59B1B1C77470A00C6BFE9 /* ViewsGenerator.swift in Sources */,
78B0FC811C6B2CD500358B64 /* App.swift in Sources */,
78C36F771D80117D00E7EBEA /* UIImage+Transformations.swift in Sources */,
786D78EA1D53C43E006B2CEA /* ApiError.swift in Sources */,
787A071A1D085750009EC97F /* CellsControllerProtocol.swift in Sources */,
95B39A861D9D51250057BD54 /* String+Localization.swift in Sources */,
78C36F7E1D801E3E00E7EBEA /* Double+Rounding.swift in Sources */,
78CFEE551C5C45E500F50370 /* NibNameProtocol.swift in Sources */,
78CFEE561C5C45E500F50370 /* ReuseIdentifierProtocol.swift in Sources */,
@ -554,9 +587,11 @@
78E59B191C773EE600C6BFE9 /* ObjectsGenerator.swift in Sources */,
78CFEE5B1C5C45E500F50370 /* ViewModelProtocol.swift in Sources */,
78C36F7B1D8015ED00E7EBEA /* UIImage+Creation.swift in Sources */,
95B39A7A1D9BFD550057BD54 /* UIImage+Loading.swift in Sources */,
7824CA521CFEE6B700D7B132 /* UIImage+RenderTemplate.swift in Sources */,
78CFEE5A1C5C45E500F50370 /* ViewHeightProtocol.swift in Sources */,
787682FA1CAD40C300532AB3 /* StaticEstimatedViewHeightProtocol.swift in Sources */,
95B39A7E1D9C069B0057BD54 /* UIImage+Text.swift in Sources */,
78A74EA91C6B373700FE9724 /* UIView+DefaultNibName.swift in Sources */,
786A17A11CB8D71D007F9661 /* UIImage+CapInsetsUtils.swift in Sources */,
78C36F791D8011FA00E7EBEA /* UIImage+Resize.swift in Sources */,
@ -564,6 +599,7 @@
787783631CA03CA0001CDC9B /* NSIndexPath+ImmutableIndexPath.swift in Sources */,
78CFEE591C5C45E500F50370 /* StoryboardIdentifierProtocol.swift in Sources */,
78011AB31D48B53600EA16A2 /* ApiRequestParameters.swift in Sources */,
95B39A7C1D9C05260057BD54 /* UIImage+Gradients.swift in Sources */,
78B0FC7D1C6B2BE200358B64 /* LogFormatter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -23,10 +23,8 @@ public class ObjectsGenerator<T> {
/**
initializer function
- parameter poolSize: number of objects to generate
- parameter contructor: objects constructor closure
- returns: nothing
- parameter poolSize: number of objects to generate
- parameter contructor: objects constructor closure
*/
init(poolSize: UInt, objectsContructor contructor: ObjectConstructor) {
self.poolSize = poolSize

View File

@ -14,9 +14,7 @@ public class ViewsGenerator<T where T: UIView>: ObjectsGenerator<T> {
initializer function
- parameter poolSize: number of cells to generate
- parameter nibName: view nib name
- returns: nothing
- parameter nibName: view nib name
*/
init(poolSize: UInt, nibName: String) {
super.init(poolSize: poolSize, objectsContructor: { T.loadFromNib(named: nibName) })

View File

@ -24,8 +24,8 @@ public extension Alamofire.Request {
return .Failure(.Network(error: err))
}
let JSONResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = JSONResponseSerializer.serializeResponse(request, response, data, error)
let jsonResponseSerializer = Request.JSONResponseSerializer(options: .AllowFragments)
let result = jsonResponseSerializer.serializeResponse(request, response, data, error)
switch result {
case .Success(let value):

View File

@ -0,0 +1,22 @@
//
// String+Localization.swift
// LeadKit
//
// Created by Николай Ашанин on 29.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
public extension String {
/**
method returns localized string with default comment and self name
- returns: localized string
*/
public func localized() -> String {
return NSLocalizedString(self, comment: "")
}
}

View File

@ -11,13 +11,11 @@ import UIKit
public extension UIColor {
/**
The shorthand three-digit hexadecimal representation of color.
the shorthand three-digit hexadecimal representation of color.
#RGB defines to the color #RRGGBB.
- parameter hex3: Three-digit hexadecimal value.
- parameter alpha: 0.0 - 1.0. The default is 1.0.
- returns: new instance with given three-digit hexadecimal value
*/
public convenience init(hex3: UInt16, alpha: CGFloat = 1) {
let red = CGFloat((hex3 & 0xF00) >> 8) / 0xF
@ -27,12 +25,10 @@ public extension UIColor {
}
/**
The shorthand four-digit hexadecimal representation of color with alpha.
the shorthand four-digit hexadecimal representation of color with alpha.
#RGBA defines to the color #RRGGBBAA.
- parameter hex4: Four-digit hexadecimal value.
- returns: new instance with given four-digit hexadecimal value
*/
public convenience init(hex4: UInt16) {
let red = CGFloat((hex4 & 0xF000) >> 12) / 0xF
@ -44,12 +40,10 @@ public extension UIColor {
}
/**
The six-digit hexadecimal representation of color of the form #RRGGBB.
the six-digit hexadecimal representation of color of the form #RRGGBB.
- parameter hex6: Six-digit hexadecimal value.
- parameter alpha: alpha: 0.0 - 1.0. The default is 1.0.
- returns: new instance with given six-digit hexadecimal value
*/
public convenience init(hex6: UInt32, alpha: CGFloat = 1) {
let red = CGFloat((hex6 & 0xFF0000) >> 16) / 0xFF
@ -60,11 +54,9 @@ public extension UIColor {
}
/**
The six-digit hexadecimal representation of color with alpha of the form #RRGGBBAA.
the six-digit hexadecimal representation of color with alpha of the form #RRGGBBAA.
- parameter hex8: Eight-digit hexadecimal value.
- returns: new instance with given eight-digit hexadecimal value
*/
public convenience init(hex8: UInt32) {
let red = CGFloat((hex8 & 0xFF000000) >> 24) / 0xFF
@ -81,8 +73,6 @@ public extension UIColor {
- parameter hexString: hex string with red green and blue values (can have `#` sign)
- parameter alpha: alpha component used if not given in hexString
- returns: new instance with given hex color or nil if hexString is incorrect
*/
public convenience init?(hexString: String, alpha: CGFloat = 1) {
let hexStr = hexString.hasPrefix("#") ? hexString.substringFromIndex(hexString.startIndex.advancedBy(1)) : hexString

View File

@ -0,0 +1,123 @@
//
// UIImage+Alpha.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
public extension UIImage {
/**
- returns: true if the image has an alpha layer.
*/
public func hasAlpha() -> Bool {
let alpha = CGImageGetAlphaInfo(CGImage)
switch alpha {
case .First, .Last, .PremultipliedFirst, .PremultipliedLast:
return true
default:
return false
}
}
/**
- returns: a copy of the given image, adding an alpha channel if it doesn't already have one.
*/
public func applyAlpha() -> UIImage? {
guard !hasAlpha() else {
return self
}
let imageRef = CGImage
let width = CGImageGetWidth(imageRef)
let height = CGImageGetHeight(imageRef)
let colorSpace = CGImageGetColorSpace(imageRef)
// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.ByteOrderDefault.rawValue |
CGImageAlphaInfo.PremultipliedFirst.rawValue)
let offscreenContext = CGBitmapContextCreate(nil, width, height, 8, 0, colorSpace, bitmapInfo.rawValue)
// Draw the image into the context and retrieve the new image, which will now have an alpha layer
CGContextDrawImage(offscreenContext,
CGRect(x: 0, y: 0, width: width, height: height),
imageRef)
guard let cgImage = CGBitmapContextCreateImage(offscreenContext) else {
return nil
}
let imageWithAlpha = UIImage(CGImage: cgImage)
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.
*/
public func applyPadding(padding: CGFloat) -> UIImage? {
// If the image does not have an alpha layer, add one
guard let image = applyAlpha() else {
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 = CGImageGetColorSpace(CGImage)
let bitmapInfo = CGImageGetBitmapInfo(CGImage)
let bitsPerComponent = CGImageGetBitsPerComponent(CGImage)
let context = CGBitmapContextCreate(nil,
Int(rect.size.width),
Int(rect.size.height),
bitsPerComponent, 0, colorSpace,
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)
CGContextDrawImage(context, imageLocation, CGImage)
// Create a mask to make the border transparent, and combine it with the image
let imageWithPadding = imageRefWithPadding(padding, size: rect.size)
guard let cgImage = CGImageCreateWithMask(CGBitmapContextCreateImage(context), imageWithPadding) else {
return nil
}
let transparentImage = UIImage(CGImage: cgImage)
return transparentImage
}
/**
creates a mask that makes the outer edges transparent and everything else opaque.
The size must include the entire mask (opaque part + transparent border).
- parameter padding: The padding amount.
- parameter size: The size of the image.
- returns: A Core Graphics Image Ref
*/
private func imageRefWithPadding(padding: CGFloat,
size: CGSize) -> CGImageRef? {
// Build a context that's the same dimensions as the new size
let colorSpace = CGColorSpaceCreateDeviceGray()
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.ByteOrderDefault.rawValue | CGImageAlphaInfo.None.rawValue)
let context = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), 8, 0, colorSpace, bitmapInfo.rawValue)
// Start with a mask that's entirely transparent
CGContextSetFillColorWithColor(context, UIColor.blackColor().CGColor)
CGContextFillRect(context, CGRect(x: 0, y: 0, width: size.width, height: size.height))
// Make the inner part (within the border) opaque
CGContextSetFillColorWithColor(context, UIColor.whiteColor().CGColor)
let fillRect = CGRect(x: padding,
y: padding,
width: size.width - padding * 2,
height: size.height - padding * 2)
CGContextFillRect(context, fillRect)
// Get an image of the context
let maskImageRef = CGBitmapContextCreateImage(context)
return maskImageRef
}
}

View File

@ -40,7 +40,7 @@ public extension UIImage {
}
/**
this metho tries to find requested image with specific parameters in cache, and if doesn't exists - create it
this method tries to find requested image with specific parameters in cache, and if doesn't exists - create it
- parameter name: name of the image used in UIImage(named:)
- parameter size: size of rendered image

View File

@ -33,4 +33,25 @@ public extension UIImage {
return UIGraphicsGetImageFromCurrentImageContext()
}
/**
creates an image from a UIView.
- parameter fromView: The source view.
- returns A new image
*/
public convenience init?(fromView view: UIView) {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, 0)
guard let context = UIGraphicsGetCurrentContext() else {
return nil
}
view.layer.renderInContext(context)
guard let cgImage = UIGraphicsGetImageFromCurrentImageContext().CGImage else {
return nil
}
self.init(CGImage: cgImage)
UIGraphicsEndImageContext()
}
}

View File

@ -0,0 +1,44 @@
//
// UIImage+Cropping.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
public extension UIImage {
/**
creates a cropped copy of an image.
- parameter bounds: The bounds of the rectangle inside the image.
- returns: A new image
*/
public func crop(bounds: CGRect) -> UIImage? {
guard let cgImage = CGImageCreateWithImageInRect(CGImage, bounds) else {
return nil
}
return UIImage(CGImage: cgImage,
scale: 0.0,
orientation: imageOrientation)
}
/**
crop image to square
- returns: cropped image
*/
public func cropToSquare() -> UIImage? {
let scaledSize = CGSize(width: size.width * scale, height: size.height * scale)
let shortest = min(scaledSize.width, scaledSize.height)
let left: CGFloat = scaledSize.width > shortest ? (scaledSize.width-shortest)/2 : 0
let top: CGFloat = scaledSize.height > shortest ? (scaledSize.height-shortest)/2 : 0
let rect = CGRect(x: 0, y: 0, width: scaledSize.width, height: scaledSize.height)
let insetRect = CGRectInset(rect, left, top)
return crop(insetRect)
}
}

View File

@ -0,0 +1,123 @@
//
// UIImage+Gradients.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
public extension UIImage {
/**
creates a gradient color image.
- parameter gradientColors: An array of colors to use for the gradient.
- parameter size: Image size (defaults: 10x10)
*/
public convenience init?(gradientColors: [UIColor],
size: CGSize = CGSize(width: 10, height: 10)) {
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 = CGGradientCreateWithColors(colorSpace, colors, nil)
CGContextDrawLinearGradient(context,
gradient,
CGPoint(x: 0, y: 0),
CGPoint(x: 0, y: size.height),
CGGradientDrawingOptions(rawValue: 0))
guard let cgImage = UIGraphicsGetImageFromCurrentImageContext().CGImage else {
return nil
}
self.init(CGImage: cgImage)
UIGraphicsEndImageContext()
}
/**
applies gradient color overlay to an image.
- parameter gradientColors: An array of colors to use for the gradient.
- parameter blendMode: The blending type to use.
- returns: A new image
*/
public func applyGradientColors(gradientColors: [UIColor],
blendMode: CGBlendMode = .Normal) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
let context = UIGraphicsGetCurrentContext()
CGContextTranslateCTM(context, 0, size.height)
CGContextScaleCTM(context, 1.0, -1.0)
CGContextSetBlendMode(context, blendMode)
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
CGContextDrawImage(context, rect, CGImage)
// Create gradient
let colorSpace = CGColorSpaceCreateDeviceRGB()
let colors = gradientColors.map {(color: UIColor) -> AnyObject? in return color.CGColor as AnyObject? } as NSArray
let gradient = CGGradientCreateWithColors(colorSpace, colors, nil)
// Apply gradient
CGContextClipToMask(context, rect, CGImage)
CGContextDrawLinearGradient(context,
gradient,
CGPoint(x: 0, y: 0),
CGPoint(x: 0, y: size.height),
CGGradientDrawingOptions(rawValue: 0))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
/**
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)
*/
public convenience init?(startColor: UIColor,
endColor: UIColor,
radialGradientCenter: CGPoint = CGPoint(x: 0.5, y: 0.5),
radius: CGFloat = 0.5,
size: CGSize = CGSize(width: 100, height: 100)) {
UIGraphicsBeginImageContextWithOptions(size, true, 0)
let numLocations: Int = 2
let locations: [CGFloat] = [0.0, 1.0]
let startComponents = CGColorGetComponents(startColor.CGColor)
let endComponents = CGColorGetComponents(endColor.CGColor)
let components: [CGFloat] = [startComponents[0],
startComponents[1],
startComponents[2],
startComponents[3],
endComponents[0],
endComponents[1],
endComponents[2],
endComponents[3]] as [CGFloat]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, numLocations)
// 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 = (min(size.width, size.height)) * (radius)
// Draw it
CGContextDrawRadialGradient(UIGraphicsGetCurrentContext(),
gradient, aCenter, 0,
aCenter, aRadius,
CGGradientDrawingOptions.DrawsAfterEndLocation)
guard let cgImage = UIGraphicsGetImageFromCurrentImageContext().CGImage else {
return nil
}
self.init(CGImage: cgImage)
// Clean up
UIGraphicsEndImageContext()
}
}

View File

@ -0,0 +1,74 @@
//
// UIImage+Loading.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
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 sharedCache: NSCache = {
return NSCache()
}
// MARK: Image From URL
/**
creates a new image from a URL with optional caching.
if using cache, the cached image is returned.
otherwise, a place holder is used until the image from web is returned by the fetchComplete.
- parameter url: The image URL.
- parameter placeholder: The placeholder image.
- parameter cacheImage: Weather or not we should cache the NSURL response (default: true)
- parameter fetchComplete: Returns the image from the web the first time is fetched.
- returns: A new image
*/
public class func imageFromURL(url: String,
placeholder: UIImage,
cacheImage: Bool = true,
fetchComplete: (image: UIImage?) -> ()) -> UIImage? {
// From Cache
if cacheImage {
if let image = UIImage.sharedCache().objectForKey(url) as? UIImage {
fetchComplete(image: nil)
return image
}
}
// Fetch Image
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
if let nsURL = NSURL(string: url) {
session.dataTaskWithURL(nsURL, completionHandler: { (data, response, error) -> Void in
if error != nil {
dispatch_async(dispatch_get_main_queue()) {
fetchComplete(image: nil)
}
} else if let data = data, image = UIImage(data: data) {
if cacheImage {
UIImage.sharedCache().setObject(image, forKey: url)
}
dispatch_async(dispatch_get_main_queue()) {
fetchComplete(image: image)
}
}
session.finishTasksAndInvalidate()
}).resume()
}
return placeholder
}
}

View File

@ -28,4 +28,53 @@ public extension UIImage {
return UIGraphicsGetImageFromCurrentImageContext()
}
/**
creates a resized copy of an image.
- parameter size: the new size of the image.
- parameter contentMode: the way to handle the content in the new size.
- returns: a new image
*/
public func resize(size: CGSize,
contentMode: UIImageContentMode = .ScaleToFill) -> UIImage? {
let horizontalRatio = size.width / size.width
let verticalRatio = size.height / size.height
var ratio: CGFloat = 1
switch contentMode {
case .ScaleToFill:
ratio = 1
case .ScaleAspectFill:
ratio = max(horizontalRatio, verticalRatio)
case .ScaleAspectFit:
ratio = min(horizontalRatio, verticalRatio)
}
let rect = CGRect(x: 0, y: 0, width: size.width * ratio, height: size.height * ratio)
let colorSpace = CGColorSpaceCreateDeviceRGB()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
let context = CGBitmapContextCreate(nil,
Int(rect.size.width),
Int(rect.size.height), 8, 0, colorSpace,
bitmapInfo.rawValue)
let transform = CGAffineTransformIdentity
CGContextConcatCTM(context, transform)
// Set the quality level to use when rescaling
guard let interpolationQuality = CGInterpolationQuality(rawValue: 3) else {
return nil
}
CGContextSetInterpolationQuality(context, interpolationQuality)
CGContextDrawImage(context, rect, CGImage)
guard let newContext = context else {
return nil
}
let newImage = UIImage(CGImage: CGBitmapContextCreateImage(newContext),
scale: scale,
orientation: imageOrientation)
return newImage
}
}

View File

@ -0,0 +1,45 @@
//
// UIImage+Text.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
public extension UIImage {
/**
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)
*/
public convenience init?(text: String,
font: UIFont = UIFont.systemFontOfSize(18),
color: UIColor = UIColor.whiteColor(),
backgroundColor: UIColor = UIColor.grayColor(),
size: CGSize = CGSize(width: 10, height: 10),
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?.drawInRect(CGRect(x: 0, y: 0, width: size.width, height: size.height))
guard let cgImage = UIGraphicsGetImageFromCurrentImageContext().CGImage else {
return nil
}
self.init(CGImage: cgImage)
UIGraphicsEndImageContext()
}
}

View File

@ -32,4 +32,123 @@ public extension UIImage {
return UIGraphicsGetImageFromCurrentImageContext()
}
/**
creates a new image with rounded corners.
- parameter cornerRadius: The corner radius.
- returns: A new image
*/
public func roundCorners(cornerRadius: CGFloat) -> UIImage? {
guard let imageWithAlpha = applyAlpha() else {
return nil
}
UIGraphicsBeginImageContextWithOptions(size, false, 0)
let width = CGImageGetWidth(imageWithAlpha?.CGImage)
let height = CGImageGetHeight(imageWithAlpha?.CGImage)
let bits = CGImageGetBitsPerComponent(imageWithAlpha?.CGImage)
let colorSpace = CGImageGetColorSpace(imageWithAlpha?.CGImage)
let bitmapInfo = CGImageGetBitmapInfo(imageWithAlpha?.CGImage)
let context = CGBitmapContextCreate(nil, width, height, bits, 0, colorSpace, bitmapInfo.rawValue)
let rect = CGRect(x: 0, y: 0, width: CGFloat(width) * scale, height: CGFloat(height) * scale)
CGContextBeginPath(context)
if cornerRadius == 0 {
CGContextAddRect(context, rect)
} else {
CGContextSaveGState(context)
CGContextTranslateCTM(context, rect.minX, rect.minY)
CGContextScaleCTM(context, cornerRadius, cornerRadius)
let roundedWidth = rect.size.width / cornerRadius
let roundedHeight = rect.size.height / cornerRadius
CGContextMoveToPoint(context, roundedWidth, roundedHeight/2)
CGContextAddArcToPoint(context, roundedWidth, roundedHeight, roundedWidth/2, roundedHeight, 1)
CGContextAddArcToPoint(context, 0, roundedHeight, 0, roundedHeight/2, 1)
CGContextAddArcToPoint(context, 0, 0, roundedWidth/2, 0, 1)
CGContextAddArcToPoint(context, roundedWidth, 0, roundedWidth, roundedHeight/2, 1)
CGContextRestoreGState(context)
}
CGContextClosePath(context)
CGContextClip(context)
CGContextDrawImage(context, rect, imageWithAlpha?.CGImage)
guard let bitmapImage = CGBitmapContextCreateImage(context) else {
return nil
}
let image = UIImage(CGImage: bitmapImage,
scale: scale,
orientation: .Up)
UIGraphicsEndImageContext()
return image
}
/**
creates a new image with rounded corners and border.
- parameter cornerRadius: The corner radius.
- parameter border: The size of the border.
- parameter color: The color of the border.
- returns: A new image
*/
public func roundCorners(cornerRadius: CGFloat,
border: CGFloat,
color: UIColor) -> UIImage? {
return roundCorners(cornerRadius)?.applyBorder(border, color: color)
}
/**
creates a new circle image.
- returns: A new image
*/
public func roundCornersToCircle() -> UIImage? {
let shortest = min(size.width, size.height)
return cropToSquare()?.roundCorners(shortest/2)
}
/**
creates a new circle image with a border.
- parameter border: CGFloat The size of the border.
- parameter color: UIColor The color of the border.
- returns: UIImage?
*/
public func roundCornersToCircle(border border: CGFloat, color: UIColor) -> UIImage? {
let shortest = min(size.width, size.height)
return cropToSquare()?.roundCorners(shortest/2, border: border, color: color)
}
/**
creates a new image with a border.
- parameter border: The size of the border.
- parameter color: The color of the border.
- returns: A new image
*/
public func applyBorder(border: CGFloat,
color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 0)
let width = CGImageGetWidth(CGImage)
let height = CGImageGetHeight(CGImage)
let bits = CGImageGetBitsPerComponent(CGImage)
let colorSpace = CGImageGetColorSpace(CGImage)
let bitmapInfo = CGImageGetBitmapInfo(CGImage)
let context = CGBitmapContextCreate(nil, width, height, bits, 0, colorSpace, bitmapInfo.rawValue)
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0
color.getRed(&red, green: &green, blue: &blue, alpha: &alpha)
CGContextSetRGBStrokeColor(context, red, green, blue, alpha)
CGContextSetLineWidth(context, border)
let rect = CGRect(x: 0, y: 0, width: size.width*scale, height: size.height*scale)
let inset = CGRectInset(rect, border*scale, border*scale)
CGContextStrokeEllipseInRect(context, inset)
CGContextDrawImage(context, inset, CGImage)
guard let bitmapImage = CGBitmapContextCreateImage(context) else {
return nil
}
let image = UIImage(CGImage: bitmapImage)
UIGraphicsEndImageContext()
return image
}
}

View File

@ -0,0 +1,52 @@
//
// UIImageView+LoadingImage.swift
// LeadKit
//
// Created by Николай Ашанин on 28.09.16.
// Copyright © 2016 Touch Instinct. All rights reserved.
//
import UIKit
import QuartzCore
public extension UIImageView {
/**
loads an image from a URL. If cached, the cached image is returned.
otherwise, a place holder is used until the image from web is returned by the closure.
- parameter url: The image URL.
- parameter placeholder: The placeholder image.
- parameter fadeIn: Weather the mage should fade in.
- parameter shouldCacheImage: Should be image cached.
- parameter closure: Returns the image from the web the first time is fetched.
- returns: A new image
*/
public func imageFromURL(url: String,
placeholder: UIImage,
fadeIn: Bool = true,
shouldCacheImage: Bool = true,
closure: ((image: UIImage?) -> ())? = nil) {
image = UIImage.imageFromURL(url,
placeholder: placeholder,
shouldCacheImage: shouldCacheImage) { [weak self]
(uploadedImage: UIImage?) in
guard let image = uploadedImage else {
return nil
}
self?.image = image
if fadeIn {
let transition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionFade
layer.addAnimation(transition, forKey: nil)
}
closure?(image: image)
}
}
}