当前位置:AIGC资讯 > AIGC > 正文

stable-diffusion.cpp 一个文件解决stable diffusion所有环境,不需要python,stable-diffusion.dll动态库C#调用Demo

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;
            }
        }
    }
}

下载 

源码下载

更新时间 2024-04-01