From e741cc14d18b2d2a360a82f78f17ef965f8aa6da Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Thu, 14 Dec 2023 21:48:14 +0100 Subject: [PATCH] Add project files. --- .gitignore | 255 ++++++++++++++++++ LICENSE | 21 ++ README.md | 16 ++ StableDiffusion.NET.sln | 25 ++ StableDiffusion.NET/Attributes/NativeName.cs | 20 ++ StableDiffusion.NET/Enums/LogLevel.cs | 16 ++ StableDiffusion.NET/Enums/Quantization.cs | 28 ++ StableDiffusion.NET/Enums/RngType.cs | 10 + StableDiffusion.NET/Enums/Sampler.cs | 31 +++ StableDiffusion.NET/Enums/Schedule.cs | 16 ++ .../Extensions/EnumExtension.cs | 17 ++ StableDiffusion.NET/Image.cs | 45 ++++ StableDiffusion.NET/ModelParameter.cs | 17 ++ StableDiffusion.NET/Native.cs | 98 +++++++ StableDiffusion.NET/Program.cs | 66 +++++ .../StableDiffusion.NET.csproj | 15 ++ .../StableDiffusion.NET.csproj.DotSettings | 4 + StableDiffusion.NET/StableDiffusion.cs | 66 +++++ .../StableDiffusionParameter.cs | 145 ++++++++++ build.bat | 26 ++ 20 files changed, 937 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 StableDiffusion.NET.sln create mode 100644 StableDiffusion.NET/Attributes/NativeName.cs create mode 100644 StableDiffusion.NET/Enums/LogLevel.cs create mode 100644 StableDiffusion.NET/Enums/Quantization.cs create mode 100644 StableDiffusion.NET/Enums/RngType.cs create mode 100644 StableDiffusion.NET/Enums/Sampler.cs create mode 100644 StableDiffusion.NET/Enums/Schedule.cs create mode 100644 StableDiffusion.NET/Extensions/EnumExtension.cs create mode 100644 StableDiffusion.NET/Image.cs create mode 100644 StableDiffusion.NET/ModelParameter.cs create mode 100644 StableDiffusion.NET/Native.cs create mode 100644 StableDiffusion.NET/Program.cs create mode 100644 StableDiffusion.NET/StableDiffusion.NET.csproj create mode 100644 StableDiffusion.NET/StableDiffusion.NET.csproj.DotSettings create mode 100644 StableDiffusion.NET/StableDiffusion.cs create mode 100644 StableDiffusion.NET/StableDiffusionParameter.cs create mode 100644 build.bat diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dc087d --- /dev/null +++ b/.gitignore @@ -0,0 +1,255 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# Documentation - till it's done +Documentation + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..56e1e5a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 leejet + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..2c634d6 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# StableDiffusion.NET + +Based on +https://github.com/seasonjs/stable-diffusion.cpp-build +https://github.com/leejet/stable-diffusion.cpp + +## Usage +### Setup +Run `build.bat` to build the native libs (modify params like CUDA-builds if needed) + +### Example +```csharp +using StableDiffusionModel sd = new(@"", new ModelParameter()); +using StableDiffusionParameter parameter = new StableDiffusionParameter(); +using Image image = sd.TextToImage("", parameter); +``` \ No newline at end of file diff --git a/StableDiffusion.NET.sln b/StableDiffusion.NET.sln new file mode 100644 index 0000000..60d61a6 --- /dev/null +++ b/StableDiffusion.NET.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34322.80 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StableDiffusion.NET", "StableDiffusion.NET\StableDiffusion.NET.csproj", "{ED9336F9-7C5F-47DD-A120-272F4835E95F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED9336F9-7C5F-47DD-A120-272F4835E95F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ED9336F9-7C5F-47DD-A120-272F4835E95F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ED9336F9-7C5F-47DD-A120-272F4835E95F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ED9336F9-7C5F-47DD-A120-272F4835E95F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8DD53974-8766-4659-97B6-4AEDF4323F65} + EndGlobalSection +EndGlobal diff --git a/StableDiffusion.NET/Attributes/NativeName.cs b/StableDiffusion.NET/Attributes/NativeName.cs new file mode 100644 index 0000000..86dcb33 --- /dev/null +++ b/StableDiffusion.NET/Attributes/NativeName.cs @@ -0,0 +1,20 @@ +namespace StableDiffusion.NET; + +[AttributeUsage(AttributeTargets.Field)] +internal class NativeName : Attribute +{ + #region Properties & Fields + + public string Name { get; set; } + + #endregion + + #region Constructors + + public NativeName(string name) + { + this.Name = name; + } + + #endregion +} \ No newline at end of file diff --git a/StableDiffusion.NET/Enums/LogLevel.cs b/StableDiffusion.NET/Enums/LogLevel.cs new file mode 100644 index 0000000..d126512 --- /dev/null +++ b/StableDiffusion.NET/Enums/LogLevel.cs @@ -0,0 +1,16 @@ +namespace StableDiffusion.NET; + +public enum LogLevel +{ + [NativeName("DEBUG")] + Debug, + + [NativeName("INFO")] + Info, + + [NativeName("WARN")] + Warn, + + [NativeName("ERROR")] + Error +} \ No newline at end of file diff --git a/StableDiffusion.NET/Enums/Quantization.cs b/StableDiffusion.NET/Enums/Quantization.cs new file mode 100644 index 0000000..1a6b02f --- /dev/null +++ b/StableDiffusion.NET/Enums/Quantization.cs @@ -0,0 +1,28 @@ +namespace StableDiffusion.NET; + +public enum Quantization +{ + [NativeName("DEFAULT")] + Default, + + [NativeName("F32")] + F32, + + [NativeName("F16")] + F16, + + [NativeName("Q4_0")] + Q4_0, + + [NativeName("Q4_1")] + Q4_1, + + [NativeName("Q5_0")] + Q5_0, + + [NativeName("Q5_1")] + Q5_1, + + [NativeName("Q8_0")] + Q8_0 +} \ No newline at end of file diff --git a/StableDiffusion.NET/Enums/RngType.cs b/StableDiffusion.NET/Enums/RngType.cs new file mode 100644 index 0000000..e8c8381 --- /dev/null +++ b/StableDiffusion.NET/Enums/RngType.cs @@ -0,0 +1,10 @@ +namespace StableDiffusion.NET; + +public enum RngType +{ + [NativeName("STD_DEFAULT_RNG")] + Standard, + + [NativeName("CUDA_RNG")] + Cuda +} \ No newline at end of file diff --git a/StableDiffusion.NET/Enums/Sampler.cs b/StableDiffusion.NET/Enums/Sampler.cs new file mode 100644 index 0000000..d1ccc45 --- /dev/null +++ b/StableDiffusion.NET/Enums/Sampler.cs @@ -0,0 +1,31 @@ +namespace StableDiffusion.NET; + +public enum Sampler +{ + [NativeName("EULER_A")] + Euler_A, + + [NativeName("EULER")] + Euler, + + [NativeName("HEUN")] + Heun, + + [NativeName("DPM2")] + DPM2, + + [NativeName("DPMPP2S_A")] + DPMPP2SA, + + [NativeName("DPMPP2M")] + DPMPP2M, + + [NativeName("DPMPP2Mv2")] + DPMPP2Mv2, + + [NativeName("LCM")] + LCM, + + [NativeName("N_SAMPLE_METHODS")] + N_Sample_Methods +} \ No newline at end of file diff --git a/StableDiffusion.NET/Enums/Schedule.cs b/StableDiffusion.NET/Enums/Schedule.cs new file mode 100644 index 0000000..a6ea523 --- /dev/null +++ b/StableDiffusion.NET/Enums/Schedule.cs @@ -0,0 +1,16 @@ +namespace StableDiffusion.NET; + +public enum Schedule +{ + [NativeName("DEFAULT")] + Default, + + [NativeName("DISCRETE")] + Discrete, + + [NativeName("KARRAS")] + Karras, + + [NativeName("N_SCHEDULES")] + N_Schedules +} \ No newline at end of file diff --git a/StableDiffusion.NET/Extensions/EnumExtension.cs b/StableDiffusion.NET/Extensions/EnumExtension.cs new file mode 100644 index 0000000..11aaa83 --- /dev/null +++ b/StableDiffusion.NET/Extensions/EnumExtension.cs @@ -0,0 +1,17 @@ +using System.Reflection; + +namespace StableDiffusion.NET; + +internal static class EnumExtension +{ + #region Methods + + public static string? GetNativeName(this Enum value) + { + FieldInfo? fieldInfo = value.GetType().GetField(value.ToString()); + NativeName? nativeName = fieldInfo?.GetCustomAttribute(); + return nativeName?.Name; + } + + #endregion +} \ No newline at end of file diff --git a/StableDiffusion.NET/Image.cs b/StableDiffusion.NET/Image.cs new file mode 100644 index 0000000..b35d187 --- /dev/null +++ b/StableDiffusion.NET/Image.cs @@ -0,0 +1,45 @@ +namespace StableDiffusion.NET; + +public sealed unsafe class Image : IDisposable +{ + #region Constants + + public const int BPP = 3; + + #endregion + + #region Properties & Fields + + private readonly byte* _imagePtr; + + public int Width { get; } + public int Height { get; } + + public ReadOnlySpan Data => new(_imagePtr, Width * Height * BPP); + + #endregion + + #region Constructors + + internal Image(byte* ptr, int width, int height) + { + this._imagePtr = ptr; + this.Width = width; + this.Height = height; + } + + ~Image() => Dispose(); + + #endregion + + #region Methods + + public void Dispose() + { + Native.stable_diffusion_free_buffer(_imagePtr); + + GC.SuppressFinalize(this); + } + + #endregion +} \ No newline at end of file diff --git a/StableDiffusion.NET/ModelParameter.cs b/StableDiffusion.NET/ModelParameter.cs new file mode 100644 index 0000000..280903d --- /dev/null +++ b/StableDiffusion.NET/ModelParameter.cs @@ -0,0 +1,17 @@ +namespace StableDiffusion.NET; + +public class ModelParameter +{ + #region Properties & Fields + + public int ThreadCount { get; set; } = 8; + public bool VaeDecodeOnly { get; set; } = false; + public string TaesdPath { get; set; } = string.Empty; + public string LoraModelDir { get; set; } = string.Empty; + public RngType RngType { get; set; } = RngType.Standard; + public string VaePath { get; set; } = string.Empty; + public Quantization Quantization { get; set; } = Quantization.Default; + public Schedule Schedule { get; set; } = Schedule.Default; + + #endregion +} diff --git a/StableDiffusion.NET/Native.cs b/StableDiffusion.NET/Native.cs new file mode 100644 index 0000000..a008fa5 --- /dev/null +++ b/StableDiffusion.NET/Native.cs @@ -0,0 +1,98 @@ +#pragma warning disable CS0169 // Field is never used +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type +#pragma warning disable IDE1006 +#pragma warning disable IDE0051 +#pragma warning disable IDE0044 +// ReSharper disable InconsistentNaming +// ReSharper disable ArrangeTypeMemberModifiers + +using System.Runtime.InteropServices; + +namespace StableDiffusion.NET; + +internal unsafe partial class Native +{ + #region Constants + + private const string LIB_NAME = "sd-abi.dll"; + + #endregion + + #region DLL-Import + + internal struct stable_diffusion_ctx; + + internal struct stable_diffusion_full_params + { + string negative_prompt; + float cfg_scale; + int width; + int height; + int sample_method; + int sample_steps; + long seed; + int batch_count; + float strength; + } + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_default_params_ref")] + internal static partial stable_diffusion_full_params* stable_diffusion_full_default_params_ref(); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_negative_prompt")] + internal static partial void stable_diffusion_full_params_set_negative_prompt(stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string negative_prompt); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_cfg_scale")] + internal static partial void stable_diffusion_full_params_set_cfg_scale(stable_diffusion_full_params* @params, float cfg_scale); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_width")] + internal static partial void stable_diffusion_full_params_set_width(stable_diffusion_full_params* @params, int width); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_height")] + internal static partial void stable_diffusion_full_params_set_height(stable_diffusion_full_params* @params, int height); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_sample_method")] + internal static partial void stable_diffusion_full_params_set_sample_method(stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string sample_method); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_sample_steps")] + internal static partial void stable_diffusion_full_params_set_sample_steps(stable_diffusion_full_params* @params, int sample_steps); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_seed")] + internal static partial void stable_diffusion_full_params_set_seed(stable_diffusion_full_params* @params, long seed); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_batch_count")] + internal static partial void stable_diffusion_full_params_set_batch_count(stable_diffusion_full_params* @params, int batch_count); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_full_params_set_strength")] + internal static partial void stable_diffusion_full_params_set_strength(stable_diffusion_full_params* @params, float strength); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_init")] + internal static partial stable_diffusion_ctx* stable_diffusion_init(int n_threads, [MarshalAs(UnmanagedType.I1)] bool vae_decode_only, [MarshalAs(UnmanagedType.LPStr)] string taesd_path, [MarshalAs(UnmanagedType.I1)] bool free_params_immediately, [MarshalAs(UnmanagedType.LPStr)] string lora_model_dir, [MarshalAs(UnmanagedType.LPStr)] string rng_type); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_load_from_file")] + [return: MarshalAs(UnmanagedType.I1)] + internal static partial bool stable_diffusion_load_from_file(stable_diffusion_ctx* ctx, [MarshalAs(UnmanagedType.LPStr)] string file_path, [MarshalAs(UnmanagedType.LPStr)] string vae_path, [MarshalAs(UnmanagedType.LPStr)] string wtype, [MarshalAs(UnmanagedType.LPStr)] string schedule); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_predict_image")] + internal static partial byte* stable_diffusion_predict_image(stable_diffusion_ctx* ctx, stable_diffusion_full_params* @params, [MarshalAs(UnmanagedType.LPStr)] string prompt); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_image_predict_image")] + internal static partial byte* stable_diffusion_image_predict_image(stable_diffusion_ctx* ctx, stable_diffusion_full_params* @params, byte* init_image, [MarshalAs(UnmanagedType.LPStr)] string prompt); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_set_log_level")] + internal static partial void stable_diffusion_set_log_level([MarshalAs(UnmanagedType.LPStr)] string level); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_get_system_info")] + [return: MarshalAs(UnmanagedType.LPStr)] + internal static partial string stable_diffusion_get_system_info(); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free")] + internal static partial void stable_diffusion_free(stable_diffusion_ctx* ctx); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free_full_params")] + internal static partial void stable_diffusion_free_full_params(stable_diffusion_full_params* @params); + + [LibraryImport(LIB_NAME, EntryPoint = "stable_diffusion_free_buffer")] + internal static partial void stable_diffusion_free_buffer(byte* buffer); + + #endregion +} \ No newline at end of file diff --git a/StableDiffusion.NET/Program.cs b/StableDiffusion.NET/Program.cs new file mode 100644 index 0000000..7ee7ba0 --- /dev/null +++ b/StableDiffusion.NET/Program.cs @@ -0,0 +1,66 @@ +using System.Drawing; +using System.Drawing.Imaging; +using StableDiffusion.NET; +using Image = StableDiffusion.NET.Image; + +using StableDiffusionModel sd = new(@"N:\StableDiffusion\stable-diffusion-webui\models\Stable-diffusion\ghostmix_v20Bakedvae.safetensors", + new ModelParameter + { + Quantization = Quantization.Q5_1, + Schedule = Schedule.Karras + }); + +using StableDiffusionParameter parameter = new StableDiffusionParameter { SampleMethod = Sampler.DPMPP2M }; +parameter.Width = 768; + +using Image image = sd.TextToImage("der ohne gesicht wo im aquarium schwimmt", parameter); +using Bitmap bitmap = ToBitmap2(image); +bitmap.Save("test.jpg"); + + +//unsafe +//{ +// Console.WriteLine(Native.stable_diffusion_get_system_info()); + +// Native.stable_diffusion_set_log_level("DEBUG"); + +// Native.stable_diffusion_ctx* ctx = Native.stable_diffusion_init(16, false, string.Empty, false, string.Empty, "STD_DEFAULT_RNG"); + +// Native.stable_diffusion_load_from_file(ctx, @"N:\StableDiffusion\stable-diffusion-webui\models\Stable-diffusion\ghostmix_v20Bakedvae.safetensors", string.Empty, "Q5_1", "KARRAS"); + +// Native.stable_diffusion_full_params* @params = Native.stable_diffusion_full_default_params_ref(); + +// Native.stable_diffusion_full_params_set_cfg_scale(@params, 7.5f); +// Native.stable_diffusion_full_params_set_width(@params, 512); +// Native.stable_diffusion_full_params_set_height(@params, 512); +// Native.stable_diffusion_full_params_set_batch_count(@params, 1); +// Native.stable_diffusion_full_params_set_sample_steps(@params, 30); +// Native.stable_diffusion_full_params_set_sample_method(@params, "DPMPP2M"); + +// byte* result = Native.stable_diffusion_predict_image(ctx, @params, "a wizard in a purple t-shirt casting a spell that causes a mountain to explode"); + +// Span image = new(result, 512 * 512 * 3); + +// using Bitmap bitmap = ToBitmap(image, 512, 512); +// bitmap.Save("test.jpg"); + +// Native.stable_diffusion_free_buffer(result); +// Native.stable_diffusion_free_full_params(@params); +// Native.stable_diffusion_free(ctx); +//} + + +static Bitmap ToBitmap2(Image image) => ToBitmap(image.Data, image.Width, image.Height); + +static unsafe Bitmap ToBitmap(ReadOnlySpan image, int width, int height) +{ + Bitmap output = new(width, height, PixelFormat.Format24bppRgb); + Rectangle rect = new(0, 0, width, height); + BitmapData bmpData = output.LockBits(rect, ImageLockMode.ReadWrite, output.PixelFormat); + + nint ptr = bmpData.Scan0; + image.CopyTo(new Span((void*)ptr, width * height * 3)); + + output.UnlockBits(bmpData); + return output; +} \ No newline at end of file diff --git a/StableDiffusion.NET/StableDiffusion.NET.csproj b/StableDiffusion.NET/StableDiffusion.NET.csproj new file mode 100644 index 0000000..57a741d --- /dev/null +++ b/StableDiffusion.NET/StableDiffusion.NET.csproj @@ -0,0 +1,15 @@ + + + + Exe + net8.0 + enable + enable + true + + + + + + + diff --git a/StableDiffusion.NET/StableDiffusion.NET.csproj.DotSettings b/StableDiffusion.NET/StableDiffusion.NET.csproj.DotSettings new file mode 100644 index 0000000..ba0522c --- /dev/null +++ b/StableDiffusion.NET/StableDiffusion.NET.csproj.DotSettings @@ -0,0 +1,4 @@ + + True + True + True \ No newline at end of file diff --git a/StableDiffusion.NET/StableDiffusion.cs b/StableDiffusion.NET/StableDiffusion.cs new file mode 100644 index 0000000..16b0f32 --- /dev/null +++ b/StableDiffusion.NET/StableDiffusion.cs @@ -0,0 +1,66 @@ +namespace StableDiffusion.NET; + +public sealed unsafe class StableDiffusionModel : IDisposable +{ + #region Properties & Fields + + private readonly string _modelPath; + private readonly ModelParameter _parameter; + + private Native.stable_diffusion_ctx* _ctx; + + #endregion + + #region Constructors + + public StableDiffusionModel(string modelPath, ModelParameter parameter) + { + this._modelPath = modelPath; + this._parameter = parameter; + + Initialize(); + } + + ~StableDiffusionModel() => Dispose(); + + #endregion + + #region Methods + + private void Initialize() + { + _ctx = Native.stable_diffusion_init(_parameter.ThreadCount, _parameter.VaeDecodeOnly, _parameter.TaesdPath, false, _parameter.LoraModelDir, _parameter.RngType.GetNativeName() ?? "STD_DEFAULT_RNG"); + if (_ctx == null) throw new NullReferenceException("Failed to initialize Stable Diffusion"); + + bool success = Native.stable_diffusion_load_from_file(_ctx, _modelPath, _parameter.VaePath, _parameter.Quantization.GetNativeName() ?? "DEFAULT", _parameter.Schedule.GetNativeName() ?? "DEFAULT"); + if (!success) throw new IOException("Failed to load model"); + } + + public Image TextToImage(string prompt, StableDiffusionParameter parameter) + { + byte* result = Native.stable_diffusion_predict_image(_ctx, parameter.ParamPtr, prompt); + return new Image(result, parameter.Width, parameter.Height); + } + + public Image ImageToImage(string prompt, Span image, StableDiffusionParameter parameter) + { + fixed (byte* imagePtr = image) + { + byte* result = Native.stable_diffusion_image_predict_image(_ctx, parameter.ParamPtr, imagePtr, prompt); + return new Image(result, parameter.Width, parameter.Height); + } + } + + public void Dispose() + { + Native.stable_diffusion_free(_ctx); + + GC.SuppressFinalize(this); + } + + public static string GetSystemInfo() => Native.stable_diffusion_get_system_info(); + + public static void SetLogLevel(LogLevel level) => Native.stable_diffusion_set_log_level(level.GetNativeName() ?? "ERROR"); + + #endregion +} diff --git a/StableDiffusion.NET/StableDiffusionParameter.cs b/StableDiffusion.NET/StableDiffusionParameter.cs new file mode 100644 index 0000000..8ce78f8 --- /dev/null +++ b/StableDiffusion.NET/StableDiffusionParameter.cs @@ -0,0 +1,145 @@ +namespace StableDiffusion.NET; + +public sealed unsafe class StableDiffusionParameter : IDisposable +{ + #region Properties & Fields + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + internal readonly Native.stable_diffusion_full_params* ParamPtr; +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + + private string _negativePrompt; + public string NegativePrompt + { + get => _negativePrompt; + set + { + _negativePrompt = value; + Native.stable_diffusion_full_params_set_negative_prompt(ParamPtr, _negativePrompt); + } + } + + private float _cfgScale; + public float CfgScale + { + get => _cfgScale; + set + { + _cfgScale = value; + Native.stable_diffusion_full_params_set_cfg_scale(ParamPtr, _cfgScale); + } + } + + private int _width; + public int Width + { + get => _width; + set + { + _width = value; + Native.stable_diffusion_full_params_set_width(ParamPtr, _width); + } + } + + private int _height; + public int Height + { + get => _height; + set + { + _height = value; + Native.stable_diffusion_full_params_set_height(ParamPtr, _height); + } + } + + private Sampler _sampleMethod; + public Sampler SampleMethod + { + get => _sampleMethod; + set + { + _sampleMethod = value; + Native.stable_diffusion_full_params_set_sample_method(ParamPtr, _sampleMethod.GetNativeName() ?? "EULER_A"); + } + } + + private int _sampleSteps; + public int SampleSteps + { + get => _sampleSteps; + set + { + _sampleSteps = value; + Native.stable_diffusion_full_params_set_sample_steps(ParamPtr, _sampleSteps); + } + } + + private long _seed; + public long Seed + { + get => _seed; + set + { + _seed = value; + Native.stable_diffusion_full_params_set_seed(ParamPtr, _seed); + } + } + + private int _batchCount; + public int BatchCount + { + get => _batchCount; + set + { + _batchCount = value; + Native.stable_diffusion_full_params_set_batch_count(ParamPtr, _batchCount); + } + } + + private float _strength; + public float Strength + { + get => _strength; + set + { + _strength = value; + Native.stable_diffusion_full_params_set_strength(ParamPtr, _strength); + } + } + + #endregion + + #region Constructors + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + public StableDiffusionParameter() + { + ParamPtr = Native.stable_diffusion_full_default_params_ref(); + + NegativePrompt = string.Empty; + CfgScale = 7.5f; + Width = 512; + Height = 512; + SampleMethod = Sampler.Euler_A; + SampleSteps = 25; + Seed = -1; + BatchCount = 1; + Strength = 0.7f; + } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + + ~StableDiffusionParameter() => Dispose(); + + #endregion + + #region Methods + + public void Dispose() + { + Native.stable_diffusion_free_full_params(ParamPtr); + + GC.SuppressFinalize(this); + } + + #endregion +} \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..3aaaa6a --- /dev/null +++ b/build.bat @@ -0,0 +1,26 @@ +if not exist stable-diffusion.cpp-build ( + git clone https://github.com/seasonjs/stable-diffusion.cpp-build +) + +cd stable-diffusion.cpp-build +git checkout 4b95d98404bbfe91698fd41b0f514656e358163a + +if not exist build ( + mkdir build +) + +cd build + +rem remove -DSD_CUBLAS=ON to disable cuda support +cmake .. -DCMAKE_BUILD_TYPE=Release -DSD_CUBLAS=ON +cmake --build . --config Release + +cd ..\.. + +dotnet publish -c Release -o bin + +copy .\stable-diffusion.cpp-build\build\bin\Release\sd-abi.dll .\StableDiffusion.NET\bin\Debug\net8.0\sd-abi.dll +copy .\stable-diffusion.cpp-build\build\bin\Release\sd-abi.dll .\StableDiffusion.NET\bin\Debug\net8.0\sd-abi.dll +copy .\stable-diffusion.cpp-build\build\bin\Release\sd-abi.dll .\StableDiffusion.NET\bin\Debug\net8.0\sd-abi.dll + +pause \ No newline at end of file