-
Notifications
You must be signed in to change notification settings - Fork 103
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from KyoheiG3/swift-4
Support Swift 4
- Loading branch information
Showing
14 changed files
with
709 additions
and
405 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// | ||
// BlurLayer.swift | ||
// DynamicBlurView | ||
// | ||
// Created by Kyohei Ito on 2017/08/14. | ||
// Copyright © 2017年 kyohei_ito. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
|
||
private extension CGRect { | ||
func rectangle(_ s: CGSize) -> CGRect { | ||
let x = origin.x / s.width | ||
let y = origin.y / s.height | ||
let width = size.width / s.width | ||
let height = size.height / s.height | ||
return CGRect(x: x, y: y, width: width, height: height) | ||
} | ||
} | ||
|
||
class BlurLayer: CALayer { | ||
private static let blurRadiusKey = "blurRadius" | ||
private static let blurLayoutKey = "blurLayout" | ||
@NSManaged var blurRadius: CGFloat | ||
@NSManaged private var blurLayout: CGFloat | ||
|
||
private var fromBlurRadius: CGFloat? | ||
var presentationRadius: CGFloat { | ||
if let radius = fromBlurRadius { | ||
if let layer = presentation() { | ||
return layer.blurRadius | ||
} else { | ||
return radius | ||
} | ||
} else { | ||
return blurRadius | ||
} | ||
} | ||
|
||
override class func needsDisplay(forKey key: String) -> Bool { | ||
if key == blurRadiusKey || key == blurLayoutKey { | ||
return true | ||
} | ||
return super.needsDisplay(forKey: key) | ||
} | ||
|
||
open override func action(forKey event: String) -> CAAction? { | ||
if event == BlurLayer.blurRadiusKey { | ||
fromBlurRadius = nil | ||
|
||
if let action = super.action(forKey: "opacity") as? CABasicAnimation { | ||
fromBlurRadius = (presentation() ?? self).blurRadius | ||
|
||
action.keyPath = event | ||
action.fromValue = fromBlurRadius | ||
return action | ||
} | ||
} | ||
|
||
if event == BlurLayer.blurLayoutKey, let action = super.action(forKey: "opacity") as? CABasicAnimation { | ||
action.keyPath = event | ||
action.fromValue = 0 | ||
action.toValue = 1 | ||
return action | ||
} | ||
|
||
return super.action(forKey: event) | ||
} | ||
} | ||
|
||
extension BlurLayer { | ||
func draw(_ image: UIImage, fixes isFixes: Bool, baseLayer: CALayer?) { | ||
contents = image.cgImage | ||
contentsScale = image.scale | ||
|
||
if isFixes, let blurLayer = presentation() { | ||
contentsRect = blurLayer.convert(blurLayer.bounds, to: baseLayer).rectangle(image.size) | ||
} | ||
} | ||
|
||
func refresh() { | ||
fromBlurRadius = nil | ||
} | ||
|
||
func animate() { | ||
UIView.performWithoutAnimation { | ||
blurLayout = 0 | ||
} | ||
blurLayout = 1 | ||
} | ||
|
||
func render(in context: CGContext, for layer: CALayer) { | ||
let layers = hideOverlappingLayers(layer.sublayers) | ||
layer.render(in: context) | ||
layers.forEach { | ||
$0.isHidden = false | ||
} | ||
} | ||
|
||
private func hideOverlappingLayers(_ layers: [CALayer]?) -> [CALayer] { | ||
var hiddenLayers: [CALayer] = [] | ||
guard let layers = layers else { | ||
return hiddenLayers | ||
} | ||
|
||
for layer in layers.reversed() { | ||
if isHang(to: layer) { | ||
return hiddenLayers + hideOverlappingLayers(layer.sublayers) | ||
} | ||
if layer.isHidden == false { | ||
layer.isHidden = true | ||
hiddenLayers.append(layer) | ||
} | ||
if layer == self { | ||
return hiddenLayers | ||
} | ||
} | ||
return hiddenLayers | ||
} | ||
|
||
private func isHang(to target: CALayer) -> Bool { | ||
var layer = superlayer | ||
while layer != nil { | ||
if layer == target { | ||
return true | ||
} | ||
layer = layer?.superlayer | ||
} | ||
return false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// CGContext+CGImage.swift | ||
// DynamicBlurView | ||
// | ||
// Created by Kyohei Ito on 2017/08/17. | ||
// Copyright © 2017年 kyohei_ito. All rights reserved. | ||
// | ||
|
||
extension CGContext { | ||
static func imageContext(with quality: CaptureQuality, rect: CGRect, opaque: Bool) -> CGContext? { | ||
UIGraphicsBeginImageContextWithOptions(rect.size, opaque, quality.imageScale) | ||
guard let context = UIGraphicsGetCurrentContext() else { | ||
return nil | ||
} | ||
|
||
context.translateBy(x: -rect.origin.x, y: -rect.origin.y) | ||
context.interpolationQuality = quality.interpolationQuality | ||
|
||
return context | ||
} | ||
|
||
func makeImage(with blendColor: UIColor?, blendMode: CGBlendMode, size: CGSize) -> CGImage? { | ||
if let color = blendColor { | ||
setFillColor(color.cgColor) | ||
setBlendMode(blendMode) | ||
fill(CGRect(origin: .zero, size: size)) | ||
} | ||
|
||
return makeImage() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
// | ||
// CGImage+Accelerate.swift | ||
// DynamicBlurView | ||
// | ||
// Created by Kyohei Ito on 2017/08/17. | ||
// Copyright © 2017年 kyohei_ito. All rights reserved. | ||
// | ||
|
||
import Accelerate | ||
|
||
extension CGImage { | ||
var area: Int { | ||
return width * height | ||
} | ||
|
||
private var size: CGSize { | ||
return CGSize(width: width, height: height) | ||
} | ||
|
||
private var bytes: Int { | ||
return bytesPerRow * height | ||
} | ||
|
||
private func imageBuffer(from data: UnsafeMutableRawPointer!) -> vImage_Buffer { | ||
return vImage_Buffer(data: data, height: vImagePixelCount(height), width: vImagePixelCount(width), rowBytes: bytesPerRow) | ||
} | ||
|
||
func blurred(with boxSize: UInt32, iterations: Int, blendColor: UIColor?, blendMode: CGBlendMode) -> CGImage? { | ||
guard let provider = dataProvider else { | ||
return nil | ||
} | ||
|
||
let inData = malloc(bytes) | ||
var inBuffer = imageBuffer(from: inData) | ||
|
||
let outData = malloc(bytes) | ||
var outBuffer = imageBuffer(from: outData) | ||
|
||
let tempSize = vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, nil, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend + kvImageGetTempBufferSize)) | ||
let tempData = malloc(tempSize) | ||
|
||
defer { | ||
free(inData) | ||
free(outData) | ||
free(tempData) | ||
} | ||
|
||
let source = CFDataGetBytePtr(provider.data) | ||
memcpy(inBuffer.data, source, bytes) | ||
|
||
for _ in 0..<iterations { | ||
vImageBoxConvolve_ARGB8888(&inBuffer, &outBuffer, tempData, 0, 0, boxSize, boxSize, nil, vImage_Flags(kvImageEdgeExtend)) | ||
|
||
let temp = inBuffer.data | ||
inBuffer.data = outBuffer.data | ||
outBuffer.data = temp | ||
} | ||
|
||
let context = colorSpace.flatMap { | ||
CGContext(data: inBuffer.data, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: $0, bitmapInfo: bitmapInfo.rawValue) | ||
} | ||
|
||
return context?.makeImage(with: blendColor, blendMode: blendMode, size: size) | ||
} | ||
} |
Oops, something went wrong.