Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 38 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Based on https://github.com/leejet/stable-diffusion.cpp
## Usage
### Setup
Install the [StableDiffusion.NET](https://www.nuget.org/packages/StableDiffusion.NET)-Nuget and at least one of the [Backend-Packages](https://www.nuget.org/packages?q=StableDiffusion.NET.Backend).
StableDiffusion.NET is using semantic versioning. Backend-packages are compatible as long as the version does only differ in the last digit.
If GPU-support is available it will prefer this over CPU.
If you want to add your own native-libraries or need more control over which backend to load, check the static `Backends` class.

Expand All @@ -17,37 +18,43 @@ If you want to add your own native-libraries or need more control over which bac

stable diffusion:
```csharp
using DiffusionModel model = ModelBuilder.StableDiffusion(@"<path to model")
.WithVae(@"<optional path to vae>")
.WithMultithreading()
.Build();
```

flux:
```csharp
using DiffusionModel model = ModelBuilder.Flux(@"<path to flux-model.gguf>",
@"<path to clip_l.safetensors>",
@"<path to t5xxl_fp16.safetensors>",
@"<path to ae.safetensors>")
.WithMultithreading()
.Build();
```

#### 2. create image

with default parameters:
```csharp
IImage<ColorRGB> image = model.TextToImage("<prompt>");
```

with custom parameters:
```csharp
IImage<ColorRGB> image = model.TextToImage("<prompt>", model.GetDefaultParameter().WithSeed(1234).WithSize(1344, 768));
```

#### 3. (optional) save the image (requires System.Dawing or SkiaSharp extension)
```csharp
File.WriteAllBytes("output.png", image.ToPng());
// Enable the Log- and Progress-events
StableDiffusionCpp.InitializeEvents();

// Register the Log and Progress-events to capture stable-diffusion.cpp output
StableDiffusionCpp.Log += (_, args) => Console.WriteLine($"LOG [{args.Level}]: {args.Text}");
StableDiffusionCpp.Progress += (_, args) => Console.WriteLine($"PROGRESS {args.Step} / {args.Steps} ({(args.Progress * 100):N2} %) {args.IterationsPerSecond:N2} it/s ({args.Time})");

Image<ColorRGB>? treeWithTiger;
// Load a StableDiffusion model in a using block to unload it again after the two images are created
using (DiffusionModel sd = ModelBuilder.StableDiffusion(@"<path to model")
// .WithVae(@"<optional path to vae>")
.WithMultithreading()
.WithFlashAttention()
.Build())
{
// Create a image from a prompt
Image<ColorRGB>? tree = sd.GenerateImage(ImageGenerationParameter.TextToImage("A beautiful tree standing on a small hill").WithSDXLDefaults());
// (optional) Save the image (requires the HPPH System.Dawing or SkiaSharp extension)
File.WriteAllBytes("image1.png", tree.ToPng());

// Use the previously created image for an image-to-image creation
treeWithTiger = sd.GenerateImage(ImageGenerationParameter.ImageToImage("A cute tiger in front of a tree on a small hill", tree).WithSDXLDefaults());
File.WriteAllBytes("image2.png", treeWithTiger.ToPng());
}

// Load a flux kontext model
using DiffusionModel flux = ModelBuilder.Flux(@"<path to flux-model.gguf>",
@"<path to clip_l.safetensors>",
@"<path to t5xxl_fp16.safetensors>",
@"<path to ae.safetensors>")
.WithMultithreading()
.WithFlashAttention()
.Build();

// Perform an edit on the previosly created image
Image<ColorRGB>? tigerOnMoon = flux.GenerateImage(ImageGenerationParameter.TextToImage("Remove the hill with the grass and place the tree with the tiger on the moon").WithFluxDefaults().WithRefImages(treeWithTiger));
File.WriteAllBytes("image3.png", tigerOnMoon.ToPng());
```

To process the resulting image further you can write your own extensions or install one of the [HPPH](https://github.com/DarthAffe/HPPH)-extension sets:
Expand Down
2 changes: 1 addition & 1 deletion StableDiffusion.NET/Backends/CudaBackend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public partial class CudaBackend : IBackend
public bool IsAvailable => (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|| RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
&& (RuntimeInformation.OSArchitecture == Architecture.X64)
&& CudaVersion is 11 or 12;
&& CudaVersion is 12;

public string PathPart => CudaVersion switch
{
Expand Down
8 changes: 0 additions & 8 deletions StableDiffusion.NET/Enums/DiffusionModelType.cs

This file was deleted.

106 changes: 57 additions & 49 deletions StableDiffusion.NET/Extensions/ParameterExtension.cs
Original file line number Diff line number Diff line change
@@ -1,92 +1,100 @@
#pragma warning disable CA2208

using JetBrains.Annotations;
using System;

namespace StableDiffusion.NET;

[PublicAPI]
public static class ParameterExtension
{
public static void Validate(this UpscaleModelParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentNullException.ThrowIfNull(parameter.ModelPath, nameof(UpscaleModelParameter.ModelPath));

if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(UpscaleModelParameter.Quantization));
}

public static void Validate(this DiffusionModelParameter parameter)
{
((IQuantizedModelParameter)parameter).Validate();
((IDiffusionModelParameter)parameter).Validate();
((IPhotomakerModelParameter)parameter).Validate();
}

public static void Validate(this IQuantizedModelParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.ThreadCount, nameof(IQuantizedModelParameter.ThreadCount));

if (!Enum.IsDefined(parameter.Quantization)) throw new ArgumentOutOfRangeException(nameof(IQuantizedModelParameter.Quantization));
}

public static void Validate(this IPhotomakerModelParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentNullException.ThrowIfNull(parameter.StackedIdEmbeddingsDirectory, nameof(IPhotomakerModelParameter.StackedIdEmbeddingsDirectory));
}

public static void Validate(this IDiffusionModelParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentNullException.ThrowIfNull(parameter.VaePath, nameof(IDiffusionModelParameter.VaePath));
ArgumentNullException.ThrowIfNull(parameter.TaesdPath, nameof(IDiffusionModelParameter.TaesdPath));
ArgumentNullException.ThrowIfNull(parameter.LoraModelDirectory, nameof(IDiffusionModelParameter.LoraModelDirectory));
ArgumentNullException.ThrowIfNull(parameter.ControlNetPath, nameof(IDiffusionModelParameter.ControlNetPath));
ArgumentNullException.ThrowIfNull(parameter.EmbeddingsDirectory, nameof(IDiffusionModelParameter.EmbeddingsDirectory));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.ThreadCount, nameof(DiffusionModelParameter.ThreadCount));
ArgumentNullException.ThrowIfNull(parameter.VaePath, nameof(DiffusionModelParameter.VaePath));
ArgumentNullException.ThrowIfNull(parameter.TaesdPath, nameof(DiffusionModelParameter.TaesdPath));
ArgumentNullException.ThrowIfNull(parameter.LoraModelDirectory, nameof(DiffusionModelParameter.LoraModelDirectory));
ArgumentNullException.ThrowIfNull(parameter.ControlNetPath, nameof(DiffusionModelParameter.ControlNetPath));
ArgumentNullException.ThrowIfNull(parameter.EmbeddingsDirectory, nameof(DiffusionModelParameter.EmbeddingsDirectory));
ArgumentNullException.ThrowIfNull(parameter.StackedIdEmbeddingsDirectory, nameof(DiffusionModelParameter.StackedIdEmbeddingsDirectory));

if (!string.IsNullOrWhiteSpace(parameter.VaePath) && !string.IsNullOrWhiteSpace(parameter.TaesdPath)) throw new ArgumentException("VAE and TAESD are mutually exclusive.");

if (!Enum.IsDefined(parameter.RngType)) throw new ArgumentOutOfRangeException(nameof(IDiffusionModelParameter.RngType));
if (!Enum.IsDefined(parameter.Schedule)) throw new ArgumentOutOfRangeException(nameof(IDiffusionModelParameter.Schedule));
if (!Enum.IsDefined(parameter.RngType)) throw new ArgumentOutOfRangeException(nameof(DiffusionModelParameter.RngType));
if (!Enum.IsDefined(parameter.Schedule)) throw new ArgumentOutOfRangeException(nameof(DiffusionModelParameter.Schedule));
}

public static void Validate(this DiffusionParameter parameter)
public static void Validate(this ImageGenerationParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentNullException.ThrowIfNull(parameter.ControlNet, nameof(DiffusionParameter.ControlNet));
ArgumentNullException.ThrowIfNull(parameter.PhotoMaker, nameof(DiffusionParameter.PhotoMaker));
ArgumentNullException.ThrowIfNull(parameter.NegativePrompt, nameof(DiffusionParameter.NegativePrompt));

ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Width, nameof(DiffusionParameter.Width));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Height, nameof(DiffusionParameter.Height));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.SampleSteps, nameof(DiffusionParameter.SampleSteps));
ArgumentNullException.ThrowIfNull(parameter.ControlNet, nameof(ImageGenerationParameter.ControlNet));
ArgumentNullException.ThrowIfNull(parameter.PhotoMaker, nameof(ImageGenerationParameter.PhotoMaker));
ArgumentNullException.ThrowIfNull(parameter.NegativePrompt, nameof(ImageGenerationParameter.NegativePrompt));

