Move Quik.StbImage to its own repository.

This commit is contained in:
H. Utku Maden 2024-03-19 22:02:20 +03:00
parent 067e0bdd03
commit 1e5e9e6fb5
16 changed files with 622 additions and 1 deletions

4
.gitignore vendored Normal file

@ -0,0 +1,4 @@
**/bin
**/obj
**/out
**/runtimes

11
CMakeLists.txt Normal file

@ -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 .)

@ -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)
{
}
}
}

@ -1 +1 @@
Subproject commit 11bb72a464215693d5a3a6896b25e568cc6e3313
Subproject commit ebfc8a694615a8a6c9d35652279a9748ff43db3d

61
Quik.StbImage.csproj Normal file

@ -0,0 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>disable</Nullable>
<LangVersion>7.3</LangVersion>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64;win-x86;win-x64</RuntimeIdentifiers>
</PropertyGroup>
<PropertyGroup>
<!-- Nuget Properties. -->
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageId>Quik.StbImage</PackageId>
<Version>1.0.0</Version>
<Authors>STBI Authors, H. Utku Maden</Authors>
<Description>
A C# wrapper for the ubiquitous Stb Image library.
</Description>
</PropertyGroup>
<!--
Because the .net build system is garbage of the purest quality, I need
to specify each runtime directory by itself or it won't be picked up as a
native specific to each platform and won't be included in the deps.json file
that determines a lot of load paths for projects.
-->
<ItemGroup>
<Content Include="runtimes/linux-arm/native/*.so">
<PackagePath>runtimes/linux-arm/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="runtimes/linux-arm64/native/*.so">
<PackagePath>runtimes/linux-arm64/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest/</CopyToOutputDirectory>
</Content>
<Content Include="runtimes/linux-x64/native/*.so">
<PackagePath>runtimes/linux-x64/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="runtimes/linux-x86/native/*.so">
<PackagePath>runtimes/linux-x86/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="runtimes/win-x64/native/*.dll">
<PackagePath>runtimes/win-x64/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="runtimes/win-x86/native/*.dll">
<PackagePath>runtimes/win-x86/native/</PackagePath>
<Pack>true</Pack>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>

25
Quik.StbImage.sln Normal file

@ -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

144
StbImage.cs Normal file

@ -0,0 +1,144 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Quik.Stb
{
/// <summary>
/// A class that encompasses all features of stb_image.h in a safe way.
/// </summary>
public unsafe class StbImage : IDisposable
{
private bool isDisposed = false;
/// <summary>
/// Pointer to the image.
/// </summary>
public IntPtr ImagePointer { get; }
/// <summary>
/// Width of the image.
/// </summary>
public int Width { get; }
/// <summary>
/// Height of the image.
/// </summary>
/// <value></value>
public int Height { get; }
/// <summary>
/// Internal image format.
/// </summary>
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;
}
/// <summary>
/// Set to flip the y-axis of loaded images on load.
/// </summary>
public static bool FlipVerticallyOnLoad { set => Stbi.set_flip_vertically_on_load(1); }
/// <summary>
/// Set to unpremultiply images on load.
/// </summary>
/// <remarks>
/// According to the stb_image documentation, only iPhone PNG images
/// can come with premultiplied alpha.
/// </remarks>
public static bool UnpremultiplyOnLoad { set => Stbi.set_unpremultiply_on_load(1); }
/// <summary>
/// Try loading an image, without raising exceptions.
/// </summary>
/// <param name="image">The resulting image.</param>
/// <param name="stream">Source stream.</param>
/// <param name="format">The desired image format.</param>
/// <returns>True on success.</returns>
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;
}
}
/// <summary>
/// Load an image.
/// </summary>
/// <param name="stream">The stream to load from.</param>
/// <param name="format">The desired image format.</param>
/// <returns>The image object.</returns>
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;
}
}
}

65
Stbi.Manual.cs Normal file

@ -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<FailedAssertProc>(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;
}
}
}

174
Stbi.cs Normal file

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

11
StbiImageFormat.cs Normal file

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

60
StbiStreamWrapper.cs Normal file

@ -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<ReadProc>(ReadCb);
cb.skip = Marshal.GetFunctionPointerForDelegate<SkipProc>(SkipCb);
cb.eof = Marshal.GetFunctionPointerForDelegate<Eof>(EofCb);
}
private int ReadCb(void *userdata, byte* buffer, int count)
{
Span<byte> bytes = new Span<byte>(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;
}
}
}

3
build_native.sh Normal file

@ -0,0 +1,3 @@
#!/bin/bash
cd $(dirname "$0")
Quik.Common/sh/quik_build_native.sh .

30
clangsharp.rsp Normal file

@ -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

7
docker-compose.yaml Normal file

@ -0,0 +1,7 @@
services:
build:
image: git.mixedup.dev/quik/docker-cross-compiler
command: "/home/quik/src/build_native.sh"
volumes:
- .:/home/quik/src

4
quik_stbi.c Normal file

@ -0,0 +1,4 @@
#include "quik_stbi.h"
#define STB_IMAGE_IMPLEMENTATION 1
#include "stb/stb_image.h"

10
quik_stbi.h Normal file

@ -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