1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
using System.Buffers.Binary;
using System.IO.Compression;
using System.Numerics;
using Raylib_cs;
namespace OnekoOnline;
class Bitmap : IDisposable
{
public readonly int Width;
public readonly int Height;
public readonly Texture2D Texture;
readonly byte[] SerializedData;
const int MaxWidth = 256;
const int MaxHeight = 256;
public Bitmap(Image img, int MaxW = 256, int MaxH = 256)
{
Width = img.Width;
Height = img.Height;
//Crop image if too big
if (Width > MaxW || Height > MaxH) Raylib.ImageCrop(ref img, new Rectangle(0f, 0f, MaxW, MaxH));
Texture = Raylib.LoadTextureFromImage(img);
//Get Data for Serialization
Color[] colors = new Color[Width*Height];
int i = 0;
for (int x = 0; x < Width; x++) {
for (int y = 0; y < Height; y++) {
colors[i] = Raylib.GetImageColor(img, x, y);
i++;
}
}
byte[] data = new byte[(colors.Length*4) + (sizeof(short)*2)];
BinaryPrimitives.WriteInt16LittleEndian(data.AsSpan(0, sizeof(short)), (short)Width);
BinaryPrimitives.WriteInt16LittleEndian(data.AsSpan(sizeof(short), sizeof(short)), (short)Height);
int position = sizeof(short)*2;
for (int c = 0; c < colors.Length; c++) {
data[position] = colors[c].R;
data[position+1] = colors[c].G;
data[position+2] = colors[c].B;
data[position+3] = colors[c].A;
position += 4;
}
using MemoryStream stream = new();
using DeflateStream compressor = new(stream, CompressionLevel.Optimal);
compressor.Write(data);
compressor.Close();
SerializedData = stream.ToArray();
Raylib.UnloadImage(img);
}
Bitmap(Image img, byte[] serializedData)
{
Width = img.Width;
Height = img.Height;
SerializedData = serializedData;
Texture = Raylib.LoadTextureFromImage(img);
Raylib.UnloadImage(img);
}
public static Bitmap FromFile(string path, int MaxW = MaxWidth, int MaxH = MaxHeight)
{
if (!File.Exists(path) || new FileInfo(path).Length > 40000 || !path.Contains(".png"))
return new Bitmap(Raylib.GenImageChecked(32, 32, 4, 4, Color.Black, Color.Pink));
byte[] memory = File.ReadAllBytes(path);
return FromPNGMemory(memory, MaxW, MaxH);
}
public static Bitmap FromPNGMemory(byte[] memory, int MaxW = MaxWidth, int MaxH = MaxHeight)
{
return new Bitmap(Raylib.LoadImageFromMemory(".png", memory), MaxW, MaxH);
}
public static Bitmap Deserialize(ReadOnlySpan<byte> span, int MaxW = MaxWidth, int MaxH = MaxHeight, byte[]? fallbackImage = null)
{
byte[] compressed = span.ToArray();
byte[] data;
{
using MemoryStream input = new(compressed);
using MemoryStream output = new();
using DeflateStream decompressor = new(input, CompressionMode.Decompress);
decompressor.CopyTo(output);
data = output.ToArray();
}
int width = BinaryPrimitives.ReadInt16LittleEndian(data.AsSpan(0, sizeof(short)));
int height = BinaryPrimitives.ReadInt16LittleEndian(data.AsSpan(sizeof(short), sizeof(short)));
bool TooBig = width > MaxW || height > MaxH;
if (TooBig) {
width = Math.Clamp(width, 0, MaxW);
height = Math.Clamp(height, 0, MaxH);
if (fallbackImage != null) return FromPNGMemory(fallbackImage, MaxW, MaxH);
}
Image img = Raylib.GenImageChecked(width, height, 4, 4, Color.Pink, Color.Black);
if (TooBig) return new Bitmap(img);
int i = sizeof(short)*2;
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
Color color = new(data[i], data[i+1], data[i+2], data[i+3]);
Raylib.ImageDrawPixel(ref img, x, y, color);
i += 4;
}
}
return new Bitmap(img, compressed);
}
public byte[] Serialize()
{
return SerializedData;
}
bool disposed = false;
public void Dispose()
{
if (disposed) return;
Raylib.UnloadTexture(Texture);
GC.SuppressFinalize(this);
disposed = true;
}
~Bitmap() => Dispose();
}
|