RustDedicated/Assembly-CSharp/ImageProcessing.cs
2025-11-07 15:19:56 +10:30

494 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Collections;
using UnityEngine;
public static class ImageProcessing
{
private static byte[] signaturePNG = new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 };
private static byte[] signatureIHDR = new byte[8] { 0, 0, 0, 13, 73, 72, 68, 82 };
public static void GaussianBlur2D(float[] data, int len1, int len2, int iterations = 1)
{
float[] a = data;
float[] b = new float[len1 * len2];
for (int i = 0; i < iterations; i++)
{
for (int j = 0; j < len1; j++)
{
int num = Mathf.Max(0, j - 1);
int num2 = Mathf.Min(len1 - 1, j + 1);
for (int k = 0; k < len2; k++)
{
int num3 = Mathf.Max(0, k - 1);
int num4 = Mathf.Min(len2 - 1, k + 1);
float num5 = a[j * len2 + k] * 4f + a[j * len2 + num3] + a[j * len2 + num4] + a[num * len2 + k] + a[num2 * len2 + k];
b[j * len2 + k] = num5 * 0.125f;
}
}
GenericsUtil.Swap(ref a, ref b);
}
if (a != data)
{
Buffer.BlockCopy(a, 0, data, 0, data.Length * 4);
}
}
public static void GaussianBlur2D(float[] data, int len1, int len2, int len3, int iterations = 1)
{
float[] src = data;
float[] dst = new float[len1 * len2 * len3];
for (int i = 0; i < iterations; i++)
{
Parallel.For(0, len1, delegate(int x)
{
int num = Mathf.Max(0, x - 1);
int num2 = Mathf.Min(len1 - 1, x + 1);
for (int j = 0; j < len2; j++)
{
int num3 = Mathf.Max(0, j - 1);
int num4 = Mathf.Min(len2 - 1, j + 1);
for (int k = 0; k < len3; k++)
{
float num5 = src[(x * len2 + j) * len3 + k] * 4f + src[(x * len2 + num3) * len3 + k] + src[(x * len2 + num4) * len3 + k] + src[(num * len2 + j) * len3 + k] + src[(num2 * len2 + j) * len3 + k];
dst[(x * len2 + j) * len3 + k] = num5 * 0.125f;
}
}
});
GenericsUtil.Swap(ref src, ref dst);
}
if (src != data)
{
Buffer.BlockCopy(src, 0, data, 0, data.Length * 4);
}
}
public static void Average2D(float[] data, int len1, int len2, int iterations = 1)
{
float[] src = data;
float[] dst = new float[len1 * len2];
for (int i = 0; i < iterations; i++)
{
Parallel.For(0, len1, delegate(int x)
{
int num = Mathf.Max(0, x - 1);
int num2 = Mathf.Min(len1 - 1, x + 1);
for (int j = 0; j < len2; j++)
{
int num3 = Mathf.Max(0, j - 1);
int num4 = Mathf.Min(len2 - 1, j + 1);
float num5 = src[x * len2 + j] + src[x * len2 + num3] + src[x * len2 + num4] + src[num * len2 + j] + src[num2 * len2 + j];
dst[x * len2 + j] = num5 * 0.2f;
}
});
GenericsUtil.Swap(ref src, ref dst);
}
if (src != data)
{
Buffer.BlockCopy(src, 0, data, 0, data.Length * 4);
}
}
public static void Average2D(float[] data, int len1, int len2, int len3, int iterations = 1)
{
float[] src = data;
float[] dst = new float[len1 * len2 * len3];
for (int i = 0; i < iterations; i++)
{
Parallel.For(0, len1, delegate(int x)
{
int num = Mathf.Max(0, x - 1);
int num2 = Mathf.Min(len1 - 1, x + 1);
for (int j = 0; j < len2; j++)
{
int num3 = Mathf.Max(0, j - 1);
int num4 = Mathf.Min(len2 - 1, j + 1);
for (int k = 0; k < len3; k++)
{
float num5 = src[(x * len2 + j) * len3 + k] + src[(x * len2 + num3) * len3 + k] + src[(x * len2 + num4) * len3 + k] + src[(num * len2 + j) * len3 + k] + src[(num2 * len2 + j) * len3 + k];
dst[(x * len2 + j) * len3 + k] = num5 * 0.2f;
}
}
});
GenericsUtil.Swap(ref src, ref dst);
}
if (src != data)
{
Buffer.BlockCopy(src, 0, data, 0, data.Length * 4);
}
}
public static void Upsample2D(float[] src, int srclen1, int srclen2, float[] dst, int dstlen1, int dstlen2)
{
if (2 * srclen1 != dstlen1 || 2 * srclen2 != dstlen2)
{
return;
}
Parallel.For(0, srclen1, delegate(int x)
{
int num = Mathf.Max(0, x - 1);
int num2 = Mathf.Min(srclen1 - 1, x + 1);
for (int i = 0; i < srclen2; i++)
{
int num3 = Mathf.Max(0, i - 1);
int num4 = Mathf.Min(srclen2 - 1, i + 1);
float num5 = src[x * srclen2 + i] * 6f;
float num6 = num5 + src[num * srclen2 + i] + src[x * srclen2 + num3];
dst[2 * x * dstlen2 + 2 * i] = num6 * 0.125f;
float num7 = num5 + src[num2 * srclen2 + i] + src[x * srclen2 + num3];
dst[(2 * x + 1) * dstlen2 + 2 * i] = num7 * 0.125f;
float num8 = num5 + src[num * srclen2 + i] + src[x * srclen2 + num4];
dst[2 * x * dstlen2 + (2 * i + 1)] = num8 * 0.125f;
float num9 = num5 + src[num2 * srclen2 + i] + src[x * srclen2 + num4];
dst[(2 * x + 1) * dstlen2 + (2 * i + 1)] = num9 * 0.125f;
}
});
}
public static void Upsample2D(float[] src, int srclen1, int srclen2, int srclen3, float[] dst, int dstlen1, int dstlen2, int dstlen3)
{
if (2 * srclen1 != dstlen1 || 2 * srclen2 != dstlen2 || srclen3 != dstlen3)
{
return;
}
Parallel.For(0, srclen1, delegate(int x)
{
int num = Mathf.Max(0, x - 1);
int num2 = Mathf.Min(srclen1 - 1, x + 1);
for (int i = 0; i < srclen2; i++)
{
int num3 = Mathf.Max(0, i - 1);
int num4 = Mathf.Min(srclen2 - 1, i + 1);
for (int j = 0; j < srclen3; j++)
{
float num5 = src[(x * srclen2 + i) * srclen3 + j] * 6f;
float num6 = num5 + src[(num * srclen2 + i) * srclen3 + j] + src[(x * srclen2 + num3) * srclen3 + j];
dst[(2 * x * dstlen2 + 2 * i) * dstlen3 + j] = num6 * 0.125f;
float num7 = num5 + src[(num2 * srclen2 + i) * srclen3 + j] + src[(x * srclen2 + num3) * srclen3 + j];
dst[((2 * x + 1) * dstlen2 + 2 * i) * dstlen3 + j] = num7 * 0.125f;
float num8 = num5 + src[(num * srclen2 + i) * srclen3 + j] + src[(x * srclen2 + num4) * srclen3 + j];
dst[(2 * x * dstlen2 + (2 * i + 1)) * dstlen3 + j] = num8 * 0.125f;
float num9 = num5 + src[(num2 * srclen2 + i) * srclen3 + j] + src[(x * srclen2 + num4) * srclen3 + j];
dst[((2 * x + 1) * dstlen2 + (2 * i + 1)) * dstlen3 + j] = num9 * 0.125f;
}
}
});
}
public static void Dilate2D(NativeArray<int> src, int len1, int len2, int srcmask, int radius, Action<int, int> action)
{
Parallel.For(0, len1, delegate(int x)
{
MaxQueue maxQueue = new MaxQueue(radius * 2 + 1);
for (int i = 0; i < radius; i++)
{
maxQueue.Push(src[x * len2 + i] & srcmask);
}
for (int j = 0; j < len2; j++)
{
if (j > radius)
{
maxQueue.Pop();
}
if (j < len2 - radius)
{
maxQueue.Push(src[x * len2 + j + radius] & srcmask);
}
if (maxQueue.Max != 0)
{
action(x, j);
}
}
});
Parallel.For(0, len2, delegate(int y)
{
MaxQueue maxQueue = new MaxQueue(radius * 2 + 1);
for (int i = 0; i < radius; i++)
{
maxQueue.Push(src[i * len2 + y] & srcmask);
}
for (int j = 0; j < len1; j++)
{
if (j > radius)
{
maxQueue.Pop();
}
if (j < len1 - radius)
{
maxQueue.Push(src[(j + radius) * len2 + y] & srcmask);
}
if (maxQueue.Max != 0)
{
action(j, y);
}
}
});
}
public static void Dilate2D(int[] src, int len1, int len2, int srcmask, int radius, Action<int, int> action)
{
Parallel.For(0, len1, delegate(int x)
{
MaxQueue maxQueue = new MaxQueue(radius * 2 + 1);
for (int i = 0; i < radius; i++)
{
maxQueue.Push(src[x * len2 + i] & srcmask);
}
for (int j = 0; j < len2; j++)
{
if (j > radius)
{
maxQueue.Pop();
}
if (j < len2 - radius)
{
maxQueue.Push(src[x * len2 + j + radius] & srcmask);
}
if (maxQueue.Max != 0)
{
action(x, j);
}
}
});
Parallel.For(0, len2, delegate(int y)
{
MaxQueue maxQueue = new MaxQueue(radius * 2 + 1);
for (int i = 0; i < radius; i++)
{
maxQueue.Push(src[i * len2 + y] & srcmask);
}
for (int j = 0; j < len1; j++)
{
if (j > radius)
{
maxQueue.Pop();
}
if (j < len1 - radius)
{
maxQueue.Push(src[(j + radius) * len2 + y] & srcmask);
}
if (maxQueue.Max != 0)
{
action(j, y);
}
}
});
}
public static void FloodFill2D(int x, int y, int[] data, int len1, int len2, int mask_any, int mask_not, Func<int, int> action)
{
Stack<KeyValuePair<int, int>> stack = new Stack<KeyValuePair<int, int>>();
stack.Push(new KeyValuePair<int, int>(x, y));
while (stack.Count > 0)
{
KeyValuePair<int, int> keyValuePair = stack.Pop();
x = keyValuePair.Key;
y = keyValuePair.Value;
int num;
for (num = y; num >= 0; num--)
{
int num2 = data[x * len2 + num];
if ((num2 & mask_any) == 0 || (num2 & mask_not) != 0)
{
break;
}
}
num++;
bool flag2;
bool flag = (flag2 = false);
for (; num < len2; num++)
{
int num3 = data[x * len2 + num];
if ((num3 & mask_any) == 0 || (num3 & mask_not) != 0)
{
break;
}
data[x * len2 + num] = action(num3);
if (x > 0)
{
int num4 = data[(x - 1) * len2 + num];
bool flag3 = (num4 & mask_any) != 0 && (num4 & mask_not) == 0;
if (!flag && flag3)
{
stack.Push(new KeyValuePair<int, int>(x - 1, num));
flag = true;
}
else if (flag && !flag3)
{
flag = false;
}
}
if (x < len1 - 1)
{
int num5 = data[(x + 1) * len2 + num];
bool flag4 = (num5 & mask_any) != 0 && (num5 & mask_not) == 0;
if (!flag2 && flag4)
{
stack.Push(new KeyValuePair<int, int>(x + 1, num));
flag2 = true;
}
else if (flag2 && !flag4)
{
flag2 = false;
}
}
}
}
}
public static bool IsValidPNG(byte[] data, int maxSizeSquare)
{
return IsValidPNG(data, maxSizeSquare, maxSizeSquare);
}
public static bool IsValidPNG(byte[] data, int maxWidth, int maxHeight)
{
if (data == null || data.Length < 29)
{
return false;
}
if (data.Length > 29 + maxWidth * maxHeight * 4)
{
return false;
}
for (int i = 0; i < signaturePNG.Length; i++)
{
if (data[i] != signaturePNG[i])
{
return false;
}
}
for (int j = 0; j < signatureIHDR.Length; j++)
{
if (data[8 + j] != signatureIHDR[j])
{
return false;
}
}
Union32 union = new Union32
{
b4 = data[16],
b3 = data[17],
b2 = data[18],
b1 = data[19]
};
if (union.i < 1 || union.i > maxWidth)
{
return false;
}
Union32 union2 = new Union32
{
b4 = data[20],
b3 = data[21],
b2 = data[22],
b1 = data[23]
};
if (union2.i < 1 || union2.i > maxHeight)
{
return false;
}
byte b = data[24];
if (b != 8 && b != 16)
{
return false;
}
byte b2 = data[25];
if (b2 != 2 && b2 != 6)
{
return false;
}
if (data[26] != 0)
{
return false;
}
if (data[27] != 0)
{
return false;
}
if (data[28] != 0)
{
return false;
}
return true;
}
public static bool IsValidJPG(byte[] data, int maxSizeSquare)
{
return IsValidJPG(data, maxSizeSquare, maxSizeSquare);
}
public static bool IsValidJPG(byte[] data, int maxWidth, int maxHeight)
{
if (data.Length < 30)
{
return false;
}
if (data.Length > 30 + maxWidth * maxHeight)
{
return false;
}
try
{
if (data[0] != byte.MaxValue || data[1] != 216)
{
return false;
}
if (data[2] != byte.MaxValue || data[3] != 224)
{
return false;
}
if (data[6] != 74 || data[7] != 70 || data[8] != 73 || data[9] != 70 || data[10] != 0)
{
return false;
}
if (data[13] != 0)
{
return false;
}
if (data[14] != data[16] || data[15] != data[17])
{
return false;
}
int num = 4;
int num2 = (data[num] << 8) | data[num + 1];
while (num < data.Length)
{
num += num2;
if (num >= data.Length)
{
return false;
}
if (data[num] != byte.MaxValue)
{
return false;
}
if (data[num + 1] == 192 || data[num + 1] == 193 || data[num + 1] == 194)
{
int num3 = (data[num + 5] << 8) | data[num + 6];
return ((data[num + 7] << 8) | data[num + 8]) <= maxWidth && num3 <= maxHeight;
}
num += 2;
num2 = (data[num] << 8) | data[num + 1];
}
return false;
}
catch
{
return false;
}
}
public static bool IsClear(Color32[] data)
{
for (int i = 0; i < data.Length; i++)
{
if (data[i].a > 5)
{
return false;
}
}
return true;
}
}