为 UIKit、AppKit 和 SwiftUI 中的图像添加可变模糊效果。可在使用 Metal 的 Apple 平台上运行。
左侧图像具有从前缘到中间的水平可变模糊。右侧图像具有从顶缘到中间的垂直可变模糊。
SwiftUI、UIKit 和 AppKit 的演示应用可在 Documentation 下找到。
垂直 | 水平 | 两点之间 | 渐变 | 多种模糊 |
---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
要在 SwiftPM 项目中使用此软件包,您需要将其设置为软件包依赖项
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
.package(
url: "https://github.com/Eskils/VariableBlurImageView",
.upToNextMinor(from: "1.1.2") // or `.upToNextMajor
)
],
targets: [
.target(
name: "MyTarget",
dependencies: [
.product(name: "VariableBlurImageView", package: "VariableBlurImageView")
]
)
]
)
此框架为 UIImageView 和 NSImageView 提供了子类,以及 SwiftUI 视图和修饰符,用于将可变模糊应用于图像。
还有一个类可用于将可变模糊应用于 CGImages。
VariableBlurImageView
是 UIImageView
/ NSImageView
的子类,它异步应用所需渐进式模糊。
您需要提供图像、起始点、结束点以及它们各自的模糊半径。
let imageView = VariableBlurImageView()
imageView.contentMode = .scaleAspectFill
let backgroundImage = UIImage(resource: .onboardingBackground)
imageView.verticalVariableBlur(
image: backgroundImage,
startPoint: 0,
endPoint: backgroundImage.size.height / 4,
startRadius: 15,
endRadius: 0
)
/// Adds a vertical variable blur to your image.
VariableBlurImageView.verticalVariableBlur(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a horizontal variable blur to your image.
VariableBlurImageView.horizontalVariableBlur(image:startPoint:endPoint:startRadius:endRadius:)
// Adds a variable blur between two points to your image.
VariableBlurImageView.variableBlur(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a variable blur following the lightness in the provided gradient image.
VariableBlurImageView.gradientBlur(image:gradient:maxRadius:)
/// Adds multiple variable blurs
VariableBlurImageView.mutlipleBlurs(image:descriptions:)
Image
上的视图和视图修饰符可用于异步应用所需的渐进式模糊。
您需要提供图像、起始点、结束点以及它们各自的模糊半径。
注意: ViewModifier 仅在 iOS 16.0 和 macOS 13.0 及更高版本中可用,并且不支持图像变体(例如,深色模式图像)
let backgroundImage = UIImage(resource: .onboardingBackground)
var body: some View {
VStack {
VerticalVariableBlurImage(
image: backgroundImage,
startPoint: 0,
endPoint: backgroundImage.size.height / 4,
startRadius: 15,
endRadius: 0
)
}
}
/// Adds a vertical variable blur to your image.
VerticalVariableBlurImage(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a horizontal variable blur to your image.
HorizontalVariableBlurImage(image:startPoint:endPoint:startRadius:endRadius:)
// Adds a variable blur between two points to your image.
VariableBlurImage(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a variable blur following the lightness in the provided gradient image.
GradientBlurImage(image:gradient:maxRadius:)
/// Adds multiple variable blurs
MultipleBlursImage(image:descriptions:)
/// Adds a vertical variable blur to your image.
Image.verticalVariableBlur(startPoint:endPoint:startRadius:endRadius:)
/// Adds a horizontal variable blur to your image.
Image.horizontalVariableBlur(startPoint:endPoint:startRadius:endRadius:)
// Adds a variable blur between two points to your image.
Image.variableBlur(startPoint:endPoint:startRadius:endRadius:)
/// Adds a variable blur following the lightness in the provided gradient image.
Image.gradientBlur(gradient:maxRadius:)
/// Adds multiple variable blurs
Image.mutlipleBlurs(descriptions:)
VariableBlurEngine
是一个用于将渐进式模糊应用于 CGImages 的对象。
您需要提供 CGImage、起始点、结束点以及它们各自的模糊半径。将返回具有可变模糊效果的新 CGImage。
let variableBlurEngine = VariableBlurEngine()
let leavesImage = UIImage(resource: .leaves)
let blurredImage = variableBlurEngine.applyVerticalVariableBlur(
toImage: leavesImage,
startPoint: 0,
endPoint: leavesImage.size.height / 4,
startRadius: 15,
endRadius: 0
)
/// Adds a vertical variable blur to your image.
VariableBlurEngine.applyVerticalVariableBlur(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a horizontal variable blur to your image.
VariableBlurEngine.applyHorizontalVariableBlur(image:startPoint:endPoint:startRadius:endRadius:)
// Adds a variable blur between two points to your image.
VariableBlurEngine.applyVariableBlur(image:startPoint:endPoint:startRadius:endRadius:)
/// Adds a variable blur following the lightness in the provided gradient image.
VariableBlurEngine.applyGradientVariableBlur(image:gradient:maxRadius:)
/// Adds multiple variable blurs
VariableBlurEngine.applyMultipleVariableBlurs(image:descriptions:)
此框架使用 Swift 和 Metal 编写。
VariableBlurImageView 是主要框架。
GenerateTestImages 是一个小型可执行文件,用于生成用于测试的图像。
VariableBlurImageView 的测试检查代码的当前状态是否生成与先前由 GenerateTestImages
生成的图像集相同的图像集。
当实现更改现有模糊类型的外观时,预计测试会失败。从 Xcode 运行 GenerateTestImages
将生成新图像并使测试成功。
在进行性能改进时,理想情况下测试不应失败。
当实现新的模糊类型时,需要提供新的测试和生成方法。
variableBlurGeneric(_:image:bufferConfigurationHandler:)
。X-variableBlurImpl
方法transformAllVariations(ofImage:variationTransformMode:applyingTransform:)
方法。UIImage
的 UIImageView 子类中编写一个新方法。NSImage
的 NSImageView 子类中编写一个新方法。originalImage
和 blurOperation
属性。GenerateTestImages
中编写新的生成方法。请参阅 生成用于测试的图像通常,每种模糊类型至少编写两个测试——一个检查生成的图像是否符合预期,另一个测量性能。
可以使用 ìsEqual(inputImageName:expectedImageName:afterPerformingImageOperations:)
方法检查相似性,如下所示
func testVerticalVariableBlur() throws {
XCTAssertTrue(
try isEqual(
inputImageName: inputImageName,
expectedImageName: "\(inputImageName)-VerticalBlur...",
afterPerformingImageOperations: { input in
try variableBlurEngine.applyVerticalVariableBlur(
toImage: input,
startPoint: 0,
endPoint: CGFloat(input.height / 2),
startRadius: 20,
endRadius: 0
)
}
)
)
}
可以使用 provideInputImage(inputImageName:)
和 measure
方法测量性能,如下所示
func testPerformanceOfVerticalVariableBlur() throws {
let inputImage = try provideInputImage(inputImageName: inputImageName)
measure {
_ = try! variableBlurEngine.applyVerticalVariableBlur(
toImage: inputImage,
startPoint: 0,
endPoint: CGFloat(inputImage.height / 2),
startRadius: 20,
endRadius: 0
)
}
}
GenerateTestImages 中的 GenerateImages.swift
文件提供了生成图像的实现。
在 OutputImage 上使用 from(image:named:performingOperations:)
方法,并将结果添加到 outputImages
数组。此数组中的条目将写入 Tests 下的 ExpectedOutputs 目录。
// Vertical blur
OutputImage
.from(image: inputImage, named: "\(name)-Vertical...") { input in
try variableBlurEngine.applyVerticalVariableBlur(
toImage: input,
startPoint: 0,
endPoint: CGFloat(input.height / 2),
startRadius: 20,
endRadius: 0
)
}?
.adding(to: &outputImages)
欢迎并鼓励贡献。随时查看项目,提交问题和代码补丁。