Survivalcraft API 1.8.2.3 v1.8.2.3
Survivalcraft 2.4
载入中...
搜索中...
未找到
Image.cs
浏览该文件的文档.
1using System.Runtime.InteropServices;
2using SixLabors.ImageSharp;
3using SixLabors.ImageSharp.Formats;
4using SixLabors.ImageSharp.Formats.Bmp;
5using SixLabors.ImageSharp.Formats.Gif;
6using SixLabors.ImageSharp.Formats.Jpeg;
7using SixLabors.ImageSharp.Formats.Pbm;
8using SixLabors.ImageSharp.Formats.Png;
9using SixLabors.ImageSharp.Formats.Qoi;
10using SixLabors.ImageSharp.Formats.Tga;
11using SixLabors.ImageSharp.Formats.Tiff;
12using SixLabors.ImageSharp.Formats.Webp;
13using SixLabors.ImageSharp.PixelFormats;
14
15namespace Engine.Media {
16 public class Image {
17 public static IImageFormatConfigurationModule[] ImageSharpModules = [
18 new BmpConfigurationModule(),
19 new GifConfigurationModule(),
20 new JpegConfigurationModule(),
21 new PbmConfigurationModule(),
22 new PngConfigurationModule(),
23 new QoiConfigurationModule(),
24 new TgaConfigurationModule(),
25 new TiffConfigurationModule(),
26 new WebpConfigurationModule()
27 ];
28
29 public static Configuration DefaultImageSharpConfiguration = new(ImageSharpModules) { PreferContiguousImageBuffers = true };
30 public static DecoderOptions DefaultImageSharpDecoderOptions = new() { Configuration = DefaultImageSharpConfiguration };
31 public static readonly JpegEncoder DefaultJpegEncoder = new() { Quality = 95, ColorType = JpegEncodingColor.YCbCrRatio420 };
32 public static readonly GifEncoder DefaultGifEncoder = new() { ColorTableMode = GifColorTableMode.Local };
33
34 public int Width => m_trueImage.Width;
35
36 public int Height => m_trueImage.Height;
37
38 public Color[] m_pixels;
39 public bool m_shouldUpdatePixelsCache = true;
40
41 public Color[] Pixels {
42 get {
43 if (m_pixels == null || m_shouldUpdatePixelsCache) {
44 m_pixels = new Color[Width * Height];
46 accessor => {
47 Span<Color> pixelsSpan = m_pixels.AsSpan();
48 for (int y = 0; y < accessor.Height; y++) {
49 MemoryMarshal.Cast<Rgba32, Color>(accessor.GetRowSpan(y)).CopyTo(pixelsSpan.Slice(y * Width, Width));
50 }
51 },
52 false
53 );
54 }
56 return m_pixels;
57 }
58 }
59
60 public readonly Image<Rgba32> m_trueImage;
61 public bool m_isDisposed;
62
63 public Image() {}
64
65 public Image(Image image) {
66 ArgumentNullException.ThrowIfNull(image);
67 m_trueImage = image.m_trueImage.Clone();
68 }
69
70 public Image(Image<Rgba32> image) {
71 ArgumentNullException.ThrowIfNull(image);
72 m_trueImage = image;
73 }
74
75 public Image(LegacyImage image) {
76 ArgumentNullException.ThrowIfNull(image);
78 ProcessPixelRows(accessor => {
79 Span<Color> pixels = image.Pixels.AsSpan();
80 for (int y = 0; y < accessor.Height; y++) {
81 MemoryMarshal.Cast<Color, Rgba32>(pixels.Slice(y * image.Width, image.Height)).CopyTo(accessor.GetRowSpan(y));
82 }
83 }
84 );
85 }
86
87 public Image(int width, int height) {
88 if (width < 0) {
89 throw new ArgumentOutOfRangeException(nameof(width));
90 }
91 if (height < 0) {
92 throw new ArgumentOutOfRangeException(nameof(height));
93 }
95 }
96
97 public Rgba32 GetPixelFast(int x, int y) => m_trueImage[x, y];
98
99 public Color GetPixel(int x, int y) => x < 0 || x >= Width ? throw new ArgumentOutOfRangeException(nameof(x)) :
100 y < 0 || y >= Height ? throw new ArgumentOutOfRangeException(nameof(y)) : new Color(m_trueImage[x, y].PackedValue);
101
102 public Rgba32 SetPixelFast(int x, int y, Rgba32 color) => m_trueImage[x, y] = color;
103
104 public void SetPixel(int x, int y, Color color) {
105 if (x < 0
106 || x >= Width) {
107 throw new ArgumentOutOfRangeException(nameof(x));
108 }
109 if (y < 0
110 || y >= Height) {
111 throw new ArgumentOutOfRangeException(nameof(y));
112 }
113 m_trueImage[x, y] = new Rgba32(color.PackedValue);
115 }
116
117 public static void PremultiplyAlpha(Image image) => image.ProcessPixels(pixel => pixel.PremultiplyAlpha());
118
119 public static ImageFileFormat DetermineFileFormat(string extension) =>
120 Name2EngineImageFormat.TryGetValue(extension.Substring(1).ToLower(), out ImageFileFormat format)
121 ? format
122 : throw new InvalidOperationException("Unsupported image file format.");
123
124 public static ImageFileFormat DetermineFileFormat(Stream stream) =>
125 Name2EngineImageFormat.TryGetValue(SixLabors.ImageSharp.Image.DetectFormat(stream).Name.ToLower(), out ImageFileFormat format)
126 ? format
127 : throw new InvalidOperationException("Unsupported image file format.");
128
129 public static Image Load(Stream stream, ImageFileFormat format) =>
130 Name2EngineImageFormat.TryGetValue(SixLabors.ImageSharp.Image.DetectFormat(stream).Name.ToLower(), out ImageFileFormat IdentifiedFormat)
131 && IdentifiedFormat == format
132 ? Load(stream)
133 : throw new FormatException($"Image format({IdentifiedFormat}) is not ${format}");
134
135 public static Image Load(string fileName, ImageFileFormat format) {
136 using (Stream stream = Storage.OpenFile(fileName, OpenFileMode.Read)) {
137 return Load(stream, format);
138 }
139 }
140
141 public static Image Load(Stream stream) => new(SixLabors.ImageSharp.Image.Load<Rgba32>(DefaultImageSharpDecoderOptions, stream));
142
143 public static Image Load(string fileName) {
144 using (Stream stream = Storage.OpenFile(fileName, OpenFileMode.Read)) {
145 return Load(stream);
146 }
147 }
148
149 public static void Save(Image image, Stream stream, ImageFileFormat format, bool saveAlpha, bool sync = false) {
150 switch (format) {
151 case ImageFileFormat.Bmp: {
152 BmpEncoder encoder = new() { BitsPerPixel = saveAlpha ? BmpBitsPerPixel.Pixel32 : BmpBitsPerPixel.Pixel24 };
153 if (sync) {
154 image.m_trueImage.SaveAsBmp(stream, encoder);
155 }
156 else {
157 image.m_trueImage.SaveAsBmpAsync(stream, encoder);
158 }
159 break;
160 }
161 case ImageFileFormat.Png: {
162 PngEncoder encoder = new() {
163 ColorType = saveAlpha ? PngColorType.RgbWithAlpha : PngColorType.Rgb, TransparentColorMode = PngTransparentColorMode.Clear
164 };
165 if (sync) {
166 image.m_trueImage.SaveAsPng(stream, encoder);
167 }
168 else {
169 image.m_trueImage.SaveAsPngAsync(stream, encoder);
170 }
171 break;
172 }
173 case ImageFileFormat.Jpg: {
174 if (sync) {
175 image.m_trueImage.SaveAsJpeg(stream, DefaultJpegEncoder);
176 }
177 else {
178 image.m_trueImage.SaveAsJpegAsync(stream, DefaultJpegEncoder);
179 }
180 break;
181 }
182 case ImageFileFormat.Gif:
183 if (sync) {
184 image.m_trueImage.SaveAsGif(stream, DefaultGifEncoder);
185 }
186 else {
187 image.m_trueImage.SaveAsGifAsync(stream, DefaultGifEncoder);
188 }
189 break;
190 case ImageFileFormat.Pbm:
191 if (sync) {
192 image.m_trueImage.SaveAsPbm(stream);
193 }
194 else {
195 image.m_trueImage.SaveAsPbmAsync(stream);
196 }
197 break;
198 case ImageFileFormat.Qoi: {
199 QoiEncoder encoder = new() {
200 ColorSpace = QoiColorSpace.SrgbWithLinearAlpha, Channels = saveAlpha ? QoiChannels.Rgba : QoiChannels.Rgb
201 };
202 if (sync) {
203 image.m_trueImage.SaveAsQoi(stream, encoder);
204 }
205 else {
206 image.m_trueImage.SaveAsQoiAsync(stream, encoder);
207 }
208 break;
209 }
210 case ImageFileFormat.Tiff: {
211 TiffEncoder encoder = new() { BitsPerPixel = saveAlpha ? TiffBitsPerPixel.Bit32 : TiffBitsPerPixel.Bit24 };
212 if (sync) {
213 image.m_trueImage.SaveAsTiff(stream, encoder);
214 }
215 else {
216 image.m_trueImage.SaveAsTiffAsync(stream, encoder);
217 }
218 break;
219 }
220 case ImageFileFormat.Tga: {
221 TgaEncoder encoder = new() {
222 BitsPerPixel = saveAlpha ? TgaBitsPerPixel.Pixel32 : TgaBitsPerPixel.Pixel24, Compression = TgaCompression.RunLength
223 };
224 if (sync) {
225 image.m_trueImage.SaveAsTga(stream, encoder);
226 }
227 else {
228 image.m_trueImage.SaveAsTgaAsync(stream, encoder);
229 }
230 break;
231 }
232 case ImageFileFormat.WebP: {
233 WebpEncoder encoder = new() {
234 TransparentColorMode = saveAlpha ? WebpTransparentColorMode.Preserve : WebpTransparentColorMode.Clear,
235 FileFormat = WebpFileFormatType.Lossless
236 };
237 if (sync) {
238 image.m_trueImage.SaveAsWebp(stream, encoder);
239 }
240 else {
241 image.m_trueImage.SaveAsWebpAsync(stream, encoder);
242 }
243 break;
244 }
245 default: throw new InvalidOperationException("Unsupported image file format.");
246 }
247 }
248
249 public static void Save(Image image, string fileName, ImageFileFormat format, bool saveAlpha) {
250 using (Stream stream = Storage.OpenFile(fileName, OpenFileMode.Create)) {
251 Save(image, stream, format, saveAlpha);
252 }
253 }
254
255 public void ProcessPixelRows(PixelAccessorAction<Rgba32> accessorAction, bool shouldUpdatePixelsCache = true) {
256 m_trueImage.ProcessPixelRows(accessorAction);
257 if (shouldUpdatePixelsCache) {
259 }
260 }
261
262 public void ProcessPixels(Func<Rgba32, Rgba32> pixelFunc, bool shouldUpdatePixelsCache = true) {
264 accessor => {
265 for (int y = 0; y < accessor.Height; y++) {
266 foreach (ref Rgba32 pixel in accessor.GetRowSpan(y)) {
267 pixel = pixelFunc(pixel);
268 }
269 }
270 },
271 shouldUpdatePixelsCache
272 );
273 }
274
275 public static readonly Dictionary<string, ImageFileFormat> Name2EngineImageFormat = new() {
276 { "bmp", ImageFileFormat.Bmp },
277 { "png", ImageFileFormat.Png },
278 { "jpg", ImageFileFormat.Jpg },
279 { "jpeg", ImageFileFormat.Jpg },
280 { "gif", ImageFileFormat.Gif },
281 { "pbm", ImageFileFormat.Pbm },
282 { "qoi", ImageFileFormat.Qoi },
283 { "tiff", ImageFileFormat.Tiff },
284 { "tga", ImageFileFormat.Tga },
285 { "webp", ImageFileFormat.WebP }
286 };
287
288 public void Dispose() {
289 if (!m_isDisposed) {
290 m_isDisposed = true;
291 m_pixels = null;
292 m_trueImage.Dispose();
293 }
294 }
295
296 public static implicit operator Image(Image<Rgba32> image) => new(image);
297
298 public static implicit operator Image<Rgba32>(Image image) => image.m_trueImage;
299 }
300}
static readonly JpegEncoder DefaultJpegEncoder
Image(int width, int height)
void SetPixel(int x, int y, Color color)
Color GetPixel(int x, int y)
Image(Image image)
Image(Image< Rgba32 > image)
static DecoderOptions DefaultImageSharpDecoderOptions
Rgba32 SetPixelFast(int x, int y, Rgba32 color)
static ImageFileFormat DetermineFileFormat(string extension)
static Image Load(string fileName)
static Image Load(Stream stream, ImageFileFormat format)
static Image Load(Stream stream)
readonly Image< Rgba32 > m_trueImage
static Image Load(string fileName, ImageFileFormat format)
bool m_shouldUpdatePixelsCache
static IImageFormatConfigurationModule[] ImageSharpModules
static ImageFileFormat DetermineFileFormat(Stream stream)
static void PremultiplyAlpha(Image image)
void ProcessPixels(Func< Rgba32, Rgba32 > pixelFunc, bool shouldUpdatePixelsCache=true)
static Configuration DefaultImageSharpConfiguration
static readonly GifEncoder DefaultGifEncoder
Image(LegacyImage image)
static void Save(Image image, Stream stream, ImageFileFormat format, bool saveAlpha, bool sync=false)
static void Save(Image image, string fileName, ImageFileFormat format, bool saveAlpha)
void ProcessPixelRows(PixelAccessorAction< Rgba32 > accessorAction, bool shouldUpdatePixelsCache=true)
Rgba32 GetPixelFast(int x, int y)
static readonly Dictionary< string, ImageFileFormat > Name2EngineImageFormat
static Stream OpenFile(string path, OpenFileMode openFileMode)
uint PackedValue
定义 Color.cs:3