stable-diffusion.cpp 一个文件解决stable-diffusion所有环境,不需要python,stable-diffusion.dll动态库C#调用Demo
目录
介绍
效果
Text To Image
Image To Image
Upscale
项目
代码
Native.cs
SDHelper.cs
MainForm.cs
下载
介绍
stable-diffusion.cpp 地址:https://github.com/leejet/stable-diffusion.cpp
StableDiffusionSharp 地址:https://github.com/IntptrMax/StableDiffusionSharp
测试模型下载地址:https://huggingface.co/runwayml/stable-diffusion-v1-5
放大模型下载地址:https://github.com/xinntao/Real-ESRGAN/releases/download/v0.2.2.4/RealESRGAN_x4plus_anime_6B.pth
效果
Text To Image
Image To Image
Upscale
项目
代码
Native.cs
using System;
using System.Runtime.InteropServices;
namespace StableDiffusionSharp
{
using static StableDiffusionSharp.Structs;
using int32_t = Int32;
using int64_t = Int64;
using SdContext = IntPtr;
using SDImagePtr = IntPtr;
using UpscalerContext = IntPtr;
internal class Native
{
const string DllName = "stable-diffusion";
internal delegate void SdLogCallback(SdLogLevel level, [MarshalAs(UnmanagedType.LPStr)] string text, IntPtr data);
internal delegate void SdProgressCallback(int step, int steps, float time, IntPtr data);
[DllImport(DllName, EntryPoint = "new_sd_ctx", CallingConvention = CallingConvention.Cdecl)]
internal extern static SdContext new_sd_ctx(string model_path,
string vae_path,
string taesd_path,
string control_net_path_c_str,
string lora_model_dir,
string embed_dir_c_str,
string stacked_id_embed_dir_c_str,
bool vae_decode_only,
bool vae_tiling,
bool free_params_immediately,
int n_threads,
WeightType weightType,
RngType rng_type,
ScheduleType s,
bool keep_clip_on_cpu,
bool keep_control_net_cpu,
bool keep_vae_on_cpu);
[DllImport(DllName, EntryPoint = "txt2img", CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImagePtr txt2img(SdContext sd_ctx,
string prompt,
string negative_prompt,
int clip_skip,
float cfg_scale,
int width,
int height,
SampleMethod sample_method,
int sample_steps,
int64_t seed,
int batch_count,
SDImagePtr control_cond,
float control_strength,
float style_strength,
bool normalize_input,
string input_id_images_path);
[DllImport(DllName, EntryPoint = "img2img", CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImagePtr img2img(SdContext sd_ctx,
SDImage init_image,
string prompt_c_str,
string negative_prompt_c_str,
int clip_skip,
float cfg_scale,
int width,
int height,
SampleMethod sample_method,
int sample_steps,
float strength,
int64_t seed,
int batch_count);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr preprocess_canny(IntPtr imgData,
int width,
int height,
float high_threshold,
float low_threshold,
float weak,
float strong,
bool inverse);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern UpscalerContext new_upscaler_ctx(string esrgan_path,
int n_threads,
WeightType wtype);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern int32_t get_num_physical_cores();
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void free_sd_ctx(SdContext sd_ctx);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void free_upscaler_ctx(UpscalerContext upscaler_ctx);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImage upscale(UpscalerContext upscaler_ctx, SDImage input_image, int upscale_factor);
[DllImport(DllName, EntryPoint = "sd_set_log_callback", CallingConvention = CallingConvention.Cdecl)]
internal static extern void sd_set_log_callback(SdLogCallback cb, IntPtr data);
[DllImport(DllName, EntryPoint = "sd_set_progress_callback", CallingConvention = CallingConvention.Cdecl)]
internal static extern void sd_set_progress_callback(SdProgressCallback cb, IntPtr data);
}
}
using System;
using System.Runtime.InteropServices;
namespace StableDiffusionSharp
{
using static StableDiffusionSharp.Structs;
using int32_t = Int32;
using int64_t = Int64;
using SdContext = IntPtr;
using SDImagePtr = IntPtr;
using UpscalerContext = IntPtr;
internal class Native
{
const string DllName = "stable-diffusion";
internal delegate void SdLogCallback(SdLogLevel level, [MarshalAs(UnmanagedType.LPStr)] string text, IntPtr data);
internal delegate void SdProgressCallback(int step, int steps, float time, IntPtr data);
[DllImport(DllName, EntryPoint = "new_sd_ctx", CallingConvention = CallingConvention.Cdecl)]
internal extern static SdContext new_sd_ctx(string model_path,
string vae_path,
string taesd_path,
string control_net_path_c_str,
string lora_model_dir,
string embed_dir_c_str,
string stacked_id_embed_dir_c_str,
bool vae_decode_only,
bool vae_tiling,
bool free_params_immediately,
int n_threads,
WeightType weightType,
RngType rng_type,
ScheduleType s,
bool keep_clip_on_cpu,
bool keep_control_net_cpu,
bool keep_vae_on_cpu);
[DllImport(DllName, EntryPoint = "txt2img", CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImagePtr txt2img(SdContext sd_ctx,
string prompt,
string negative_prompt,
int clip_skip,
float cfg_scale,
int width,
int height,
SampleMethod sample_method,
int sample_steps,
int64_t seed,
int batch_count,
SDImagePtr control_cond,
float control_strength,
float style_strength,
bool normalize_input,
string input_id_images_path);
[DllImport(DllName, EntryPoint = "img2img", CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImagePtr img2img(SdContext sd_ctx,
SDImage init_image,
string prompt_c_str,
string negative_prompt_c_str,
int clip_skip,
float cfg_scale,
int width,
int height,
SampleMethod sample_method,
int sample_steps,
float strength,
int64_t seed,
int batch_count);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr preprocess_canny(IntPtr imgData,
int width,
int height,
float high_threshold,
float low_threshold,
float weak,
float strong,
bool inverse);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern UpscalerContext new_upscaler_ctx(string esrgan_path,
int n_threads,
WeightType wtype);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern int32_t get_num_physical_cores();
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void free_sd_ctx(SdContext sd_ctx);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern void free_upscaler_ctx(UpscalerContext upscaler_ctx);
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
internal static extern SDImage upscale(UpscalerContext upscaler_ctx, SDImage input_image, int upscale_factor);
[DllImport(DllName, EntryPoint = "sd_set_log_callback", CallingConvention = CallingConvention.Cdecl)]
internal static extern void sd_set_log_callback(SdLogCallback cb, IntPtr data);
[DllImport(DllName, EntryPoint = "sd_set_progress_callback", CallingConvention = CallingConvention.Cdecl)]
internal static extern void sd_set_progress_callback(SdProgressCallback cb, IntPtr data);
}
}
SDHelper.cs
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace StableDiffusionSharp
{
using static StableDiffusionSharp.Structs;
using SdContext = IntPtr;
using SDImagePtr = IntPtr;
using UpscalerContext = IntPtr;
public class SDHelper
{
public bool IsInitialized => SdContext.Zero != sd_ctx;
public bool IsUpscalerInitialized => UpscalerContext.Zero != upscaler_ctx;
private SdContext sd_ctx = new SdContext();
private UpscalerContext upscaler_ctx = new UpscalerContext();
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionLogEventArgs> Log;
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionProgressEventArgs> Progress;
static readonly Native.SdLogCallback sd_Log_Cb;
static readonly Native.SdProgressCallback sd_Progress_Cb;
static SDHelper()
{
sd_Log_Cb = new Native.SdLogCallback(OnNativeLog);
Native.sd_set_log_callback(sd_Log_Cb, IntPtr.Zero);
sd_Progress_Cb = new Native.SdProgressCallback(OnProgressRunning);
Native.sd_set_progress_callback(sd_Progress_Cb, IntPtr.Zero);
}
public bool Initialize(ModelParams modelParams)
{
sd_ctx = Native.new_sd_ctx(modelParams.ModelPath,
modelParams.VaePath,
modelParams.TaesdPath,
modelParams.ControlnetPath,
modelParams.LoraModelDir,
modelParams.EmbeddingsPath,
modelParams.StackedIdEmbeddingsPath,
modelParams.VaeDecodeOnly,
modelParams.VaeTiling,
modelParams.FreeParamsImmediately,
modelParams.Threads,
modelParams.SdType,
modelParams.RngType,
modelParams.Schedule,
modelParams.KeepClipOnCpu,
modelParams.KeepControlNetOnCpu,
modelParams.KeepVaeOnCpu);
return SdContext.Zero != sd_ctx;
}
public bool InitializeUpscaler(UpscalerParams @params)
{
upscaler_ctx = Native.new_upscaler_ctx(@params.ESRGANPath, @params.Threads, @params.SdType);
return UpscalerContext.Zero != upscaler_ctx;
}
public void FreeSD()
{
if (SdContext.Zero != sd_ctx)
{
Native.free_sd_ctx(sd_ctx);
sd_ctx = SdContext.Zero;
}
}
public void FreeUpscaler()
{
if (UpscalerContext.Zero != upscaler_ctx)
{
Native.free_upscaler_ctx(upscaler_ctx);
upscaler_ctx = UpscalerContext.Zero;
}
}
public Bitmap[] TextToImage(TextToImageParams textToImageParams)
{
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
SDImagePtr sd_Image_ptr = Native.txt2img(sd_ctx,
textToImageParams.Prompt,
textToImageParams.NegativePrompt,
textToImageParams.ClipSkip,
textToImageParams.CfgScale,
textToImageParams.Width,
textToImageParams.Height,
textToImageParams.SampleMethod,
textToImageParams.SampleSteps,
textToImageParams.Seed,
textToImageParams.BatchCount,
SDImagePtr.Zero,
textToImageParams.ControlStrength,
textToImageParams.StyleStrength,
textToImageParams.NormalizeInput,
textToImageParams.InputIdImagesPath);
Bitmap[] images = new Bitmap[textToImageParams.BatchCount];
for (int i = 0; i < textToImageParams.BatchCount; i++)
{
SDImage sd_image = Marshal.PtrToStructure<SDImage>(sd_Image_ptr + i * Marshal.SizeOf<SDImage>());
images[i] = GetBitmapFromSdImage(sd_image);
}
return images;
}
public Bitmap ImageToImage(ImageToImageParams imageToImageParams)
{
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
SDImage input_sd_image = GetSDImageFromBitmap(imageToImageParams.InputImage);
SDImagePtr sdImgPtr = Native.img2img(sd_ctx,
input_sd_image,
imageToImageParams.Prompt,
imageToImageParams.NegativePrompt,
imageToImageParams.ClipSkip,
imageToImageParams.CfgScale,
imageToImageParams.Width,
imageToImageParams.Height,
imageToImageParams.SampleMethod,
imageToImageParams.SampleSteps,
imageToImageParams.Strength,
imageToImageParams.Seed,
imageToImageParams.BatchCount);
SDImage sdImg = Marshal.PtrToStructure<SDImage>(sdImgPtr);
return GetBitmapFromSdImage(sdImg);
}
public Bitmap UpscaleImage(Bitmap image, int upscaleFactor)
{
if (!IsUpscalerInitialized) throw new ArgumentNullException("Upscaler not loaded!");
SDImage inputSDImg = GetSDImageFromBitmap(image);
SDImage result = Native.upscale(upscaler_ctx, inputSDImg, upscaleFactor);
return GetBitmapFromSdImage(result);
}
private Bitmap GetBitmapFromSdImage(SDImage sd_Image)
{
int width = (int)sd_Image.Width;
int height = (int)sd_Image.Height;
int channel = (int)sd_Image.Channel;
byte[] bytes = new byte[width * height * channel];
Marshal.Copy(sd_Image.Data, bytes, 0, bytes.Length);
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
int stride = bmp.Width * channel;
byte[] des = new byte[bytes.Length];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
des[stride * i + channel * j + 0] = bytes[stride * i + channel * j + 2];
des[stride * i + channel * j + 1] = bytes[stride * i + channel * j + 1];
des[stride * i + channel * j + 2] = bytes[stride * i + channel * j + 0];
}
}
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(des, 0, bitmapData.Scan0, bytes.Length);
bmp.UnlockBits(bitmapData);
return bmp;
}
private SDImage GetSDImageFromBitmap(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
int channel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8;
int stride = width * channel;
byte[] bytes = new byte[width * height * channel];
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);
Marshal.Copy(bitmapData.Scan0, bytes, 0, bytes.Length);
bmp.UnlockBits(bitmapData);
byte[] sdImageBytes = new byte[bytes.Length];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
sdImageBytes[stride * i + j * 3 + 0] = bytes[stride * i + j * 3 + 2];
sdImageBytes[stride * i + j * 3 + 1] = bytes[stride * i + j * 3 + 1];
sdImageBytes[stride * i + j * 3 + 2] = bytes[stride * i + j * 3 + 0];
}
}
SDImage sd_Image = new SDImage
{
Width = (uint)width,
Height = (uint)height,
Channel = 3,
Data = Marshal.UnsafeAddrOfPinnedArrayElement(sdImageBytes, 0),
};
return sd_Image;
}
private static void OnNativeLog(SdLogLevel level, string text, IntPtr data)
{
Log?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionLogEventArgs { Level = level, Text = text });
}
private static void OnProgressRunning(int step, int steps, float time, IntPtr data)
{
Progress?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionProgressEventArgs { Step = step, Steps = steps, Time = time });
}
}
}
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
namespace StableDiffusionSharp
{
using static StableDiffusionSharp.Structs;
using SdContext = IntPtr;
using SDImagePtr = IntPtr;
using UpscalerContext = IntPtr;
public class SDHelper
{
public bool IsInitialized => SdContext.Zero != sd_ctx;
public bool IsUpscalerInitialized => UpscalerContext.Zero != upscaler_ctx;
private SdContext sd_ctx = new SdContext();
private UpscalerContext upscaler_ctx = new UpscalerContext();
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionLogEventArgs> Log;
public static event EventHandler<StableDiffusionEventArgs.StableDiffusionProgressEventArgs> Progress;
static readonly Native.SdLogCallback sd_Log_Cb;
static readonly Native.SdProgressCallback sd_Progress_Cb;
static SDHelper()
{
sd_Log_Cb = new Native.SdLogCallback(OnNativeLog);
Native.sd_set_log_callback(sd_Log_Cb, IntPtr.Zero);
sd_Progress_Cb = new Native.SdProgressCallback(OnProgressRunning);
Native.sd_set_progress_callback(sd_Progress_Cb, IntPtr.Zero);
}
public bool Initialize(ModelParams modelParams)
{
sd_ctx = Native.new_sd_ctx(modelParams.ModelPath,
modelParams.VaePath,
modelParams.TaesdPath,
modelParams.ControlnetPath,
modelParams.LoraModelDir,
modelParams.EmbeddingsPath,
modelParams.StackedIdEmbeddingsPath,
modelParams.VaeDecodeOnly,
modelParams.VaeTiling,
modelParams.FreeParamsImmediately,
modelParams.Threads,
modelParams.SdType,
modelParams.RngType,
modelParams.Schedule,
modelParams.KeepClipOnCpu,
modelParams.KeepControlNetOnCpu,
modelParams.KeepVaeOnCpu);
return SdContext.Zero != sd_ctx;
}
public bool InitializeUpscaler(UpscalerParams @params)
{
upscaler_ctx = Native.new_upscaler_ctx(@params.ESRGANPath, @params.Threads, @params.SdType);
return UpscalerContext.Zero != upscaler_ctx;
}
public void FreeSD()
{
if (SdContext.Zero != sd_ctx)
{
Native.free_sd_ctx(sd_ctx);
sd_ctx = SdContext.Zero;
}
}
public void FreeUpscaler()
{
if (UpscalerContext.Zero != upscaler_ctx)
{
Native.free_upscaler_ctx(upscaler_ctx);
upscaler_ctx = UpscalerContext.Zero;
}
}
public Bitmap[] TextToImage(TextToImageParams textToImageParams)
{
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
SDImagePtr sd_Image_ptr = Native.txt2img(sd_ctx,
textToImageParams.Prompt,
textToImageParams.NegativePrompt,
textToImageParams.ClipSkip,
textToImageParams.CfgScale,
textToImageParams.Width,
textToImageParams.Height,
textToImageParams.SampleMethod,
textToImageParams.SampleSteps,
textToImageParams.Seed,
textToImageParams.BatchCount,
SDImagePtr.Zero,
textToImageParams.ControlStrength,
textToImageParams.StyleStrength,
textToImageParams.NormalizeInput,
textToImageParams.InputIdImagesPath);
Bitmap[] images = new Bitmap[textToImageParams.BatchCount];
for (int i = 0; i < textToImageParams.BatchCount; i++)
{
SDImage sd_image = Marshal.PtrToStructure<SDImage>(sd_Image_ptr + i * Marshal.SizeOf<SDImage>());
images[i] = GetBitmapFromSdImage(sd_image);
}
return images;
}
public Bitmap ImageToImage(ImageToImageParams imageToImageParams)
{
if (!IsInitialized) throw new ArgumentNullException("Model not loaded!");
SDImage input_sd_image = GetSDImageFromBitmap(imageToImageParams.InputImage);
SDImagePtr sdImgPtr = Native.img2img(sd_ctx,
input_sd_image,
imageToImageParams.Prompt,
imageToImageParams.NegativePrompt,
imageToImageParams.ClipSkip,
imageToImageParams.CfgScale,
imageToImageParams.Width,
imageToImageParams.Height,
imageToImageParams.SampleMethod,
imageToImageParams.SampleSteps,
imageToImageParams.Strength,
imageToImageParams.Seed,
imageToImageParams.BatchCount);
SDImage sdImg = Marshal.PtrToStructure<SDImage>(sdImgPtr);
return GetBitmapFromSdImage(sdImg);
}
public Bitmap UpscaleImage(Bitmap image, int upscaleFactor)
{
if (!IsUpscalerInitialized) throw new ArgumentNullException("Upscaler not loaded!");
SDImage inputSDImg = GetSDImageFromBitmap(image);
SDImage result = Native.upscale(upscaler_ctx, inputSDImg, upscaleFactor);
return GetBitmapFromSdImage(result);
}
private Bitmap GetBitmapFromSdImage(SDImage sd_Image)
{
int width = (int)sd_Image.Width;
int height = (int)sd_Image.Height;
int channel = (int)sd_Image.Channel;
byte[] bytes = new byte[width * height * channel];
Marshal.Copy(sd_Image.Data, bytes, 0, bytes.Length);
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
int stride = bmp.Width * channel;
byte[] des = new byte[bytes.Length];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
des[stride * i + channel * j + 0] = bytes[stride * i + channel * j + 2];
des[stride * i + channel * j + 1] = bytes[stride * i + channel * j + 1];
des[stride * i + channel * j + 2] = bytes[stride * i + channel * j + 0];
}
}
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(des, 0, bitmapData.Scan0, bytes.Length);
bmp.UnlockBits(bitmapData);
return bmp;
}
private SDImage GetSDImageFromBitmap(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
int channel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8;
int stride = width * channel;
byte[] bytes = new byte[width * height * channel];
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bmp.PixelFormat);
Marshal.Copy(bitmapData.Scan0, bytes, 0, bytes.Length);
bmp.UnlockBits(bitmapData);
byte[] sdImageBytes = new byte[bytes.Length];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
sdImageBytes[stride * i + j * 3 + 0] = bytes[stride * i + j * 3 + 2];
sdImageBytes[stride * i + j * 3 + 1] = bytes[stride * i + j * 3 + 1];
sdImageBytes[stride * i + j * 3 + 2] = bytes[stride * i + j * 3 + 0];
}
}
SDImage sd_Image = new SDImage
{
Width = (uint)width,
Height = (uint)height,
Channel = 3,
Data = Marshal.UnsafeAddrOfPinnedArrayElement(sdImageBytes, 0),
};
return sd_Image;
}
private static void OnNativeLog(SdLogLevel level, string text, IntPtr data)
{
Log?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionLogEventArgs { Level = level, Text = text });
}
private static void OnProgressRunning(int step, int steps, float time, IntPtr data)
{
Progress?.Invoke(null, new StableDiffusionEventArgs.StableDiffusionProgressEventArgs { Step = step, Steps = steps, Time = time });
}
}
}
MainForm.cs
using StableDiffusionSharp;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StableDiffusionSharpGUI
{
public partial class MainForm : Form
{
private readonly SDHelper helper = new SDHelper();
public MainForm()
{
InitializeComponent();
}
private void Button_LoadModel_Click(object sender, EventArgs e)
{
if (Button_LoadModel.Text == "Load Model")
{
if (!helper.IsInitialized)
{
string modelPath = TextBox_ModelPath.Text;
string vaePath = TextBox_VaePath.Text;
string loraModelDir = TextBox_LoraModelDir.Text;
bool keepVaeOnCpu = CheckBox_CpuVae.Checked;
bool vaeTiling = CheckBox_VaeTiling.Checked;
if (!File.Exists(modelPath))
{
Button_LoadModel.Enabled = true;
MessageBox.Show("Cannot find the Model");
return;
}
Task.Run(() =>
{
Button_LoadModel.Invoke((Action)delegate
{
Button_LoadModel.Enabled = false;
TextBox_ModelPath.Enabled = false;
TextBox_VaePath.Enabled = false;
TextBox_LoraModelDir.Enabled = false;
CheckBox_CpuVae.Enabled = false;
CheckBox_VaeTiling.Enabled = false;
Button_ScanLoraPath.Enabled = false;
Button_ScanModelPath.Enabled = false;
Button_ScanVaePath.Enabled = false;
});
Structs.ModelParams modelParams = new Structs.ModelParams
{
ModelPath = modelPath,
VaePath = vaePath,
RngType = Structs.RngType.CUDA_RNG,
KeepVaeOnCpu = keepVaeOnCpu,
VaeTiling = vaeTiling,
LoraModelDir = loraModelDir,
};
bool result = helper.Initialize(modelParams);
Debug.WriteLine(result ? "Model loaded" : "Model not loaded");
Button_LoadModel.Invoke((Action)delegate
{
Button_LoadModel.Text = "Unload Model";
Button_LoadModel.Enabled = true;
});
});
}
}
else
{
helper.FreeSD();
Button_LoadModel.Text = "Load Model";
TextBox_ModelPath.Enabled = true;
TextBox_VaePath.Enabled = true;
TextBox_LoraModelDir.Enabled = true;
CheckBox_CpuVae.Enabled = true;
CheckBox_VaeTiling.Enabled = true;
Button_ScanLoraPath.Enabled = true;
Button_ScanModelPath.Enabled = true;
Button_ScanVaePath.Enabled = true;
}
}
private void Helper_Progress(object sender, StableDiffusionEventArgs.StableDiffusionProgressEventArgs e)
{
base.Invoke((Action)delegate
{
label11.Text = $"{e.Step}/{e.Steps}";
label14.Text = $"{e.IterationsPerSecond:f2} it/s";
ProgressBar_Progress.Value = (int)((e.Progress > 1 ? 1 : e.Progress) * 100);
});
}
private void Button_TextToImage_Click(object sender, EventArgs e)
{
if (!helper.IsInitialized)
{
MessageBox.Show("Please load Model first");
return;
}
Math.DivRem((int)NumericUpDown_Width.Value, 64, out int result1);
Math.DivRem((int)NumericUpDown_Height.Value, 64, out int result2);
if (result1 != 0 || result2 != 0)
{
MessageBox.Show("The width and height of the generated image must be a multiple of 64");
return;
}
Button_TextToImage.Enabled = false;
Button_ImageToImage.Enabled = false;
Structs.TextToImageParams textToImageParams = new Structs.TextToImageParams
{
Prompt = TextBox_Prompt.Text,
NegativePrompt = TextBox_NegativePrompt.Text,
SampleMethod = (Structs.SampleMethod)Enum.Parse(typeof(Structs.SampleMethod), ComboBox_SampleMethod.Text),
Width = (int)NumericUpDown_Width.Value,
Height = (int)NumericUpDown_Height.Value,
NormalizeInput = true,
ClipSkip = (int)NumericUpDown_ClipSkip.Value,
CfgScale = (float)NumericUpDown_CFG.Value,
SampleSteps = (int)NumericUpDown_SampleSteps.Value,
Seed = (long)NumericUpDown_Seed.Value,
};
Task.Run(() =>
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Restart();
Bitmap[] outputImages = helper.TextToImage(textToImageParams);
for (int i = 0; i < outputImages.Length; i++)
{
if (!Directory.Exists("output"))
{
Directory.CreateDirectory("output");
}
if (!Directory.Exists("./output/txt2img"))
{
Directory.CreateDirectory("./output/txt2img");
}
outputImages[i].Save($"./output/txt2img/{DateTime.Now:yyyyMMddHHmmss}-{i}.png");
}
base.Invoke((Action)delegate
{
PictureBox_OutputImage.Image = outputImages[0];
Button_TextToImage.Enabled = true;
Button_ImageToImage.Enabled = true;
});
Debug.WriteLine($"Time to elapsed: {stopwatch.ElapsedMilliseconds} ms");
});
}
private void MainForm_Load(object sender, EventArgs e)
{
SDHelper.Log += SDHelper_Log;
SDHelper.Progress += Helper_Progress;
ComboBox_SampleMethod.Items.AddRange(Enum.GetNames(typeof(Structs.SampleMethod)));
ComboBox_SampleMethod.SelectedIndex = 0;
PictureBox_InputImage.AllowDrop = true;
PictureBox_UpscaleInput.AllowDrop = true;
}
private void SDHelper_Log(object sender, StableDiffusionEventArgs.StableDiffusionLogEventArgs e)
{
Console.WriteLine($"time:{DateTime.Now}, {e.Level}: {e.Text}");
if (e.Text.Contains("vae compute"))
{
base.Invoke((Action)delegate { label12.Text = "VAE Progress"; });
}
else if (e.Text.Contains("generating image"))
{
base.Invoke((Action)delegate { label12.Text = "Generate Progress"; });
}
}
private void Button_ScanModelPath_Click(object sender, EventArgs e)
{
FileDialog fileDialog = new OpenFileDialog
{
Filter = "Safetensors Files (*.safetensors)|*.safetensors|CheckPoint Files (*.ckpt)|*.ckpt|GGUF Files (*.gguf)|*.gguf|All Files (*.*)|*.*"
};
if (fileDialog.ShowDialog() == DialogResult.OK)
{
TextBox_ModelPath.Text = fileDialog.FileName;
}
}
private void Button_ScanVaePath_Click(object sender, EventArgs e)
{
FileDialog fileDialog = new OpenFileDialog
{
Filter = "Safetensors Files (*.safetensors)|*.safetensors|CheckPoint Files (*.ckpt)|*.ckpt|GGUF Files (*.gguf)|*.gguf|All Files (*.*)|*.*"
};
if (fileDialog.ShowDialog() == DialogResult.OK)
{
TextBox_VaePath.Text = fileDialog.FileName;
}
}
private void Button_ScanLoraPath_Click(object sender, EventArgs e)
{
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
{
TextBox_LoraModelDir.Text = folderBrowserDialog.SelectedPath;
}
}
private void Button_ImageToImage_Click(object sender, EventArgs e)
{
if (!helper.IsInitialized)
{
MessageBox.Show("Please load a Model");
return;
}
if (null == PictureBox_InputImage.Image)
{
MessageBox.Show("Please select an Image");
return;
}
Bitmap inputBitmap = PictureBox_InputImage.Image.Clone() as Bitmap;
Math.DivRem(inputBitmap.Width, 64, out int result1);
Math.DivRem(inputBitmap.Height, 64, out int result2);
if (result1 != 0 || result2 != 0)
{
MessageBox.Show("The width and height of the generated image must be a multiple of 64");
return;
}
Button_TextToImage.Enabled = false;
Button_ImageToImage.Enabled = false;
Structs.ImageToImageParams imageToImageParams = new Structs.ImageToImageParams
{
InputImage = inputBitmap,
Prompt = TextBox_Prompt.Text,
NegativePrompt = TextBox_NegativePrompt.Text,
CfgScale = (float)NumericUpDown_CFG.Value,
Width = inputBitmap.Width,
Height = inputBitmap.Height,
SampleMethod = (Structs.SampleMethod)Enum.Parse(typeof(Structs.SampleMethod), ComboBox_SampleMethod.Text),
SampleSteps = (int)NumericUpDown_SampleSteps.Value,
Strength = (float)NumericUpDown_ReDrawStrength.Value,
Seed = (long)NumericUpDown_Seed.Value,
ClipSkip = (int)NumericUpDown_ClipSkip.Value,
};
Task.Run(() =>
{
Bitmap outputImage = helper.ImageToImage(imageToImageParams);
if (!Directory.Exists("output"))
{
Directory.CreateDirectory("output");
}
if (!Directory.Exists("./output/img2img"))
{
Directory.CreateDirectory("./output/img2img");
}
outputImage.Save($"./output/img2img/{DateTime.Now:yyyyMMddHHmmss}.png");
base.Invoke((Action)delegate
{
PictureBox_OutputImage.Image = outputImage;
Button_TextToImage.Enabled = true;
Button_ImageToImage.Enabled = true;
Button_TextToImage.Enabled = true;
});
});
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
helper.FreeSD();
helper.FreeUpscaler();
GC.Collect();
}
private void Button_RandomSeed_Click(object sender, EventArgs e)
{
Random random = new Random();
int randomPositiveInteger = random.Next(1, int.MaxValue);
NumericUpDown_Seed.Value = randomPositiveInteger;
}
private void PictureBox_InputImage_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Filter = "Image Files (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp"
};
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Bitmap bitmap = new Bitmap(openFileDialog.FileName);
PictureBox_InputImage.Image = bitmap;
}
}
private void PictureBox_InputImage_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Link;
else e.Effect = DragDropEffects.None;
}
private void PictureBox_InputImage_DragDrop(object sender, DragEventArgs e)
{
string fileName = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
Bitmap bitmap = new Bitmap(fileName);
PictureBox_InputImage.Image = bitmap;
}
private void Button_ScanUpscaleModelPath_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Filter = "ESRGAN Files (*.pth)|*.pth"
};
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
TextBox_UpscaleModelPath.Text = openFileDialog.FileName;
}
}
private void PictureBox_UpscaleInput_DragDrop(object sender, DragEventArgs e)
{
string fileName = ((Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
Bitmap bitmap = new Bitmap(fileName);
PictureBox_UpscaleInput.Image = bitmap;
}
private void PictureBox_UpscaleInput_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
e.Effect = DragDropEffects.Link;
else e.Effect = DragDropEffects.None;
}
private void Button_Upscale_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(TextBox_UpscaleModelPath.Text))
{
MessageBox.Show("Please select a upscale Model");
return;
}
bool upscalerInited = helper.InitializeUpscaler(new Structs.UpscalerParams
{
ESRGANPath = TextBox_UpscaleModelPath.Text,
});
if (!upscalerInited)
{
MessageBox.Show("There is an error in loading upscale Model");
return;
}
if (PictureBox_UpscaleInput.Image == null)
{
MessageBox.Show("Please select an Image");
return;
}
Bitmap upscaleInputImage = PictureBox_UpscaleInput.Image as Bitmap;
Button_Upscale.Enabled = false;
Task.Run(() =>
{
try
{
Button_Upscale.Enabled = false;
Bitmap bitmap = helper.UpscaleImage(PictureBox_UpscaleInput.Image as Bitmap, 4);
helper.FreeUpscaler();
if (!Directory.Exists("output"))
{
Directory.CreateDirectory("output");
}
if (!Directory.Exists("./output/upscale"))
{
Directory.CreateDirectory("./output/upscale");
}
bitmap.Save($"./output/upscale/{DateTime.Now:yyyyMMddHHmmss}.png");
base.Invoke((Action)delegate { PictureBox_UpscaleOutput.Image = bitmap; });
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
base.Invoke((Action)delegate { Button_Upscale.Enabled = true; });
helper.FreeUpscaler();
}
});
}
private void PictureBox_UpscaleInput_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog
{
Filter = "Image Files (*.png, *.jpg, *.bmp)|*.png;*.jpg;*.bmp"
};
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
Bitmap bitmap = new Bitmap(openFileDialog.FileName);
PictureBox_UpscaleInput.Image = bitmap;
}
}
}
}
下载
源码下载