Commit dbd0f8ca by Daniel Dahan

added FilterBlur

parent eb6a255a
......@@ -20,7 +20,7 @@
location = "group:Programmatic/Grid/Grid.xcodeproj">
</FileRef>
<FileRef
location = "group:Programmatic/ImageBlur/ImageBlur.xcodeproj">
location = "group:Programmatic/FilterBlur/FilterBlur.xcodeproj">
</FileRef>
<FileRef
location = "group:Programmatic/MaterialLayer/MaterialLayer.xcodeproj">
......
......@@ -50,6 +50,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
bottomNavigationController.tabBar.backgroundColor = MaterialColor.grey.darken4
let sideNavigationController: SideNavigationController = SideNavigationController(rootViewController: bottomNavigationController, leftViewController: AppLeftViewController())
sideNavigationController.statusBarStyle = .LightContent
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window!.rootViewController = sideNavigationController
......
......@@ -61,7 +61,6 @@ class AppNavigationController: NavigationController {
/// Prepares the navigationBar
private func prepareNavigationBar() {
navigationBar.statusBarStyle = .LightContent
navigationBar.tintColor = MaterialColor.white
navigationBar.backgroundColor = MaterialColor.blue.base
}
......
......@@ -44,7 +44,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
......@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:ImageBlur.xcodeproj">
location = "self:FilterBlur.xcodeproj">
</FileRef>
</Workspace>
......@@ -32,14 +32,12 @@ import UIKit
import Material
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
prepareView()
blurImage()
}
/// General preparation statements.
private func prepareView() {
view.backgroundColor = MaterialColor.white
......@@ -47,12 +45,10 @@ class ViewController: UIViewController {
/// Blur image.
private func blurImage() {
let v: MaterialView = MaterialView(frame: view.bounds)
v.image = UIImage(named: "CosmicMindFlat")?.applyBlur(25, tintColor: MaterialColor.blue.base.colorWithAlphaComponent(0.1), saturationDeltaFactor: 100)
v.contentsGravityPreset = .ResizeAspectFill
view.addSubview(v)
let materialView: MaterialView = MaterialView(frame: view.bounds)
materialView.image = UIImage(named: "CosmicMindFlat")?.filterBlur(25, tintColor: MaterialColor.blue.base.colorWithAlphaComponent(0.1), saturationDeltaFactor: 100)
materialView.contentsGravityPreset = .ResizeAspectFill
view.addSubview(materialView)
}
}
......@@ -12,7 +12,7 @@
9660161D1CB2ED6C00AAB661 /* Material.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 966016131CB2ED6C00AAB661 /* Material.framework */; };
9660162A1CB2F04E00AAB661 /* Material.h in Headers */ = {isa = PBXBuildFile; fileRef = 96D88C091C1328D800B91418 /* Material.h */; settings = {ATTRIBUTES = (Public, ); }; };
96815B381CA07BA20006CBE2 /* MaterialViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 967887881C9777CB0037F6C9 /* MaterialViewTests.swift */; };
96977DA61CBB2E49000BEFC4 /* Material+UIImage+Blur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96977DA51CBB2E49000BEFC4 /* Material+UIImage+Blur.swift */; };
96977DA61CBB2E49000BEFC4 /* Material+UIImage+FilterBlur.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96977DA51CBB2E49000BEFC4 /* Material+UIImage+FilterBlur.swift */; };
96BCB7A11CB40DC500C806FE /* BottomNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7581CB40DC500C806FE /* BottomNavigationController.swift */; };
96BCB7A21CB40DC500C806FE /* BottomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB7591CB40DC500C806FE /* BottomTabBar.swift */; };
96BCB7A31CB40DC500C806FE /* CapturePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BCB75A1CB40DC500C806FE /* CapturePreview.swift */; };
......@@ -198,7 +198,7 @@
966016131CB2ED6C00AAB661 /* Material.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Material.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9660161C1CB2ED6C00AAB661 /* Material OSX Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Material OSX Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
967887881C9777CB0037F6C9 /* MaterialViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaterialViewTests.swift; sourceTree = "<group>"; };
96977DA51CBB2E49000BEFC4 /* Material+UIImage+Blur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UIImage+Blur.swift"; sourceTree = "<group>"; };
96977DA51CBB2E49000BEFC4 /* Material+UIImage+FilterBlur.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Material+UIImage+FilterBlur.swift"; sourceTree = "<group>"; };
96BCB7581CB40DC500C806FE /* BottomNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomNavigationController.swift; sourceTree = "<group>"; };
96BCB7591CB40DC500C806FE /* BottomTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BottomTabBar.swift; sourceTree = "<group>"; };
96BCB75A1CB40DC500C806FE /* CapturePreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CapturePreview.swift; sourceTree = "<group>"; };
......@@ -537,7 +537,7 @@
96BCB76A1CB40DC500C806FE /* Material+UIImage+Resize.swift */,
96BCB76B1CB40DC500C806FE /* Material+UIImage+Size.swift */,
96BCB76C1CB40DC500C806FE /* Material+UIImage.swift */,
96977DA51CBB2E49000BEFC4 /* Material+UIImage+Blur.swift */,
96977DA51CBB2E49000BEFC4 /* Material+UIImage+FilterBlur.swift */,
);
name = Extension;
sourceTree = "<group>";
......@@ -931,7 +931,7 @@
96BCB7A81CB40DC500C806FE /* FabButton.swift in Sources */,
96BCB7E41CB40DC500C806FE /* Text.swift in Sources */,
96BCB7AB1CB40DC500C806FE /* ImageCardView.swift in Sources */,
96977DA61CBB2E49000BEFC4 /* Material+UIImage+Blur.swift in Sources */,
96977DA61CBB2E49000BEFC4 /* Material+UIImage+FilterBlur.swift in Sources */,
96BCB7CB1CB40DC500C806FE /* MaterialPulseAnimation.swift in Sources */,
96BCB7B71CB40DC500C806FE /* MaterialBasicAnimation.swift in Sources */,
96BCB7AE1CB40DC500C806FE /* Material+UIFont.swift in Sources */,
......
......@@ -58,8 +58,15 @@ Material is a growing project and will encounter changes throughout its developm
#### Colors
* [MaterialColor](#materialcolor)
#### Icons
* [MaterialIcon](#materialicon)
#### Filters
* [Blur](#filterblur)
#### Base Layers & Views
* [MaterialLayer](#materiallayer)
......@@ -135,6 +142,13 @@ MaterialIcon is a library of Google and CosmicMind icons that are available for
![MaterialMaterialIcon](http://www.cosmicmind.io/MK/MaterialMaterialIcon.png)
<a name="filterblur"></a>
#### Filters
Material will be expanding its library to add image filters. The initial filter is blur.
![MaterialFilterBlur](http://www.cosmicmind.io/MK/MaterialFilterBlur.png)
<a name="materiallayer"></a>
#### MaterialLayer
......
......@@ -31,65 +31,62 @@
import UIKit
import Accelerate
/// Creates an effect buffer for images that are already effected.
private func createEffectBuffer(context: CGContext) -> vImage_Buffer {
let data = CGBitmapContextGetData(context)
let width = vImagePixelCount(CGBitmapContextGetWidth(context))
let height = vImagePixelCount(CGBitmapContextGetHeight(context))
let rowBytes = CGBitmapContextGetBytesPerRow(context)
return vImage_Buffer(data: data, height: height, width: width, rowBytes: rowBytes)
}
public extension UIImage {
/**
Applies a blur effect to a UIImage
- Parameter blurRadius: The radius of the blur effect
- Parameter tintColor: The color used for the blur effect (optional)
- Parameter saturationDeltaFactor: The delta factor for the saturation of the blur effect
- Returns: a UIImage
Applies a blur effect to a UIImage.
- Parameter blurRadius: The radius of the blur effect.
- Parameter tintColor: The color used for the blur effect (optional).
- Parameter saturationDeltaFactor: The delta factor for the saturation of the blur effect.
- Returns: a UIImage.
*/
func applyBlur(blurRadius: CGFloat, tintColor: UIColor?, saturationDeltaFactor: CGFloat) -> UIImage? {
let screenScale = UIScreen.mainScreen().scale
let imageRect = CGRect(origin: CGPointZero, size: size)
var effectImage = self
func filterBlur(blurRadius: CGFloat = 0, tintColor: UIColor? = nil, saturationDeltaFactor: CGFloat = 0) -> UIImage? {
var effectImage: UIImage = self
let hasBlur = blurRadius > CGFloat(FLT_EPSILON)
let hasSaturationChange = fabs(saturationDeltaFactor - 1.0) > CGFloat(FLT_EPSILON)
let screenScale: CGFloat = MaterialDevice.scale
let imageRect: CGRect = CGRect(origin: CGPointZero, size: size)
let hasBlur: Bool = blurRadius > CGFloat(FLT_EPSILON)
let hasSaturationChange: Bool = fabs(saturationDeltaFactor - 1.0) > CGFloat(FLT_EPSILON)
if hasBlur || hasSaturationChange {
func createEffectBuffer(context: CGContext) -> vImage_Buffer {
let data = CGBitmapContextGetData(context)
let width = vImagePixelCount(CGBitmapContextGetWidth(context))
let height = vImagePixelCount(CGBitmapContextGetHeight(context))
let rowBytes = CGBitmapContextGetBytesPerRow(context)
return vImage_Buffer(data: data, height: height, width: width, rowBytes: rowBytes)
}
UIGraphicsBeginImageContextWithOptions(size, false, screenScale)
let effectInContext = UIGraphicsGetCurrentContext()
let effectInContext: CGContext = UIGraphicsGetCurrentContext()!
CGContextScaleCTM(effectInContext, 1.0, -1.0)
CGContextTranslateCTM(effectInContext, 0, -size.height)
CGContextDrawImage(effectInContext, imageRect, self.CGImage)
var effectInBuffer = createEffectBuffer(effectInContext!)
var effectInBuffer: vImage_Buffer = createEffectBuffer(effectInContext)
UIGraphicsBeginImageContextWithOptions(size, false, screenScale)
let effectOutContext = UIGraphicsGetCurrentContext()
var effectOutBuffer = createEffectBuffer(effectOutContext!)
let effectOutContext: CGContext = UIGraphicsGetCurrentContext()!
var effectOutBuffer: vImage_Buffer = createEffectBuffer(effectOutContext)
if hasBlur {
let inputRadius = blurRadius * screenScale
var radius = UInt32(floor(inputRadius * 3.0 * CGFloat(sqrt(2 * M_PI)) / 4 + 0.5))
if radius % 2 != 1 {
let inputRadius: CGFloat = blurRadius * screenScale
var radius: UInt32 = UInt32(floor(inputRadius * 3.0 * CGFloat(sqrt(2 * M_PI)) / 4 + 0.5))
if 1 != radius % 2 {
radius += 1 // force radius to be odd so that the three box-blur methodology works.
}
let imageEdgeExtendFlags = vImage_Flags(kvImageEdgeExtend)
let imageEdgeExtendFlags: UInt32 = vImage_Flags(kvImageEdgeExtend)
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, nil, 0, 0, radius, radius, nil, imageEdgeExtendFlags)
vImageBoxConvolve_ARGB8888(&effectOutBuffer, &effectInBuffer, nil, 0, 0, radius, radius, nil, imageEdgeExtendFlags)
vImageBoxConvolve_ARGB8888(&effectInBuffer, &effectOutBuffer, nil, 0, 0, radius, radius, nil, imageEdgeExtendFlags)
}
var effectImageBuffersAreSwapped = false
var effectImageBuffersAreSwapped: Bool = false
if hasSaturationChange {
let s: CGFloat = saturationDeltaFactor
let floatingPointSaturationMatrix: [CGFloat] = [
let floatingPointSaturationMatrix: Array<CGFloat> = [
0.0722 + 0.9278 * s, 0.0722 - 0.0722 * s, 0.0722 - 0.0722 * s, 0,
0.7152 - 0.7152 * s, 0.7152 + 0.2848 * s, 0.7152 - 0.7152 * s, 0,
0.2126 - 0.2126 * s, 0.2126 - 0.2126 * s, 0.2126 + 0.7873 * s, 0,
......@@ -97,8 +94,8 @@ public extension UIImage {
]
let divisor: CGFloat = 256
let matrixSize = floatingPointSaturationMatrix.count
var saturationMatrix = [Int16](count: matrixSize, repeatedValue: 0)
let matrixSize: Int = floatingPointSaturationMatrix.count
var saturationMatrix: Array<Int16> = Array<Int16>(count: matrixSize, repeatedValue: 0)
for i: Int in 0 ..< matrixSize {
saturationMatrix[i] = Int16(round(floatingPointSaturationMatrix[i] * divisor))
......@@ -127,7 +124,7 @@ public extension UIImage {
// Set up output context.
UIGraphicsBeginImageContextWithOptions(size, false, screenScale)
let outputContext = UIGraphicsGetCurrentContext()
let outputContext: CGContext = UIGraphicsGetCurrentContext()!
CGContextScaleCTM(outputContext, 1.0, -1.0)
CGContextTranslateCTM(outputContext, 0, -size.height)
......@@ -142,15 +139,15 @@ public extension UIImage {
}
// Add in color tint.
if let color = tintColor {
if let v: UIColor = tintColor {
CGContextSaveGState(outputContext)
CGContextSetFillColorWithColor(outputContext, color.CGColor)
CGContextSetFillColorWithColor(outputContext, v.CGColor)
CGContextFillRect(outputContext, imageRect)
CGContextRestoreGState(outputContext)
}
// Output image is ready.
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
let outputImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage
......
......@@ -67,20 +67,19 @@ public class SearchBar : StatusBarView {
}
}
/// A wrapper for searchBar.placeholder.
/// Sets the textField placeholder value.
@IBInspectable public var placeholder: String? {
get {
return textField.placeholder
}
set(value) {
textField.placeholder = value
didSet {
if let v: String = placeholder {
textField.attributedPlaceholder = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: placeholderTextColor])
}
}
}
/// Placeholder textColor.
@IBInspectable public var placeholderTextColor: UIColor = MaterialColor.grey.base {
@IBInspectable public var placeholderTextColor: UIColor = MaterialColor.darkText.others {
didSet {
if let v: String = textField.placeholder {
if let v: String = placeholder {
textField.attributedPlaceholder = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: placeholderTextColor])
}
}
......@@ -125,10 +124,9 @@ public class SearchBar : StatusBarView {
textField.font = RobotoFont.regularWithSize(20)
textField.backgroundColor = MaterialColor.clear
textField.clearButtonMode = .WhileEditing
tintColor = MaterialColor.grey.base
textColor = MaterialColor.grey.darken4
tintColor = placeholderTextColor
textColor = MaterialColor.darkText.primary
placeholder = "Search"
placeholderTextColor = MaterialColor.grey.base
contentView.addSubview(textField)
}
......@@ -137,9 +135,10 @@ public class SearchBar : StatusBarView {
let image: UIImage? = MaterialIcon.cm.close
clearButton = FlatButton()
clearButton.contentEdgeInsets = UIEdgeInsetsZero
clearButton.pulseColor = MaterialColor.grey.base
clearButton.pulseColor = MaterialColor.black
clearButton.pulseOpacity = 0.12
clearButton.pulseScale = false
clearButton.tintColor = MaterialColor.grey.base
clearButton.tintColor = placeholderTextColor
clearButton.setImage(image, forState: .Normal)
clearButton.setImage(image, forState: .Highlighted)
clearButtonAutoHandleEnabled = true
......
......@@ -114,6 +114,9 @@ public protocol SideNavigationControllerDelegate {
@IBDesignable
@objc(SideNavigationController)
public class SideNavigationController : UIViewController, UIGestureRecognizerDelegate {
/// A Boolean to determine if the statusBar will be hidden.
private var willHideStatusBar: Bool = false
/**
A CGFloat property that is used internally to track
the original (x) position of the container view when panning.
......@@ -154,6 +157,12 @@ public class SideNavigationController : UIViewController, UIGestureRecognizerDel
@IBInspectable public var rightThreshold: CGFloat?
private var rightViewThreshold: CGFloat = 0
/// Sets the animation type for the statusBar when hiding.
public var statusBarUpdateAnimation: UIStatusBarAnimation = .Fade
/// Sets the statusBar style.
public var statusBarStyle: UIStatusBarStyle = .Default
/**
A SideNavigationControllerDelegate property used to bind
the delegation object.
......@@ -319,6 +328,18 @@ public class SideNavigationController : UIViewController, UIGestureRecognizerDel
}
}
public override func preferredStatusBarUpdateAnimation() -> UIStatusBarAnimation {
return statusBarUpdateAnimation
}
public override func prefersStatusBarHidden() -> Bool {
return willHideStatusBar
}
public override func preferredStatusBarStyle() -> UIStatusBarStyle {
return statusBarStyle
}
/**
A method to swap rootViewController objects.
- Parameter toViewController: The UIViewController to swap
......@@ -850,6 +871,7 @@ public class SideNavigationController : UIViewController, UIGestureRecognizerDel
/// Shows the statusBar.
private func showStatusBar() {
willHideStatusBar = false
UIView.animateWithDuration(NSTimeInterval(UINavigationControllerHideShowBarDuration),
animations: { [weak self] in
self?.setNeedsStatusBarAppearanceUpdate()
......@@ -861,6 +883,7 @@ public class SideNavigationController : UIViewController, UIGestureRecognizerDel
/// Hides the statusBar.
private func hideStatusBar() {
if enableHideStatusbar {
willHideStatusBar = true
UIView.animateWithDuration(NSTimeInterval(UINavigationControllerHideShowBarDuration),
animations: { [weak self] in
self?.setNeedsStatusBarAppearanceUpdate()
......
......@@ -369,7 +369,7 @@ public class TextField : UITextField {
}
}
/// A wrapper for searchBar.placeholder.
/// Sets the placeholder value.
@IBInspectable public override var placeholder: String? {
didSet {
if let v: String = placeholder {
......@@ -379,7 +379,7 @@ public class TextField : UITextField {
}
/// Placeholder textColor.
@IBInspectable public var placeholderTextColor: UIColor = MaterialColor.black {
@IBInspectable public var placeholderTextColor: UIColor = MaterialColor.darkText.others {
didSet {
if let v: String = placeholder {
attributedPlaceholder = NSAttributedString(string: v, attributes: [NSForegroundColorAttributeName: placeholderTextColor])
......@@ -485,7 +485,6 @@ public class TextField : UITextField {
public func prepareView() {
backgroundColor = MaterialColor.white
masksToBounds = false
placeholderTextColor = MaterialColor.darkText.others
font = RobotoFont.regularWithSize(16)
textColor = MaterialColor.darkText.primary
borderStyle = .None
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment