| Soul | Combination |
|---|---|
![]() |
![]() |
A texture-first Metal render engine for image and frame pipelines on Apple platforms.
Harbeth processes UIImage / NSImage, CGImage, CIImage, MTLTexture, CVPixelBuffer, and CMSampleBuffer. It provides filters, render graphs, masks, transitions, geometry and optics primitives, output contracts, diagnostics, and preview hosting.
It is the rendering core inside a product, not the product workflow itself: the host decides interaction, media lifecycle, persistence, and product policy; Harbeth turns one image or frame description into a GPU-rendered result with explicit output semantics.
English | 简体中文
| Platform | Minimum |
|---|---|
| iOS / iPadOS | 15.0 |
| macOS | 12.0 |
| tvOS | 15.0 |
| Toolchain | Xcode 16+, Swift 6 |
dependencies: [
.package(url: "https://github.com/yangKJ/Harbeth.git", from: "3.0.0")
]Add Harbeth to the target that renders images or frames.
pod 'Harbeth', '~> 3.0'Harbeth exposes two normal integration routes. Runtime, analysis, recipes, and preview hosts support these routes; they are not additional entry points.
| Route | Use it when | Canonical result |
|---|---|---|
HarbethIO |
You already have a source and a filter chain | try output() / await transmitOutput() |
ImageNode |
You need Harbeth's advanced unified graph, editing, contract, inspection, and delivery surface | makeTexture() / makeFrame() / makeFrameAsync() |
| Source | Direct HarbethIO result |
Advanced ImageNode result |
|---|---|---|
UIImage / NSImage (C7Image) |
Same image type | Texture, frame, image readback |
CGImage / CIImage |
Same source type | Texture, frame, image readback |
MTLTexture |
MTLTexture |
Texture or metadata-carrying frame |
CVPixelBuffer |
CVPixelBuffer |
Texture, frame, attachments |
CMSampleBuffer |
CMSampleBuffer |
Texture, frame, preview-host metadata |
Data / ImageAsset |
Use ImageNode for decoded assets |
Texture, frame, diagnostics |
let outputImage = try HarbethIO(
element: inputImage,
filters: [
C7Exposure(exposure: 0.25),
C7Contrast(contrast: 1.08),
C7Saturation(saturation: 0.94)
]
).output()output() is the primary synchronous API because rendering failures remain observable. transmitOutput(...) is its core asynchronous counterpart.
For non-blocking submission, use the async counterpart:
let outputImage = try await HarbethIO(
element: inputImage,
filters: filters
).transmitOutput()Callback-based integrations can use transmitOutput(outputColorSpace:complete:). Filtered work is encoded on Harbeth's render operation queue and completes after GPU completion under the default profile. The callback queue is unspecified, so UI updates must return to MainActor. The no-filter fast path may complete inline.
For low-latency asynchronous texture pipelines, keep the established
transmitOutputRealTimeCommit switch as the single public control:
var io = HarbethIO(
element: inputTexture,
filters: filters
)
io.transmitOutputRealTimeCommit = true
let outputTexture = try await io.transmitOutput()When the switch is true, asynchronous texture-first output may be delivered after its command buffer is scheduled rather than completed. The switch does not change synchronous output() behavior. Image, pixel-buffer and sample-buffer outputs still wait for GPU completion before CPU materialization, even when the switch is enabled.
ImageNode is Harbeth's advanced unified entry. Use it when a render description must carry more than a one-shot filter chain: reusable sources, structured edits, output intent, metadata, cache policy, diagnostics, or multiple delivery forms.
let node = ImageNode.image(inputImage)
.applying(C7Exposure(exposure: 0.25))
.applying(C7Contrast(contrast: 1.08))
.transforming(ImageTransformRecipe(rotationDegrees: 90))
.withCachePolicy(.transient)
let previewFrame = try node.makeFrame(profile: .stablePreview)
let backgroundFrame = try await node.makeFrameAsync(profile: .stablePreview)
let exportTexture = try node.makeTexture(profile: .exportQuality)Its core capabilities are:
- Unified sources: image,
CGImage,CIImage, texture, pixel buffer, sample buffer, encoded data, andImageAsset. - Composable processing: filters, explicit kernel contracts, plugins, cache policy, and sampler policy.
- Structured editing:
EditRecipe, Geometry, Optics, local effects, gradient/shape/path/composite masks, and reusable preview/final modes. - Multi-source composition: transitions and ordered layer composites with masks, transforms, blend contracts, and output contracts.
- Stable delivery semantics:
RenderProfile,ImageDerivativeSpec, color/alpha/orientation/source-tier metadata, and texture ownership travel withRenderedFrame. - Inspection and replay: image graph, diagnostics, debug snapshot, deferred
RenderRequest, histogram/statistics/color probes, masks, and output attachments.
Use makeTexture() for a texture result, makeFrame() when metadata and host delivery matter, makeFrameAsync() when the caller must not block, and makeRenderRequest() when execution must be deferred or inspected. When a node already exists, prefer instance chains such as node.editing(...), node.transforming(...), and node.applying(optics: ...). Recipe families are editing-description primitives inside the ImageNode route, not a third public route.
UIKit and AppKit can host a RenderedFrame directly:
renderView.display(previewFrame)SwiftUI can use the same Harbeth preview substrate without image readback:
HarbethRenderView(
frame: previewFrame,
resizingMode: .aspectFit
)RenderView and HarbethRenderView are render-output hosts. Harbeth retains frame metadata, chooses an available backing strategy, handles visibility pause/resume, and exposes execution reports. The host application still owns media capture, playback, recording, timeline, export, and persistence.
Keep image readback explicit and local to the host UI. Use HarbethRenderView whenever SwiftUI previews a texture or RenderedFrame.
- Image, texture, pixel-buffer, and sample-buffer input/output paths.
- Compute, render, blit, MPS, filter pipelines, and an explicit Metal command-encoding escape hatch; see the source-aligned Filter Catalog for all 183 public execution types and 30
C7Blendmodes. - Color adjustment, blur, blend, edge/detail, geometry, optics, LUT/Cube, utility, generator, and quality filters.
- Public Combination filters implemented through
C7FilterPipelineProtocol. - Mask, local-effect, layer-composite, transition, and edit-recipe primitives.
- Texture pooling, real
MTLHeapallocation, request budgets, binary archives, derived-resource governance, prewarming, render-plan caching, and stable fingerprints. - Alpha, working/output color profiles, YUV, HDR metadata, output quantization, output-size, orientation, and readback contracts.
- GPU waveform/vectorscope, histogram, statistics, probes, graph snapshots, preview/export parity, and performance metrics.
- Custom
.metal,.metallib, and optional Metal library-provider integration.
Harbeth is capability-driven: support for a contract or platform does not imply that every device has the same Metal feature set. Query capability reports and use the documented fallback behavior for advanced features.
Heap-backed allocation is opt-in and uses real MTLHeap resources in 3.0. It keeps the public workflow on HarbethIO / ImageNode, while the runtime owns descriptor compatibility, budgets, memory pressure, leases, and direct-allocation fallback. See the 3.0 Migration Guide before enabling it.
Common pointwise adjustments can execute as one Metal dispatch when their pixel contracts prove the chain safe to fuse. Neighbor sampling, multi-texture kernels, global dependencies, CPU readback, and explicit barriers remain separate passes. RenderRequest can reject work against an explicit resource budget before allocating textures, compare preview/export parity, and return allocator-observed resource reports. These are supporting contracts under the two canonical routes, not additional processing APIs.
Harbeth throws HarbethError from its canonical processing APIs and is silent by default. Route structured events into your own logger when needed:
HarbethLogger.minimumLevel = .warning
HarbethLogger.handler = { event in
appLogger.log("[\(event.category)] \(event.message)")
}Generate a privacy-safe environment summary for a GitHub Issue:
let supportJSON = try HarbethSupportSnapshot.capture().json()The snapshot contains the Harbeth version, platform, OS, Metal device name, and monitoring state. It does not include images or user data.
Harbeth keeps high-frequency routes texture-first, caches render plans and pipeline states, and can reuse texture allocations. Performance depends on device, source dimensions, pixel format, filter chain, and output contract; the project does not claim one universal speed multiplier.
Use RenderProfile.interactiveLatency for low-latency presentation, stablePreview for reusable preview output, and exportQuality / readbackQuality when completion or CPU access is part of the contract. See Performance Governance for repeatable measurement rules.
The workspace contains three integration workbenches:
Harbeth-iOS-Demo: UIKit showcase, ImageNode Lab, camera-frame reference wiring, masks, and the complete filter catalog.Harbeth-SwiftUI-Demo: SwiftUI route selection and output-host examples.Harbeth-macOS-Demo: AppKit filter and desktop integration examples.
These are workbenches for Harbeth's render capabilities, not packaged camera or video-editing SDKs.
- Documentation map
- DocC catalog
- Filter catalog
- Custom filter guide
- Troubleshooting
- Public API surface
- Capability map
- Performance governance
- Maintenance and release checks
- Changelog
Bug reports should use the repository Issue form and include a minimal HarbethIO or ImageNode reproduction plus a HarbethSupportSnapshot. Use Discussions for integration questions and architecture tradeoffs.
Harbeth is maintained as long-term open-source infrastructure, not as a one-off sample project. The work that makes a GPU engine dependable is often the least visible: following Apple platform changes, reproducing edge cases, profiling real workloads, refining API contracts, and keeping the documentation honest.
If Harbeth has saved you an afternoon of Metal infrastructure work, helped you avoid a production issue, or become a dependable part of your rendering stack, consider returning a small part of that value in the way that fits you best:
- Star or share the project to help other Apple-platform developers discover it.
- Use GitHub Sponsors for ongoing support.
- Use Buy Me a Coffee, Alipay, or WeChat for a one-time show of support.
Support is never a paywall or an obligation. Harbeth remains available under the MIT License; sponsorship simply makes it easier to give platform changes, regressions, and difficult edge cases the attention they deserve.
For one-time support via Alipay or WeChat:
Maintainer: yangKJ · yangkj310@gmail.com
Harbeth is available under the MIT License.