ArgumentOutOfRangeException.ThrowIfNegative(parameter.CfgScale, nameof(DiffusionParameter.CfgScale));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Guidance, nameof(DiffusionParameter.Guidance));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(DiffusionParameter.Strength));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Width, nameof(ImageGenerationParameter.Width));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.Height, nameof(ImageGenerationParameter.Height));
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(parameter.SampleSteps, nameof(ImageGenerationParameter.SampleSteps));

if (!Enum.IsDefined(parameter.SampleMethod)) throw new ArgumentOutOfRangeException(nameof(DiffusionParameter.SampleMethod));
if (!Enum.IsDefined(parameter.SampleMethod)) throw new ArgumentOutOfRangeException(nameof(ImageGenerationParameter.SampleMethod));

parameter.Guidance.Validate();
parameter.ControlNet.Validate();
parameter.PhotoMaker.Validate();
}

public static void Validate(this ControlNetParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(DiffusionParameter.ControlNet));
ArgumentNullException.ThrowIfNull(parameter, nameof(ImageGenerationParameter.ControlNet));

ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strength, nameof(ControlNetParameter.Strength));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyHighThreshold, nameof(ControlNetParameter.CannyHighThreshold));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyLowThreshold, nameof(ControlNetParameter.CannyLowThreshold));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyWeak, nameof(ControlNetParameter.CannyWeak));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.CannyStrong, nameof(ControlNetParameter.CannyStrong));
}

