9public static class SkiaExtensions
16 public static Rectangle ToRectangle(
this SKRect rect)
17 =>
Rectangle.FromLTRB((
int)rect.Left, (
int)rect.Top, (
int)rect.Right, (
int)rect.Bottom);
24 public static SKColor ToSKColor(
this Color color)
25 =>
new(color.R, color.G, color.B, color.A);
32 public static Color ToColor(
this SKColor skcolor)
33 => Color.FromArgb(skcolor.Alpha, skcolor.Red, skcolor.Green, skcolor.Blue);
40 public static SKRect ToSKRect(
this Rectangle rect)
41 =>
new(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
48 public static SKRect ToSKRect(
this RectangleF rect)
49 =>
new(rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
56 public static SKRectI ToSKRectI(
this Rectangle rect)
57 =>
new(rect.Left, rect.Top, rect.Right, rect.Bottom);
65 public static SKPoint[] ToSKPoints(
this Point[] points,
bool enclose =
false)
68 return points.Select(p =>
new SKPoint(p.X, p.Y)).ToArray(); ;
70 var len = points.Length + 1;
71 var result =
new SKPoint[len];
73 for (
int i = 0; i < points.Length; i++)
74 result[i] =
new SKPoint(points[i].X, points[i].Y);
77 result[^1] = result[0];
88 public static SKBitmap CopyRegion(
this SKBitmap source, Rectangle sourceRect)
90 if (source ==
null || source.IsEmpty)
91 throw new ArgumentException(
"Invalid source bitmap.", nameof(source));
93 if (sourceRect.Width <= 0 || sourceRect.Height <= 0)
94 throw new ArgumentException(
"Source rectangle must have positive size.", nameof(sourceRect));
96 var skSourceRect = sourceRect.ToSKRectI();
98 if (!source.Info.Rect.Contains(skSourceRect))
99 throw new ArgumentOutOfRangeException(nameof(sourceRect),
"Source rectangle is outside the bitmap bounds.");
101 var copy =
new SKBitmap(
new SKImageInfo(
104 source.Info.ColorType,
105 source.Info.AlphaType));
107 using var canvas =
new SKCanvas(copy);
109 canvas.Clear(SKColors.Transparent);
114 new SKRect(0, 0, sourceRect.Width, sourceRect.Height));
125 public static SKImage CopyRegion(
this SKImage source, Rectangle sourceRect)
128 throw new ArgumentNullException(nameof(source));
130 if (sourceRect.Width <= 0 || sourceRect.Height <= 0)
131 throw new ArgumentException(
"Source rectangle must have positive size.", nameof(sourceRect));
133 var skSourceRect =
new SKRect(
139 var skDestRect =
new SKRect(
145 var imageInfo =
new SKImageInfo(
152 using var surface = SKSurface.Create(imageInfo)
153 ??
throw new InvalidOperationException(
"Could not create SKSurface.");
155 surface.Canvas.Clear(SKColors.Transparent);
157 surface.Canvas.DrawImage(
162 return surface.Snapshot();
172 public static void SaveBitmapToFile(
this SKBitmap bitmap,
string filePath,
173 SKEncodedImageFormat format = SKEncodedImageFormat.Png,
int quality = 100)
175 if (bitmap ==
null || bitmap.IsEmpty)
176 throw new ArgumentException(
"Invalid bitmap.");
178 using var image = SKImage.FromBitmap(bitmap);
179 using var data = image.Encode(format, quality);
180 using var stream = File.OpenWrite(filePath);
191 public static byte[] EncodeBitmapToBytes(
this SKBitmap bitmap, SKEncodedImageFormat format = SKEncodedImageFormat.Png,
int quality = 100)
193 if (bitmap ==
null || bitmap.IsEmpty)
194 throw new ArgumentException(
"Invalid bitmap.");
196 using var image = SKImage.FromBitmap(bitmap);
197 using var data = image.Encode(format, quality);
198 return data.ToArray();
208 public static void ApplyAlphaMask(
this SKBitmap bitmap, SKColor targetColor,
byte tolerance = 5)
210 if (bitmap ==
null || bitmap.IsEmpty)
211 throw new ArgumentException(
"Invalid bitmap.");
213 int width = bitmap.Width;
214 int height = bitmap.Height;
216 for (
int y = 0; y < height; y++)
218 for (
int x = 0; x < width; x++)
220 var color = bitmap.GetPixel(x, y);
222 if (IsColorClose(color, targetColor, tolerance))
225 bitmap.SetPixel(x, y,
new SKColor(0, 0, 0, 0));
230 bitmap.NotifyPixelsChanged();
240 public static SKBitmap PremultiplyAlpha(
this SKBitmap bitmap)
242 if (bitmap ==
null || bitmap.IsEmpty)
243 throw new ArgumentException(
"Invalid bitmap.");
245 if (bitmap.AlphaType == SKAlphaType.Premul)
248 var info =
new SKImageInfo(bitmap.Width, bitmap.Height, bitmap.ColorType, SKAlphaType.Premul);
249 var premulBitmap =
new SKBitmap(info);
251 int width = bitmap.Width;
252 int height = bitmap.Height;
254 for (
int y = 0; y < height; y++)
256 for (
int x = 0; x < width; x++)
258 var c = bitmap.GetPixel(x, y);
261 byte r = (byte)((c.Red * a + 127) / 255);
262 byte g = (byte)((c.Green * a + 127) / 255);
263 byte b = (byte)((c.Blue * a + 127) / 255);
265 premulBitmap.SetPixel(x, y,
new SKColor(r, g, b, a));
269 premulBitmap.NotifyPixelsChanged();
273 private static bool IsColorClose(SKColor a, SKColor b,
byte tolerance)
276 Math.Abs(a.Red - b.Red) <= tolerance &&
277 Math.Abs(a.Green - b.Green) <= tolerance &&
278 Math.Abs(a.Blue - b.Blue) <= tolerance;
@ Rectangle
Particles are spawned uniformly within a rectangular area. This is the default distribution.