Skip to content

Commit

Permalink
Merge pull request #7 from Eskils/develop
Browse files Browse the repository at this point in the history
Dithering Engine 1.7.0
  • Loading branch information
Eskils authored Jan 10, 2024
2 parents 35f84a4 + d6c709d commit e402ea8
Show file tree
Hide file tree
Showing 35 changed files with 137 additions and 38 deletions.
8 changes: 4 additions & 4 deletions Documentation/Demo/Dithering.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Dithering/Dithering.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8;
CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"Dithering/Preview Content\"";
DEVELOPMENT_TEAM = EUKTZ7725R;
ENABLE_HARDENED_RUNTIME = NO;
Expand All @@ -373,7 +373,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.2;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = com.skillbreak.Dithering;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand All @@ -392,7 +392,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = Dithering/Dithering.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 8;
CURRENT_PROJECT_VERSION = 9;
DEVELOPMENT_ASSET_PATHS = "\"Dithering/Preview Content\"";
DEVELOPMENT_TEAM = EUKTZ7725R;
ENABLE_HARDENED_RUNTIME = NO;
Expand All @@ -409,7 +409,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.6.2;
MARKETING_VERSION = 1.7.0;
PRODUCT_BUNDLE_IDENTIFIER = com.skillbreak.Dithering;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,67 +1,67 @@
{
"images" : [
{
"filename" : "DitheringEngineIconGeneratedScaled-iOS.png",
"filename" : "DitherableIconNewBackground.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 9.png",
"filename" : "DitherableIconNew-kopi 9.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "16x16"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 8.png",
"filename" : "DitherableIconNew-kopi 8.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "16x16"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 7.png",
"filename" : "DitherableIconNew-kopi 7.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "32x32"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 6.png",
"filename" : "DitherableIconNew-kopi 6.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "32x32"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 5.png",
"filename" : "DitherableIconNew-kopi 5.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "128x128"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 4.png",
"filename" : "DitherableIconNew-kopi 4.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "128x128"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 3.png",
"filename" : "DitherableIconNew-kopi 3.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "256x256"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 2.png",
"filename" : "DitherableIconNew-kopi 2.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "256x256"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded 1.png",
"filename" : "DitherableIconNew-kopi 1.png",
"idiom" : "mac",
"scale" : "1x",
"size" : "512x512"
},
{
"filename" : "DitheringEngineIconGeneratedScaledPadded.png",
"filename" : "DitherableIconNew-kopi.png",
"idiom" : "mac",
"scale" : "2x",
"size" : "512x512"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"images" : [
{
"filename" : "DitheringEngineIconGeneratedScaled.png",
"filename" : "DitherableIconNew.png",
"idiom" : "universal"
}
],
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
3 changes: 2 additions & 1 deletion Documentation/Demo/Dithering/Views/Toolbar/ToolbarView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ struct ToolbarView: View {
)
}

private func didProcessVideo(withProgress progress: Float) {
private func didProcessVideo(withProgress progress: Float) -> Bool {
self.exportProgress = progress
return true
}

private func didFinishProcessingVideo(withResult result: Result<URL, Error>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ extension ToolbarView {
}
}

func ditherVideo(name: String, progressHandler: @escaping (Float) -> Void, completionHandler: @escaping (Result<URL, Error>) -> Void) {
func ditherVideo(name: String, progressHandler: @escaping (Float) -> Bool, completionHandler: @escaping (Result<URL, Error>) -> Void) {
let additionalPalleteSettings = additionalPaletteSelectionSetting
let additionalDitherMethodSetting = additionalDitherMethodSetting

Expand Down
Binary file modified Documentation/Resources/DitheringEngineLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 27 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Check out the [demo application](./Documentation/Demo/) for iOS and macOS.
* [Game Boy](#game-boy)
* [Creating your own palette](#creating-your-own-palette)
* [Video Dithering Engine](#video-dithering-engine)
* [Ordered dithering is more suitable](#ordered-dithering-is-more-suitable)
* [Video framerate](#video-framerate)
* [Concurrent frame processing](#concurrent-frame-processing)
* [Video Dither Options](#video-dither-options)
* [Video Description](#video-description)

## Installation
Expand All @@ -47,7 +51,7 @@ let package = Package(
dependencies: [
.package(
url: "https://github.com/Eskils/DitheringEngine",
.upToNextMinor(from: "1.6.3") // or `.upToNextMajor
.upToNextMinor(from: "1.7.0") // or `.upToNextMajor
)
],
targets: [
Expand Down Expand Up @@ -568,13 +572,31 @@ videoDitheringEngine.dither(
)
```

Some key takeaways:
- Using an ordered dither method is faster, and will give the best result as the pattern will not “move” (like static noise).
- By default, the final video has a framerate of 30. You may adjust the final framerate by providing a frame rate when initializing VideoDitheringEngine. The final frame rate is less than or equal to the specified value.:
### Ordered dithering is more suitable

Using an ordered dither method is faster, and will give the best result as the pattern will not “move” (like static noise).

### Video framerate

By default, the final video has a framerate of 30. You may adjust the final framerate by providing a frame rate when initializing VideoDitheringEngine. The final frame rate is less than or equal to the specified value.:
```swift
VideoDitheringEngine(frameRate: Int)
```

### Concurrent frame processing

By default, video frames are rendered concurrently. You can disable this behaviour, or change the number of frames processed simultaneously using the `numberOfConcurrentFrames` property.

Setting this to 1 will effectively disable concurrent frame processing. A higher number will be faster if the CPU has enough cores to handle the load, but will also use more memory.

### Video Dither Options

When dithering a video, you may provide options for how the video should be processed. The following options are available:

- `precalculateDitheredColorForAllColors`: Makes an indexed map of all colors to dithered color. This adds an increased wait time in the begining. Might be faster with large LUTCollections (e.g. CGA) and longer videos. Is ignored with LUT (e.g. Quantized Color) which is already index based.

- `removeAudio`: Does not transfer audio from the original video.

### Video Description

You set the video you want to use as input through the `VideoDescription` type. This is a convenient wrapper around `AVAsset` and lets you set the preferred output size.
Expand All @@ -587,6 +609,7 @@ You set the video you want to use as input through the `VideoDescription` type.
|------|------|---------|-------------|
| renderSize | CGSize? { get set } | nil | Specifies the size for which to render the final dithered video. |
| framerate | Float? { get } | nominalFrameRate | Returns the number of frames per second. Nil if the asset does not contain video. |
| transform| CGAffineTransform? { get } | preferredTransform | The transfor (orientation, scale) of the video.
| duration | TimeInterval { get } | duration.seconds | Returns the duration of the video. |
| sampleRate | Int? { get } | naturalTimeScale | Returns the number of audio samples per second. Nil if the asset does not contain audio. |
| size | CGSize? { get } | naturalSize | Returns the size of the video. Nil if the asset does not contain video. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Combine

public final class BayerSettingsConfiguration: SettingsConfiguration, OrderedDitheringThresholdConfiguration {

/// Exponent for size of threshold map m=2^n. mxm. Value between 1 and 6. Default value is 5.
/// Exponent for size of threshold map m=2^n. mxm. Value between 1 and 6. Default value is 4.
public let thresholdMapSize: CurrentValueSubject<Int, Never>

/// Determines wether to perform the computation on the CPU. If false, the GPU is used for quicker performance.
Expand All @@ -20,7 +20,7 @@ public final class BayerSettingsConfiguration: SettingsConfiguration, OrderedDit
return 2 << (exponent - 1)
}

public init(thresholdMapSize: Int = 5, performOnCPU: Bool = false) {
public init(thresholdMapSize: Int = 4, performOnCPU: Bool = false) {
self.thresholdMapSize = CurrentValueSubject(thresholdMapSize)
self.performOnCPU = CurrentValueSubject(performOnCPU)
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/DitheringEngine/Video/VideoAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class VideoAssembler {

private var framecount: Int = 0

init(outputURL: URL, width: Int, height: Int, framerate: Int, sampleRate: Int, emitFrames: Bool = false) throws {
init(outputURL: URL, width: Int, height: Int, framerate: Int, sampleRate: Int, transform: CGAffineTransform? = nil, emitFrames: Bool = false) throws {
self.width = width
self.height = height
self.framerate = framerate
Expand All @@ -48,6 +48,9 @@ class VideoAssembler {
] as [String : Any]

self.videoInput = AVAssetWriterInput(mediaType: .video, outputSettings: videoSettings)
if let transform {
videoInput.transform = transform
}
self.videoInputAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoInput, sourcePixelBufferAttributes: nil)

self.audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: audioSettings)
Expand Down
9 changes: 9 additions & 0 deletions Sources/DitheringEngine/Video/VideoDescription.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ public struct VideoDescription {
return videoTrack.nominalFrameRate
}

/// The transform applied to the video
public var transform: CGAffineTransform? {
guard let videoTrack = asset.tracks(withMediaType: .video).first else {
return nil
}

return videoTrack.preferredTransform
}

/// Returns the duration of the video.
public var duration: TimeInterval {
asset.duration.seconds
Expand Down
Loading

0 comments on commit e402ea8

Please sign in to comment.