Added new namespace `Misaki.HighPerformance.Image` for image processing, including classes for animated GIF handling and memory management. Added `AnimatedFrameResult` class for individual frames in animated images. Added `AnimatedGifEnumerator` class for enumerating frames in animated GIFs. Added `ColorComponents` enum for different color formats. Added `ImageInfo` struct for image dimensions and color components. Added `CRuntime` class for low-level memory management functions. Added `MemoryStats` class to track memory allocation statistics. Added utility functions for creating multi-dimensional arrays. Added new structures for fixed-size UTF-8 encoded strings. Added benchmarking classes to test new memory management features. Changed `StbImage.cs` to include new namespaces and functionality for image data manipulation. Changed project files to target .NET 9.0 and enable new features. Changed `Arena.cs` and `DynamicArena.cs` to use `nuint` for size parameters. Changed `BitSet.cs` to enhance bit manipulation methods. Changed `Program.cs` to run `FunctionPtrBenchmark` for performance testing. Removed memory tracking code from `AllocationManager.cs`, including the `_allocated` dictionary and related logic. Removed `Free` method from `IAllocator.cs` interface. Removed `UNSAFE_COLLECTION_CHECK` preprocessor directive from the codebase. Refactored various files to improve organization, moving from `Unsafe` to `LowLevel` namespace. Refactored `MemoryUtilities` class to include new memory operation methods. Refactored `UnsafeUtilities.cs` to support new collection structures.
495 lines
12 KiB
C#
495 lines
12 KiB
C#
// Generated by Sichem at 9/16/2024 9:09:30 AM
|
|
|
|
using System.Runtime.InteropServices;
|
|
using Misaki.HighPerformance.Image.Runtime;
|
|
using Misaki.HighPerformance.Image;
|
|
|
|
namespace Misaki.HighPerformance.Image
|
|
{
|
|
unsafe partial class StbImage
|
|
{
|
|
public static int stbi__bmp_test(stbi__context s)
|
|
{
|
|
var r = stbi__bmp_test_raw(s);
|
|
stbi__rewind(s);
|
|
return r;
|
|
}
|
|
|
|
public static void* stbi__bmp_load(stbi__context s, int* x, int* y, int* comp, int req_comp,
|
|
stbi__result_info* ri)
|
|
{
|
|
byte* _out_;
|
|
uint mr = 0;
|
|
uint mg = 0;
|
|
uint mb = 0;
|
|
uint ma = 0;
|
|
uint all_a = 0;
|
|
var pal = Utility.CreateArray<byte>(256, 4);
|
|
var psize = 0;
|
|
var i = 0;
|
|
var j = 0;
|
|
var width = 0;
|
|
var flip_vertically = 0;
|
|
var pad = 0;
|
|
var target = 0;
|
|
var info = new stbi__bmp_data();
|
|
info.all_a = 255;
|
|
if (stbi__bmp_parse_header(s, &info) == null)
|
|
return null;
|
|
flip_vertically = (int)s.img_y > 0 ? 1 : 0;
|
|
s.img_y = (uint)CRuntime.abs((int)s.img_y);
|
|
if (s.img_y > 1 << 24)
|
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
|
if (s.img_x > 1 << 24)
|
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
|
mr = info.mr;
|
|
mg = info.mg;
|
|
mb = info.mb;
|
|
ma = info.ma;
|
|
all_a = info.all_a;
|
|
if (info.hsz == 12)
|
|
{
|
|
if (info.bpp < 24)
|
|
psize = (info.offset - info.extra_read - 24) / 3;
|
|
}
|
|
else
|
|
{
|
|
if (info.bpp < 16)
|
|
psize = (info.offset - info.extra_read - info.hsz) >> 2;
|
|
}
|
|
|
|
if (psize == 0)
|
|
{
|
|
var bytes_read_so_far = (int)s.Stream.Position;
|
|
var header_limit = 1024;
|
|
var extra_data_limit = 256 * 4;
|
|
if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit)
|
|
return (byte*)(ulong)(stbi__err("bad header") != 0 ? 0 : 0);
|
|
|
|
if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit)
|
|
return (byte*)(ulong)(stbi__err("bad offset") != 0 ? 0 : 0);
|
|
stbi__skip(s, info.offset - bytes_read_so_far);
|
|
}
|
|
|
|
if (info.bpp == 24 && ma == 0xff000000)
|
|
s.img_n = 3;
|
|
else
|
|
s.img_n = ma != 0 ? 4 : 3;
|
|
if (req_comp != 0 && req_comp >= 3)
|
|
target = req_comp;
|
|
else
|
|
target = s.img_n;
|
|
if (stbi__mad3sizes_valid(target, (int)s.img_x, (int)s.img_y, 0) == 0)
|
|
return (byte*)(ulong)(stbi__err("too large") != 0 ? 0 : 0);
|
|
_out_ = (byte*)stbi__malloc_mad3(target, (int)s.img_x, (int)s.img_y, 0);
|
|
if (_out_ == null)
|
|
return (byte*)(ulong)(stbi__err("outofmem") != 0 ? 0 : 0);
|
|
if (info.bpp < 16)
|
|
{
|
|
var z = 0;
|
|
if (psize == 0 || psize > 256)
|
|
{
|
|
CRuntime.free(_out_);
|
|
return (byte*)(ulong)(stbi__err("invalid") != 0 ? 0 : 0);
|
|
}
|
|
|
|
for (i = 0; i < psize; ++i)
|
|
{
|
|
pal[i][2] = stbi__get8(s);
|
|
pal[i][1] = stbi__get8(s);
|
|
pal[i][0] = stbi__get8(s);
|
|
if (info.hsz != 12)
|
|
stbi__get8(s);
|
|
pal[i][3] = 255;
|
|
}
|
|
|
|
stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
|
|
if (info.bpp == 1)
|
|
{
|
|
width = (int)((s.img_x + 7) >> 3);
|
|
}
|
|
else if (info.bpp == 4)
|
|
{
|
|
width = (int)((s.img_x + 1) >> 1);
|
|
}
|
|
else if (info.bpp == 8)
|
|
{
|
|
width = (int)s.img_x;
|
|
}
|
|
else
|
|
{
|
|
CRuntime.free(_out_);
|
|
return (byte*)(ulong)(stbi__err("bad bpp") != 0 ? 0 : 0);
|
|
}
|
|
|
|
pad = -width & 3;
|
|
if (info.bpp == 1)
|
|
for (j = 0; j < (int)s.img_y; ++j)
|
|
{
|
|
var bit_offset = 7;
|
|
int v = stbi__get8(s);
|
|
for (i = 0; i < (int)s.img_x; ++i)
|
|
{
|
|
var color = (v >> bit_offset) & 0x1;
|
|
_out_[z++] = pal[color][0];
|
|
_out_[z++] = pal[color][1];
|
|
_out_[z++] = pal[color][2];
|
|
if (target == 4)
|
|
_out_[z++] = 255;
|
|
if (i + 1 == (int)s.img_x)
|
|
break;
|
|
if (--bit_offset < 0)
|
|
{
|
|
bit_offset = 7;
|
|
v = stbi__get8(s);
|
|
}
|
|
}
|
|
|
|
stbi__skip(s, pad);
|
|
}
|
|
else
|
|
for (j = 0; j < (int)s.img_y; ++j)
|
|
{
|
|
for (i = 0; i < (int)s.img_x; i += 2)
|
|
{
|
|
int v = stbi__get8(s);
|
|
var v2 = 0;
|
|
if (info.bpp == 4)
|
|
{
|
|
v2 = v & 15;
|
|
v >>= 4;
|
|
}
|
|
|
|
_out_[z++] = pal[v][0];
|
|
_out_[z++] = pal[v][1];
|
|
_out_[z++] = pal[v][2];
|
|
if (target == 4)
|
|
_out_[z++] = 255;
|
|
if (i + 1 == (int)s.img_x)
|
|
break;
|
|
v = info.bpp == 8 ? stbi__get8(s) : v2;
|
|
_out_[z++] = pal[v][0];
|
|
_out_[z++] = pal[v][1];
|
|
_out_[z++] = pal[v][2];
|
|
if (target == 4)
|
|
_out_[z++] = 255;
|
|
}
|
|
|
|
stbi__skip(s, pad);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var rshift = 0;
|
|
var gshift = 0;
|
|
var bshift = 0;
|
|
var ashift = 0;
|
|
var rcount = 0;
|
|
var gcount = 0;
|
|
var bcount = 0;
|
|
var acount = 0;
|
|
var z = 0;
|
|
var easy = 0;
|
|
stbi__skip(s, info.offset - info.extra_read - info.hsz);
|
|
if (info.bpp == 24)
|
|
width = (int)(3 * s.img_x);
|
|
else if (info.bpp == 16)
|
|
width = (int)(2 * s.img_x);
|
|
else
|
|
width = 0;
|
|
pad = -width & 3;
|
|
if (info.bpp == 24)
|
|
easy = 1;
|
|
else if (info.bpp == 32)
|
|
if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
|
|
easy = 2;
|
|
|
|
if (easy == 0)
|
|
{
|
|
if (mr == 0 || mg == 0 || mb == 0)
|
|
{
|
|
CRuntime.free(_out_);
|
|
return (byte*)(ulong)(stbi__err("bad masks") != 0 ? 0 : 0);
|
|
}
|
|
|
|
rshift = stbi__high_bit(mr) - 7;
|
|
rcount = stbi__bitcount(mr);
|
|
gshift = stbi__high_bit(mg) - 7;
|
|
gcount = stbi__bitcount(mg);
|
|
bshift = stbi__high_bit(mb) - 7;
|
|
bcount = stbi__bitcount(mb);
|
|
ashift = stbi__high_bit(ma) - 7;
|
|
acount = stbi__bitcount(ma);
|
|
if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8)
|
|
{
|
|
CRuntime.free(_out_);
|
|
return (byte*)(ulong)(stbi__err("bad masks") != 0 ? 0 : 0);
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < (int)s.img_y; ++j)
|
|
{
|
|
if (easy != 0)
|
|
{
|
|
for (i = 0; i < (int)s.img_x; ++i)
|
|
{
|
|
byte a = 0;
|
|
_out_[z + 2] = stbi__get8(s);
|
|
_out_[z + 1] = stbi__get8(s);
|
|
_out_[z + 0] = stbi__get8(s);
|
|
z += 3;
|
|
a = (byte)(easy == 2 ? stbi__get8(s) : 255);
|
|
all_a |= a;
|
|
if (target == 4)
|
|
_out_[z++] = a;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var bpp = info.bpp;
|
|
for (i = 0; i < (int)s.img_x; ++i)
|
|
{
|
|
var v = bpp == 16 ? (uint)stbi__get16le(s) : stbi__get32le(s);
|
|
uint a = 0;
|
|
_out_[z++] = (byte)(stbi__shiftsigned(v & mr, rshift, rcount) & 255);
|
|
_out_[z++] = (byte)(stbi__shiftsigned(v & mg, gshift, gcount) & 255);
|
|
_out_[z++] = (byte)(stbi__shiftsigned(v & mb, bshift, bcount) & 255);
|
|
a = (uint)(ma != 0 ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
|
|
all_a |= a;
|
|
if (target == 4)
|
|
_out_[z++] = (byte)(a & 255);
|
|
}
|
|
}
|
|
|
|
stbi__skip(s, pad);
|
|
}
|
|
}
|
|
|
|
if (target == 4 && all_a == 0)
|
|
for (i = (int)(4 * s.img_x * s.img_y - 1); i >= 0; i -= 4)
|
|
_out_[i] = 255;
|
|
|
|
if (flip_vertically != 0)
|
|
{
|
|
byte t = 0;
|
|
for (j = 0; j < (int)s.img_y >> 1; ++j)
|
|
{
|
|
var p1 = _out_ + j * s.img_x * target;
|
|
var p2 = _out_ + (s.img_y - 1 - j) * s.img_x * target;
|
|
for (i = 0; i < (int)s.img_x * target; ++i)
|
|
{
|
|
t = p1[i];
|
|
p1[i] = p2[i];
|
|
p2[i] = t;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (req_comp != 0 && req_comp != target)
|
|
{
|
|
_out_ = stbi__convert_format(_out_, target, req_comp, s.img_x, s.img_y);
|
|
if (_out_ == null)
|
|
return _out_;
|
|
}
|
|
|
|
*x = (int)s.img_x;
|
|
*y = (int)s.img_y;
|
|
if (comp != null)
|
|
*comp = s.img_n;
|
|
return _out_;
|
|
}
|
|
|
|
public static int stbi__bmp_info(stbi__context s, int* x, int* y, int* comp)
|
|
{
|
|
void* p;
|
|
var info = new stbi__bmp_data();
|
|
info.all_a = 255;
|
|
p = stbi__bmp_parse_header(s, &info);
|
|
if (p == null)
|
|
{
|
|
stbi__rewind(s);
|
|
return 0;
|
|
}
|
|
|
|
if (x != null)
|
|
*x = (int)s.img_x;
|
|
if (y != null)
|
|
*y = (int)s.img_y;
|
|
if (comp != null)
|
|
{
|
|
if (info.bpp == 24 && info.ma == 0xff000000)
|
|
*comp = 3;
|
|
else
|
|
*comp = info.ma != 0 ? 4 : 3;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
public static int stbi__bmp_test_raw(stbi__context s)
|
|
{
|
|
var r = 0;
|
|
var sz = 0;
|
|
if (stbi__get8(s) != 66)
|
|
return 0;
|
|
if (stbi__get8(s) != 77)
|
|
return 0;
|
|
stbi__get32le(s);
|
|
stbi__get16le(s);
|
|
stbi__get16le(s);
|
|
stbi__get32le(s);
|
|
sz = (int)stbi__get32le(s);
|
|
r = sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124 ? 1 : 0;
|
|
return r;
|
|
}
|
|
|
|
public static int stbi__bmp_set_mask_defaults(stbi__bmp_data* info, int compress)
|
|
{
|
|
if (compress == 3)
|
|
return 1;
|
|
if (compress == 0)
|
|
{
|
|
if (info->bpp == 16)
|
|
{
|
|
info->mr = 31u << 10;
|
|
info->mg = 31u << 5;
|
|
info->mb = 31u << 0;
|
|
}
|
|
else if (info->bpp == 32)
|
|
{
|
|
info->mr = 0xffu << 16;
|
|
info->mg = 0xffu << 8;
|
|
info->mb = 0xffu << 0;
|
|
info->ma = 0xffu << 24;
|
|
info->all_a = 0;
|
|
}
|
|
else
|
|
{
|
|
info->mr = info->mg = info->mb = info->ma = 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static void* stbi__bmp_parse_header(stbi__context s, stbi__bmp_data* info)
|
|
{
|
|
var hsz = 0;
|
|
if (stbi__get8(s) != 66 || stbi__get8(s) != 77)
|
|
return (byte*)(ulong)(stbi__err("not BMP") != 0 ? 0 : 0);
|
|
stbi__get32le(s);
|
|
stbi__get16le(s);
|
|
stbi__get16le(s);
|
|
info->offset = (int)stbi__get32le(s);
|
|
info->hsz = hsz = (int)stbi__get32le(s);
|
|
info->mr = info->mg = info->mb = info->ma = 0;
|
|
info->extra_read = 14;
|
|
if (info->offset < 0)
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124)
|
|
return (byte*)(ulong)(stbi__err("unknown BMP") != 0 ? 0 : 0);
|
|
if (hsz == 12)
|
|
{
|
|
s.img_x = (uint)stbi__get16le(s);
|
|
s.img_y = (uint)stbi__get16le(s);
|
|
}
|
|
else
|
|
{
|
|
s.img_x = stbi__get32le(s);
|
|
s.img_y = stbi__get32le(s);
|
|
}
|
|
|
|
if (stbi__get16le(s) != 1)
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
info->bpp = stbi__get16le(s);
|
|
if (hsz != 12)
|
|
{
|
|
var compress = (int)stbi__get32le(s);
|
|
if (compress == 1 || compress == 2)
|
|
return (byte*)(ulong)(stbi__err("BMP RLE") != 0 ? 0 : 0);
|
|
if (compress >= 4)
|
|
return (byte*)(ulong)(stbi__err("BMP JPEG/PNG") != 0 ? 0 : 0);
|
|
if (compress == 3 && info->bpp != 16 && info->bpp != 32)
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
if (hsz == 40 || hsz == 56)
|
|
{
|
|
if (hsz == 56)
|
|
{
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
}
|
|
|
|
if (info->bpp == 16 || info->bpp == 32)
|
|
{
|
|
if (compress == 0)
|
|
{
|
|
stbi__bmp_set_mask_defaults(info, compress);
|
|
}
|
|
else if (compress == 3)
|
|
{
|
|
info->mr = stbi__get32le(s);
|
|
info->mg = stbi__get32le(s);
|
|
info->mb = stbi__get32le(s);
|
|
info->extra_read += 12;
|
|
if (info->mr == info->mg && info->mg == info->mb)
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
}
|
|
else
|
|
{
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var i = 0;
|
|
if (hsz != 108 && hsz != 124)
|
|
return (byte*)(ulong)(stbi__err("bad BMP") != 0 ? 0 : 0);
|
|
info->mr = stbi__get32le(s);
|
|
info->mg = stbi__get32le(s);
|
|
info->mb = stbi__get32le(s);
|
|
info->ma = stbi__get32le(s);
|
|
if (compress != 3)
|
|
stbi__bmp_set_mask_defaults(info, compress);
|
|
stbi__get32le(s);
|
|
for (i = 0; i < 12; ++i)
|
|
stbi__get32le(s);
|
|
|
|
if (hsz == 124)
|
|
{
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
stbi__get32le(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
return (void*)1;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct stbi__bmp_data
|
|
{
|
|
public int bpp;
|
|
public int offset;
|
|
public int hsz;
|
|
public uint mr;
|
|
public uint mg;
|
|
public uint mb;
|
|
public uint ma;
|
|
public uint all_a;
|
|
public int extra_read;
|
|
}
|
|
}
|
|
}
|