public static void Validate(this PhotoMakerParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(DiffusionParameter.PhotoMaker));
ArgumentNullException.ThrowIfNull(parameter, nameof(ImageGenerationParameter.PhotoMaker));
ArgumentNullException.ThrowIfNull(parameter.InputIdImageDirectory, nameof(PhotoMakerParameter.InputIdImageDirectory));

ArgumentOutOfRangeException.ThrowIfNegative(parameter.StyleRatio, nameof(PhotoMakerParameter.StyleRatio));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.StyleStrength, nameof(PhotoMakerParameter.StyleStrength));
}

public static void Validate(this GuidanceParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));

ArgumentOutOfRangeException.ThrowIfNegative(parameter.ImgCfg);
ArgumentOutOfRangeException.ThrowIfNegative(parameter.DistilledGuidance);
ArgumentOutOfRangeException.ThrowIfNegative(parameter.MinCfg);
ArgumentOutOfRangeException.ThrowIfNegative(parameter.TxtCfg);

parameter.Slg.Validate();
}

public static void Validate(this SlgParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));
ArgumentNullException.ThrowIfNull(parameter.Layers);

ArgumentOutOfRangeException.ThrowIfNegative(parameter.Scale);
ArgumentOutOfRangeException.ThrowIfNegative(parameter.SkipLayerStart);
ArgumentOutOfRangeException.ThrowIfNegative(parameter.SkipLayerEnd);
}

public static void Validate(this CannyParameter parameter)
{
ArgumentNullException.ThrowIfNull(parameter, nameof(parameter));

ArgumentNullException.ThrowIfNull(parameter.Image);

ArgumentOutOfRangeException.ThrowIfNegative(parameter.HighThreshold, nameof(CannyParameter.HighThreshold));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.LowThreshold, nameof(CannyParameter.LowThreshold));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Weak, nameof(CannyParameter.Weak));
ArgumentOutOfRangeException.ThrowIfNegative(parameter.Strong, nameof(CannyParameter.Strong));
}
}
Loading