# AsyncGraphics
AsyncGraphics is a Swift package for working with images and video with concurrency on the GPU. The core type is called [`Graphic`](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic), it's like an image and is backed by a [`MTLTexture`](https://developer.apple.com/documentation/metal/mtltexture).
## Documentation
[**Documentation**](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics) (DocC)
See the [**Graphic**](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic) docs for all content and effects.
### Articles
- [Blending](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/blending)
- [Layout](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/layout)
- [Video Playback](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/videoplayback)
- [Video Editing](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/videoediting)
- [Camera](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/camera)
### Resources
[Image](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic#Image),
[Video](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Video),
[Camera](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Camera),
[View](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#View),
[Screen](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Screen),
[Maps](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Maps)
### Shapes
[Rectangle](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Rectangle),
[Circle](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Circle),
[Polygon](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Polygon),
[Arc](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Arc),
[Star](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Star),
[Line](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Line)
### Visuals
[Color](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Color),
[Gradient](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Gradient),
[Noise](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Noise)
### Particles
[Particles](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Particles)
### Color Effects
[Levels](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Levels) (Brightness, Contrast, Invert, Opacity),
[Luma Levels](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Luma-Levels),
[Color Shift](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Color-Shift) (Hue, Saturation),
[Luma Color Shift](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Luma-Color-Shift),
[Sepia](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Sepia),
[Threshold](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Threshold),
[Quantize](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Quantize),
[Lookup](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Lookup),
[Gradient Lookup](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Gradient-Lookup),
[Clamp](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Clamp),
[Cross](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Cross) (Fade),
[Chroma Key](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Chroma-Key) (Green Screen),
[Person Segmentation](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Person-Segmentation) (Background Removal),
[Color Convert](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Color-Convert),
[Range](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Range)
### Space Effects
[Blur](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Blur),
[Rainbow Blur](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Rainbow-Blur),
[Luma Rainbow Blur](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Luma-Rainbow-Blur),
[Pixelate](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Pixelate),
[Displace](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Displace),
[Edge](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Edge),
[Sharpen](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Sharpen),
[Kaleidoscope](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Kaleidoscope),
[Morph](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Morph),
[Channel Mix](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Channel-Mix)
### Layout
[Stack](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Stack),
[Resize](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Resize) (Resolution),
[Mirror](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Mirror),
[Rotate](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Rotate)
### Info
[Pixels](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Pixels),
[Channels](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Channels),
[Stereoscopic](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Stereoscopic)
### Convert
[Crop](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Crop),
[Padding](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Padding),
[Corner Pin](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Corner-Pin),
[Sample Line](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Sample-Line),
[Slope](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Slope),
[Remap](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Remap),
[Polar](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Polar),
[Flood Fill](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Flood-Fill),
[Reduce](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Reduce),
[LUTs](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#LUTs),
[Buffer](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Buffer)
### Detection
[Face Detection](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Face-Detection)
### Metal
[Metal](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Metal)
## Install
```swift
.package(url: "https://github.com/heestand-xyz/AsyncGraphics", from: "3.0.0")
```
## Views
In AsyncGraphics there are a couple ways to present a graphic.
- [AGView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agview) to declaratively view [AGGraph](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/aggraph)s
- [GraphicView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphicview) to imperatively view [Graphic](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic)s
- [AsyncGraphicView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/asyncgraphicview) to imperatively view [Graphic](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic)s asynchronously.
- [Graphic3DView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic3dview) to view [Graphic3D](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic3d/)s
```swift
import AsyncGraphics
struct ContentView: View {
var body: some View {
AsyncGraphicView { resolution in
try await .circle(resolution: resolution)
}
}
}
```
or for more control:
```swift
import AsyncGraphics
struct ContentView: View {
private static let resolution = CGSize(width: 1000, height: 1000)
@State private var graphic: Graphic?
var body: some View {
ZStack {
if let graphic {
GraphicView(graphic: graphic)
}
}
.task {
graphic = try? await .circle(resolution: Self.resolution)
}
}
}
```
# Examples
## Images
To import and export images there are [multiple ways](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Image) to do this. The simplest way is to load an asset from the asset catalog by name. If the asset does not exist, an error will be thrown.
```swift
let graphic: Graphic = try await .image(named: "Kite")
```
To export an UIImage or NSImage just call `try await graphic.image` or for a SwiftUI image `try await graphic.imageForSwiftUI`.
## Blending
First we create an [AGView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agview/), this is the container for all [AGGraph](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/aggraph)s.
In this example we have a [AGZStack](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agzstack) with 3 [AGHStack](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/aghstack)s. Each graph has a blend mode ([AGBlendMode](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agblendmode)), in this case .screen.
```swift
import SwiftUI
import AsyncGraphics
struct ContentView: View {
var body: some View {
AGView {
AGZStack {
AGHStack {
AGSpacer()
AGCircle()
.foregroundColor(.red)
}
AGHStack {
AGSpacer()
AGCircle()
.foregroundColor(.green)
AGSpacer()
}
.blendMode(.screen)
AGHStack {
AGCircle()
.foregroundColor(.blue)
AGSpacer()
}
.blendMode(.screen)
}
}
}
}
```
## Layout
First we create an [AGView](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agview/), this is the container for all [AGGraph](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/aggraph/)s.
In this example we create an [AGHStack](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/aghstack/) to contain the boxes, then we loop 3 times with an [AGForEach](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agforeach/), calculate the width and create [AGRoundedRectangles](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/agroundedrectangle/). After that we set the frame to get a fixed size and apply a color. After the stack we apply some padding and finally add a background.
```swift
import SwiftUI
import AsyncGraphics
struct ContentView: View {
var body: some View {
AGView {
AGHStack(alignment: .top, spacing: 15) {
AGForEach(0..<3) { index in
let width = 50 * CGFloat(index + 1)
AGRoundedRectangle(cornerRadius: 15)
.frame(width: width, height: width)
.foregroundColor(Color(hue: Double(index) / 3,
saturation: 0.5,
brightness: 1.0))
}
}
.padding(15)
.background {
AGRoundedRectangle(cornerRadius: 30)
.opacity(0.1)
}
}
}
}
```
## Camera
```swift
import SwiftUI
import AsyncGraphics
struct ContentView: View {
var body: some View {
AGView {
AGZStack {
AGCamera(.front)
.resizable()
.aspectRatio(contentMode: .fill)
AGCircle()
.blendMode(.multiply)
}
}
}
}
```
You can also do the same with `Graphic`s:
```swift
import SwiftUI
import AsyncGraphics
struct ContentView: View {
@State private var graphic: Graphic?
var body: some View {
ZStack {
if let graphic {
GraphicView(graphic: graphic)
}
}
.task {
do {
let resolution = CGSize(width: 1_000, height: 1_000)
let circleGraphic: Graphic = try await .circle(radius: 500,
backgroundColor: .clear,
resolution: resolution)
for await cameraGraphic in try await Graphic.camera(at: .front) {
graphic = try await circleGraphic
.blended(with: cameraGraphic,
blendingMode: .multiply,
placement: .fill)
}
} catch {
print(error)
}
}
}
}
```
> Remember to set the Info.plist key `NSCameraUsageDescription` "Privacy - Camera Usage Description"
## Metal
There is the option to write high level [metal](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/metal) code in AsyncGraphics. No need to setup a pipeline.
## Colors
Colors are represented with the `PixelColor` type.
`import PixelColor` to create custom colors with hex values.
[PixelColor](https://github.com/heestand-xyz/PixelColor) on GitHub.
## Tiling
Most shapes can be tiled (rendered in chunks).
Use the [tiled](https://heestand-xyz.github.io/AsyncGraphics-Docs/documentation/asyncgraphics/graphic/#Tile) methods to render tiles. Add padding if using a space effect, like blur or displace.
## Author
Created by [Anton Heestand](http://heestand.xyz)
## License
[MIT](https://github.com/heestand-xyz/AsyncGraphics/blob/main/LICENSE)