From bb5b3c638deb8d7f5c8cc68deef27cab87fed105 Mon Sep 17 00:00:00 2001 From: "H. Utku Maden" Date: Tue, 19 Mar 2024 22:02:20 +0300 Subject: [PATCH] [v1.0.0] Create Quik.StbImage nuget package. Make more shell scripts. Fix removed old function. Add a workflow. Add docker-compose.yaml version. Update .gitea/workflows/build.yaml Trying to see if this helps. Add executable bit to shell scripts. Where did my files go? Fix executable bit of higher repository. Change build scripts slightly to maybe fix CI? Update .gitea/workflows/build.yaml List all files in home directory of the runner. Another silly push. List stuff. YEss another useless push. Yet another attempt to fix CI builds. This is getting out of hand. Chnage build script. Use unencrypted storage for the key because Nuget is nuget. --- .gitattributes | 1 + .gitea/workflows/build.yaml | 25 ++++++ .gitignore | 6 ++ CMakeLists.txt | 11 +++ NativeTypeNameAttribute.cs | 12 +++ Quik.Common | 2 +- Quik.StbImage.csproj | 61 +++++++++++++ Quik.StbImage.sln | 25 ++++++ StbImage.cs | 144 +++++++++++++++++++++++++++++ Stbi.Manual.cs | 65 ++++++++++++++ Stbi.cs | 174 ++++++++++++++++++++++++++++++++++++ StbiImageFormat.cs | 11 +++ StbiStreamWrapper.cs | 60 +++++++++++++ build_ci_cd.sh | 11 +++ build_native.sh | 4 + clangsharp.rsp | 30 +++++++ docker-compose.yaml | 16 ++++ publish.sh | 14 +++ quik_stbi.c | 4 + quik_stbi.h | 10 +++ 20 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .gitea/workflows/build.yaml create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 NativeTypeNameAttribute.cs create mode 100644 Quik.StbImage.csproj create mode 100644 Quik.StbImage.sln create mode 100644 StbImage.cs create mode 100644 Stbi.Manual.cs create mode 100644 Stbi.cs create mode 100644 StbiImageFormat.cs create mode 100644 StbiStreamWrapper.cs create mode 100644 build_ci_cd.sh create mode 100755 build_native.sh create mode 100644 clangsharp.rsp create mode 100644 docker-compose.yaml create mode 100755 publish.sh create mode 100644 quik_stbi.c create mode 100644 quik_stbi.h 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