diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..cc0d143
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.sh text eof=lf
diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml
new file mode 100644
index 0000000..f213893
--- /dev/null
+++ b/.gitea/workflows/build.yaml
@@ -0,0 +1,25 @@
+name: Build
+run-name: Building docker container.
+on:
+ workflow_dispatch:
+ push:
+ branches: stable
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ container:
+ image: git.mixedup.dev/quik/docker-cross-compiler
+ env:
+ QUIK_API_KEY: "${{secrets.QUIK_API_KEY}}"
+ volumes:
+ - ${{ gitea.workspace }}:/home/quik/src
+ steps:
+ - name: Check repository out.
+ uses: actions/checkout@v3
+ with:
+ submodules: recursive
+ - name: Run Build Script
+ run: "./build_native.sh"
+ - name: Publish Package
+ run: "./publish.sh"
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c27cc2c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+**/bin
+**/obj
+**/out
+**/runtimes
+**/.vs*
+**/.atom
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..a4c74ed
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(quik_stbi LANGUAGES C VERSION 1.0)
+
+add_compile_options(-static-libgcc)
+
+add_library(stbi SHARED "quik_stbi.c")
+install(
+ TARGETS stbi
+ RUNTIME DESTINATION .
+ LIBRARY DESTINATION .)
diff --git a/NativeTypeNameAttribute.cs b/NativeTypeNameAttribute.cs
new file mode 100644
index 0000000..becb962
--- /dev/null
+++ b/NativeTypeNameAttribute.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Quik.Stb.Image
+{
+ [AttributeUsage(System.AttributeTargets.All, Inherited = false, AllowMultiple = true)]
+ internal sealed class NativeTypeNameAttribute : System.Attribute
+ {
+ public NativeTypeNameAttribute(string typename)
+ {
+ }
+ }
+}
diff --git a/Quik.Common b/Quik.Common
index 11bb72a..d9c98b5 160000
--- a/Quik.Common
+++ b/Quik.Common
@@ -1 +1 @@
-Subproject commit 11bb72a464215693d5a3a6896b25e568cc6e3313
+Subproject commit d9c98b5cdc37b2ba1855c8fa9ce0fac8266b0f89
diff --git a/Quik.StbImage.csproj b/Quik.StbImage.csproj
new file mode 100644
index 0000000..c8f983f
--- /dev/null
+++ b/Quik.StbImage.csproj
@@ -0,0 +1,61 @@
+
+
+
+ net6.0
+ disable
+ 7.3
+ True
+ linux-arm;linux-arm64;linux-x64;win-x86;win-x64
+
+
+
+
+ True
+ Quik.StbImage
+ 1.0.0
+ STBI Authors, H. Utku Maden
+
+ A C# wrapper for the ubiquitous Stb Image library.
+
+
+
+
+
+
+ runtimes/linux-arm/native/
+ true
+ PreserveNewest
+
+
+ runtimes/linux-arm64/native/
+ true
+ PreserveNewest/
+
+
+ runtimes/linux-x64/native/
+ true
+ PreserveNewest
+
+
+ runtimes/linux-x86/native/
+ true
+ PreserveNewest
+
+
+ runtimes/win-x64/native/
+ true
+ PreserveNewest
+
+
+ runtimes/win-x86/native/
+ true
+ PreserveNewest
+
+
+
+
diff --git a/Quik.StbImage.sln b/Quik.StbImage.sln
new file mode 100644
index 0000000..6b44dac
--- /dev/null
+++ b/Quik.StbImage.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.002.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Quik.StbImage", "Quik.StbImage.csproj", "{C808B4BC-C3AF-4682-8EDA-EAAC780800C3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C808B4BC-C3AF-4682-8EDA-EAAC780800C3}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B04E5FBA-41E6-4B0B-BC31-F996BE353F5A}
+ EndGlobalSection
+EndGlobal
diff --git a/StbImage.cs b/StbImage.cs
new file mode 100644
index 0000000..e2af68f
--- /dev/null
+++ b/StbImage.cs
@@ -0,0 +1,144 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Quik.Stb
+{
+ ///
+ /// A class that encompasses all features of stb_image.h in a safe way.
+ ///
+ public unsafe class StbImage : IDisposable
+ {
+ private bool isDisposed = false;
+
+ ///
+ /// Pointer to the image.
+ ///
+ public IntPtr ImagePointer { get; }
+
+ ///
+ /// Width of the image.
+ ///
+ public int Width { get; }
+
+ ///
+ /// Height of the image.
+ ///
+ ///
+ public int Height { get; }
+
+ ///
+ /// Internal image format.
+ ///
+ public StbiImageFormat Format { get; }
+ public bool IsFloat { get; }
+
+ private StbImage(IntPtr image, int x, int y, StbiImageFormat format, bool isFloat)
+ {
+ ImagePointer = image;
+ Width = x;
+ Height = y;
+ Format = format;
+ IsFloat = isFloat;
+ }
+
+ ~StbImage()
+ {
+ Dispose(false);
+ }
+
+ public void Dispose() => Dispose(true);
+
+ private void Dispose(bool disposing)
+ {
+ if (isDisposed) return;
+
+ if (disposing)
+ {
+ GC.SuppressFinalize(this);
+ }
+
+ Stbi.image_free(ImagePointer.ToPointer());
+ isDisposed = true;
+ }
+
+ ///
+ /// Set to flip the y-axis of loaded images on load.
+ ///
+ public static bool FlipVerticallyOnLoad { set => Stbi.set_flip_vertically_on_load(1); }
+
+ ///
+ /// Set to unpremultiply images on load.
+ ///
+ ///
+ /// According to the stb_image documentation, only iPhone PNG images
+ /// can come with premultiplied alpha.
+ ///
+ public static bool UnpremultiplyOnLoad { set => Stbi.set_unpremultiply_on_load(1); }
+
+ ///
+ /// Try loading an image, without raising exceptions.
+ ///
+ /// The resulting image.
+ /// Source stream.
+ /// The desired image format.
+ /// True on success.
+ public static bool TryLoad(out StbImage image, Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool isFloat = false)
+ {
+ int x, y, iFormat;
+ StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true);
+ wrapper.CreateCallbacks(out stbi_io_callbacks cb);
+
+ stream.Position = 0;
+ IntPtr imagePtr;
+ if (isFloat)
+ {
+ imagePtr = (IntPtr)Stbi.loadf_from_callbacks(&cb, null, &x, &y, &iFormat, (int)format);
+ }
+ else
+ {
+ imagePtr = (IntPtr)Stbi.load_from_callbacks(&cb, null, &x, &y, &iFormat, (int)format);
+ }
+
+ if (imagePtr != IntPtr.Zero)
+ {
+ image = new StbImage(imagePtr, x, y, (StbiImageFormat)iFormat, isFloat);
+ return true;
+ }
+ else
+ {
+ image = null;
+ return false;
+ }
+ }
+
+ ///
+ /// Load an image.
+ ///
+ /// The stream to load from.
+ /// The desired image format.
+ /// The image object.
+ public static StbImage Load(Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool isFloat = false)
+ {
+ if (TryLoad(out StbImage image, stream, format, isFloat))
+ {
+ return image;
+ }
+
+ string reason = Marshal.PtrToStringUTF8((IntPtr)Stbi.failure_reason());
+ throw new Exception($"Failed to load image: {reason}");
+ }
+
+ public bool IsLoadable(Stream stream)
+ {
+ int x, y, iFormat;
+ StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true);
+ wrapper.CreateCallbacks(out stbi_io_callbacks cb);
+
+ stream.Position = 0;
+ int result = Stbi.info_from_callbacks(&cb, null, &x, &y, &iFormat);
+
+ return result != 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Stbi.Manual.cs b/Stbi.Manual.cs
new file mode 100644
index 0000000..30e8254
--- /dev/null
+++ b/Stbi.Manual.cs
@@ -0,0 +1,65 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Reflection;
+
+namespace Quik.Stb
+{
+ public unsafe static partial class Stbi
+ {
+ private delegate void FailedAssertProc(byte *expression, byte *file, int line, byte *function);
+
+ private static readonly string[] LibraryNames = new string[]
+ {
+ //FIXME: This is wrong on so many levels, but, i need to do this
+ // in order to get a change of this running.
+ "runtimes/win-x64/native/libstbi.dll",
+ "runtimes/win-x86/native/libstbi.dll",
+ "runtimes/linux-arm/native/libstbi.so",
+ "runtimes/linux-arm64/native/libstbi.so",
+ "runtimes/linux-x64/native/libstbi.so",
+ "runtimes/native/libstbi.dylib",
+ "libstbi.dll",
+ "libstbi.so",
+ "libstbi.dylib",
+ };
+
+ static Stbi()
+ {
+ NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), Resolver);
+
+ // quik_stbi_failed_assert_store(Marshal.GetFunctionPointerForDelegate(FailedAssert));
+ }
+
+ private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
+ {
+ if (libraryName != "stbi")
+ return IntPtr.Zero;
+
+ foreach (string name in LibraryNames)
+ {
+ if (NativeLibrary.TryLoad(name, assembly, searchPath, out IntPtr handle))
+ {
+ return handle;
+ }
+ }
+
+ return NativeLibrary.Load(libraryName);
+ }
+
+ private static void FailedAssert(byte *expression, byte *file, int line, byte *function)
+ {
+ string expr = expression == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)expression);
+ string f = file == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)file);
+ string func = function == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)function);
+
+ Exception ex = new Exception("Assert failed in native stbi code.");
+ ex.Data.Add("Expression", expr);
+ ex.Data.Add("File", f);
+ ex.Data.Add("Line", line);
+ ex.Data.Add("Function", func);
+ throw ex;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Stbi.cs b/Stbi.cs
new file mode 100644
index 0000000..0a9510c
--- /dev/null
+++ b/Stbi.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Runtime.InteropServices;
+using Quik.Stb.Image;
+
+namespace Quik.Stb
+{
+ [NativeTypeName("unsigned int")]
+ public enum StbiEnum : uint
+ {
+ STBI_default = 0,
+ STBI_grey = 1,
+ STBI_grey_alpha = 2,
+ STBI_rgb = 3,
+ STBI_rgb_alpha = 4,
+ }
+
+ public partial struct stbi_io_callbacks
+ {
+ [NativeTypeName("int (*)(void *, char *, int)")]
+ public IntPtr read;
+
+ [NativeTypeName("void (*)(void *, int)")]
+ public IntPtr skip;
+
+ [NativeTypeName("int (*)(void *)")]
+ public IntPtr eof;
+ }
+
+ public static unsafe partial class Stbi
+ {
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_memory", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_uc *")]
+ public static extern byte* load_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_callbacks", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_uc *")]
+ public static extern byte* load_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_uc *")]
+ public static extern byte* load([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_file", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_uc *")]
+ public static extern byte* load_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_gif_from_memory", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_uc *")]
+ public static extern byte* load_gif_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int** delays, int* x, int* y, int* z, int* comp, int req_comp);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16_from_memory", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_us *")]
+ public static extern ushort* load_16_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16_from_callbacks", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_us *")]
+ public static extern ushort* load_16_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_16", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_us *")]
+ public static extern ushort* load_16([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_load_from_file_16", ExactSpelling = true)]
+ [return: NativeTypeName("stbi_us *")]
+ public static extern ushort* load_from_file_16([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_memory", ExactSpelling = true)]
+ public static extern float* loadf_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_callbacks", ExactSpelling = true)]
+ public static extern float* loadf_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf", ExactSpelling = true)]
+ public static extern float* loadf([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_loadf_from_file", ExactSpelling = true)]
+ public static extern float* loadf_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* channels_in_file, int desired_channels);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_hdr_to_ldr_gamma", ExactSpelling = true)]
+ public static extern void hdr_to_ldr_gamma(float gamma);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_hdr_to_ldr_scale", ExactSpelling = true)]
+ public static extern void hdr_to_ldr_scale(float scale);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_ldr_to_hdr_gamma", ExactSpelling = true)]
+ public static extern void ldr_to_hdr_gamma(float gamma);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_ldr_to_hdr_scale", ExactSpelling = true)]
+ public static extern void ldr_to_hdr_scale(float scale);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_callbacks", ExactSpelling = true)]
+ public static extern int is_hdr_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_memory", ExactSpelling = true)]
+ public static extern int is_hdr_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr", ExactSpelling = true)]
+ public static extern int is_hdr([NativeTypeName("const char *")] sbyte* filename);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_hdr_from_file", ExactSpelling = true)]
+ public static extern int is_hdr_from_file([NativeTypeName("FILE *")] void* f);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_failure_reason", ExactSpelling = true)]
+ [return: NativeTypeName("const char *")]
+ public static extern sbyte* failure_reason();
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_image_free", ExactSpelling = true)]
+ public static extern void image_free(void* retval_from_stbi_load);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_memory", ExactSpelling = true)]
+ public static extern int info_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len, int* x, int* y, int* comp);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_callbacks", ExactSpelling = true)]
+ public static extern int info_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user, int* x, int* y, int* comp);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_memory", ExactSpelling = true)]
+ public static extern int is_16_bit_from_memory([NativeTypeName("const stbi_uc *")] byte* buffer, int len);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_callbacks", ExactSpelling = true)]
+ public static extern int is_16_bit_from_callbacks([NativeTypeName("const stbi_io_callbacks *")] stbi_io_callbacks* clbk, void* user);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info", ExactSpelling = true)]
+ public static extern int info([NativeTypeName("const char *")] sbyte* filename, int* x, int* y, int* comp);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_info_from_file", ExactSpelling = true)]
+ public static extern int info_from_file([NativeTypeName("FILE *")] void* f, int* x, int* y, int* comp);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit", ExactSpelling = true)]
+ public static extern int is_16_bit([NativeTypeName("const char *")] sbyte* filename);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_is_16_bit_from_file", ExactSpelling = true)]
+ public static extern int is_16_bit_from_file([NativeTypeName("FILE *")] void* f);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_unpremultiply_on_load", ExactSpelling = true)]
+ public static extern void set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_convert_iphone_png_to_rgb", ExactSpelling = true)]
+ public static extern void convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_flip_vertically_on_load", ExactSpelling = true)]
+ public static extern void set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_unpremultiply_on_load_thread", ExactSpelling = true)]
+ public static extern void set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_convert_iphone_png_to_rgb_thread", ExactSpelling = true)]
+ public static extern void convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_set_flip_vertically_on_load_thread", ExactSpelling = true)]
+ public static extern void set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc_guesssize", ExactSpelling = true)]
+ [return: NativeTypeName("char *")]
+ public static extern sbyte* zlib_decode_malloc_guesssize([NativeTypeName("const char *")] sbyte* buffer, int len, int initial_size, int* outlen);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc_guesssize_headerflag", ExactSpelling = true)]
+ [return: NativeTypeName("char *")]
+ public static extern sbyte* zlib_decode_malloc_guesssize_headerflag([NativeTypeName("const char *")] sbyte* buffer, int len, int initial_size, int* outlen, int parse_header);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_malloc", ExactSpelling = true)]
+ [return: NativeTypeName("char *")]
+ public static extern sbyte* zlib_decode_malloc([NativeTypeName("const char *")] sbyte* buffer, int len, int* outlen);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_buffer", ExactSpelling = true)]
+ public static extern int zlib_decode_buffer([NativeTypeName("char *")] sbyte* obuffer, int olen, [NativeTypeName("const char *")] sbyte* ibuffer, int ilen);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_noheader_malloc", ExactSpelling = true)]
+ [return: NativeTypeName("char *")]
+ public static extern sbyte* zlib_decode_noheader_malloc([NativeTypeName("const char *")] sbyte* buffer, int len, int* outlen);
+
+ [DllImport("stbi", CallingConvention = CallingConvention.Cdecl, EntryPoint = "stbi_zlib_decode_noheader_buffer", ExactSpelling = true)]
+ public static extern int zlib_decode_noheader_buffer([NativeTypeName("char *")] sbyte* obuffer, int olen, [NativeTypeName("const char *")] sbyte* ibuffer, int ilen);
+ }
+}
diff --git a/StbiImageFormat.cs b/StbiImageFormat.cs
new file mode 100644
index 0000000..a4c0c61
--- /dev/null
+++ b/StbiImageFormat.cs
@@ -0,0 +1,11 @@
+namespace Quik.Stb
+{
+ public enum StbiImageFormat
+ {
+ Default = (int)StbiEnum.STBI_default,
+ Grey = (int)StbiEnum.STBI_grey,
+ GreyAlpha = (int)StbiEnum.STBI_grey_alpha,
+ Rgb = (int)StbiEnum.STBI_rgb,
+ Rgba = (int)StbiEnum.STBI_rgb_alpha
+ }
+}
\ No newline at end of file
diff --git a/StbiStreamWrapper.cs b/StbiStreamWrapper.cs
new file mode 100644
index 0000000..4038c48
--- /dev/null
+++ b/StbiStreamWrapper.cs
@@ -0,0 +1,60 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Quik.Stb
+{
+ public unsafe class StbiStreamWrapper : IDisposable
+ {
+ private Stream _stream;
+ private bool _keepOpen;
+ private bool _isDisposed;
+
+ private delegate int ReadProc(void *userdata, byte* buffer, int count);
+ private delegate void SkipProc(void *userdata, int count);
+ private delegate int Eof(void *userdata);
+
+ public StbiStreamWrapper(Stream stream, bool keepOpen = false)
+ {
+ if (stream == null) throw new ArgumentNullException(nameof(stream));
+
+ _stream = stream;
+ _keepOpen = keepOpen;
+ }
+
+ public void CreateCallbacks(out stbi_io_callbacks cb)
+ {
+ cb = default;
+ cb.read = Marshal.GetFunctionPointerForDelegate(ReadCb);
+ cb.skip = Marshal.GetFunctionPointerForDelegate(SkipCb);
+ cb.eof = Marshal.GetFunctionPointerForDelegate(EofCb);
+ }
+
+ private int ReadCb(void *userdata, byte* buffer, int count)
+ {
+ Span bytes = new Span(buffer, count);
+ return _stream.Read(bytes);
+ }
+
+ private void SkipCb(void *userdata, int count)
+ {
+ _stream.Seek(count, SeekOrigin.Current);
+ }
+
+ private int EofCb(void *userdata)
+ {
+ if (!_stream.CanRead || _stream.Position == _stream.Length)
+ return 1;
+ return 0;
+ }
+
+ public void Dispose()
+ {
+ if (_isDisposed) return;
+
+ if (!_keepOpen) _stream.Dispose();
+
+ _isDisposed = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/build_ci_cd.sh b/build_ci_cd.sh
new file mode 100644
index 0000000..d76789c
--- /dev/null
+++ b/build_ci_cd.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+cd $(dirname "$0")
+if [ -z "$QUIK_API_KEY" ]
+then
+ echo "Please define QUIK_API_KEY"
+ exit 1
+fi
+
+pwd
+docker-compose run build && docker-compose run publish
diff --git a/build_native.sh b/build_native.sh
new file mode 100755
index 0000000..eb77add
--- /dev/null
+++ b/build_native.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+cd $(dirname "$0")
+./Quik.Common/sh/quik_build_native.sh .
+dotnet build
diff --git a/clangsharp.rsp b/clangsharp.rsp
new file mode 100644
index 0000000..d0ebfed
--- /dev/null
+++ b/clangsharp.rsp
@@ -0,0 +1,30 @@
+-x
+ c
+-l
+ stbi
+--config
+ compatible-codegen
+ single-file
+ exclude-fnptr-codegen
+ generate-aggressive-inlining
+ generate-setslastsystemerror-attribute
+ unix-types
+--include-directory
+ ../lib
+--include-directory
+ ../Quik.StbImage
+--include-directory
+ /usr/lib/llvm-14/lib/clang/14.0.6/include
+--file
+ ../Quik.StbImage.redist/quik_stbi.h
+ ../lib/stb/stb_image.h
+--methodClassName
+ Stbi
+--namespace
+ Quik.Stb
+--output
+ Stbi.cs
+--prefixStrip
+ stbi_
+--with-type
+ FILE=void
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..c73e8d6
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,16 @@
+version: "2"
+
+services:
+ build:
+ image: git.mixedup.dev/quik/docker-cross-compiler
+ command: "/home/quik/src/build_native.sh"
+ volumes:
+ - .:/home/quik/src
+ publish:
+ image: git.mixedup.dev/quik/docker-cross-compiler
+ command: "/home/quik/src/publish.sh"
+ environment:
+ QUIK_API_KEY: ${QUIK_API_KEY}
+ volumes:
+ - .:/home/quik/src
+
\ No newline at end of file
diff --git a/publish.sh b/publish.sh
new file mode 100755
index 0000000..01762a4
--- /dev/null
+++ b/publish.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+cd $(dirname "$0")
+if [ -z "$QUIK_API_KEY" ]
+then
+ echo "Please define QUIK_API_KEY"
+ exit 1
+fi
+
+dotnet nuget add source \
+ -n QUIK -u themixedupstuff -p "$QUIK_API_KEY" \
+ --store-password-in-clear-text \
+ https://git.mixedup.dev/api/packages/QUIK/nuget/index.json
+dotnet nuget push -s QUIK bin/*/*.nupkg
diff --git a/quik_stbi.c b/quik_stbi.c
new file mode 100644
index 0000000..312c61b
--- /dev/null
+++ b/quik_stbi.c
@@ -0,0 +1,4 @@
+#include "quik_stbi.h"
+
+#define STB_IMAGE_IMPLEMENTATION 1
+#include "stb/stb_image.h"
diff --git a/quik_stbi.h b/quik_stbi.h
new file mode 100644
index 0000000..cd2b84b
--- /dev/null
+++ b/quik_stbi.h
@@ -0,0 +1,10 @@
+#ifndef _QUIK_STBI_H_
+#define _QUIK_STBI_H_
+
+#include "Quik.Common/include/quik_common.h"
+
+#define STBIDEF QEXTERN
+
+#include "stb/stb_image.h"
+
+#endif