Merge pull request #19 from TouchInstinct/image/roundcorners
image extension added
This commit is contained in:
commit
823bbd54fe
Binary file not shown.
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) })
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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: "")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue