DEV Community

Condy
Condy

Posted on

🚀 Harbeth: High-Performance Swift Image Processing Library

🚀 Harbeth: High-Performance Swift Image Processing Library

Harbeth Banner

The Journey Behind Harbeth

As an iOS/macOS developer, I've always been fascinated by the power of GPU-accelerated image processing. After working with various libraries and facing performance bottlenecks in real-time applications, I decided to create Harbeth - a library that combines the best of Metal performance with an intuitive Swift API.

The Challenges I Faced

  • Performance Limitations: Existing solutions either lacked performance or had complex APIs
  • Cross-Platform Consistency: Ensuring the same code worked seamlessly across iOS, macOS, tvOS, and watchOS
  • Memory Management: Optimizing texture usage to avoid memory spikes during real-time processing
  • API Design: Creating an intuitive interface that hides the complexity of Metal while providing full control

What Makes Harbeth Special

After months of development and optimization, Harbeth has become a library that I'm truly proud of. Let me share what makes it stand out:

🎨 Technical Deep Dive

Metal-Powered Architecture

Harbeth is built on a layered architecture that maximizes Metal's capabilities:

// Core rendering pipeline
class C7RenderPipeline {
    private let device: MTLDevice
    private let commandQueue: MTLCommandQueue
    private let library: MTLLibrary

    func render(with filter: C7FilterProtocol, inputTexture: MTLTexture) -> MTLTexture {
        // 1. Create render pass descriptor
        // 2. Set up command buffer
        // 3. Encode render commands
        // 4. Execute and return output texture
    }
}
Enter fullscreen mode Exit fullscreen mode

Smart Texture Pooling

One of the key optimizations is the texture pool system, which dramatically reduces memory allocation overhead:

class TexturePool {
    private var textureCache: [TextureKey: [MTLTexture]] = [:]

    func getTexture(width: Int, height: Int, pixelFormat: MTLPixelFormat) -> MTLTexture {
        // Check cache first
        // Create new texture if needed
        // Return texture for use
    }

    func returnTexture(_ texture: MTLTexture) {
        // Return texture to cache for reuse
    }
}
Enter fullscreen mode Exit fullscreen mode

Real-time Performance Monitoring

Harbeth includes a built-in performance monitoring system that helps identify bottlenecks:

// Enable performance monitoring
Device.setEnablePerformanceMonitor(true)

// Process with HarbethIO
let io = HarbethIO(element: image, filters: filters)
let result = try? io.output()

// Get performance statistics
let stats = PerformanceMonitor.shared.getStatistics()
print("Total Time: \(stats.totalTime)ms | GPU Time: \(stats.gpuTime)ms")
Enter fullscreen mode Exit fullscreen mode

🚀 Advanced Usage Examples

Creating Custom Filters

Harbeth makes it easy to create custom filters using Metal shaders:

class C7CustomFilter: C7FilterProtocol {
    var modifier: Modifier { return .compute(kernel: "customKernel") }

    // Custom parameters
    var intensity: Float = 0.5

    func setupSpecialEncodeCommand(with encoder: MTLComputeCommandEncoder) {
        encoder.setBytes(&intensity, length: MemoryLayout<Float>.stride, index: 0)
    }
}

// Metal shader (customKernel.metal)
/*
kernel void customKernel(
    texture2d<half, access::read> input [[texture(0)]],
    texture2d<half, access::write> output [[texture(1)]],
    constant float &intensity [[buffer(0)]],
    uint2 gid [[thread_position_in_grid]]
) {
    half4 color = input.read(gid);
    // Custom processing
    color.rgb = mix(color.rgb, half3(1.0), intensity);
    output.write(color, gid);
}
*/
Enter fullscreen mode Exit fullscreen mode

Complex Filter Chains

Combine multiple filters for sophisticated effects:

// Create a cinematic effect chain
let cinematicFilter = C7CombinationCinematic()

// Or build your own custom chain
let filters: [C7FilterProtocol] = [
    C7Brightness(brightness: 0.1),
    C7Contrast(contrast: 1.2),
    C7Saturation(saturation: 1.1),
    C7Vignette(intensity: 0.5),
    C7Granularity(grain: 0.3)
]

// Apply with operator chaining
let result = image ->> filters
Enter fullscreen mode Exit fullscreen mode

Real-time Camera Processing

Process camera feed with filters at 60 FPS:

// Setup camera collector
let camera = C7CollectorCamera(delegate: self)
camera.captureSession.sessionPreset = .hd1280x720

// Apply real-time filters
let filters = [C7EdgeGlow(lineColor: .red)]
camera.filters = filters

// Start capture
camera.startRunning()

// Handle filtered frames
extension CameraViewController: C7CollectorImageDelegate {
    func preview(_ collector: C7Collector, fliter image: C7Image) {
        // Update UI with filtered image
        DispatchQueue.main.async {
            self.imageView.image = image
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

📊 Performance Breakdown

Performance Chart

Key Performance Insights

  • GPU Acceleration: Up to 5x faster than CPU processing
  • Scalability: GPU time grows logarithmically while CPU time grows linearly
  • Memory Efficiency: Texture pooling reduces memory usage by up to 70%
  • Real-time Capability: Maintain 60 FPS even with 10+ filters

💻 macOS-specific Features

Harbeth includes several macOS-specific optimizations:

  • AppKit Integration: Seamless integration with NSImage and AppKit
  • High-Resolution Support: Optimized for Retina displays
  • Multi-window Processing: Handle multiple images across different windows
  • Drag & Drop Support: Easy integration with macOS drag and drop
// macOS-specific implementation
class MacImageProcessor {
    func processDroppedImage(_ image: NSImage) {
        let filters = [C7ColorMatrix4x4(matrix: .sepia)]
        let result = try? image.make(filters: filters)
        // Update UI with result
    }
}
Enter fullscreen mode Exit fullscreen mode

🎨 SwiftUI Integration

Harbeth provides native SwiftUI support with the HarbethView component:

import SwiftUI
import Harbeth

struct FilteredImageView: View {
    @State private var inputImage: UIImage = UIImage(named: "sample")!
    @State private var intensity: Float = 0.5

    var body: some View {
        VStack {
            HarbethView(image: inputImage, filters: [
                CIHighlight(highlight: intensity),
                C7WaterRipple(ripple: intensity),
            ]) { image in
                image
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .cornerRadius(12)
                    .shadow(radius: 5)
            }

            Slider(value: $intensity, in: 0...1)
                .padding()
        }
        .padding()
    }
}
Enter fullscreen mode Exit fullscreen mode

🌟 Use Cases and Success Stories

Camera Apps

  • Real-time filters during capture
  • Beauty effects with skin smoothing
  • Creative filters for social media

Photo Editors

  • Professional color grading
  • Batch processing of multiple images
  • Artistic effects and stylization

Video Processing

  • Filtered video playback
  • Real-time effects during recording
  • Video enhancement and color correction

📚 Getting Started

Installation

CocoaPods:

pod 'Harbeth'
Enter fullscreen mode Exit fullscreen mode

Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/yangKJ/Harbeth.git", branch: "master"),
]
Enter fullscreen mode Exit fullscreen mode

Quick Start

import Harbeth

// Method 1: HarbethIO
let io = HarbethIO(element: image, filters: [C7SoulOut(soul: 0.7)])
let result = try? io.output()

// Method 2: Direct extension
let result = try? image.make(filters: [C7SoulOut(soul: 0.7)])

// Method 3: Operator chaining
let result = image ->> C7SoulOut(soul: 0.7)
Enter fullscreen mode Exit fullscreen mode

🤔 Common Questions

Q: How does Harbeth compare to CoreImage?
A: Harbeth offers better performance for complex filter chains and a more intuitive API, while still integrating with CoreImage for additional functionality.

Q: Can I use Harbeth in production?
A: Yes, Harbeth is production-ready and used in several apps. It's stable, well-documented, and actively maintained.

Q: How do I handle memory constraints?
A: Harbeth includes automatic texture pooling and memory management. For memory-constrained devices, use Device.setMemoryLimitMB() to set appropriate limits.

Q: Does Harbeth support live camera processing?
A: Yes, Harbeth provides C7CollectorCamera for real-time camera processing with filters applied at 60 FPS.

📞 Support and Community

🎯 Future Roadmap

  • More filters and effects
  • Enhanced Metal Shader support
  • Machine learning integration for advanced effects
  • Improved documentation and examples
  • Community contributions and plugin system

Have you used Harbeth in your projects? I'd love to hear about your experiences and see what creative effects you've created. Let's push the boundaries of image processing together!

Top comments (0)