├── .github └── FUNDING.yml ├── .gitignore ├── .swiftpm └── xcode │ ├── package.xcworkspace │ └── contents.xcworkspacedata │ └── xcshareddata │ └── xcschemes │ └── Harbeth.xcscheme ├── CATALOGUE.txt ├── Demo ├── Harbeth-Demo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ ├── Harbeth-iOS-Demo.xcscheme │ │ └── Harbeth-macOS-Demo.xcscheme ├── Harbeth-SwiftUI-Demo │ ├── ContentView.swift │ ├── Harbeth-SwiftUI-Demo.entitlements │ ├── HarbethExamples.swift │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── Resources │ │ ├── Assets.xcassets │ │ │ ├── AX.imageset │ │ │ │ ├── AX.jpg │ │ │ │ └── Contents.json │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ ├── IMG_0020.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── IMG_0020.jpg │ │ │ ├── IMG_2606.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── IMG_2606.jpg │ │ │ ├── IMG_4931.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── IMG_4931.png │ │ │ ├── SP.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── SP.png │ │ │ ├── SampleImage.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── SampleImage.jpg │ │ │ ├── lut.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── lut.png │ │ │ └── yuan002.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── yuan002.jpeg │ │ ├── ErrorView.swift │ │ ├── Extensions.swift │ │ ├── ImageLoader.swift │ │ ├── Res.swift │ │ ├── violet.CUBE │ │ └── vista200 v1.CUBE │ └── Views │ │ ├── BlendView.swift │ │ ├── CoreImageViews.swift │ │ ├── CubeView.swift │ │ ├── CustomViews.swift │ │ ├── MetalKernelViews.swift │ │ └── SwiftUIView.swift ├── Harbeth-iOS-Demo │ ├── AppDelegate.swift │ ├── Collector │ │ ├── C7Collector.swift │ │ ├── C7CollectorCamera.swift │ │ └── C7CollectorVideo.swift │ ├── HomeViewController.swift │ ├── HomeViewModel.swift │ ├── HomeViewType+Ext.swift │ ├── HomeViewType.swift │ ├── Modules │ │ ├── CameraViewController.swift │ │ ├── ImageViewController.swift │ │ ├── PlayerViewController.swift │ │ └── UnitTestViewController.swift │ └── Resources │ │ ├── Assets.xcassets │ │ ├── AX.imageset │ │ │ ├── AX.jpg │ │ │ └── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── logoiPhoneApp_60pt@2x.png │ │ │ ├── logoiPhoneApp_60pt@3x.png │ │ │ ├── logoiPhoneNotification_20pt@2x.png │ │ │ ├── logoiPhoneNotification_20pt@3x.png │ │ │ ├── logoiPhoneSpootlight5_29pt@2x.png │ │ │ ├── logoiPhoneSpootlight5_29pt@3x.png │ │ │ ├── logoiPhoneSpootlight7_40pt@2x.png │ │ │ ├── logoiPhoneSpootlight7_40pt@3x.png │ │ │ └── logostore_1024pt.png │ │ ├── Contents.json │ │ ├── IMG_1668.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_1668.jpg │ │ ├── IMG_2606.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_2606.jpg │ │ ├── IMG_2623.imageset │ │ │ ├── Contents.json │ │ │ └── test.jpeg │ │ ├── IMG_3960.imageset │ │ │ ├── Contents.json │ │ │ └── IMG_3960.heic │ │ ├── P1040808.imageset │ │ │ ├── Contents.json │ │ │ └── P1040808.jpg │ │ ├── Zlookup │ │ │ ├── Contents.json │ │ │ ├── ll.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── ll.png │ │ │ └── lut_abao.imageset │ │ │ │ ├── Contents.json │ │ │ │ └── lut_abao.png │ │ ├── timg-2.imageset │ │ │ ├── Contents.json │ │ │ └── timg-2.jpeg │ │ ├── timg-3.imageset │ │ │ ├── Contents.json │ │ │ └── timg-3.jpeg │ │ ├── yuan000.imageset │ │ │ ├── 9.jpeg │ │ │ └── Contents.json │ │ ├── yuan001.imageset │ │ │ ├── 10.jpeg │ │ │ └── Contents.json │ │ ├── yuan002.imageset │ │ │ ├── 11.jpeg │ │ │ └── Contents.json │ │ ├── yuan003.imageset │ │ │ ├── 12.jpeg │ │ │ └── Contents.json │ │ ├── yuan004.imageset │ │ │ ├── 17.jpg │ │ │ └── Contents.json │ │ └── yuan005.imageset │ │ │ ├── 18.jpg │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Color.xcassets │ │ ├── Contents.json │ │ ├── background.colorset │ │ │ └── Contents.json │ │ ├── background2.colorset │ │ │ └── Contents.json │ │ └── defaultTint.colorset │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── SceneDelegate.swift │ │ └── Skateboarding.mp4 └── Harbeth-macOS-Demo │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AR.imageset │ │ ├── 11.jpeg │ │ └── Contents.json │ ├── AX.imageset │ │ ├── AX.jpg │ │ └── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── lut_abao.imageset │ │ ├── Contents.json │ │ └── lut_abao.png │ └── lut_ll.imageset │ │ ├── Contents.json │ │ └── lut_ll.png │ ├── Base.lproj │ └── Main.storyboard │ ├── DisplayLink.swift │ ├── Harbeth_macOS_Demo.entitlements │ └── ViewController.swift ├── Document ├── Metal.pdf └── Shader.pdf ├── Harbeth.podspec ├── Harbeth.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Harbeth.xcscheme ├── Harbeth.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── LICENSE ├── Language ├── Language.metal └── Metal.metal ├── Package.swift ├── README.md ├── README_CN.md ├── Screenshot ├── 001.png ├── EdgeGlow.gif ├── M.jpeg ├── Mix.png ├── Mix2.png ├── ShiftGlitch.gif ├── Soul.gif ├── SoulOut.gif ├── WechatIMG1.jpg ├── WechatIMG2.jpg ├── flow.png └── launch.jpeg └── Sources ├── Basic ├── Core │ ├── Compute.swift │ ├── Device.swift │ ├── Filtering.swift │ ├── Rendering.swift │ ├── Shared.swift │ └── TextureLoader.swift ├── Extensions │ ├── C7Color+Driver.swift │ ├── C7Color+Ext.swift │ ├── C7Image+Ext.swift │ ├── C7Image+iOS.swift │ ├── C7Image+macOS.swift │ ├── C7View+iOS.swift │ ├── CATransform3D+Ext.swift │ ├── CGContext+Ext.swift │ ├── CGImage+Ext.swift │ ├── CGPath+Ext.swift │ ├── CGPoint+Ext.swift │ ├── CGRect+Ext.swift │ ├── CGSize+Ext.swift │ ├── CIImage+Ext.swift │ ├── CMSampleBuffer+Ext.swift │ ├── CVPixelBuffer+Ext.swift │ ├── Data+Ext.swift │ ├── MTLCommandBuffer+Ext.swift │ ├── MTLSize+Ext.swift │ ├── MTLTexture+Ext.swift │ ├── String+Ext.swift │ └── URL+Ext.swift ├── Matrix │ ├── Matrix.swift │ ├── Matrix3x3.swift │ ├── Matrix4x4.swift │ ├── Matrix4x5.swift │ ├── Vector3.swift │ └── Vector4.swift ├── Outputs │ ├── Destype.swift │ ├── HarbethIO.swift │ ├── HugeImage.swift │ ├── Operators.swift │ ├── Outputable.swift │ ├── RenderImageView.swift │ ├── RenderView.swift │ └── Renderable.swift └── Setup │ ├── Cacheable.swift │ ├── Clamping.swift │ ├── Degree.swift │ ├── Error.swift │ ├── Files.swift │ ├── Locked.swift │ ├── Mirrorable.swift │ ├── ParameterRange.swift │ ├── Pixel.swift │ ├── Placement.swift │ ├── Point2D.swift │ ├── R.swift │ ├── RGBA.swift │ ├── ResizingMode.swift │ ├── Size.swift │ ├── Typealias.swift │ ├── Wrapper.swift │ └── ZeroOneRange.swift ├── Compute ├── Blend │ ├── C7Blend.swift │ ├── C7BlendChromaKey.metal │ ├── C7BlendColorAdd.metal │ ├── C7BlendColorAlpha.metal │ ├── C7BlendColorBurn.metal │ ├── C7BlendColorDodge.metal │ ├── C7BlendDarken.metal │ ├── C7BlendDifference.metal │ ├── C7BlendDissolve.metal │ ├── C7BlendDivide.metal │ ├── C7BlendExclusion.metal │ ├── C7BlendHardLight.metal │ ├── C7BlendHue.metal │ ├── C7BlendLighten.metal │ ├── C7BlendLinearBurn.metal │ ├── C7BlendLuminosity.metal │ ├── C7BlendMask.metal │ ├── C7BlendMultiply.metal │ ├── C7BlendNormal.metal │ ├── C7BlendOverlay.metal │ ├── C7BlendScreen.metal │ ├── C7BlendSoftLight.metal │ ├── C7BlendSourceOver.metal │ └── C7BlendSubtract.metal ├── Blur │ ├── C7BilateralBlur.metal │ ├── C7BilateralBlur.swift │ ├── C7CircleBlur.metal │ ├── C7CircleBlur.swift │ ├── C7GaussianBlur.metal │ ├── C7GaussianBlur.swift │ ├── C7MeanBlur.metal │ ├── C7MeanBlur.swift │ ├── C7MotionBlur.metal │ ├── C7MotionBlur.swift │ ├── C7RedMonochromeBlur.metal │ ├── C7RedMonochromeBlur.swift │ ├── C7ZoomBlur.metal │ └── C7ZoomBlur.swift ├── Combination │ ├── C7CombinationBeautiful.metal │ ├── C7CombinationBeautiful.swift │ └── C7CombinationBilateralBlur.swift ├── Coordinate │ ├── C7Bulge.metal │ ├── C7Bulge.swift │ ├── C7ColorCGASpace.metal │ ├── C7ColorCGASpace.swift │ ├── C7ColorPacking.metal │ ├── C7ColorPacking.swift │ ├── C7Fluctuate.metal │ ├── C7Fluctuate.swift │ ├── C7GlassSphere.metal │ ├── C7GlassSphere.swift │ ├── C7Glitch.metal │ ├── C7Glitch.swift │ ├── C7Halftone.metal │ ├── C7Halftone.swift │ ├── C7Kuwahara.metal │ ├── C7Kuwahara.swift │ ├── C7OilPainting.metal │ ├── C7OilPainting.swift │ ├── C7Pinch.metal │ ├── C7Pinch.swift │ ├── C7Pixellated.metal │ ├── C7Pixellated.swift │ ├── C7PolarPixellate.metal │ ├── C7PolarPixellate.swift │ ├── C7PolkaDot.metal │ ├── C7PolkaDot.swift │ ├── C7RGBADilation.metal │ ├── C7RGBADilation.swift │ ├── C7Sharpen.metal │ ├── C7Sharpen.swift │ ├── C7Sketch.metal │ ├── C7Sketch.swift │ ├── C7SoulOut.metal │ ├── C7SoulOut.swift │ ├── C7SphereRefraction.metal │ ├── C7SphereRefraction.swift │ ├── C7SplitScreen.metal │ ├── C7SplitScreen.swift │ ├── C7Storyboard.metal │ ├── C7Storyboard.swift │ ├── C7Swirl.metal │ ├── C7Swirl.swift │ ├── C7ThresholdSketch.metal │ ├── C7ThresholdSketch.swift │ ├── C7Toon.metal │ ├── C7Toon.swift │ ├── C7WaterRipple.metal │ └── C7WaterRipple.swift ├── Generator │ ├── C7ColorGradient.metal │ ├── C7ColorGradient.swift │ ├── C7SolidColor.metal │ └── C7SolidColor.swift ├── Lookup │ ├── C7LookupSplit.metal │ ├── C7LookupSplit.swift │ ├── C7LookupTable.metal │ └── C7LookupTable.swift ├── Matrix │ ├── C7ColorMatrix4x4.metal │ ├── C7ColorMatrix4x4.swift │ ├── C7ColorMatrix4x5.metal │ ├── C7ColorMatrix4x5.swift │ ├── C7ColorVector4.metal │ ├── C7ColorVector4.swift │ ├── C7ConvolutionMatrix3x3.metal │ ├── C7ConvolutionMatrix3x3.swift │ ├── C7EdgeGlow.metal │ ├── C7EdgeGlow.swift │ ├── C7Nostalgic.metal │ ├── C7Nostalgic.swift │ ├── C7Sepia.metal │ └── C7Sepia.swift ├── Pixel │ ├── C7Brightness.metal │ ├── C7Brightness.swift │ ├── C7ChromaKey.metal │ ├── C7ChromaKey.swift │ ├── C7ColorConvert.metal │ ├── C7ColorConvert.swift │ ├── C7ColorRGBA.metal │ ├── C7ColorRGBA.swift │ ├── C7ColorSpace.metal │ ├── C7ColorSpace.swift │ ├── C7ComicStrip.metal │ ├── C7ComicStrip.swift │ ├── C7Contrast.metal │ ├── C7Contrast.swift │ ├── C7Crosshatch.metal │ ├── C7Crosshatch.swift │ ├── C7DepthLuminance.metal │ ├── C7DepthLuminance.swift │ ├── C7Exposure.metal │ ├── C7Exposure.swift │ ├── C7FalseColor.metal │ ├── C7FalseColor.swift │ ├── C7Gamma.metal │ ├── C7Gamma.swift │ ├── C7Granularity.metal │ ├── C7Granularity.swift │ ├── C7Grayed.metal │ ├── C7Grayed.swift │ ├── C7Haze.metal │ ├── C7Haze.swift │ ├── C7HighlightShadow.metal │ ├── C7HighlightShadow.swift │ ├── C7HighlightShadowTint.metal │ ├── C7HighlightShadowTint.swift │ ├── C7Hue.metal │ ├── C7Hue.swift │ ├── C7Levels.metal │ ├── C7Levels.swift │ ├── C7Luminance.metal │ ├── C7Luminance.swift │ ├── C7LuminanceRangeReduction.metal │ ├── C7LuminanceRangeReduction.swift │ ├── C7LuminanceThreshold.metal │ ├── C7LuminanceThreshold.swift │ ├── C7Monochrome.metal │ ├── C7Monochrome.swift │ ├── C7Opacity.metal │ ├── C7Opacity.swift │ ├── C7Posterize.metal │ ├── C7Posterize.swift │ ├── C7Pow.metal │ ├── C7Pow.swift │ ├── C7Saturation.metal │ ├── C7Saturation.swift │ ├── C7ShiftGlitch.metal │ ├── C7ShiftGlitch.swift │ ├── C7Sobel.metal │ ├── C7Sobel.swift │ ├── C7Vibrance.metal │ ├── C7Vibrance.swift │ ├── C7Vignette.metal │ ├── C7Vignette.swift │ ├── C7VoronoiOverlay.metal │ ├── C7VoronoiOverlay.swift │ ├── C7WhiteBalance.metal │ └── C7WhiteBalance.swift └── Shape │ ├── C7Crop.metal │ ├── C7Crop.swift │ ├── C7Flip.metal │ ├── C7Flip.swift │ ├── C7Resize.metal │ ├── C7Resize.swift │ ├── C7Rotate.metal │ ├── C7Rotate.swift │ ├── C7Transform.metal │ └── C7Transform.swift ├── CoreImage ├── CIBrightness.swift ├── CIColorControls.swift ├── CIColorCube.swift ├── CIColorMonochrome.swift ├── CIContrast.swift ├── CIExposure.swift ├── CIFade.swift ├── CIGaussianBlur.swift ├── CIHighlight.swift ├── CILookupTable.swift ├── CINoiseReduction.swift ├── CIPhotoEffect.swift ├── CIResizedSmooth.swift ├── CISaturation.swift ├── CIShadows.swift ├── CISharpen.swift ├── CISketch.swift ├── CITemperature.swift ├── CIUnsharpMask.swift ├── CIVignette.swift └── CIWhitePoint.swift ├── Harbeth.h ├── MPS ├── MPSBoxBlur.swift ├── MPSGaussianBlur.swift └── MPSHistogram.swift └── SwiftUI ├── Color+Ext.swift ├── HarbethView.swift ├── HarbethViewInput.swift ├── Image+Ext.swift └── Published_Image.swift /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [yangKJ] 4 | buy_me_a_coffee: yangkj3102 5 | custom: ["https://raw.githubusercontent.com/yangKJ/Harbeth/master/Screenshot/WechatIMG2.jpg", "https://raw.githubusercontent.com/yangKJ/Harbeth/master/Screenshot/WechatIMG1.jpg"] 6 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Harbeth-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/Harbeth-Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Harbeth-SwiftUI-Demo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.network.client 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/HarbethExamples.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HarbethExamples.swift 3 | // Harbeth-SwiftUI-Demo 4 | // 5 | // Created by Condy on 2023/3/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct HarbethExamples: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | #if os(macOS) 16 | .frame(width: 888, height: 600) 17 | #endif 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/AX.imageset/AX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/AX.imageset/AX.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/AX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AX.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_0020.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_0020.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_0020.imageset/IMG_0020.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_0020.imageset/IMG_0020.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_2606.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_2606.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_2606.imageset/IMG_2606.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_2606.imageset/IMG_2606.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_4931.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_4931.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_4931.imageset/IMG_4931.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/IMG_4931.imageset/IMG_4931.png -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SP.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "SP.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SP.imageset/SP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SP.imageset/SP.png -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SampleImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "SampleImage.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SampleImage.imageset/SampleImage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/SampleImage.imageset/SampleImage.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/lut.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "lut.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/lut.imageset/lut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/lut.imageset/lut.png -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/yuan002.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "yuan002.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/yuan002.imageset/yuan002.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-SwiftUI-Demo/Resources/Assets.xcassets/yuan002.imageset/yuan002.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/Res.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Res.swift 3 | // Harbeth-SwiftUI-Demo 4 | // 5 | // Created by Condy on 2023/7/29. 6 | // 7 | 8 | import Foundation 9 | import Harbeth 10 | 11 | struct Res { 12 | 13 | public static func rgUVB1Gradient(_ size: CGSize = .onePixel) throws -> MTLTexture { 14 | let texture = try TextureLoader.makeTexture(at: size) 15 | let filter = C7ColorGradient(with: .rgUVB1) 16 | var dest = HarbethIO(element: texture, filter: filter) 17 | //dest.createDestTexture = false 18 | return try dest.output() 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Demo/Harbeth-SwiftUI-Demo/Resources/violet.CUBE: -------------------------------------------------------------------------------- 1 | #Created by: Adobe Photoshop Export Color Lookup Plugin 2 | TITLE "violet.psd" 3 | 4 | #LUT size 5 | LUT_3D_SIZE 2 6 | 7 | #data domain 8 | DOMAIN_MIN 0.0 0.0 0.0 9 | DOMAIN_MAX 1.0 1.0 1.0 10 | 11 | #LUT data points 12 | 0 0 0 13 | 0.1 0 1 14 | 0 1 0 15 | 1 1 0 16 | 0 0 1 17 | 1 0 1 18 | 0 1 1 19 | 1 1 1 20 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AX.imageset/AX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AX.imageset/AX.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AX.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneApp_60pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneApp_60pt@2x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneApp_60pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneApp_60pt@3x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneNotification_20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneNotification_20pt@2x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneNotification_20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneNotification_20pt@3x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight5_29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight5_29pt@2x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight5_29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight5_29pt@3x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight7_40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight7_40pt@2x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight7_40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logoiPhoneSpootlight7_40pt@3x.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logostore_1024pt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/AppIcon.appiconset/logostore_1024pt.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_1668.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_1668.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_1668.imageset/IMG_1668.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_1668.imageset/IMG_1668.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2606.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_2606.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2606.imageset/IMG_2606.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2606.imageset/IMG_2606.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2623.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "test.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2623.imageset/test.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_2623.imageset/test.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_3960.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IMG_3960.heic", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_3960.imageset/IMG_3960.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/IMG_3960.imageset/IMG_3960.heic -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/P1040808.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "P1040808.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/P1040808.imageset/P1040808.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/P1040808.imageset/P1040808.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/ll.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ll.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/ll.imageset/ll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/ll.imageset/ll.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/lut_abao.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "lut_abao.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/lut_abao.imageset/lut_abao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/Zlookup/lut_abao.imageset/lut_abao.png -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "timg-2.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-2.imageset/timg-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-2.imageset/timg-2.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "timg-3.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-3.imageset/timg-3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/timg-3.imageset/timg-3.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan000.imageset/9.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan000.imageset/9.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan000.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "9.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan001.imageset/10.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan001.imageset/10.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan001.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "10.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan002.imageset/11.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan002.imageset/11.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan002.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "11.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan003.imageset/12.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan003.imageset/12.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan003.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "12.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan004.imageset/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan004.imageset/17.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan004.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "17.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan005.imageset/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan005.imageset/18.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Assets.xcassets/yuan005.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "18.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Color.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Color.xcassets/background.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.957", 9 | "green" : "0.953", 10 | "red" : "0.953" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "light" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.957", 27 | "green" : "0.953", 28 | "red" : "0.953" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | }, 33 | { 34 | "appearances" : [ 35 | { 36 | "appearance" : "luminosity", 37 | "value" : "dark" 38 | } 39 | ], 40 | "color" : { 41 | "color-space" : "srgb", 42 | "components" : { 43 | "alpha" : "1.000", 44 | "blue" : "0.090", 45 | "green" : "0.078", 46 | "red" : "0.067" 47 | } 48 | }, 49 | "idiom" : "universal" 50 | } 51 | ], 52 | "info" : { 53 | "author" : "xcode", 54 | "version" : 1 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Color.xcassets/background2.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.262", 9 | "green" : "0.176", 10 | "red" : "0.833" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "0.602", 28 | "red" : "0.033" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Color.xcassets/defaultTint.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.010", 9 | "green" : "0.000", 10 | "red" : "0.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "1.000", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Demo/Harbeth-iOS-Demo/Resources/Skateboarding.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-iOS-Demo/Resources/Skateboarding.mp4 -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Harbeth-macOS-Demo 4 | // 5 | // Created by Condy on 2023/2/9. 6 | // 7 | 8 | import Cocoa 9 | 10 | @main 11 | class AppDelegate: NSObject, NSApplicationDelegate { 12 | 13 | lazy var window: NSWindow = { 14 | let rect = NSMakeRect(0, 0, 700, 700) 15 | let mask = [.titled, .resizable, .miniaturizable, .closable, .fullSizeContentView] as NSWindow.StyleMask 16 | let window = NSWindow(contentRect: rect, styleMask: mask, backing: .buffered, defer: false) 17 | window.minSize = window.frame.size 18 | window.maxSize = window.frame.size 19 | window.center() 20 | return window 21 | }() 22 | 23 | func applicationDidFinishLaunching(_ aNotification: Notification) { 24 | // Insert code here to initialize your application 25 | window.makeKeyAndOrderFront(nil) 26 | NSApplication.shared.mainWindow?.title = "Unit testing" 27 | let vc = ViewController() 28 | window.contentViewController = vc 29 | } 30 | 31 | func applicationWillTerminate(_ aNotification: Notification) { 32 | // Insert code here to tear down your application 33 | } 34 | 35 | func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { 36 | return true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AR.imageset/11.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-macOS-Demo/Assets.xcassets/AR.imageset/11.jpeg -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AR.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "11.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AX.imageset/AX.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-macOS-Demo/Assets.xcassets/AX.imageset/AX.jpg -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AX.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "AX.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_abao.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "lut_abao.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_abao.imageset/lut_abao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_abao.imageset/lut_abao.png -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_ll.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "lut_ll.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_ll.imageset/lut_ll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Demo/Harbeth-macOS-Demo/Assets.xcassets/lut_ll.imageset/lut_ll.png -------------------------------------------------------------------------------- /Demo/Harbeth-macOS-Demo/Harbeth_macOS_Demo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Document/Metal.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Document/Metal.pdf -------------------------------------------------------------------------------- /Document/Shader.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Document/Shader.pdf -------------------------------------------------------------------------------- /Harbeth.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Harbeth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Harbeth.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Harbeth.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 AT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Screenshot/001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/001.png -------------------------------------------------------------------------------- /Screenshot/EdgeGlow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/EdgeGlow.gif -------------------------------------------------------------------------------- /Screenshot/M.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/M.jpeg -------------------------------------------------------------------------------- /Screenshot/Mix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/Mix.png -------------------------------------------------------------------------------- /Screenshot/Mix2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/Mix2.png -------------------------------------------------------------------------------- /Screenshot/ShiftGlitch.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/ShiftGlitch.gif -------------------------------------------------------------------------------- /Screenshot/Soul.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/Soul.gif -------------------------------------------------------------------------------- /Screenshot/SoulOut.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/SoulOut.gif -------------------------------------------------------------------------------- /Screenshot/WechatIMG1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/WechatIMG1.jpg -------------------------------------------------------------------------------- /Screenshot/WechatIMG2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/WechatIMG2.jpg -------------------------------------------------------------------------------- /Screenshot/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/flow.png -------------------------------------------------------------------------------- /Screenshot/launch.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yangKJ/Harbeth/c195eed9192c8686eb28d2434269077e12371d0b/Screenshot/launch.jpeg -------------------------------------------------------------------------------- /Sources/Basic/Extensions/CGRect+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CGRect+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | extension CGRect: HarbethCompatible { } 11 | 12 | extension HarbethWrapper where Base == CGRect { 13 | 14 | public func radius(_ value: Float, max: Float) -> Float { 15 | let base = Float(sqrt(pow(base.width, 2) + pow(base.height, 2))) 16 | return base / 20 * value / max 17 | } 18 | 19 | public func toPoint2D(with size: C7Size) -> C7Point2D { 20 | C7Point2D(x: Float(base.origin.x) / Float(size.width), 21 | y: Float(base.origin.y) / Float(size.height)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Basic/Extensions/Data+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/27. 6 | // 7 | 8 | import Foundation 9 | import MetalKit 10 | 11 | extension Data: HarbethCompatible { } 12 | 13 | extension HarbethWrapper where Base == Data { 14 | 15 | /// Image data to texture 16 | /// 17 | /// Texture loader can not load image data to create texture 18 | /// If image orientation is not up, texture loader may not load texture from image data. 19 | /// Create a UIImage from image data to get metal texture 20 | /// Draw image and create texture 21 | /// - Parameter options: Dictonary of MTKTextureLoaderOptions 22 | /// - Returns: MTLTexture 23 | public func toTexture(options: [MTKTextureLoader.Option: Any]? = nil) -> MTLTexture? { 24 | return try? TextureLoader.init(with: base, options: options).texture 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Basic/Extensions/MTLCommandBuffer+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MTLCommandBuffer+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/8. 6 | // 7 | 8 | import Foundation 9 | import MetalKit 10 | 11 | extension MTLCommandBuffer { 12 | 13 | /// Asynchronous submission of texture drawing. 14 | func asyncCommit(complete: @escaping (Result) -> Void) { 15 | self.addCompletedHandler { (buffer) in 16 | switch buffer.status { 17 | case .completed: 18 | complete(.success(())) 19 | case .error where buffer.error != nil: 20 | complete(.failure(.error(buffer.error!))) 21 | default: 22 | break 23 | } 24 | } 25 | self.commit() 26 | } 27 | 28 | func commitAndWaitUntilCompleted() { 29 | // Commit a command buffer so it can be executed as soon as possible. 30 | self.commit() 31 | // Wait to make sure that output texture contains new data. 32 | self.waitUntilCompleted() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Basic/Extensions/URL+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URL+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/12/8. 6 | // 7 | 8 | import Foundation 9 | 10 | extension URL: HarbethCompatible { } 11 | 12 | extension HarbethWrapper where Base == URL { 13 | 14 | public func loadCGImage() -> CGImage? { 15 | #if os(macOS) 16 | guard let nsImage = C7Image(contentsOf: base), 17 | let tiffData = nsImage.tiffRepresentation, 18 | let cgImageSource = CGImageSourceCreateWithData(tiffData as CFData, nil), 19 | let cgImage = CGImageSourceCreateImageAtIndex(cgImageSource, 0, nil) else { 20 | return nil 21 | } 22 | return cgImage 23 | #else 24 | guard let uiImage = C7Image(contentsOfFile: base.path) else { 25 | return nil 26 | } 27 | return uiImage.cgImage 28 | #endif 29 | } 30 | 31 | public var isLocalResource: Bool { 32 | base.scheme == "file" || base.scheme == "data" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Basic/Matrix/Matrix.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/18. 6 | // 7 | 8 | import Foundation 9 | import QuartzCore 10 | 11 | public protocol Matrix { 12 | associatedtype MatrixType 13 | 14 | static var size: Int { get } 15 | 16 | var values: [Float] { get set } 17 | 18 | init(values: [Float]) 19 | 20 | func to_factor() -> MatrixType 21 | } 22 | 23 | extension Matrix { 24 | public static var size: Int { 25 | MemoryLayout.size 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Basic/Matrix/Matrix4x5.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Matrix4x5.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 4 x 5 颜色矩阵 11 | public struct Matrix4x5 { 12 | 13 | public let matrix4x4: Matrix4x4 14 | public let vector4: Vector4 15 | 16 | public init(values: [Float]) { 17 | if values.count != 20 { 18 | HarbethError.failed("There must be twenty values for 4x5 Matrix.") 19 | } 20 | var matrix = [Float]() 21 | var vector = [Float]() 22 | for (index, value) in values.enumerated() { 23 | if (index+7) % 5 == 1 { 24 | vector.append(value) 25 | } else { 26 | matrix.append(value) 27 | } 28 | } 29 | self.matrix4x4 = Matrix4x4(values: matrix) 30 | self.vector4 = Vector4(values: vector) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Basic/Matrix/Vector3.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Vector3.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | import simd 10 | 11 | /// 3维向量 12 | public struct Vector3: Matrix { 13 | 14 | public typealias MatrixType = vector_float3 15 | 16 | public var values: [Float] 17 | 18 | public init(values: [Float]) { 19 | if values.count != 3 { 20 | HarbethError.failed("There must be three values for Vector3.") 21 | } 22 | self.values = values 23 | } 24 | 25 | public init(color: C7Color) { 26 | let (red, green, blue, _) = color.c7.toRGBA() 27 | self.init(values: [red, green, blue]) 28 | } 29 | 30 | public func to_factor() -> vector_float3 { 31 | vector_float3.init(values[0], values[1], values[2]) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Basic/Outputs/HugeImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HugeImage.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/3/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 超大图像 11 | public struct HugeImage { 12 | 13 | public let image: C7Image 14 | 15 | public init(image: C7Image) { 16 | self.image = image 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Basic/Outputs/RenderImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RenderView.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/3/20. 6 | // 7 | 8 | import Foundation 9 | import MetalKit 10 | 11 | public final class RenderImageView: C7ImageView, Renderable { 12 | 13 | public typealias Element = C7Image 14 | 15 | public override var image: C7Image? { 16 | didSet { 17 | if lockedSource { 18 | return 19 | } 20 | self.setupInputSource() 21 | self.filtering() 22 | } 23 | } 24 | } 25 | 26 | extension Renderable where Self: C7ImageView { 27 | 28 | public func setupInputSource() { 29 | if lockedSource { 30 | return 31 | } 32 | if let image = self.image { 33 | self.inputSource = try? TextureLoader(with: image).texture 34 | } 35 | } 36 | 37 | public func setupOutputDest(_ dest: MTLTexture) { 38 | DispatchQueue.main.async { 39 | if let image = self.image { 40 | self.lockedSource = true 41 | self.image = try? dest.c7.fixImageOrientation(refImage: image) 42 | self.lockedSource = false 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Clamping.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Clamping.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/1/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Range wrapper. 11 | /// Example: ``@Clamping(0...2) var radius: Float = 1.0`` 12 | @propertyWrapper public struct Clamping { 13 | private var value: Value 14 | private let range: ClosedRange 15 | 16 | public var wrappedValue: Value { 17 | get { value } 18 | set { value = Swift.min(Swift.max(newValue, range.lowerBound), range.upperBound) } 19 | } 20 | 21 | public init(wrappedValue: Value, _ range: ClosedRange) { 22 | self.value = Swift.min(Swift.max(wrappedValue, range.lowerBound), range.upperBound) 23 | self.range = range 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Degree.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Degree.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Degree { 11 | 12 | public let value: Float 13 | 14 | public init(value: Float) { 15 | self.value = value 16 | } 17 | 18 | public var radians: Float { 19 | return Float(value * Float.pi / 180.0) 20 | } 21 | } 22 | 23 | // MARK: - Negative Degrees 24 | public prefix func -(degree: Degree) -> Degree { 25 | return Degree(value: -1 * degree.value) 26 | } 27 | 28 | /// `0.0 ..< 360.0` 范围角度区间属性包装器 29 | @propertyWrapper public struct DegreeRange { 30 | 31 | public var wrappedValue: Float { 32 | didSet { 33 | let value = wrappedValue.truncatingRemainder(dividingBy: 360.0) 34 | wrappedValue = value >= 0 ? value : 360 + value 35 | } 36 | } 37 | 38 | public init(wrappedValue: Float) { 39 | let value = wrappedValue.truncatingRemainder(dividingBy: 360.0) 40 | self.wrappedValue = value >= 0 ? value : 360 + value 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Mirrorable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Mirrorable.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/12/8. 6 | // 7 | 8 | import Foundation 9 | 10 | public protocol Mirrorable { 11 | /// Parametric description. 12 | var parameterDescription: [String: Any] { get } 13 | } 14 | 15 | extension Mirrorable { 16 | public var parameterDescription: [String: Any] { 17 | mapDictionary(mirror: Mirror(reflecting: self)) 18 | } 19 | } 20 | 21 | extension Mirrorable { 22 | private func mapDictionary(mirror: Mirror) -> [String: Any] { 23 | var dict: [String: Any] = [:] 24 | for child in mirror.children { 25 | // If there is no labe, it will be discarded. 26 | if let label = child.label { 27 | //_ = Mirror(reflecting: child.value) 28 | dict[label] = child.value 29 | } 30 | } 31 | if let superMirror = mirror.superclassMirror { 32 | let superDic = mapDictionary(mirror: superMirror) 33 | for x in superDic { 34 | dict[x.key] = x.value 35 | } 36 | } 37 | return dict 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/ParameterRange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ParameterRange.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct ParameterRange { 11 | 12 | public let min: T 13 | public let max: T 14 | public let value: T 15 | 16 | /// Initialize the parameter range. 17 | /// - Parameters: 18 | /// - min: Indicates the minimum value 19 | /// - max: Indicates the maximum value 20 | /// - value: Indicates the default value 21 | public init(min: T, max: T, value: T) { 22 | self.min = min 23 | self.max = max 24 | self.value = value 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Pixel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pixel.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/2/28. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct Pixel { 11 | /// 颜色通道 12 | public enum Channel: Int { 13 | case red = 0 14 | case green 15 | case blue 16 | case alpha 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Point2D.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Point2D.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/12. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 对于 2D 纹理,采用归一化之后的纹理坐标, 在 x 轴和 y 轴方向上都是从 0.0 到 1.0 11 | /// 2D textures, normalized texture coordinates are used, from 0.0 to 1.0 in both x and y directions 12 | public struct C7Point2D { 13 | 14 | public static let maximum = C7Point2D(x: 1.0, y: 1.0) 15 | public static let center = C7Point2D(x: 0.5, y: 0.5) 16 | public static let zero = C7Point2D(x: 0.0, y: 0.0) 17 | 18 | @ZeroOneRange public var x: Float 19 | @ZeroOneRange public var y: Float 20 | 21 | public init(x: Float, y: Float) { 22 | self.x = x 23 | self.y = y 24 | } 25 | 26 | /// Initialize the normalized texture coordinates. 27 | /// - Parameters: 28 | /// - point: Current coordinate point. 29 | /// - size: Image size. 30 | public init(point: CGPoint, size: CGSize) { 31 | let x_ = Float(point.x / size.width) 32 | let y_ = Float(point.y / size.height) 33 | self.init(x: x_, y: y_) 34 | } 35 | } 36 | 37 | extension C7Point2D { 38 | public func toXY() -> [Float] { 39 | [x, y] 40 | } 41 | } 42 | 43 | extension C7Point2D: Equatable { 44 | 45 | public static func == (lhs: C7Point2D, rhs: C7Point2D) -> Bool { 46 | lhs.x == rhs.x && lhs.y == rhs.y 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Size.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Size.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/12. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Size { 11 | 12 | public static let zero = C7Size(width: 0, height: 0) 13 | 14 | public var width: Int 15 | public var height: Int 16 | 17 | public init(width: Int, height: Int) { 18 | self.width = width 19 | self.height = height 20 | } 21 | } 22 | 23 | extension C7Size { 24 | public func toFloatArray() -> [Float] { 25 | [Float(width), Float(height)] 26 | } 27 | } 28 | 29 | extension C7Size: Equatable { 30 | 31 | public static func == (lhs: C7Size, rhs: C7Size) -> Bool { 32 | lhs.width == rhs.width && lhs.height == rhs.height 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Typealias.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Typealias.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | @_exported import MetalKit 10 | @_exported import CoreVideo 11 | @_exported import CoreImage 12 | @_exported import CoreMedia 13 | @_exported import AVFoundation 14 | import ImageIO 15 | 16 | #if os(iOS) || os(tvOS) || os(watchOS) 17 | import UIKit 18 | public typealias C7View = UIView 19 | public typealias C7Color = UIColor 20 | public typealias C7Image = UIImage 21 | public typealias C7EdgeInsets = UIEdgeInsets 22 | public typealias C7ImageView = UIImageView 23 | public typealias C7ImageOrientation = UIImage.Orientation 24 | #elseif os(macOS) 25 | import AppKit 26 | public typealias C7View = NSView 27 | public typealias C7Color = NSColor 28 | public typealias C7Image = NSImage 29 | public typealias C7EdgeInsets = NSEdgeInsets 30 | public typealias C7ImageView = NSImageView 31 | public typealias C7ImageOrientation = CGImagePropertyOrientation 32 | #endif 33 | 34 | public typealias C7InputTextures = [MTLTexture] 35 | public typealias C7FilterImageCallback = (_ image: C7Image) -> Void 36 | 37 | typealias C7KernelFunction = String 38 | 39 | // Make sure to run on the main thread. 40 | //@inline(__always) func make_run_on_main_thread() { 41 | // assert(Thread.isMainThread) 42 | //} 43 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/Wrapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Wrapper.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Add the `c7` prefix namespace. 11 | public struct HarbethWrapper { 12 | /// Stores the type or meta-type of any extended type. 13 | public private(set) var base: Base 14 | /// Create an instance from the provided value. 15 | public init(base: Base) { 16 | self.base = base 17 | } 18 | } 19 | 20 | /// Protocol describing the `c7` extension points for Alamofire extended types. 21 | public protocol HarbethCompatible { } 22 | 23 | extension HarbethCompatible { 24 | 25 | public var c7: HarbethWrapper { 26 | get { return HarbethWrapper(base: self) } 27 | set { } 28 | } 29 | 30 | public static var c7: HarbethWrapper.Type { 31 | HarbethWrapper.self 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Basic/Setup/ZeroOneRange.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ZeroOneRange.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/25. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 0.0 ~ 1.0 范围区间属性包装器 11 | /// 0.0 ~ 1.0 Range Interval Property Packer. 12 | @propertyWrapper public struct ZeroOneRange { 13 | 14 | public var wrappedValue: Float { 15 | didSet { 16 | wrappedValue = min(1.0, max(0.0, wrappedValue)) 17 | } 18 | } 19 | 20 | public init(wrappedValue: Float) { 21 | self.wrappedValue = min(1.0, max(0.0, wrappedValue)) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendColorAlpha.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendColorAlpha.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendColorAlpha(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *mixturePercent [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor(mix(inColor.rgb, overlay.rgb, overlay.a * half(*mixturePercent)), inColor.a); 22 | 23 | outputTexture.write(outColor, grid); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendColorBurn.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendColorBurn.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendColorBurn(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 whiteColor = half4(1.0h); 22 | const half4 outColor = whiteColor - (whiteColor - inColor) / overlay; 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendDarken.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendDarken.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendDarken(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor(min(overlay.rgb * inColor.a, inColor.rgb * overlay.a) + overlay.rgb * (1.0h - inColor.a) + inColor.rgb * (1.0h - overlay.a), 1.0h); 22 | 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendDifference.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendDifference.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendDifference(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor(abs(overlay.rgb - inColor.rgb), inColor.a); 22 | 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendDissolve.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendDissolve.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendDissolve(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = mix(inColor, overlay, half(*intensity)); 22 | 23 | outputTexture.write(outColor, grid); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendExclusion.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendExclusion.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendExclusion(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half3 excolor = half3(overlay.rgb * inColor.a + inColor.rgb * overlay.a - 2.0h * overlay.rgb * inColor.rgb) + overlay.rgb * (1.0h - inColor.a) + inColor.rgb * (1.0h - overlay.a); 22 | const half4 outColor = half4(excolor, inColor.a); 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendLighten.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendLighten.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendLighten(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = max(inColor, overlay); 22 | const half4 output = mix(inColor, outColor, half(*intensity)); 23 | 24 | outputTexture.write(output, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendLinearBurn.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendLinearBurn.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendLinearBurn(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = half4(clamp(inColor.rgb + overlay.rgb - half3(1.0h), half3(0.0h), half3(1.0h)), inColor.a); 22 | const half4 output = mix(inColor, outColor, half(*intensity)); 23 | 24 | outputTexture.write(output, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendMask.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendMask.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendMask(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half newAlpha = dot(overlay.rgb, half3(.33333334, .33333334, .33333334)) * overlay.a; 22 | const half4 outColor = half4(inColor.rgb, newAlpha); 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendMultiply.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendMultiply.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendMultiply(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = overlay * inColor + overlay * (1.0h - inColor.a) + inColor * (1.0h - overlay.a); 22 | const half4 output = mix(inColor, outColor, half(*intensity)); 23 | 24 | outputTexture.write(output, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendNormal.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendNormal.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendNormal(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | half4 outColor; 22 | outColor.rgb = overlay.rgb + inColor.rgb * inColor.a * (1 - overlay.a); 23 | outColor.a = overlay.a + inColor.a * (1 - overlay.a); 24 | 25 | const half4 output = mix(inColor, outColor, half(*intensity)); 26 | 27 | outputTexture.write(output, grid); 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendScreen.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendScreen.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendScreen(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 whiteColor = half4(1.0); 22 | const half4 outColor = whiteColor - ((whiteColor - overlay) * (whiteColor - inColor)); 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendSoftLight.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendSoftLight.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendSoftLight(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half alphaDivisor = inColor.a + step(inColor.a, 0.0h); 22 | const half4 outColor = inColor * (overlay.a * (inColor / alphaDivisor) + (2.0h * overlay * (1.0h - (inColor / alphaDivisor)))) + overlay * (1.0h - inColor.a) + inColor * (1.0h - overlay.a); 23 | const half4 output = mix(inColor, outColor, half(*intensity)); 24 | 25 | outputTexture.write(output, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendSourceOver.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendSourceOver.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendSourceOver(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = mix(inColor, overlay, overlay.a); 22 | const half4 output = mix(inColor, outColor, half(*intensity)); 23 | 24 | outputTexture.write(output, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Blend/C7BlendSubtract.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7BlendSubtract.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7BlendSubtract(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | texture2d inputTexture2 [[texture(2)]], 14 | constant float *intensity [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | const half4 overlay = inputTexture2.sample(quadSampler, textureCoordinate); 20 | 21 | const half4 outColor = half4(inColor.rgb - overlay.rgb, inColor.a); 22 | const half4 output = mix(inColor, outColor, half(*intensity)); 23 | 24 | outputTexture.write(output, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7BilateralBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7BilateralBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 双边模糊 11 | public struct C7BilateralBlur: C7FilterProtocol { 12 | 13 | public var radius: Float = 1 14 | 15 | public var offect: C7Point2D = C7Point2D.center 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7BilateralBlur") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [radius, offect.x, offect.y] 23 | } 24 | 25 | public init(radius: Float = 1) { 26 | self.radius = radius 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7CircleBlur.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7CircleBlur.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/17. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7CircleBlur(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *blurRadius [[buffer(0)]], 14 | constant float *sampleCountPointer [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 17 | const float2 textureCoordinate = float2(grid) / float2(outputTexture.get_width(), outputTexture.get_height()); 18 | const half radius = half(*blurRadius) / 100.0h; 19 | const half sampleCount = half(*sampleCountPointer); 20 | 21 | half4 result = half4(0.0h); 22 | for (int i = 0; i < sampleCount; ++i) { 23 | float fraction = float(i) / sampleCount; 24 | float x = textureCoordinate.x; 25 | float y = textureCoordinate.y; 26 | float angle = fraction * M_PI_F * 2; 27 | x += cos(angle) * radius; 28 | y += sin(angle) * radius; 29 | const half4 sample = inputTexture.sample(quadSampler, float2(x, y)); 30 | result += sample; 31 | } 32 | 33 | const half4 outColor = result / sampleCount; 34 | outputTexture.write(outColor, grid); 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7CircleBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7CircleBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/17. 6 | // 7 | 8 | import Foundation 9 | 10 | // See: https://www.imgonline.com.ua/eng/blur-angular.php 11 | // https://support.apple.com/en-in/guide/motion/motn169f953e/mac 12 | public struct C7CircleBlur: C7FilterProtocol { 13 | 14 | public static let range: ParameterRange = .init(min: 0, max: 100, value: 10) 15 | 16 | /// Sets the radius of the circle defining the blurred area. You can also drag the onscreen controls in the canvas. 17 | public var radius: Float = range.value 18 | 19 | /// Sets the amount of the blur. 20 | public var amount: Int = 20 21 | 22 | public var modifier: Modifier { 23 | return .compute(kernel: "C7CircleBlur") 24 | } 25 | 26 | public var factors: [Float] { 27 | return [radius, Float(amount)] 28 | } 29 | 30 | public init(radius: Float = range.value, amount: Int = 20) { 31 | self.radius = radius 32 | self.amount = amount 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7GaussianBlur.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7GaussianBlur.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | // 理论知识 9 | // https://juejin.cn/post/6944757638005686286 10 | 11 | #include 12 | using namespace metal; 13 | 14 | kernel void C7GaussianBlur(texture2d outputTexture [[texture(0)]], 15 | texture2d inputTexture [[texture(1)]], 16 | constant float *blurRadius [[buffer(0)]], 17 | uint2 grid [[thread_position_in_grid]]) { 18 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 19 | const float2 textureCoordinate = float2(grid) / float2(outputTexture.get_width(), outputTexture.get_height()); 20 | const half radius = half(*blurRadius) / 100.0h; 21 | const float x = textureCoordinate.x; 22 | const float y = textureCoordinate.y; 23 | 24 | // 高斯模糊卷积核 25 | const half3x3 matrix = half3x3({1.0, 2.0, 1.0}, {2.0, 4.0, 2.0}, {1.0, 2.0, 1.0}); 26 | half4 result = half4(0.0h); 27 | for (int i = 0; i < 9; i++) { 28 | int a = i % 3; int b = i / 3; 29 | const half4 sample = inputTexture.sample(quadSampler, float2(x + (a-1) * radius, y + (b-1) * radius)); 30 | result += sample * matrix[a][b]; 31 | } 32 | 33 | const half4 outColor = result / 16.0h; 34 | outputTexture.write(outColor, grid); 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7GaussianBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7GaussianBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7GaussianBlur: C7FilterProtocol { 11 | 12 | public static let range: ParameterRange = .init(min: 0, max: 100, value: 10) 13 | 14 | /// Sets the radius of the blur. 15 | public var radius: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7GaussianBlur") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [radius] 23 | } 24 | 25 | public init(radius: Float = range.value) { 26 | self.radius = radius 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7MeanBlur.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7MeanBlur.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | // 均值模糊原理其实很简单通过多个纹理叠加,每个纹理偏移量设置不同达到一点重影效果来实现模糊 12 | kernel void C7MeanBlur(texture2d outputTexture [[texture(0)]], 13 | texture2d inputTexture [[texture(1)]], 14 | constant float *blurRadius [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 17 | const float2 coordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 18 | const half radius = half(*blurRadius) / 100.0h; 19 | 20 | const half4 sample1 = inputTexture.sample(quadSampler, float2(coordinate.x - radius, coordinate.y - radius)); 21 | const half4 sample2 = inputTexture.sample(quadSampler, float2(coordinate.x + radius, coordinate.y + radius)); 22 | const half4 sample3 = inputTexture.sample(quadSampler, float2(coordinate.x + radius, coordinate.y - radius)); 23 | const half4 sample4 = inputTexture.sample(quadSampler, float2(coordinate.x - radius, coordinate.y + radius)); 24 | 25 | const half4 outColor = (sample1 + sample2 + sample3 + sample4) / 4.0h; 26 | outputTexture.write(outColor, grid); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7MeanBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7MeanBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 均值模糊效果 11 | /// https://docs.gimp.org/2.10/en/gimp-filter-median-blur.html 12 | public struct C7MeanBlur: C7FilterProtocol { 13 | 14 | public static let range: ParameterRange = .init(min: 0, max: 100, value: 10) 15 | 16 | /// The radius of the neighborhood. Increasing radius increases blur. 17 | /// Contrary to the “Gaussian” filter, edges are not blurred. Corners are rounded and convex surfaces are eroded. 18 | public var radius: Float = range.value 19 | 20 | public var modifier: Modifier { 21 | return .compute(kernel: "C7MeanBlur") 22 | } 23 | 24 | public var factors: [Float] { 25 | return [radius] 26 | } 27 | 28 | public init(radius: Float = range.value) { 29 | self.radius = radius 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7MotionBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7MotionBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 移动模糊 11 | public struct C7MotionBlur: C7FilterProtocol { 12 | 13 | /// A multiplier for the blur size 14 | public var radius: Float = 0 15 | 16 | /// The angular direction of the blur, in degrees, with a default of 0.0 17 | public var blurAngle: Float = 0 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7MotionBlur") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [radius, blurAngle] 25 | } 26 | 27 | public init(radius: Float = 0, blurAngle: Float = 0) { 28 | self.radius = radius 29 | self.blurAngle = blurAngle 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7RedMonochromeBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7RedMonochromeBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 红色单色模糊效果,呈黑白状态。 11 | /// Red monochrome blur effect, single channel expansion. 12 | public struct C7RedMonochromeBlur: C7FilterProtocol { 13 | 14 | /// Radius in pixel, with a default of 0.0 15 | public var pixelRadius: Int = 0 16 | 17 | /// Whether to blurred in horizontal direction. 18 | public var horizontal: Bool = true 19 | 20 | /// Whether to blurred in vertical direction. 21 | public var vertical: Bool = true 22 | 23 | public var modifier: Modifier { 24 | return .compute(kernel: "C7RedMonochromeBlur") 25 | } 26 | 27 | public var factors: [Float] { 28 | return [Float(pixelRadius), vertical ? 1:0, horizontal ? 1:0] 29 | } 30 | 31 | public init(pixelRadius: Int = 0) { 32 | self.pixelRadius = pixelRadius 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Compute/Blur/C7ZoomBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ZoomBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/10. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 缩放模糊效果 11 | /// See: https://support.apple.com/en-in/guide/motion/motn169fc244/mac 12 | public struct C7ZoomBlur: C7FilterProtocol { 13 | 14 | /// A multiplier for the blur size, ranging from 0.0 on up, with a default of 0.0 15 | /// Sets the radius of the blur. Drag the small circle (above the Center onscreen control) in the canvas to adjust the blur amount. 16 | public var radius: Float = 0 17 | 18 | /// Sets the position of the center of the blur. Drag the Center onscreen control in the canvas to adjust the center position. 19 | public var blurCenter: C7Point2D = C7Point2D.center 20 | 21 | public var modifier: Modifier { 22 | return .compute(kernel: "C7ZoomBlur") 23 | } 24 | 25 | public var factors: [Float] { 26 | return [blurCenter.x, blurCenter.y, radius] 27 | } 28 | 29 | public init(radius: Float = 0) { 30 | self.radius = radius 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Bulge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Bulge.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Bulge: C7FilterProtocol { 11 | 12 | /// 2D textures, normalized texture coordinates are used, from 0.0 to 1.0 in both x and y directions 13 | public var center: C7Point2D = C7Point2D.center 14 | /// The radius from the center to apply the distortion, with a default of 0.25 15 | public var radius: Float = 0.25 16 | /// The amount of distortion to apply, from -1.0 to 1.0, with a default of 0.5 17 | public var scale: Float = 0.5 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Bulge") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [center.x, center.y, radius, scale] 25 | } 26 | 27 | public init(radius: Float = 0.25, scale: Float = 0.5) { 28 | self.radius = radius 29 | self.scale = scale 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7ColorCGASpace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorCGASpace.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 图像CGA色彩滤镜,形成黑、浅蓝、紫色块的画面 11 | public struct C7ColorCGASpace: C7FilterProtocol { 12 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 13 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 14 | 15 | public var modifier: Modifier { 16 | return .compute(kernel: "C7ColorCGASpace") 17 | } 18 | 19 | public var factors: [Float] { 20 | return [intensity] 21 | } 22 | 23 | public init() { } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7ColorPacking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorPacking.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 色彩丢失/模糊效果 11 | public struct C7ColorPacking: C7FilterProtocol { 12 | 13 | /// The larger the transverse offset, the more the green contour shadow offset to the right. 14 | /// The texel width and height determines how far out to sample from this texel. 15 | public var horizontalTexel: Float 16 | /// The larger the vertical offset, the more the blue contour shadow offset downward. 17 | public var verticalTexel: Float 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7ColorPacking") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [horizontalTexel, verticalTexel] 25 | } 26 | 27 | public init(horizontalTexel: Float = 0, verticalTexel: Float = 0) { 28 | self.horizontalTexel = horizontalTexel 29 | self.verticalTexel = verticalTexel 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Fluctuate.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Fluctuate.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/30. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Fluctuate(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *extent [[buffer(0)]], 14 | constant float *amplitude [[buffer(1)]], 15 | constant float *fluctuate [[buffer(2)]], 16 | uint2 grid [[thread_position_in_grid]]) { 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | const float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 19 | 20 | float2 offset = float2(0, 0); 21 | offset.x = sin(grid.x * *extent + *fluctuate) * *amplitude; 22 | offset.y = cos(grid.y * *extent + *fluctuate) * *amplitude; 23 | 24 | const float2 tx = textureCoordinate + offset; 25 | const half4 outColor = inputTexture.sample(quadSampler, tx); 26 | 27 | outputTexture.write(outColor, grid); 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Fluctuate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Fluctuate.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/30. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 波动效果,还可类似涂鸦效果 11 | public struct C7Fluctuate: C7FilterProtocol { 12 | 13 | /// 控制振幅的大小,越大图像越夸张 14 | /// Control the size of the amplitude, the larger the image, the more exaggerated the image. 15 | public var amplitude: Float = 0.002 16 | public var extent: Float = 50.0 17 | public var fluctuate: Float = 0.5 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Fluctuate") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [extent, amplitude, fluctuate] 25 | } 26 | 27 | public init(extent: Float = 50.0, amplitude: Float = 0.002, fluctuate: Float = 0.5) { 28 | self.extent = extent 29 | self.amplitude = amplitude 30 | self.fluctuate = fluctuate 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7GlassSphere.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7GlassSphere.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7GlassSphere: C7FilterProtocol { 11 | 12 | public var radius: Float = 0.25 13 | public var refractiveIndex: Float = 0.71 14 | public var aspectRatio: Float = 1 15 | public var center: C7Point2D = C7Point2D.center 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7GlassSphere") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [radius, refractiveIndex, aspectRatio, center.x, center.y] 23 | } 24 | 25 | public init(radius: Float = 0.25, refractiveIndex: Float = 0.71, aspectRatio: Float = 1) { 26 | self.radius = radius 27 | self.refractiveIndex = refractiveIndex 28 | self.aspectRatio = aspectRatio 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Glitch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Glitch.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/17. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Glitch: C7FilterProtocol { 11 | 12 | /// The adjusted glitch, from 0.0 to 1.0, with a default of 0.5 13 | public var glitch: Float = 0.5 14 | 15 | /// Maximum jitter ratio. 16 | public var maxJitter: Float = 0.06 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Glitch") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [glitch, maxJitter] 24 | } 25 | 26 | public init(glitch: Float = 0.5, maxJitter: Float = 0.06) { 27 | self.glitch = glitch 28 | self.maxJitter = maxJitter 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Halftone.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Halftone.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Halftone: C7FilterProtocol { 11 | 12 | /// How large the halftone dots are, as a fraction of the width of the image, default of 0.01 13 | public var fractionalWidth: Float = 0.01 14 | 15 | public var modifier: Modifier { 16 | return .compute(kernel: "C7Halftone") 17 | } 18 | 19 | public var factors: [Float] { 20 | return [fractionalWidth] 21 | } 22 | 23 | public init(fractionalWidth: Float = 0.01) { 24 | self.fractionalWidth = fractionalWidth 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Kuwahara.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Kuwahara.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Kuwahara: C7FilterProtocol { 11 | 12 | /// The radius to sample from when creating the brush-stroke effect, with a default of 3. 13 | /// The larger the radius, the slower the filter. 14 | public var radius: Int = 3 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Kuwahara") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [Float(radius)] 22 | } 23 | 24 | public init(radius: Int = 3) { 25 | self.radius = radius 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7OilPainting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7OilPainting.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/29. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 油画滤镜 11 | public struct C7OilPainting: C7FilterProtocol { 12 | 13 | public var radius: Float = 3.0 14 | public var pixel: Int = 1 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7OilPainting") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [radius, Float(pixel)] 22 | } 23 | 24 | public init(radius: Float = 3.0, pixel: Int = 1) { 25 | self.radius = radius 26 | self.pixel = pixel 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Pinch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Pinch.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Pinch: C7FilterProtocol { 11 | 12 | public var center: C7Point2D = C7Point2D.center 13 | /// The radius from the center to apply the distortion, with a default of 0.25 14 | public var radius: Float = 0.5 15 | /// The amount of distortion to apply, from -2.0 to 2.0, with a default of 0.5 16 | public var scale: Float = 0.5 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Pinch") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [center.x, center.y, radius, scale] 24 | } 25 | 26 | public init(radius: Float = 0.5, scale: Float = 0.5) { 27 | self.radius = radius 28 | self.scale = scale 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Pixellated.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Pixellated.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Pixellated(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *pixelScale [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 16 | 17 | const float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 18 | const float2 scale = float2(*pixelScale, *pixelScale); 19 | const float2 samplePos = textureCoordinate - fmod(textureCoordinate, scale) + scale * 0.5; 20 | 21 | const half4 outColor = inputTexture.sample(quadSampler, samplePos); 22 | 23 | outputTexture.write(outColor, grid); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Pixellated.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Pixellated.swift 3 | // MetalDemo 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 马赛克像素化 11 | public struct C7Pixellated: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.05) 14 | 15 | /// Adjust the pixel color block size, from 0.0 to 1.0, with a default of 0.05 16 | @ZeroOneRange public var scale: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Pixellated") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [scale] 24 | } 25 | 26 | public init(scale: Float = range.value) { 27 | self.scale = scale 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7PolarPixellate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7PolarPixellate.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7PolarPixellate: C7FilterProtocol { 11 | 12 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.05) 13 | 14 | public var center: C7Point2D = C7Point2D.center 15 | 16 | /// The fractional pixel size, from 0.0 to 1.0, with a default of 0.05 17 | @ZeroOneRange public var scale: Float = range.value 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7PolarPixellate") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [scale, center.x, center.y] 25 | } 26 | 27 | public init(scale: Float = range.value) { 28 | self.scale = scale 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7PolkaDot.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7PolkaDot.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7PolkaDot: C7FilterProtocol { 11 | 12 | /// How large the dots are, as a fraction of the width and height of the image, default of 0.05 13 | public var fractionalWidth: Float = 0.05 14 | /// What fraction of each grid space is taken up by a dot, default of 0.9 15 | public var dotScaling: Float = 0.9 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7PolkaDot") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [fractionalWidth, dotScaling] 23 | } 24 | 25 | public init(fractionalWidth: Float = 0.05, dotScaling: Float = 0.9) { 26 | self.fractionalWidth = fractionalWidth 27 | self.dotScaling = dotScaling 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7RGBADilation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7RGBADilation.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Find the maximum value of each color channel in the range of radius, and set the maximum value to the current pixel. 11 | public struct C7RGBADilation: C7FilterProtocol { 12 | 13 | /// Radius in pixel, with a default of 0.0 14 | public var pixelRadius: Int = 0 15 | 16 | public var vertical: Bool = false 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7RGBADilation") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [Float(pixelRadius), vertical ? 1 : 0] 24 | } 25 | 26 | public init(pixelRadius: Int = 0) { 27 | self.pixelRadius = pixelRadius 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Sharpen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Sharpen.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Sharpen: C7FilterProtocol { 11 | 12 | public static let range: ParameterRange = .init(min: -4.0, max: 4.0, value: 0.0) 13 | 14 | /// Change the opacity of an image, from -4.0 to 4.0, with a default of 0.0 15 | public var sharpeness: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7Sharpen") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [sharpeness] 23 | } 24 | 25 | public init(sharpeness: Float = range.value) { 26 | self.sharpeness = sharpeness 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Sketch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Sketch.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Sketch: C7FilterProtocol { 11 | 12 | /// Adjusts the dynamic range of the filter. 13 | /// Higher values lead to stronger edges, but can saturate the intensity colorspace. 14 | public var edgeStrength: Float = 1 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Sketch") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [edgeStrength] 22 | } 23 | 24 | public init(edgeStrength: Float = 1) { 25 | self.edgeStrength = edgeStrength 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7SoulOut.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7SoulOut.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/17. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 灵魂出窍效果 11 | public struct C7SoulOut: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.5) 14 | 15 | /// The adjusted soul, from 0.0 to 1.0, with a default of 0.5 16 | @ZeroOneRange public var soul: Float = range.value 17 | public var maxScale: Float = 1.5 18 | @ZeroOneRange public var maxAlpha: Float = 0.5 19 | 20 | public var modifier: Modifier { 21 | return .compute(kernel: "C7SoulOut") 22 | } 23 | 24 | public var factors: [Float] { 25 | return [soul, maxScale, maxAlpha] 26 | } 27 | 28 | public init(soul: Float = range.value, maxScale: Float = 1.5, maxAlpha: Float = 0.5) { 29 | self.soul = soul 30 | self.maxScale = maxScale 31 | self.maxAlpha = maxAlpha 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7SphereRefraction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7SphereRefraction.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7SphereRefraction: C7FilterProtocol { 11 | 12 | public var radius: Float = 0.25 13 | public var refractiveIndex: Float = 0.71 14 | public var aspectRatio: Float = 1 15 | public var center: C7Point2D = C7Point2D.center 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7SphereRefraction") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [radius, refractiveIndex, aspectRatio, center.x, center.y] 23 | } 24 | 25 | public init(radius: Float = 0.25, refractiveIndex: Float = 0.71, aspectRatio: Float = 1) { 26 | self.radius = radius 27 | self.refractiveIndex = refractiveIndex 28 | self.aspectRatio = aspectRatio 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7SplitScreen.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7SplitScreen.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/17. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7SplitScreen(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *screen [[buffer(0)]], 14 | constant float *direction [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const float x = float(grid.x) / outputTexture.get_width(); 17 | const float y = float(grid.y) / outputTexture.get_height(); 18 | 19 | float temp = (*direction) ? y : x; 20 | if (*screen == 2.0) { 21 | temp += temp < 0.5 ? 0.25 : -0.25; 22 | } else if (*screen == 3.0) { 23 | temp += temp < 1.0/3.0 ? 1.0/3.0 : (temp > 2.0/3.0) ? -1.0/3.0 : 0.0; 24 | } 25 | const float2 xy = (*direction) ? float2(x, temp) : float2(temp, y); 26 | 27 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 28 | const half4 outColor = inputTexture.sample(quadSampler, xy); 29 | outputTexture.write(outColor, grid); 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7SplitScreen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7SplitScreen.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/17. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7SplitScreen: C7FilterProtocol { 11 | 12 | public enum ScreenType: Int { 13 | case two = 2 14 | case three = 3 15 | } 16 | 17 | public enum DirectionType: Int { 18 | case horizontal 19 | case vertical 20 | } 21 | 22 | public var type: ScreenType = .two 23 | 24 | public var direction: DirectionType = .vertical 25 | 26 | public var modifier: Modifier { 27 | return .compute(kernel: "C7SplitScreen") 28 | } 29 | 30 | public var factors: [Float] { 31 | return [Float(type.rawValue), Float(direction.rawValue)] 32 | } 33 | 34 | public init(type: ScreenType = .two, direction: DirectionType = .vertical) { 35 | self.type = type 36 | self.direction = direction 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Storyboard.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Storyboard.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | // See:https://www.shadertoy.com/view/7sscDX 9 | 10 | #include 11 | using namespace metal; 12 | 13 | kernel void C7Storyboard(texture2d outputTexture [[texture(0)]], 14 | texture2d inputTexture [[texture(1)]], 15 | constant float *few [[buffer(0)]], 16 | uint2 grid [[thread_position_in_grid]]) { 17 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 18 | const float x = float(grid.x) / outputTexture.get_width(); 19 | const float y = float(grid.y) / outputTexture.get_height(); 20 | const float2 textureCoordinate = float2(x, y); 21 | const int N = int(*few); 22 | const float2 uv = fmod(textureCoordinate, 1.0 / N) * N; 23 | 24 | const half4 outColor = inputTexture.sample(quadSampler, uv); 25 | 26 | outputTexture.write(outColor, grid); 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Storyboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Storyboard.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/2. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 分镜滤镜 11 | public struct C7Storyboard: C7FilterProtocol { 12 | 13 | /// It is divided into `ranks²` screens. 14 | @Clamping(1...Int.max) public var ranks: Int = 2 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Storyboard") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [Float(ranks)] 22 | } 23 | 24 | public init(ranks: Int = 2) { 25 | self.ranks = ranks 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Swirl.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Swirl.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Swirl: C7FilterProtocol { 11 | 12 | public var center: C7Point2D = C7Point2D.center 13 | /// The radius from the center to apply the distortion, with a default of 0.25 14 | public var radius: Float = 0.5 15 | /// The amount of twist to apply to the image 16 | public var angle: Float = 1 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Swirl") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [center.x, center.y, radius, angle] 24 | } 25 | 26 | public init(radius: Float = 0.5, angle: Float = 1) { 27 | self.radius = radius 28 | self.angle = angle 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7ThresholdSketch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ThresholdSketch.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 阀值素描感滤镜 11 | public struct C7ThresholdSketch: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.25) 14 | 15 | /// Any edge above this threshold will be black, and anything below white. Ranges from 0.0 to 1.0 16 | @ZeroOneRange public var threshold: Float = range.value 17 | 18 | /// Adjusts the dynamic range of the filter. 19 | /// Higher values lead to stronger edges, but can saturate the intensity colorspace. 20 | public var edgeStrength: Float = 1 21 | 22 | public var modifier: Modifier { 23 | return .compute(kernel: "C7ThresholdSketch") 24 | } 25 | 26 | public var factors: [Float] { 27 | return [edgeStrength, threshold] 28 | } 29 | 30 | public init(edgeStrength: Float = 1, threshold: Float = range.value) { 31 | self.edgeStrength = edgeStrength 32 | self.threshold = threshold 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7Toon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Toon.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Toon: C7FilterProtocol { 11 | 12 | public static let thresholdRange: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.2) 13 | 14 | /// The sensitivity of the edge detection, with lower values being more sensitive. Ranges from 0.0 to 1.0 15 | @ZeroOneRange public var threshold: Float = thresholdRange.value 16 | 17 | /// The number of color levels to represent in the final image. Default is 10.0 18 | public var quantizationLevels: Float = 10 19 | 20 | public var modifier: Modifier { 21 | return .compute(kernel: "C7Toon") 22 | } 23 | 24 | public var factors: [Float] { 25 | return [threshold, quantizationLevels] 26 | } 27 | 28 | public init(quantizationLevels: Float = 10, threshold: Float = thresholdRange.value) { 29 | self.quantizationLevels = quantizationLevels 30 | self.threshold = threshold 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Compute/Coordinate/C7WaterRipple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7WaterRipple.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/21. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 水波纹效果 11 | public struct C7WaterRipple: C7FilterProtocol { 12 | 13 | public static let rippleRange: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.0) 14 | 15 | /// The waves, from 0.0 to 1.0 16 | @ZeroOneRange public var ripple: Float = rippleRange.value 17 | /// Click location, normalized 18 | public var touchCenter: C7Point2D = C7Point2D.center 19 | /// The wave size 20 | public var boundary: Float = 0.06 21 | 22 | public var modifier: Modifier { 23 | return .compute(kernel: "C7WaterRipple") 24 | } 25 | 26 | public var factors: [Float] { 27 | return [touchCenter.x, touchCenter.y, ripple, boundary] 28 | } 29 | 30 | public init(ripple: Float = rippleRange.value, boundary: Float = 0.06) { 31 | self.ripple = ripple 32 | self.boundary = boundary 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Compute/Generator/C7ColorGradient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorGradient.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/7/27. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 常见渐变色滤镜 11 | public struct C7ColorGradient: C7FilterProtocol { 12 | 13 | public enum GradientType { 14 | case rgUV 15 | case rgUVB1 16 | case radial 17 | } 18 | 19 | /// There is no need to create a new output texture, just use the input texture. 20 | public var needCreateDestTexture: Bool = false 21 | 22 | public var modifier: Modifier { 23 | return .compute(kernel: type.kernel) 24 | } 25 | 26 | let type: GradientType 27 | 28 | public init(with type: GradientType) { 29 | self.type = type 30 | } 31 | } 32 | 33 | extension C7ColorGradient.GradientType { 34 | public var kernel: String { 35 | switch self { 36 | case .rgUV: 37 | return "C7RGUVGradient" 38 | case .rgUVB1: 39 | return "C7RGUVB1Gradient" 40 | case .radial: 41 | return "C7RadialGradient" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Sources/Compute/Generator/C7SolidColor.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7SolidColor.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/10. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | // Bytes are being bound at index 0 to a shader argument with write access enabled.' 12 | // If use `device` and then throw the error as above. 13 | // See: https://developer.apple.com/forums/thread/658233 14 | 15 | kernel void C7SolidColor(texture2d outputTexture [[texture(0)]], 16 | texture2d inputTexture [[texture(1)]], 17 | constant float4 *colorVector [[buffer(0)]], 18 | uint2 grid [[thread_position_in_grid]]) { 19 | const half4 outColor = half4(*colorVector); 20 | 21 | outputTexture.write(outColor, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Generator/C7SolidColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7SolidColor.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/10/10. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 纯色滤镜 11 | public struct C7SolidColor: C7FilterProtocol { 12 | 13 | /// There is no need to create a new output texture, just use the input texture. 14 | public var needCreateDestTexture: Bool = false 15 | 16 | public var color: C7Color = .white 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7SolidColor") 20 | } 21 | 22 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 23 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 24 | var factor = Vector4.init(color: color).to_factor() 25 | computeEncoder.setBytes(&factor, length: Vector4.size, index: index + 1) 26 | } 27 | 28 | public init(color: C7Color = .white) { 29 | self.color = color 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Lookup/C7LookupTable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7LookupTable.swift 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/9. 6 | // 7 | 8 | import Foundation 9 | import MetalKit 10 | 11 | /// LUT映射滤镜 12 | /// See: https://juejin.cn/post/7169096223100829709 13 | public struct C7LookupTable: C7FilterProtocol { 14 | 15 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 16 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7LookupTable") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [intensity] 24 | } 25 | 26 | public var otherInputTextures: C7InputTextures { 27 | return lookupTexture == nil ? [] : [lookupTexture!] 28 | } 29 | 30 | private let lookupImage: C7Image? 31 | private let lookupTexture: MTLTexture? 32 | 33 | public init(image: C7Image?) { 34 | self.lookupImage = image 35 | self.lookupTexture = image?.cgImage?.c7.toTexture() 36 | } 37 | 38 | public init(name: String) { 39 | self.init(image: R.image(name)) 40 | } 41 | 42 | public init(lookupTexture: MTLTexture) { 43 | self.lookupImage = nil 44 | self.lookupTexture = lookupTexture 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7ColorMatrix4x4.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorMatrix4x4.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/21. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 4x4 color matrix. 11 | public struct C7ColorMatrix4x4: C7FilterProtocol { 12 | 13 | /// The degree to which the new transformed color replaces the original color for each pixel, default 1 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | /// Color offset for each channel. 16 | public var offset: Vector4 = .zero 17 | public var matrix: Matrix4x4 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7ColorMatrix4x4") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [intensity] + offset.values 25 | } 26 | 27 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 28 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 29 | var factor = matrix.to_factor() 30 | computeEncoder.setBytes(&factor, length: Matrix4x4.size, index: index + 1) 31 | } 32 | 33 | public init(matrix: Matrix4x4) { 34 | self.matrix = matrix 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7ColorMatrix4x5.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorMatrix4x5.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 4 x 5 color matrix. 11 | public struct C7ColorMatrix4x5: C7FilterProtocol { 12 | 13 | /// The degree to which the new transformed color replaces the original color for each pixel, default 1 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | public var matrix: Matrix4x5 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7ColorMatrix4x5") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [intensity] 24 | } 25 | 26 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 27 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 28 | var factor = matrix.matrix4x4.to_factor() 29 | computeEncoder.setBytes(&factor, length: Matrix4x4.size, index: index + 1) 30 | var factor2 = matrix.vector4.to_factor() 31 | computeEncoder.setBytes(&factor2, length: Vector4.size, index: index + 2) 32 | } 33 | 34 | public init(matrix: Matrix4x5) { 35 | self.matrix = matrix 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7ColorVector4.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorVector4.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7ColorVector4(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *intensity [[buffer(0)]], 14 | constant float4 *vector [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half4 outColor = inColor + half4(*vector); 19 | const half4 output = mix(inColor, outColor, half(*intensity)); 20 | 21 | outputTexture.write(output, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7ColorVector4.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorVector4.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/11. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 四维向量颜色 11 | public struct C7ColorVector4: C7FilterProtocol { 12 | 13 | /// The degree to which the new transformed color replaces the original color for each pixel, default 1 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | public var vector: Vector4 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7ColorVector4") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [intensity] 24 | } 25 | 26 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 27 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 28 | var factor = vector.to_factor() 29 | computeEncoder.setBytes(&factor, length: Vector4.size, index: index + 1) 30 | } 31 | 32 | public init(vector: Vector4) { 33 | self.vector = vector 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7EdgeGlow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7EdgeGlow.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/25. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7EdgeGlow: C7FilterProtocol { 11 | 12 | /// The adjusted time, from 0.0 to 1.0, with a default of 0.5 13 | public var time: Float = 0.5 14 | /// The edge span is larger than this. form 0.0 to 1.0 15 | public var spacing: Float = 0.5 16 | 17 | public var lineColor: C7Color = C7Color.green 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7EdgeGlow") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [time, spacing] 25 | } 26 | 27 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 28 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 29 | var factor = Vector4.init(color: lineColor).to_factor() 30 | computeEncoder.setBytes(&factor, length: Vector4.size, index: index + 1) 31 | } 32 | 33 | public init(time: Float = 0.5, spacing: Float = 0.5, lineColor: C7Color = .green) { 34 | self.time = time 35 | self.spacing = spacing 36 | self.lineColor = lineColor 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7Nostalgic.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Nostalgic.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/3. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Nostalgic(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *intensity [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4x4 matrix = half4x4({0.272, 0.534, 0.131, 0.0}, 18 | {0.349, 0.686, 0.168, 0.0}, 19 | {0.393, 0.769, 0.189, 0.0}, 20 | {0.000, 0.000, 0.000, 1.0}); 21 | const half4 outColor = half(*intensity) * (inColor * matrix) + (1.0h - half(*intensity)) * inColor; 22 | 23 | outputTexture.write(outColor, grid); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7Nostalgic.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Nostalgic.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/3. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 怀旧滤镜 11 | public struct C7Nostalgic: C7FilterProtocol { 12 | 13 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Nostalgic") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [intensity] 22 | } 23 | 24 | public init(intensity: Float = R.intensityRange.value) { 25 | self.intensity = intensity 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7Sepia.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Sepia.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/23. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Sepia(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *intensity [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4x4 matrix = half4x4({0.3588, 0.7044, 0.1368, 0.0}, 18 | {0.2990, 0.5870, 0.1140, 0.0}, 19 | {0.2392, 0.4696, 0.0912, 0.0}, 20 | {0.0000, 0.0000, 0.0000, 1.0}); 21 | const half4 outColor = half(*intensity) * (inColor * matrix) + (1.0h - half(*intensity)) * inColor; 22 | 23 | outputTexture.write(outColor, grid); 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Compute/Matrix/C7Sepia.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Sepia.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/23. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 棕褐色,老照片 11 | public struct C7Sepia: C7FilterProtocol { 12 | 13 | /// The degree to which tan replaces normal image color, from 0.0 to 1.0 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Sepia") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [intensity] 22 | } 23 | 24 | public init(intensity: Float = R.intensityRange.value) { 25 | self.intensity = intensity 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Brightness.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Brightness.metal 3 | // MetalQueen 4 | // 5 | // Created by Condy on 2021/8/7. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Brightness(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *brightness [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4 outColor = half4(inColor.rgb + half3(*brightness), inColor.a); 18 | 19 | outputTexture.write(outColor, grid); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Brightness.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Brightness.swift 3 | // MetalQueen 4 | // 5 | // Created by Condy on 2021/8/7. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 亮度 11 | public struct C7Brightness: C7FilterProtocol { 12 | 13 | /// The adjusted brightness, from -1.0 to 1.0, with a default of 0.0 being the original picture. 14 | public static let range: ParameterRange = .init(min: -1.0, max: 1.0, value: 0.0) 15 | 16 | @Clamping(range.min...range.max) public var brightness: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Brightness") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [brightness] 24 | } 25 | 26 | public init(brightness: Float = range.value) { 27 | self.brightness = brightness 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ColorConvert.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorConvert.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 颜色通道`RGB`位置转换 11 | public struct C7ColorConvert: C7FilterProtocol { 12 | 13 | public enum ColorType: String, CaseIterable { 14 | case invert = "C7ColorInvert" 15 | case gray = "C7Color2Gray" 16 | case bgra = "C7Color2BGRA" 17 | case brga = "C7Color2BRGA" 18 | case gbra = "C7Color2GBRA" 19 | case grba = "C7Color2GRBA" 20 | case rbga = "C7Color2RBGA" 21 | case y = "C7Color2Y" 22 | } 23 | 24 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 25 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 26 | 27 | private let type: ColorType 28 | 29 | public var modifier: Modifier { 30 | return .compute(kernel: type.rawValue) 31 | } 32 | 33 | public var factors: [Float] { 34 | return [intensity] 35 | } 36 | 37 | public init(with type: ColorType) { 38 | self.type = type 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ColorRGBA.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorRGBA.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7ColorRGBA(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *intensity [[buffer(0)]], 14 | constant float4 *colorVector [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half4 outColor(inColor * half4(*colorVector)); 19 | const half4 output = mix(inColor, outColor, half(*intensity)); 20 | 21 | outputTexture.write(output, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ColorRGBA.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorRGBA.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7ColorRGBA: C7FilterProtocol { 11 | 12 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 13 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 14 | 15 | /// Transparent colors are not processed, Will directly modify the overall color scheme 16 | public var color: C7Color = .white 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7ColorRGBA") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [intensity] 24 | } 25 | 26 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 27 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 28 | var factor = Vector4.init(color: color).to_factor() 29 | computeEncoder.setBytes(&factor, length: Vector4.size, index: index + 1) 30 | } 31 | 32 | public init(color: C7Color = .white) { 33 | self.color = color 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ColorSpace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ColorSpace.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/12/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 色彩空间转换 11 | public struct C7ColorSpace: C7FilterProtocol { 12 | 13 | public enum SwapType: String, CaseIterable { 14 | case rgb_to_yiq = "C7ColorSpaceRGB2YIQ" 15 | case yiq_to_rgb = "C7ColorSpaceYIQ2RGB" 16 | case rgb_to_yuv = "C7ColorSpaceRGB2YUV" 17 | case yuv_to_rgb = "C7ColorSpaceYUV2RGB" 18 | } 19 | 20 | private let type: SwapType 21 | 22 | public var modifier: Modifier { 23 | return .compute(kernel: type.rawValue) 24 | } 25 | 26 | public init(with type: SwapType) { 27 | self.type = type 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ComicStrip.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7ComicStrip.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/3. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7ComicStrip(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *intensity [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | const half r = inColor.r; 17 | const half g = inColor.g; 18 | const half b = inColor.b; 19 | 20 | const half R = half(abs(g - b + g + r) * r); 21 | const half G = half(abs(b - g + b + r) * r); 22 | const half B = half(abs(b - g + b + r) * g); 23 | 24 | const half4 outColor = half4(R, G, B, inColor.a); 25 | const half4 output = mix(inColor, outColor, half(*intensity)); 26 | 27 | outputTexture.write(output, grid); 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ComicStrip.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ComicStrip.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/3. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 连环画滤镜 11 | public struct C7ComicStrip: C7FilterProtocol { 12 | 13 | /// Intensity range, used to adjust the mixing ratio of filters and sources. 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7ComicStrip") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [intensity] 22 | } 23 | 24 | public init() { } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Contrast.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Contrast.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Contrast(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *contrast [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half3 zero = half3(0.5h); 18 | const half4 outColor = half4((zero + (inColor.rgb - zero) * (*contrast)), inColor.a); 19 | 20 | outputTexture.write(outColor, grid); 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Contrast.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Contrast.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 对比度 11 | public struct C7Contrast: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0, max: 2.0, value: 1.0) 14 | 15 | /// The adjusted contrast, from 0 to 2.0, with a default of 1.0 being the original picture. 16 | public var contrast: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Contrast") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [contrast] 24 | } 25 | 26 | public init(contrast: Float = range.value) { 27 | self.contrast = contrast 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Crosshatch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Crosshatch.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 绘制阴影线 11 | public struct C7Crosshatch: C7FilterProtocol { 12 | 13 | /// The fractional width of the image to use as the spacing for the crosshatch, default of 0.03 14 | public var crosshatchSpacing: Float = 0.03 15 | /// A relative width for the crosshatch lines, default of 0.003 16 | public var lineWidth: Float = 0.003 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Crosshatch") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [crosshatchSpacing, lineWidth] 24 | } 25 | 26 | public init(crosshatchSpacing: Float = 0.03, lineWidth: Float = 0.003) { 27 | self.crosshatchSpacing = crosshatchSpacing 28 | self.lineWidth = lineWidth 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7DepthLuminance.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7DepthLuminance.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7DepthLuminance(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *offset [[buffer(0)]], 14 | constant float *range [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 textureCoordinate = inputTexture.read(grid); 17 | 18 | half depth = textureCoordinate.x; 19 | // Normalize the value between 0 and 1. 20 | depth = (depth - half(*offset)) / half(*range); 21 | 22 | const half4 outputColor = half4(half3(depth), 1.0h); 23 | 24 | outputTexture.write(outputColor, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7DepthLuminance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7DepthLuminance.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7DepthLuminance: C7FilterProtocol { 11 | 12 | public var offect: Float = 0 13 | public var range: Float = 0 14 | 15 | public var modifier: Modifier { 16 | return .compute(kernel: "C7DepthLuminance") 17 | } 18 | 19 | public var factors: [Float] { 20 | return [offect, range] 21 | } 22 | 23 | public init(offect: Float = 0, range: Float = 0) { 24 | self.offect = offect 25 | self.range = range 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Exposure.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Exposure.metal 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Exposure(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *exposure [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4 outColor = half4((inColor.rgb * pow(2.0, *exposure)), inColor.a); 18 | 19 | outputTexture.write(outColor, grid); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Exposure.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Exposure.swift 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 曝光效果 11 | /// See: https://docs.unity3d.com/cn/Packages/com.unity.render-pipelines.high-definition@10.4/manual/Override-Exposure.html 12 | public struct C7Exposure: C7FilterProtocol { 13 | 14 | public static let range: ParameterRange = .init(min: -10.0, max: 10.0, value: 0.0) 15 | 16 | /// The adjusted exposure, from -10.0 to 10.0, with a default of 0.0 17 | public var exposure: Float = range.value 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Exposure") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [exposure] 25 | } 26 | 27 | public init(exposure: Float = range.value) { 28 | self.exposure = exposure 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7FalseColor.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7FalseColor.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7FalseColor(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float3 *firstVector [[buffer(0)]], 14 | constant float3 *secondVector [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); 19 | const half luminance = dot(inColor.rgb, luminanceWeighting); 20 | const half3 color1 = half3(*firstVector); 21 | const half3 color2 = half3(*secondVector); 22 | const half4 outColor = half4(mix(color1.rgb, color2.rgb, half3(luminance)), inColor.a); 23 | 24 | outputTexture.write(outColor, grid); 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7FalseColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7FalseColor.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 使用图像的亮度在两种用户指定的颜色之间进行混合 11 | /// Uses the luminance of the image to mix between two user-specified colors 12 | public struct C7FalseColor: C7FilterProtocol { 13 | 14 | /// The first and second colors specify what colors replace the dark and light areas of the image, respectively. 15 | public var fristColor: C7Color = .zero 16 | 17 | public var secondColor: C7Color = .zero 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7FalseColor") 21 | } 22 | 23 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 24 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 25 | var fristFactor = Vector3.init(color: fristColor).to_factor() 26 | computeEncoder.setBytes(&fristFactor, length: Vector3.size, index: index + 1) 27 | var secondFactor = Vector3(color: secondColor).to_factor() 28 | computeEncoder.setBytes(&secondFactor, length: Vector3.size, index: index + 2) 29 | } 30 | 31 | public init(fristColor: C7Color = .zero, secondColor: C7Color = .zero) { 32 | self.fristColor = fristColor 33 | self.secondColor = secondColor 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Gamma.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Gamma.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Gamma(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *gamma [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4 outColor = half4(pow(inColor.rgb, half3(*gamma)), inColor.a); 18 | 19 | outputTexture.write(outColor, grid); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Gamma.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Gamma.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 灰度系数 11 | public struct C7Gamma: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 3.0, value: 1.0) 14 | 15 | /// The adjusted gamma, from 0 to 3.0, with a default of 1.0 16 | public var gamma: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Gamma") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [gamma] 24 | } 25 | 26 | public init(gamma: Float = range.value) { 27 | self.gamma = gamma 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Granularity.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Granularity.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/21. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Granularity(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *grain [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | const float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 17 | 18 | const float d = dot(textureCoordinate, float2(12.9898, 78.233) * 2.0); 19 | const half noise = half(fract(sin(d) * 43758.5453h)); 20 | const half4 outColor = half4(inColor - noise * (*grain)); 21 | 22 | outputTexture.write(outColor, grid); 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Granularity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Granularity.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/21. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 调节胶片颗粒感 11 | public struct C7Granularity: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 0.5, value: 0.3) 14 | 15 | /// The grain size is adjusted by adjusting the grain parameter. The grain size ranges from 0.0 to 0.5, 16 | /// Where 0.0 represents the original image, 17 | public var grain: Float = range.value 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Granularity") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [grain] 25 | } 26 | 27 | public init(grain: Float = range.value) { 28 | self.grain = grain 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Haze.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Haze.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Haze(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *hazeDistance [[buffer(0)]], 14 | constant float *slope [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half4 white = half4(1.0h); 19 | const half dd = half(grid.y) / half(inputTexture.get_height()) * half(*slope) + half(*hazeDistance); 20 | const half4 outColor = half4((inColor - dd * white) / (1.0h - dd)); 21 | 22 | outputTexture.write(outColor, grid); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Haze.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Haze.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 去雾,类似于UV过滤器 11 | public struct C7Haze: C7FilterProtocol { 12 | 13 | /// Strength of the color applied. 14 | public var distance: Float = 0 15 | /// Amount of color change. 16 | public var slope: Float = 0 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Haze") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [distance, slope] 24 | } 25 | 26 | public init(distance: Float = 0, slope: Float = 0) { 27 | self.distance = distance 28 | self.slope = slope 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7HighlightShadow.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7HighlightShadow.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7HighlightShadow(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *shadows [[buffer(0)]], 14 | constant float *highlights [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); 19 | const half luminance = dot(inColor.rgb, luminanceWeighting); 20 | const half shadow = clamp((pow(luminance, 1.0h / (half(*shadows) + 1.0h)) + (-0.76) * pow(luminance, 2.0h / (half(*shadows) + 1.0h))) - luminance, 0.0, 1.0); 21 | const half highlight = clamp((1.0 - (pow(1.0 - luminance, 1.0 / (2.0 - half(*highlights))) + (-0.8) * pow(1.0 - luminance, 2.0 / (2.0 - half(*highlights))))) - luminance, -1.0, 0.0); 22 | const half3 result = half3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((inColor.rgb - half3(0.0, 0.0, 0.0)) / (luminance - 0.0)); 23 | const half4 outColor = half4(result.rgb, inColor.a); 24 | 25 | outputTexture.write(outColor, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7HighlightShadow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7HighlightShadow.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 高光阴影 11 | public struct C7HighlightShadow: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.0) 14 | 15 | /// Increase to lighten shadows, from 0.0 to 1.0, with 0.0 as the default. 16 | @ZeroOneRange public var shadows: Float = range.value 17 | 18 | /// Decrease to darken highlights, from 1.0 to 0.0, with 1.0 as the default. 19 | @ZeroOneRange public var highlights: Float = range.value 20 | 21 | public var modifier: Modifier { 22 | return .compute(kernel: "C7HighlightShadow") 23 | } 24 | 25 | public var factors: [Float] { 26 | return [shadows, highlights] 27 | } 28 | 29 | public init(highlights: Float = range.value, shadows: Float = range.value) { 30 | self.highlights = highlights 31 | self.shadows = shadows 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Hue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Hue.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/13. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Hue: C7FilterProtocol { 11 | 12 | /// Hue adjustment, unit is degree 13 | @DegreeRange public var hue: Float = 90.0 14 | 15 | public var modifier: Modifier { 16 | return .compute(kernel: "C7Hue") 17 | } 18 | 19 | public var factors: [Float] { 20 | return [Degree(value: hue).radians] 21 | } 22 | 23 | public init(hue: Float = 90.0) { 24 | self.hue = hue 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Luminance.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Luminance.metal 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Luminance(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *luminance [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); // 亮度常量 18 | const half _luminance = dot(inColor.rgb, luminanceWeighting); 19 | const half4 outColor = half4(mix(half3(_luminance), inColor.rgb, half3(*luminance)), inColor.a); 20 | 21 | outputTexture.write(outColor, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Luminance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Luminance.swift 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 亮度 11 | public struct C7Luminance: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 1.0) 14 | 15 | @ZeroOneRange public var luminance: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7Luminance") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [luminance] 23 | } 24 | 25 | public init(luminance: Float = range.value) { 26 | self.luminance = luminance 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7LuminanceRangeReduction.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7LuminanceRangeReduction.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/23. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7LuminanceRangeReduction(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *rangeReductionFactor [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); // 亮度常量 18 | const half _luminance = dot(inColor.rgb, luminanceWeighting); 19 | half luminanceRatio = ((0.5h - _luminance) * half(*rangeReductionFactor)); 20 | const half4 outColor = half4(half3((inColor.rgb) + (luminanceRatio)), inColor.w); 21 | 22 | outputTexture.write(outColor, grid); 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7LuminanceRangeReduction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7LuminanceRangeReduction.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/23. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7LuminanceRangeReduction: C7FilterProtocol { 11 | 12 | public var rangeReductionFactor: Float = 0.6 13 | 14 | public var modifier: Modifier { 15 | return .compute(kernel: "C7LuminanceRangeReduction") 16 | } 17 | 18 | public var factors: [Float] { 19 | return [rangeReductionFactor] 20 | } 21 | 22 | public init(rangeReductionFactor: Float = 0.6) { 23 | self.rangeReductionFactor = rangeReductionFactor 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7LuminanceThreshold.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7LuminanceThreshold.metal 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | // 阈值滤镜 阈值的大小是动态(根据图片情况) 12 | kernel void C7LuminanceThreshold(texture2d outputTexture [[texture(0)]], 13 | texture2d inputTexture [[texture(1)]], 14 | constant float *threshold [[buffer(0)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const half4 inColor = inputTexture.read(grid); 17 | 18 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); // 亮度常量 19 | const half luminance = dot(inColor.rgb, luminanceWeighting); 20 | 21 | // step luminance >= half(*threshold) 的值为1,小于则为0 22 | half thresholdResult = step(half(*threshold), luminance); 23 | const half4 outColor = half4(half3(thresholdResult), inColor.w); 24 | 25 | outputTexture.write(outColor, grid); 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7LuminanceThreshold.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7LuminanceThreshold.swift 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 阈值滤镜 阈值的大小是动态(根据图片情况) 11 | /// Threshold filter threshold size is dynamic (according to the image) 12 | public struct C7LuminanceThreshold: C7FilterProtocol { 13 | 14 | public var threshold: Float = 0.5 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7LuminanceThreshold") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [threshold] 22 | } 23 | 24 | public init(threshold: Float = 0.5) { 25 | self.threshold = threshold 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Monochrome.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Monochrome.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 将图像转换为单色版本,根据每个像素的亮度进行着色 11 | public struct C7Monochrome: C7FilterProtocol { 12 | 13 | /// The degree to which the specific color replaces the normal image color 14 | @ZeroOneRange public var intensity: Float = R.intensityRange.value 15 | 16 | /// Keep the color scheme 17 | public var color: C7Color = .zero 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Monochrome") 21 | } 22 | 23 | public var factors: [Float] { 24 | let rgb = color.c7.toRGBA() 25 | return [intensity] + [rgb.red, rgb.green, rgb.blue] 26 | } 27 | 28 | public init(intensity: Float = R.intensityRange.value, color: C7Color = .zero) { 29 | self.intensity = intensity 30 | self.color = color 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Opacity.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Opacity.metal 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Opacity(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *opacity [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4 outColor = half4(inColor.rgb, half(*opacity) * inColor.a); 18 | 19 | outputTexture.write(outColor, grid); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Opacity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Opacity.swift 3 | // MetalQueenDemo 4 | // 5 | // Created by Condy on 2021/8/8. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 透明度调整,核心就是改变`alpha` 11 | public struct C7Opacity: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 1.0) 14 | 15 | /// Change the opacity of an image, from 0.0 to 1.0, with a default of 1.0 16 | @ZeroOneRange public var opacity: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Opacity") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [opacity] 24 | } 25 | 26 | public init(opacity: Float = range.value) { 27 | self.opacity = opacity 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Posterize.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Posterize.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Posterize(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *colorLevelsPointer [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half colorLevels = half(*colorLevelsPointer); 18 | const half4 outColor = floor((inColor * colorLevels) + half4(0.5h)) / colorLevels; 19 | 20 | outputTexture.write(outColor, grid); 21 | } 22 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Posterize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Posterize.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 海报化效果滤镜 11 | public struct C7Posterize: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 1.0, max: 255.0, value: 10.0) 14 | 15 | /// The number of color levels to reduce the image space to. 16 | /// This ranges from 1 to 256, with a default of 10 17 | @Clamping(range.min...range.max) public var colorLevels: Float = range.value 18 | 19 | public var modifier: Modifier { 20 | return .compute(kernel: "C7Posterize") 21 | } 22 | 23 | public var factors: [Float] { 24 | return [colorLevels] 25 | } 26 | 27 | public init(colorLevels: Float = range.value) { 28 | self.colorLevels = colorLevels 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Pow.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Pow.metal 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/7/28. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Pow(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *value [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half4 outColor = half4(pow(inColor.rgb, (*value)), 1.0); 18 | 19 | outputTexture.write(outColor, grid); 20 | } 21 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Pow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Pow.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/7/28. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Pow: C7FilterProtocol { 11 | 12 | public var value: Float = 0.2 13 | 14 | public var modifier: Modifier { 15 | return .compute(kernel: "C7Pow") 16 | } 17 | 18 | public var factors: [Float] { 19 | return [value] 20 | } 21 | 22 | public init(value: Float = 0.2) { 23 | self.value = value 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Saturation.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Saturation.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Saturation(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *saturation [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half3 luminanceWeighting = half3(0.2125, 0.7154, 0.0721); 18 | const half luminance = dot(inColor.rgb, luminanceWeighting); 19 | const half4 outColor = half4(mix(half3(luminance), inColor.rgb, half(*saturation)), inColor.a); 20 | 21 | outputTexture.write(outColor, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Saturation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Saturation.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 饱和度 11 | public struct C7Saturation: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 2.0, value: 1.0) 14 | 15 | /// Saturation refers to the brightness of the colors of images, which is adjusted by adjusting saturation. 16 | /// Saturation ranges from 0.0 to 2.0, in which 1.0 refers to the original figure. 17 | /// The greater the saturation is, the brighter the colors are. Otherwise, the more monotonous the colors are. 18 | public var saturation: Float = range.value 19 | 20 | public var modifier: Modifier { 21 | return .compute(kernel: "C7Saturation") 22 | } 23 | 24 | public var factors: [Float] { 25 | return [saturation] 26 | } 27 | 28 | public init(saturation: Float = range.value) { 29 | self.saturation = saturation 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7ShiftGlitch.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7ShiftGlitch.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/2/25. 6 | // 7 | 8 | import Foundation 9 | 10 | /// RGB Shift Glitch 11 | public struct C7ShiftGlitch: C7FilterProtocol { 12 | 13 | /// The adjusted time, from 0.0 to 1.0, with a default of 0.5 14 | public var time: Float = 0.5 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7ShiftGlitch") 18 | } 19 | 20 | public var factors: [Float] { 21 | return [time] 22 | } 23 | 24 | public init(time: Float = 0.5) { 25 | self.time = time 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Sobel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Sobel.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/16. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 特征提取,基于Sobel算子 11 | /// Feature extraction, based on Sobel operator 12 | public struct C7Sobel: C7FilterProtocol { 13 | 14 | /// Adjusts the dynamic range of the filter. default is 1.0 15 | /// Higher values lead to stronger edges, but can saturate the intensity colorspace. 16 | public var edgeStrength: Float = 1.0 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Sobel") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [edgeStrength] 24 | } 25 | 26 | public init(edgeStrength: Float = 1.0) { 27 | self.edgeStrength = edgeStrength 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Vibrance.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Vibrance.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Vibrance(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *vibrance [[buffer(0)]], 14 | uint2 grid [[thread_position_in_grid]]) { 15 | const half4 inColor = inputTexture.read(grid); 16 | 17 | const half average = (inColor.r + inColor.g + inColor.b) / 3.0h; 18 | const half mx = max(inColor.r, max(inColor.g, inColor.b)); 19 | const half amt = (mx - average) * (-half(*vibrance) * 3.0h); 20 | const half4 outColor = half4(mix(inColor.rgb, half3(mx), amt), inColor.a); 21 | 22 | outputTexture.write(outColor, grid); 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Vibrance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Vibrance.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 自然饱和度 11 | public struct C7Vibrance: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -1.2, max: 1.2, value: 0.0) 14 | 15 | /// Change the vibrance of an image, from -1.2 to 1.2, with a default of 0.0 16 | public var vibrance: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7Vibrance") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [vibrance] 24 | } 25 | 26 | public init(vibrance: Float = range.value) { 27 | self.vibrance = vibrance 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Vignette.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Vignette.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Vignette(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *centerX [[buffer(0)]], 14 | constant float *centerY [[buffer(1)]], 15 | constant float *start [[buffer(2)]], 16 | constant float *end [[buffer(3)]], 17 | constant float3 *colorVector [[buffer(4)]], 18 | uint2 grid [[thread_position_in_grid]]) { 19 | const half4 inColor = inputTexture.read(grid); 20 | const float2 textureCoordinate = float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height()); 21 | 22 | const half2 center = half2(*centerX, *centerY); 23 | const float dd = distance(textureCoordinate, float2(center)); 24 | const half percent = smoothstep(*start, *end, dd); 25 | const half4 outColor = half4(mix(inColor.rgb, half3(*colorVector), percent), inColor.a); 26 | 27 | outputTexture.write(outColor, grid); 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7Vignette.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Vignette.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/14. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 渐晕效果,使边缘的图像淡化 11 | public struct C7Vignette: C7FilterProtocol { 12 | 13 | /// The normalized distance from the center where the vignette effect starts, with a default of 0.3 14 | public var start: Float = 0.3 15 | /// The normalized distance from the center where the vignette effect ends, with a default of 0.75 16 | public var end: Float = 0.75 17 | public var center: C7Point2D = C7Point2D.center 18 | /// Keep the color scheme 19 | public var color: C7Color = .zero 20 | 21 | public var modifier: Modifier { 22 | return .compute(kernel: "C7Vignette") 23 | } 24 | 25 | public var factors: [Float] { 26 | return [center.x, center.y, start, end] 27 | } 28 | 29 | public func setupSpecialFactors(for encoder: MTLCommandEncoder, index: Int) { 30 | guard let computeEncoder = encoder as? MTLComputeCommandEncoder else { return } 31 | var factor = Vector3.init(color: color).to_factor() 32 | computeEncoder.setBytes(&factor, length: Vector3.size, index: index + 1) 33 | } 34 | 35 | public init(start: Float = 0.3, end: Float = 0.75, color: C7Color = .zero) { 36 | self.start = start 37 | self.end = end 38 | self.color = color 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7VoronoiOverlay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7VoronoiOverlay.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/3/1. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 泰森多边形法叠加效果 11 | /// 改变`Voronoi`模式中的距离度量以获得不同的形状 12 | public struct C7VoronoiOverlay: C7FilterProtocol { 13 | 14 | public var time: Float = 0.5 15 | public var alpha: Float = 0.05 16 | public var iResolution: C7Point2D = C7Point2D.center 17 | 18 | public var modifier: Modifier { 19 | return .compute(kernel: "C7VoronoiOverlay") 20 | } 21 | 22 | public var factors: [Float] { 23 | return [time, alpha, iResolution.x, iResolution.y] 24 | } 25 | 26 | public init(time: Float = 0.5, alpha: Float = 0.05) { 27 | self.time = time 28 | self.alpha = alpha 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Compute/Pixel/C7WhiteBalance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7WhiteBalance.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// 基于色温调整白平衡 11 | public struct C7WhiteBalance: C7FilterProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 4000, max: 7000, value: 5000) 14 | 15 | /// The tint to adjust the image by. A value of -200 is very green and 200 is very pink. 16 | @Clamping(-200...200) public var tint: Float = 0 17 | /// The temperature to adjust the image by, in ºK. A value of 4000 is very cool and 7000 very warm. 18 | /// Note that the scale between 4000 and 5000 is nearly as visually significant as that between 5000 and 7000. 19 | @Clamping(range.min...range.max) public var temperature: Float = range.value 20 | 21 | public var modifier: Modifier { 22 | return .compute(kernel: "C7WhiteBalance") 23 | } 24 | 25 | public var factors: [Float] { 26 | return [temperature, tint] 27 | } 28 | 29 | public init(temperature: Float = range.value, tint: Float = 0) { 30 | self.temperature = temperature 31 | self.tint = tint 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Crop.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Crop.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Crop(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *originX [[buffer(0)]], 14 | constant float *originY [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 17 | 18 | const float minX = inputTexture.get_width() * (*originX); 19 | const float minY = inputTexture.get_height() * (*originY); 20 | const half4 outColor = inputTexture.sample(quadSampler, float2((grid.x + minX) / inputTexture.get_width(), (grid.y + minY) / inputTexture.get_height())); 21 | 22 | outputTexture.write(outColor, grid); 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Flip.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Flip.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Flip(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | constant float *horizontal [[buffer(0)]], 14 | constant float *vertical [[buffer(1)]], 15 | uint2 grid [[thread_position_in_grid]]) { 16 | const uint x = (*horizontal) ? inputTexture.get_width() - 1 - grid.x : grid.x; 17 | const uint y = (*vertical) ? inputTexture.get_height() - 1 - grid.y : grid.y; 18 | // Read the pixels that have been transformed from coordinates 19 | const half4 outColor = inputTexture.read(uint2(x, y)); 20 | 21 | outputTexture.write(outColor, grid); 22 | } 23 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Flip.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Flip.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Flip: C7FilterProtocol { 11 | 12 | /// Whether to flip horizontally or not 13 | public var horizontal: Bool = false 14 | /// Whether to flip vertically or not 15 | public var vertical: Bool = false 16 | 17 | public var modifier: Modifier { 18 | return .compute(kernel: "C7Flip") 19 | } 20 | 21 | public var factors: [Float] { 22 | return [horizontal ? 1.0 : 0.0, vertical ? 1.0 : 0.0] 23 | } 24 | 25 | public init(horizontal: Bool = false, vertical: Bool = false) { 26 | self.horizontal = horizontal 27 | self.vertical = vertical 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Resize.metal: -------------------------------------------------------------------------------- 1 | // 2 | // C7Resize.metal 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | #include 9 | using namespace metal; 10 | 11 | kernel void C7Resize(texture2d outputTexture [[texture(0)]], 12 | texture2d inputTexture [[texture(1)]], 13 | uint2 grid [[thread_position_in_grid]]) { 14 | constexpr sampler quadSampler(mag_filter::linear, min_filter::linear); 15 | 16 | const half4 outColor = inputTexture.sample(quadSampler, float2(float(grid.x) / outputTexture.get_width(), float(grid.y) / outputTexture.get_height())); 17 | 18 | outputTexture.write(outColor, grid); 19 | } 20 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Resize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Resize.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Pull and compress the picture, the picture will be distorted 11 | public struct C7Resize: C7FilterProtocol { 12 | 13 | public var width: Float 14 | public var height: Float 15 | 16 | public var modifier: Modifier { 17 | return .compute(kernel: "C7Resize") 18 | } 19 | 20 | public func resize(input size: C7Size) -> C7Size { 21 | return Placement.fit.resize(width: width, height: height, size: size) 22 | } 23 | 24 | public init(size: CGSize) { 25 | self.width = Float(size.width) 26 | self.height = Float(size.height) 27 | } 28 | 29 | public init(width: Float, height: Float) { 30 | self.width = width 31 | self.height = height 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Compute/Shape/C7Rotate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // C7Rotate.swift 3 | // ATMetalBand 4 | // 5 | // Created by Condy on 2022/2/15. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct C7Rotate: C7FilterProtocol { 11 | 12 | /// Angle to rotate, unit is degree 13 | @DegreeRange public var angle: Float 14 | 15 | public var modifier: Modifier { 16 | return .compute(kernel: "C7Rotate") 17 | } 18 | 19 | public var factors: [Float] { 20 | return [Degree(value: angle).radians] 21 | } 22 | 23 | public func resize(input size: C7Size) -> C7Size { 24 | return mode.rotate(angle: Degree(value: angle).radians, size: size) 25 | } 26 | 27 | private var mode: Placement = .fit 28 | 29 | public init(mode: Placement = .fit, angle: Float = 0) { 30 | self.angle = angle 31 | self.mode = mode 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIBrightness.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIBrightness.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIBrightness: CoreImageProtocol { 12 | 13 | /// The adjusted brightness, from -1.0 to 1.0, with a default of 0.0 being the original picture. 14 | public static let range: ParameterRange = .init(min: -1.0, max: 1.0, value: 0.0) 15 | 16 | @Clamping(range.min...range.max) public var brightness: Float = range.value 17 | 18 | public var modifier: Modifier { 19 | return .coreimage(CIName: "CIColorControls") 20 | } 21 | 22 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 23 | filter.setValue(brightness, forKey: kCIInputBrightnessKey) 24 | return ciImage 25 | } 26 | 27 | public init(brightness: Float = range.value) { 28 | self.brightness = brightness 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIColorControls.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIColorControls.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | /// 调整亮度、饱和度和对比度 12 | public struct CIColorControls: CoreImageProtocol { 13 | 14 | /// The adjusted brightness, from -1.0 to 1.0, with a default of 0.0. 15 | @Clamping(CIBrightness.range.min...CIBrightness.range.max) public var brightness: Float = CIBrightness.range.value 16 | 17 | /// The adjusted saturation, from -1.0 to 1.0, with a default of 0.0. 18 | @Clamping(CISaturation.range.min...CISaturation.range.max) public var saturation: Float = CISaturation.range.value 19 | 20 | /// The adjusted contrast, from -0.18 to 0.18, with a default of 0.0. 21 | @Clamping(CIContrast.range.min...CIContrast.range.max) public var contrast: Float = CIContrast.range.value 22 | 23 | public var modifier: Modifier { 24 | return .coreimage(CIName: "CIColorControls") 25 | } 26 | 27 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 28 | filter.setValue(brightness, forKey: kCIInputBrightnessKey) 29 | filter.setValue(saturation + 1, forKey: kCIInputSaturationKey) 30 | filter.setValue(contrast + 1, forKey: kCIInputContrastKey) 31 | return ciImage 32 | } 33 | 34 | public init() { } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIColorMonochrome.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIColorMonochrome.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/3/3. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | /// 单色滤镜 12 | public struct CIColorMonochrome: CoreImageProtocol { 13 | 14 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 1.0) 15 | 16 | @Clamping(range.min...range.max) public var intensity: Float = range.value 17 | 18 | /// A color to use as the white point. 19 | public var color: C7Color = .white { 20 | didSet { 21 | self.ciColor = CIColor.init(color: color) 22 | } 23 | } 24 | 25 | public var modifier: Modifier { 26 | return .coreimage(CIName: "CIColorMonochrome") 27 | } 28 | 29 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 30 | filter.setValue(intensity, forKey: kCIInputIntensityKey) 31 | filter.setValue(ciColor, forKey: kCIInputColorKey) 32 | return ciImage 33 | } 34 | 35 | private var ciColor: CIColor! 36 | 37 | public init(color: C7Color = .white) { 38 | self.color = color 39 | self.ciColor = CIColor.init(color: color) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIContrast.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIContrast.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIContrast: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -1.0, max: 1.0, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var contrast: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIColorControls") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | filter.setValue(contrast + 1, forKey: kCIInputContrastKey) 23 | return ciImage 24 | } 25 | 26 | public init(contrast: Float = range.value) { 27 | self.contrast = contrast 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIExposure.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIExposure.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIExposure: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -1.8, max: 1.8, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var exposure: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIExposureAdjust") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | filter.setValue(exposure, forKey: kCIInputEVKey) 23 | return ciImage 24 | } 25 | 26 | public init(exposure: Float = range.value) { 27 | self.exposure = exposure 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIFade.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIFade.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIFade: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var intensity: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CISourceOverCompositing") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | let mFilter = CIFilter(name: "CIConstantColorGenerator", parameters: [ 23 | kCIInputColorKey : CIColor(red: 1, green: 1, blue: 1, alpha: CGFloat(intensity)) 24 | ]) 25 | guard let foreground = mFilter?.outputImage else { 26 | throw HarbethError.outputCIImage("CIConstantColorGenerator") 27 | } 28 | filter.setValue(ciImage, forKey: kCIInputBackgroundImageKey) 29 | return foreground 30 | } 31 | 32 | public init(intensity: Float = range.value) { 33 | self.intensity = intensity 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIGaussianBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIGaussianBlur.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIGaussianBlur: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0, max: 100, value: 10.0) 14 | 15 | @Clamping(range.min...range.max) public var radius: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIGaussianBlur") 19 | } 20 | 21 | public var croppedOutputImage: Bool { 22 | return true 23 | } 24 | 25 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 26 | let radius = ciImage.extent.c7.radius(radius, max: Self.range.max) 27 | filter.setValue(radius, forKey: kCIInputRadiusKey) 28 | // Return a new infinite image by replicating the edge pixels of a rectangle. 29 | // Cut the blurred area next to it. 30 | return ciImage.clamped(to: ciImage.extent) 31 | } 32 | 33 | public init(radius: Float = range.value) { 34 | self.radius = radius 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIHighlight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIHighlight.swift 3 | // Harbeth 4 | // 5 | // Created by 77。 on 2022/7/13. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | /// 高光 12 | /// https://cifilter.io/CIHighlightShadowAdjust/ 13 | public struct CIHighlight: CoreImageProtocol { 14 | 15 | public static let range: ParameterRange = .init(min: 0.0, max: 1.0, value: 0.0) 16 | 17 | @ZeroOneRange public var highlight: Float = range.value 18 | 19 | public var modifier: Modifier { 20 | return .coreimage(CIName: "CIHighlightShadowAdjust") 21 | } 22 | 23 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 24 | filter.setValue(1 - highlight, forKey: "inputHighlightAmount") 25 | return ciImage 26 | } 27 | 28 | public init(highlight: Float = range.value) { 29 | self.highlight = highlight 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/CoreImage/CINoiseReduction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CINoiseReduction.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/3/25. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CINoiseReduction: CoreImageProtocol { 12 | 13 | public var noiseLevel: Float = 0.02 14 | 15 | public var modifier: Modifier { 16 | return .coreimage(CIName: "CINoiseReduction") 17 | } 18 | 19 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 20 | filter.setValue(noiseLevel, forKey: "inputNoiseLevel") 21 | return ciImage 22 | } 23 | 24 | public init(noiseLevel: Float = 0.02) { 25 | self.noiseLevel = noiseLevel 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIResizedSmooth.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIResizedSmooth.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2024/4/8. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIResizedSmooth: CIImageDisplaying { 12 | 13 | public var modifier: Modifier { 14 | return .coreimage(CIName: "CILanczosScaleTransform") 15 | } 16 | 17 | public var ciFilter: CIFilter? 18 | 19 | public var postProcessing: (CIImage) -> CIImage = { $0 } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | let scale = targetSize.height / ciImage.extent.height 23 | let aspectRatio = targetSize.width / (ciImage.extent.width) * scale 24 | filter.setValue(scale, forKey: kCIInputScaleKey) 25 | filter.setValue(aspectRatio, forKey: kCIInputAspectRatioKey) 26 | return ciImage 27 | } 28 | 29 | public var targetSize: CGSize 30 | 31 | public init(targetSize: CGSize) { 32 | self.targetSize = targetSize 33 | self.ciFilter = CIFilter(name: "CILanczosScaleTransform") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/CoreImage/CISaturation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CISaturation.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CISaturation: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -1.0, max: 1.0, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var saturation: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIColorControls") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | filter.setValue(saturation + 1, forKey: kCIInputSaturationKey) 23 | return ciImage 24 | } 25 | 26 | public init(saturation: Float = range.value) { 27 | self.saturation = saturation 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIShadows.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIShadows.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIShadows: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -1, max: 1, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var shadows: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIHighlightShadowAdjust") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | filter.setValue(shadows, forKey: "inputShadowAmount") 23 | return ciImage 24 | } 25 | 26 | public init(shadows: Float = range.value) { 27 | self.shadows = shadows 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/CoreImage/CISharpen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CISharpen.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CISharpen: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0, max: 1.0, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var sharpness: Float = range.value 16 | 17 | public var radius: Float = 0.0 18 | 19 | public var modifier: Modifier { 20 | return .coreimage(CIName: "CISharpenLuminance") 21 | } 22 | 23 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 24 | let radius = ciImage.extent.c7.radius(radius, max: Self.range.max) 25 | filter.setValue(radius, forKey: kCIInputRadiusKey) 26 | filter.setValue(sharpness, forKey: kCIInputSharpnessKey) 27 | return ciImage 28 | } 29 | 30 | public init(sharpness: Float = range.value, radius: Float = 0.0) { 31 | self.radius = radius 32 | self.sharpness = sharpness 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/CoreImage/CITemperature.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CITemperature.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CITemperature: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: -3000, max: 3000, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var temperature: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CITemperatureAndTint") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | filter.setValue(CIVector.init(x: CGFloat(temperature) + 6500, y: 0), forKey: "inputNeutral") 23 | filter.setValue(CIVector.init(x: 6500, y: 0), forKey: "inputTargetNeutral") 24 | return ciImage 25 | } 26 | 27 | public init(temperature: Float = range.value) { 28 | self.temperature = temperature 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIUnsharpMask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIUnsharpMask.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIUnsharpMask: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0, max: 0.3, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var intensity: Float = range.value 16 | 17 | @ZeroOneRange public var radius: Float = 0.0 18 | 19 | public var modifier: Modifier { 20 | return .coreimage(CIName: "CIUnsharpMask") 21 | } 22 | 23 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 24 | let radius = ciImage.extent.c7.radius(radius, max: Self.range.max) 25 | filter.setValue(radius, forKey: kCIInputRadiusKey) 26 | filter.setValue(intensity, forKey: kCIInputIntensityKey) 27 | return ciImage 28 | } 29 | 30 | public init(intensity: Float = range.value, radius: Float = 0) { 31 | self.radius = radius 32 | self.intensity = intensity 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIVignette.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIVignette.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/8/6. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | public struct CIVignette: CoreImageProtocol { 12 | 13 | public static let range: ParameterRange = .init(min: 0, max: 2, value: 0.0) 14 | 15 | @Clamping(range.min...range.max) public var vignette: Float = range.value 16 | 17 | public var modifier: Modifier { 18 | return .coreimage(CIName: "CIVignette") 19 | } 20 | 21 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 22 | let radius = ciImage.extent.c7.radius(vignette, max: Self.range.max) 23 | filter.setValue(radius, forKey: kCIInputRadiusKey) 24 | filter.setValue(vignette, forKey: kCIInputIntensityKey) 25 | return ciImage 26 | } 27 | 28 | public init(vignette: Float = range.value) { 29 | self.vignette = vignette 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/CoreImage/CIWhitePoint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CIWhitePoint.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2022/11/24. 6 | // 7 | 8 | import Foundation 9 | import CoreImage 10 | 11 | /// Adjusts the reference white point for an image and maps all colors in the source using the new reference. 12 | /// https://cifilter.io/CIWhitePointAdjust/ 13 | public struct CIWhitePoint: CoreImageProtocol { 14 | 15 | /// A color to use as the white point. 16 | public var color: C7Color = .white { 17 | didSet { 18 | self.ciColor = CIColor(color: color) 19 | } 20 | } 21 | 22 | public var modifier: Modifier { 23 | return .coreimage(CIName: "CIWhitePointAdjust") 24 | } 25 | 26 | public func coreImageApply(filter: CIFilter, input ciImage: CIImage) throws -> CIImage { 27 | filter.setValue(ciColor, forKey: kCIInputColorKey) 28 | return ciImage 29 | } 30 | 31 | private var ciColor: CIColor! 32 | 33 | public init(color: C7Color = .white) { 34 | self.color = color 35 | self.ciColor = CIColor(color: color) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftUI/Color+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/12/1. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) 12 | extension Color { 13 | 14 | /// Creates a color from an hex integer, e.g. 0xD6A5A4. 15 | /// - Parameter hex: A hexa-decimal UInt64 that represents a color. 16 | public init(hex: Int) { 17 | let mask = 0xFF 18 | let r = Double((hex >> 16) & mask) / 255 19 | let g = Double((hex >> 8) & mask) / 255 20 | let b = Double((hex) & mask) / 255 21 | self.init(red: r, green: g, blue: b, opacity: 1.0) 22 | } 23 | 24 | /// Creates a color from an hex string, e.g. "#D6A5A4". 25 | /// Support hex string `#RGB`,`RGB`,`#RGBA`,`RGBA`,`#RRGGBB`,`RRGGBB`,`#RRGGBBAA`,`RRGGBBAA`. 26 | /// - Parameter hex: A hexa-decimal color string representation. 27 | public init(hex: String) { 28 | let (r, g, b, a) = hex.c7.hex2RGBA() 29 | self.init(red: r, green: g, blue: b, opacity: a) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftUI/HarbethViewInput.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HarbethViewInput.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2025/1/1. 6 | // 7 | 8 | import Foundation 9 | 10 | public struct HarbethViewInput { 11 | 12 | public let texture: MTLTexture? 13 | /// A filters add into a data source. 14 | public var filters: [C7FilterProtocol] = [] 15 | /// Whether to use asynchronous processing, the UI will not be updated in real time. 16 | public var asynchronousProcessing: Bool = false 17 | /// Placeholder image, without source data. 18 | public var placeholder: C7Image? 19 | 20 | public init(texture: MTLTexture?) { 21 | self.texture = texture 22 | } 23 | 24 | public init(image: C7Image) { 25 | self.init(texture: image.c7.toTexture()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SwiftUI/Image+Ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Image+Ext.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/7/27. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) 12 | extension Image { 13 | 14 | public init(cgImage: CGImage) { 15 | self.init(c7Image: cgImage.c7.toC7Image()) 16 | } 17 | 18 | public init(c7Image: C7Image) { 19 | #if os(iOS) 20 | self.init(uiImage: c7Image) 21 | #elseif os(macOS) 22 | self.init(nsImage: c7Image) 23 | #else 24 | #error("Unsupported Platform") 25 | #endif 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SwiftUI/Published_Image.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Published_Image.swift 3 | // Harbeth 4 | // 5 | // Created by Condy on 2023/12/5. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) 11 | public final class Published_Image: ObservableObject { 12 | 13 | @Published public var image: C7Image 14 | 15 | public init(_ image: C7Image) { 16 | self.image = image 17 | } 18 | } 19 | 20 | @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) 21 | public final class Published_Source: ObservableObject { 22 | 23 | @Published public var source: T 24 | 25 | public init(_ source: T) { 26 | self.source = source 27 | } 28 | } 29 | --------------------------------------------------------------------------------