Compare commits
14 Commits
v2.0.0-rc
...
redis-work
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f418866a4 | |||
| 776719648e | |||
| b7983c96b2 | |||
| cb75b7c244 | |||
| 6ffcd38cbc | |||
| 09b5238b24 | |||
| 7157db6bd0 | |||
| df61cdc5aa | |||
| 50c37e58fc | |||
| 8e8c86b2c1 | |||
| ff83cb20f9 | |||
|
|
3801bc29f8 | ||
| bcd82900c7 | |||
| e759efacf6 |
@@ -5,6 +5,7 @@ project(rf_stbi LANGUAGES C VERSION 1.0)
|
||||
if (NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin"))
|
||||
add_compile_options(-static-libgcc -static-libstdc++ -fno-exceptions)
|
||||
endif()
|
||||
add_compile_options(-O3)
|
||||
|
||||
add_library(stbi SHARED "rf_stbi.c")
|
||||
install(
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Quik.Stb
|
||||
{
|
||||
[AttributeUsage(System.AttributeTargets.All, Inherited = false, AllowMultiple = true)]
|
||||
internal sealed class NativeTypeNameAttribute : System.Attribute
|
||||
{
|
||||
public NativeTypeNameAttribute(string typename)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
209
ReFuel.StbImage.Viewer/Program.cs
Normal file
209
ReFuel.StbImage.Viewer/Program.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* ReFuel.StbImage.Viewer - A simple image viewer demo for ReFuel.StbImage.
|
||||
* ------------------------------------------------------------------------
|
||||
*
|
||||
* Pass an image file as path (or drag and drop over the executable or window) to view
|
||||
* of the file formats stb_image supports. Otherwise the default embedded image will be
|
||||
* shown.
|
||||
*
|
||||
* The demo uses OpenGL2.1 for brevity sake - I did not feel like writing a shader program
|
||||
* for this demo. It is very easy to port this demo to modern OpenGL if desired. Just
|
||||
* replace the FFP calls with the equivalent programmable pipeline calls (glVertexAttribPointer,
|
||||
* glUseShader and its friends).
|
||||
*/
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using ReFuel.Stb;
|
||||
|
||||
NativeWindow window = new NativeWindow(new NativeWindowSettings()
|
||||
{
|
||||
Profile = ContextProfile.Any,
|
||||
APIVersion = new Version(2, 1),
|
||||
Title = "ReFuel StbImage Viewer",
|
||||
AutoLoadBindings = true,
|
||||
Flags = ContextFlags.Default,
|
||||
});
|
||||
|
||||
bool quit = false;
|
||||
int texture = 0;
|
||||
int imageWidth = 0, imageHeight = 0;
|
||||
|
||||
// This flag is important for OpenGL users, as texture coordinate systems
|
||||
// are the opposite of what most image formats use. Y is up not down.
|
||||
// Does not matter for DX, for example.
|
||||
StbImage.FlipVerticallyOnLoad = true;
|
||||
|
||||
Vertex[] vertices = new Vertex[]
|
||||
{
|
||||
new Vertex(-1, -1, 0, 0),
|
||||
new Vertex(1, -1, 1, 0),
|
||||
new Vertex(1, 1, 1, 1),
|
||||
new Vertex(-1, -1, 0, 0),
|
||||
new Vertex(1, 1, 1, 1),
|
||||
new Vertex(-1, 1, 0, 1),
|
||||
};
|
||||
|
||||
LoadImage(args.Length > 0 ? args[0] : null);
|
||||
|
||||
GL.ClearColor(Color4.Black);
|
||||
GL.Enable(EnableCap.Texture2D);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); // conventional blending function.
|
||||
GL.EnableClientState(ArrayCap.VertexArray);
|
||||
GL.EnableClientState(ArrayCap.TextureCoordArray);
|
||||
GL.EnableClientState(ArrayCap.ColorArray);
|
||||
|
||||
window.Closing += (_) => quit = true;
|
||||
window.FramebufferResize += (_) => {
|
||||
ResizeImage();
|
||||
Paint();
|
||||
};
|
||||
window.FileDrop += (args) =>
|
||||
LoadImage(
|
||||
args.FileNames
|
||||
.Select(x => new FileInfo(x))
|
||||
.FirstOrDefault(x => x.Exists)?.FullName);
|
||||
|
||||
window.WindowState = WindowState.Normal;
|
||||
while (!quit)
|
||||
{
|
||||
NativeWindow.ProcessWindowEvents(true);
|
||||
Paint();
|
||||
};
|
||||
|
||||
void Paint()
|
||||
{
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
GL.Viewport(0, 0, window.FramebufferSize.X, window.FramebufferSize.Y);
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (Vertex* pvert = vertices)
|
||||
{
|
||||
// We have to do it this way because the garbage collector may
|
||||
// move the vertex data at any time. The OpenGL client will
|
||||
// handle streaming the data at the glDrawArrays call, unlike
|
||||
// the modern method.
|
||||
GL.VertexPointer(2, VertexPointerType.Float, 32, (nint)(&pvert->X));
|
||||
GL.TexCoordPointer(2, TexCoordPointerType.Float, 32, (nint)(&pvert->U));
|
||||
GL.ColorPointer(4, ColorPointerType.Float, 32, (nint)(&pvert->Color));
|
||||
GL.DrawArrays(PrimitiveType.Triangles, 0, vertices.Length);
|
||||
}
|
||||
}
|
||||
|
||||
window.Context.SwapBuffers();
|
||||
}
|
||||
|
||||
void ResizeImage()
|
||||
{
|
||||
// Regenerates the vertex positions to maintain the aspect ratio and fill the window.
|
||||
float windowAspect = (float)window.FramebufferSize.X / window.FramebufferSize.Y;
|
||||
float imageAspect = (float)imageWidth / imageHeight;
|
||||
float ratio = imageAspect / windowAspect;
|
||||
|
||||
float widthNDC, heightNDC;
|
||||
if (ratio > 1)
|
||||
{
|
||||
widthNDC = 2.0f;
|
||||
heightNDC = 2.0f / ratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
heightNDC = 2.0f;
|
||||
widthNDC = 2.0f * ratio;
|
||||
}
|
||||
|
||||
vertices[0].X = -widthNDC / 2; vertices[0].Y = -heightNDC / 2;
|
||||
vertices[1].X = widthNDC / 2; vertices[1].Y = -heightNDC / 2;
|
||||
vertices[2].X = widthNDC / 2; vertices[2].Y = heightNDC / 2;
|
||||
vertices[3].X = -widthNDC / 2; vertices[3].Y = -heightNDC / 2;
|
||||
vertices[4].X = widthNDC / 2; vertices[4].Y = heightNDC / 2;
|
||||
vertices[5].X = -widthNDC / 2; vertices[5].Y = heightNDC / 2;
|
||||
}
|
||||
|
||||
void LoadImage(string? path)
|
||||
{
|
||||
// Load the given image, or the default if the path is null, or any other error happens.
|
||||
StbImage? image = null;
|
||||
if (path != null && File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
using Stream str = File.OpenRead(path);
|
||||
StbImage.TryLoad(out image, str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
using Stream str = Assembly.GetExecutingAssembly().GetManifestResourceStream("default.png")!;
|
||||
image = StbImage.Load(str);
|
||||
}
|
||||
|
||||
// Boilerplate code for creating a new OpenGL texture.
|
||||
|
||||
GL.DeleteTexture(texture);
|
||||
texture = GL.GenTexture();
|
||||
GL.BindTexture(TextureTarget.Texture2D, texture);
|
||||
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, image.Width, image.Height, 0, image.Format switch
|
||||
{
|
||||
StbiImageFormat.Grey => PixelFormat.Red,
|
||||
StbiImageFormat.GreyAlpha => PixelFormat.Rg,
|
||||
StbiImageFormat.Rgb => PixelFormat.Rgb,
|
||||
StbiImageFormat.Rgba => PixelFormat.Rgba,
|
||||
_ => throw new Exception()
|
||||
}, image.IsFloat ? PixelType.Float : PixelType.UnsignedByte, image.ImagePointer);
|
||||
|
||||
// Generate mipmaps for better minification.
|
||||
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
|
||||
// Enable them.
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.LinearMipmapLinear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
|
||||
// Set texture wrap mode to clamp to border to prevent bleeding on the image edges.
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToBorder);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToBorder);
|
||||
|
||||
// For R or RA format images, we need to set the swizzle mask.
|
||||
switch (image.Format)
|
||||
{
|
||||
case StbiImageFormat.Grey:
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, (int)TextureSwizzle.Red);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, (int)TextureSwizzle.Red);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, (int)TextureSwizzle.Red);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, (int)TextureSwizzle.One);
|
||||
break;
|
||||
case StbiImageFormat.GreyAlpha:
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleR, (int)TextureSwizzle.Red);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleG, (int)TextureSwizzle.Red);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleA, (int)TextureSwizzle.Green);
|
||||
// Yes the last channel is green, we uploaded the texture with the Rg color format.
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleB, (int)TextureSwizzle.Red);
|
||||
break;
|
||||
}
|
||||
|
||||
imageWidth = image.Width;
|
||||
imageHeight = image.Height;
|
||||
ResizeImage();
|
||||
|
||||
image.Dispose();
|
||||
}
|
||||
|
||||
// Vertex struct for convenience. Padded to 32 bytes for memory alignment.
|
||||
[StructLayout(LayoutKind.Sequential, Size = 32)]
|
||||
struct Vertex(float x, float y, float u, float v)
|
||||
{
|
||||
public float X = x, Y = y, U = u, V = v;
|
||||
public Color4 Color = Color4.White;
|
||||
}
|
||||
|
||||
18
ReFuel.StbImage.Viewer/ReFuel.StbImage.Viewer.csproj
Normal file
18
ReFuel.StbImage.Viewer/ReFuel.StbImage.Viewer.csproj
Normal file
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- <ProjectReference Include="..\ReFuel.StbImage\ReFuel.StbImage.csproj" /> -->
|
||||
<PackageReference Include="ReFuel.StbImage" Version="2.1.0"/>
|
||||
<PackageReference Include="OpenTK" Version="4.9.4" />
|
||||
<EmbeddedResource Include="../rf_stbimage.png" LogicalName="default.png"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -3,20 +3,46 @@ Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.31903.59
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReFuel.StbImage", "ReFuel.StbImage.csproj", "{413ACBF4-3851-416F-B2A2-F7157EC306B2}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReFuel.StbImage", "ReFuel.StbImage\ReFuel.StbImage.csproj", "{EB001CC8-6821-4579-BD5D-27C56A3C121E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReFuel.StbImage.Viewer", "ReFuel.StbImage.Viewer\ReFuel.StbImage.Viewer.csproj", "{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EB001CC8-6821-4579-BD5D-27C56A3C121E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4CFB8D5B-8CE9-46EE-A34B-0D61693BDE50}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{413ACBF4-3851-416F-B2A2-F7157EC306B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{413ACBF4-3851-416F-B2A2-F7157EC306B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{413ACBF4-3851-416F-B2A2-F7157EC306B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{413ACBF4-3851-416F-B2A2-F7157EC306B2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<RuntimeIdentifiers>linux-arm;linux-arm64;linux-x64;win-x86;win-x64;osx-arm64;osx-x64</RuntimeIdentifiers>
|
||||
<RootNamespace>ReFuel.Stb</RootNamespace>
|
||||
<Optimize>true</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- Nuget Properties. -->
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageId>ReFuel.StbImage</PackageId>
|
||||
<Version>2.0-rc</Version>
|
||||
<Version>2.1.0</Version>
|
||||
<Authors>STBI Authors, H. Utku Maden</Authors>
|
||||
<Description>
|
||||
A C# wrapper for the ubiquitous stb_image.h and stb_image_write.h library.
|
||||
@@ -25,7 +26,15 @@
|
||||
<RepositoryUrl>https://git.mixedup.dev/ReFuel/ReFuel.StbImage</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PackageTags>stb; stb_image; stbi; image; load; save; read; write</PackageTags>
|
||||
<PackageReleaseNotes># 2.0.0
|
||||
<PackageReleaseNotes># 2.1.0 (ABI BRAKING)
|
||||
* Fixed calling convention of unmanaged function pointers. (Thanks NogginBops!)
|
||||
* Modified StbiStreamWrapper in order to fixed backing delegates of function pointers from being prematurely collected
|
||||
by release mode JIT and the GC. StbiStreamWrapper.Callbacks is now a readonly field. (ABI BREAKING)
|
||||
|
||||
# 2.0.1
|
||||
* Enabled optimizations across the board for native and managed assemblies.
|
||||
|
||||
# 2.0.0
|
||||
* Exposed stbi_image_write.h
|
||||
* Moved native function calls to ReFuel.Stb.Native</PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
@@ -47,7 +56,7 @@
|
||||
<Content Include="runtimes/linux-arm64/native/*.so">
|
||||
<PackagePath>runtimes/linux-arm64/native/</PackagePath>
|
||||
<Pack>true</Pack>
|
||||
<CopyToOutputDirectory>PreserveNewest/</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="runtimes/linux-x64/native/*.so">
|
||||
<PackagePath>runtimes/linux-x64/native/</PackagePath>
|
||||
@@ -33,6 +33,7 @@ namespace ReFuel.Stb
|
||||
/// Internal image format.
|
||||
/// </summary>
|
||||
public StbiImageFormat Format { get; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the image is a floating point image.
|
||||
/// </summary>
|
||||
@@ -66,7 +67,7 @@ namespace ReFuel.Stb
|
||||
StbiImageFormat.GreyAlpha => 2,
|
||||
StbiImageFormat.Rgb => 3,
|
||||
StbiImageFormat.Rgba => 4,
|
||||
_ => throw new Exception("unkown image format")
|
||||
_ => throw new Exception("unknown image format")
|
||||
} * (IsFloat ? sizeof(float) : sizeof(byte));
|
||||
|
||||
return new ReadOnlySpan<T>((T*)ImagePointer, Width * Height * sz / sizeof(T));
|
||||
@@ -112,6 +113,7 @@ namespace ReFuel.Stb
|
||||
/// Write image to a PNG file.
|
||||
/// </summary>
|
||||
/// <param name="dest">The destination stream.</param>
|
||||
/// <param name="quality">The JPEG quality factor.</param>
|
||||
/// <remarks>
|
||||
/// Incurs a conversion cost if the image format is not a byte format. Ignores alpha channel. Affected by non-thread safe global options.
|
||||
/// </remarks>
|
||||
@@ -149,7 +151,7 @@ namespace ReFuel.Stb
|
||||
/// 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); }
|
||||
public static bool UnpremultiplyOnLoad { set => Stbi.set_unpremultiply_on_load(value ? 1 : 0); }
|
||||
|
||||
/// <summary>
|
||||
/// Force a filter on PNG filter when saving.
|
||||
@@ -157,7 +159,7 @@ namespace ReFuel.Stb
|
||||
/// <remarks>
|
||||
/// -1 for auto, 0 through 5 to pick a filter. Higher is more. Not thread safe.
|
||||
/// </remarks>
|
||||
public int WriteForcePngFilter
|
||||
public static int WriteForcePngFilter
|
||||
{
|
||||
get => Stbi.write_force_png_filter;
|
||||
set
|
||||
@@ -177,7 +179,7 @@ namespace ReFuel.Stb
|
||||
/// <remarks>
|
||||
/// Higher is more. Defaults to 8. Not thread safe.
|
||||
/// </remarks>
|
||||
public int WritePngCompressionLevel
|
||||
public static int WritePngCompressionLevel
|
||||
{
|
||||
get => Stbi.write_png_compression_level;
|
||||
set => Stbi.write_png_compression_level = value;
|
||||
@@ -189,7 +191,7 @@ namespace ReFuel.Stb
|
||||
/// <remarks>
|
||||
/// Not thread safe.
|
||||
/// </remarks>
|
||||
public bool WriteTgaEnableRLE
|
||||
public static bool WriteTgaEnableRLE
|
||||
{
|
||||
get => Stbi.write_tga_with_rle != 0;
|
||||
set => Stbi.write_tga_with_rle = value ? 1 : 0;
|
||||
@@ -201,22 +203,24 @@ namespace ReFuel.Stb
|
||||
/// <param name="image">The resulting image.</param>
|
||||
/// <param name="stream">Source stream.</param>
|
||||
/// <param name="format">The desired image format.</param>
|
||||
/// <param name="asFloat">The buffer uses floating point pixels if true.</param>
|
||||
/// <returns>True on success.</returns>
|
||||
public static bool TryLoad([NotNullWhen(true)] out StbImage? image, Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool asFloat = false)
|
||||
{
|
||||
int x, y, iFormat;
|
||||
StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true);
|
||||
wrapper.CreateCallbacks(out stbi_io_callbacks cb);
|
||||
|
||||
stream.Position = 0;
|
||||
IntPtr imagePtr;
|
||||
fixed (stbi_io_callbacks* cb = &wrapper.Callbacks)
|
||||
{
|
||||
if (asFloat)
|
||||
{
|
||||
imagePtr = (IntPtr)Stbi.loadf_from_callbacks(&cb, null, &x, &y, &iFormat, (int)format);
|
||||
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);
|
||||
imagePtr = (IntPtr)Stbi.load_from_callbacks(cb, null, &x, &y, &iFormat, (int)format);
|
||||
}
|
||||
}
|
||||
|
||||
if (imagePtr != IntPtr.Zero)
|
||||
@@ -237,6 +241,7 @@ namespace ReFuel.Stb
|
||||
/// <param name="image">The resulting image.</param>
|
||||
/// <param name="span">Source memory span.</param>
|
||||
/// <param name="format">The desired image format.</param>
|
||||
/// <param name="asFloat">The buffer uses floating point pixels if true.</param>
|
||||
/// <returns>True on success.</returns>
|
||||
public static bool TryLoad([NotNullWhen(true)] out StbImage? image, ReadOnlySpan<byte> span, StbiImageFormat format = StbiImageFormat.Default, bool asFloat = false)
|
||||
{
|
||||
@@ -271,6 +276,7 @@ namespace ReFuel.Stb
|
||||
/// </summary>
|
||||
/// <param name="stream">The stream to load from.</param>
|
||||
/// <param name="format">The desired image format.</param>
|
||||
/// <param name="asFloat">The buffer uses floating point pixels if true.</param>
|
||||
/// <returns>The image object.</returns>
|
||||
public static StbImage Load(Stream stream, StbiImageFormat format = StbiImageFormat.Default, bool asFloat = false)
|
||||
{
|
||||
@@ -288,6 +294,7 @@ namespace ReFuel.Stb
|
||||
/// </summary>
|
||||
/// <param name="span">The span of memory to load from.</param>
|
||||
/// <param name="format">The desired image format.</param>
|
||||
/// <param name="asFloat">The buffer uses floating point pixels if true.</param>
|
||||
/// <returns>The image object.</returns>
|
||||
public static StbImage Load(ReadOnlySpan<byte> span, StbiImageFormat format = StbiImageFormat.Default, bool asFloat = false)
|
||||
{
|
||||
@@ -312,10 +319,12 @@ namespace ReFuel.Stb
|
||||
{
|
||||
int x, y, iFormat;
|
||||
StbiStreamWrapper wrapper = new StbiStreamWrapper(stream, true);
|
||||
wrapper.CreateCallbacks(out stbi_io_callbacks cb);
|
||||
|
||||
int result;
|
||||
stream.Position = 0;
|
||||
int result = Stbi.info_from_callbacks(&cb, null, &x, &y, &iFormat);
|
||||
fixed (stbi_io_callbacks* cb = &wrapper.Callbacks)
|
||||
{
|
||||
result = Stbi.info_from_callbacks(cb, null, &x, &y, &iFormat);
|
||||
}
|
||||
|
||||
width = x;
|
||||
height = y;
|
||||
@@ -389,7 +398,7 @@ namespace ReFuel.Stb
|
||||
/// <param name="data">Span of pixel data.</param>
|
||||
/// <param name="width">Width of the pixel data in pixels.</param>
|
||||
/// <param name="height">Height of the pixel data in pixels.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat.StbiImageFormat"/>.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat"/>.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="isFloat">True if the pixel format in data is a floating point format.</param>
|
||||
/// <remarks>
|
||||
@@ -425,7 +434,7 @@ namespace ReFuel.Stb
|
||||
/// <param name="data">Span of pixel data.</param>
|
||||
/// <param name="width">Width of the pixel data in pixels.</param>
|
||||
/// <param name="height">Height of the pixel data in pixels.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat.StbiImageFormat"/>.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat"/>.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="isFloat">True if the pixel format in data is a floating point format.</param>
|
||||
/// <remarks>
|
||||
@@ -461,7 +470,7 @@ namespace ReFuel.Stb
|
||||
/// <param name="data">Span of pixel data.</param>
|
||||
/// <param name="width">Width of the pixel data in pixels.</param>
|
||||
/// <param name="height">Height of the pixel data in pixels.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat.StbiImageFormat"/>.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat"/>.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="isFloat">True if the pixel format in data is a floating point format.</param>
|
||||
/// <remarks>
|
||||
@@ -497,7 +506,7 @@ namespace ReFuel.Stb
|
||||
/// <param name="data">Span of pixel data.</param>
|
||||
/// <param name="width">Width of the pixel data in pixels.</param>
|
||||
/// <param name="height">Height of the pixel data in pixels.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat.StbiImageFormat"/>.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat"/>.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="isFloat">True if the pixel format in data is a floating point format.</param>
|
||||
/// <remarks>
|
||||
@@ -533,8 +542,9 @@ namespace ReFuel.Stb
|
||||
/// <param name="data">Span of pixel data.</param>
|
||||
/// <param name="width">Width of the pixel data in pixels.</param>
|
||||
/// <param name="height">Height of the pixel data in pixels.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat.StbiImageFormat"/>.</param>
|
||||
/// <param name="format">Color format of the pixel data. Must not be <see cref="StbiImageFormat"/>.</param>
|
||||
/// <param name="destination">The destination stream.</param>
|
||||
/// <param name="quality">The JPEG quality factor.</param>
|
||||
/// <param name="isFloat">True if the pixel format in data is a floating point format.</param>
|
||||
/// <remarks>
|
||||
/// This will incur a conversion cost if the pixel format is not a byte format. Ignores the alpha channel. Affected by global non-thread safe options.
|
||||
@@ -12,26 +12,32 @@ namespace ReFuel.Stb
|
||||
/// <param name="buffer">C array to read into.</param>
|
||||
/// <param name="count">Size of the C array in bytes.</param>
|
||||
/// <returns>The number of bytes read from the stream.</returns>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public unsafe delegate int StbiReadProc(void *userdata, byte* buffer, int count);
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to STBI stream skip function.
|
||||
/// </summary>
|
||||
/// <param name="userdata">User provided userdata pointer.</param>
|
||||
/// <param name="count">Number of bytes to skip.</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public unsafe delegate void StbiSkipProc(void *userdata, int count);
|
||||
|
||||
/// <summary>
|
||||
/// Pointer to STBI stream end of file function.
|
||||
/// </summary>
|
||||
/// <param name="userdata">User provided userdata pointer.</param>
|
||||
/// <returns>Non-zero value if the end of the stream has been reached.</returns>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public unsafe delegate int StbiEofProc(void *userdata);
|
||||
|
||||
/// <summary>
|
||||
/// An easy to use stream wrapper for use with STBI image load functions.
|
||||
/// An easy-to-use stream wrapper for use with STBI image load functions.
|
||||
/// </summary>
|
||||
public unsafe class StbiStreamWrapper : IDisposable
|
||||
{
|
||||
private readonly stbi_io_callbacks _callbacks;
|
||||
public readonly stbi_io_callbacks Callbacks;
|
||||
|
||||
private readonly Stream _stream;
|
||||
private readonly bool _keepOpen;
|
||||
private bool _isDisposed;
|
||||
@@ -40,8 +46,6 @@ namespace ReFuel.Stb
|
||||
private StbiSkipProc _skipCb;
|
||||
private StbiEofProc _eofCb;
|
||||
|
||||
public ref readonly stbi_io_callbacks Callbacks => ref _callbacks;
|
||||
|
||||
public StbiStreamWrapper(Stream stream, bool keepOpen = false)
|
||||
{
|
||||
if (stream == null) throw new ArgumentNullException(nameof(stream));
|
||||
@@ -53,18 +57,10 @@ namespace ReFuel.Stb
|
||||
_skipCb = SkipCb;
|
||||
_eofCb = EofCb;
|
||||
|
||||
_callbacks = default;
|
||||
_callbacks.read = Marshal.GetFunctionPointerForDelegate<StbiReadProc>(_readCb);
|
||||
_callbacks.skip = Marshal.GetFunctionPointerForDelegate<StbiSkipProc>(_skipCb);
|
||||
_callbacks.eof = Marshal.GetFunctionPointerForDelegate<StbiEofProc>(_eofCb);
|
||||
}
|
||||
|
||||
public void CreateCallbacks(out stbi_io_callbacks cb)
|
||||
{
|
||||
cb = default;
|
||||
cb.read = Marshal.GetFunctionPointerForDelegate<StbiReadProc>(_readCb);
|
||||
cb.skip = Marshal.GetFunctionPointerForDelegate<StbiSkipProc>(_skipCb);
|
||||
cb.eof = Marshal.GetFunctionPointerForDelegate<StbiEofProc>(_eofCb);
|
||||
Callbacks = default;
|
||||
Callbacks.read = Marshal.GetFunctionPointerForDelegate<StbiReadProc>(_readCb);
|
||||
Callbacks.skip = Marshal.GetFunctionPointerForDelegate<StbiSkipProc>(_skipCb);
|
||||
Callbacks.eof = Marshal.GetFunctionPointerForDelegate<StbiEofProc>(_eofCb);
|
||||
}
|
||||
|
||||
private int ReadCb(void *userdata, byte* buffer, int count)
|
||||
@@ -9,6 +9,7 @@ namespace ReFuel.Stb.Native
|
||||
/// <param name="context">User provided context pointer.</param>
|
||||
/// <param name="data">C Array of data to write.</param>
|
||||
/// <param name="size">Size of the C array in bytes.</param>
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public unsafe delegate void StbiWriteProc(void* context, void* data, int size);
|
||||
|
||||
public unsafe partial class Stbi
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
cd $(dirname "$0")
|
||||
./docker-cross-compiler/sh/build_native.sh .
|
||||
dotnet build
|
||||
dotnet build -c Release
|
||||
|
||||
Submodule docker-cross-compiler updated: 5901e3e317...d0f5760c7a
0
etc/ReFuel.StbImage.Common.props
Normal file
0
etc/ReFuel.StbImage.Common.props
Normal file
@@ -7,6 +7,7 @@
|
||||
#define STBI_NO_THREAD_LOCALS 1
|
||||
#include "stb/stb_image.h"
|
||||
|
||||
#define STBIWDEF RFEXTERN
|
||||
#define STBI_WRITE_NO_STDIO 1
|
||||
#include "stb/stb_image_write.h"
|
||||
|
||||
|
||||
2
stb
2
stb
Submodule stb updated: 013ac3bedd...f7f20f39fe
Reference in New Issue
Block a user