Files
UltimateFishing/Assets/Scripts/Assembly-CSharp/JPGEncoder.cs
2026-02-21 16:45:37 +08:00

635 lines
14 KiB
C#

using System;
using UnityEngine;
public class JPGEncoder
{
public int[] ZigZag = new int[64]
{
0, 1, 5, 6, 14, 15, 27, 28, 2, 4,
7, 13, 16, 26, 29, 42, 3, 8, 12, 17,
25, 30, 41, 43, 9, 11, 18, 24, 31, 40,
44, 53, 10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60, 21, 34,
37, 47, 50, 56, 59, 61, 35, 36, 48, 49,
57, 58, 62, 63
};
private int[] YTable = new int[64];
private int[] UVTable = new int[64];
private float[] fdtbl_Y = new float[64];
private float[] fdtbl_UV = new float[64];
private BitString[] YDC_HT;
private BitString[] UVDC_HT;
private BitString[] YAC_HT;
private BitString[] UVAC_HT;
private int[] std_dc_luminance_nrcodes = new int[17]
{
0, 0, 1, 5, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0
};
private int[] std_dc_luminance_values = new int[12]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11
};
private int[] std_ac_luminance_nrcodes = new int[17]
{
0, 0, 2, 1, 3, 3, 2, 4, 3, 5,
5, 4, 4, 0, 0, 1, 125
};
private int[] std_ac_luminance_values = new int[162]
{
1, 2, 3, 0, 4, 17, 5, 18, 33, 49,
65, 6, 19, 81, 97, 7, 34, 113, 20, 50,
129, 145, 161, 8, 35, 66, 177, 193, 21, 82,
209, 240, 36, 51, 98, 114, 130, 9, 10, 22,
23, 24, 25, 26, 37, 38, 39, 40, 41, 42,
52, 53, 54, 55, 56, 57, 58, 67, 68, 69,
70, 71, 72, 73, 74, 83, 84, 85, 86, 87,
88, 89, 90, 99, 100, 101, 102, 103, 104, 105,
106, 115, 116, 117, 118, 119, 120, 121, 122, 131,
132, 133, 134, 135, 136, 137, 138, 146, 147, 148,
149, 150, 151, 152, 153, 154, 162, 163, 164, 165,
166, 167, 168, 169, 170, 178, 179, 180, 181, 182,
183, 184, 185, 186, 194, 195, 196, 197, 198, 199,
200, 201, 202, 210, 211, 212, 213, 214, 215, 216,
217, 218, 225, 226, 227, 228, 229, 230, 231, 232,
233, 234, 241, 242, 243, 244, 245, 246, 247, 248,
249, 250
};
private int[] std_dc_chrominance_nrcodes = new int[17]
{
0, 0, 3, 1, 1, 1, 1, 1, 1, 1,
1, 1, 0, 0, 0, 0, 0
};
private int[] std_dc_chrominance_values = new int[12]
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11
};
private int[] std_ac_chrominance_nrcodes = new int[17]
{
0, 0, 2, 1, 2, 4, 4, 3, 4, 7,
5, 4, 4, 0, 1, 2, 119
};
private int[] std_ac_chrominance_values = new int[162]
{
0, 1, 2, 3, 17, 4, 5, 33, 49, 6,
18, 65, 81, 7, 97, 113, 19, 34, 50, 129,
8, 20, 66, 145, 161, 177, 193, 9, 35, 51,
82, 240, 21, 98, 114, 209, 10, 22, 36, 52,
225, 37, 241, 23, 24, 25, 26, 38, 39, 40,
41, 42, 53, 54, 55, 56, 57, 58, 67, 68,
69, 70, 71, 72, 73, 74, 83, 84, 85, 86,
87, 88, 89, 90, 99, 100, 101, 102, 103, 104,
105, 106, 115, 116, 117, 118, 119, 120, 121, 122,
130, 131, 132, 133, 134, 135, 136, 137, 138, 146,
147, 148, 149, 150, 151, 152, 153, 154, 162, 163,
164, 165, 166, 167, 168, 169, 170, 178, 179, 180,
181, 182, 183, 184, 185, 186, 194, 195, 196, 197,
198, 199, 200, 201, 202, 210, 211, 212, 213, 214,
215, 216, 217, 218, 226, 227, 228, 229, 230, 231,
232, 233, 234, 242, 243, 244, 245, 246, 247, 248,
249, 250
};
private BitString[] bitcode = new BitString[65535];
private int[] category = new int[65535];
private int bytenew;
private int bytepos = 7;
public ByteArray byteout = new ByteArray();
private int[] DU = new int[64];
private float[] YDU = new float[64];
private float[] UDU = new float[64];
private float[] VDU = new float[64];
public bool isDone;
private BitmapData image;
private int sf;
public JPGEncoder(Color[] pixels, int width, int height, float quality)
{
image = new BitmapData(pixels, width, height);
if (quality <= 0f)
{
quality = 1f;
}
if (quality > 100f)
{
quality = 100f;
}
if (quality < 50f)
{
sf = (int)(5000f / quality);
}
else
{
sf = (int)(200f - quality * 2f);
}
}
private void initQuantTables(int sf)
{
int[] array = new int[64]
{
16, 11, 10, 16, 24, 40, 51, 61, 12, 12,
14, 19, 26, 58, 60, 55, 14, 13, 16, 24,
40, 57, 69, 56, 14, 17, 22, 29, 51, 87,
80, 62, 18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92, 49, 64,
78, 87, 103, 121, 120, 101, 72, 92, 95, 98,
112, 100, 103, 99
};
int i;
for (i = 0; i < 64; i++)
{
float num = Mathf.Floor(((float)(array[i] * sf) + 50f) / 100f);
if (num < 1f)
{
num = 1f;
}
else if (num > 255f)
{
num = 255f;
}
YTable[ZigZag[i]] = (int)num;
}
int[] array2 = new int[64]
{
17, 18, 24, 47, 99, 99, 99, 99, 18, 21,
26, 66, 99, 99, 99, 99, 24, 26, 56, 99,
99, 99, 99, 99, 47, 66, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99
};
for (i = 0; i < 64; i++)
{
float num = Mathf.Floor(((float)(array2[i] * sf) + 50f) / 100f);
if (num < 1f)
{
num = 1f;
}
else if (num > 255f)
{
num = 255f;
}
UVTable[ZigZag[i]] = (int)num;
}
float[] array3 = new float[8] { 1f, 1.3870399f, 1.306563f, 1.1758755f, 1f, 0.78569496f, 0.5411961f, 0.27589938f };
i = 0;
for (int j = 0; j < 8; j++)
{
for (int k = 0; k < 8; k++)
{
fdtbl_Y[i] = 1f / ((float)YTable[ZigZag[i]] * array3[j] * array3[k] * 8f);
fdtbl_UV[i] = 1f / ((float)UVTable[ZigZag[i]] * array3[j] * array3[k] * 8f);
i++;
}
}
}
private BitString[] computeHuffmanTbl(int[] nrcodes, int[] std_table)
{
int num = 0;
int num2 = 0;
BitString[] array = new BitString[256];
for (int i = 1; i <= 16; i++)
{
for (int j = 1; j <= nrcodes[i]; j++)
{
array[std_table[num2]] = new BitString();
array[std_table[num2]].val = num;
array[std_table[num2]].len = i;
num2++;
num++;
}
num *= 2;
}
return array;
}
private void initHuffmanTbl()
{
YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_values);
UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes, std_dc_chrominance_values);
YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values);
UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
}
private void initCategoryfloat()
{
int num = 1;
int num2 = 2;
for (int i = 1; i <= 15; i++)
{
for (int j = num; j < num2; j++)
{
category[32767 + j] = i;
BitString bitString = new BitString();
bitString.len = i;
bitString.val = j;
bitcode[32767 + j] = bitString;
}
for (int j = -(num2 - 1); j <= -num; j++)
{
category[32767 + j] = i;
BitString bitString = new BitString();
bitString.len = i;
bitString.val = num2 - 1 + j;
bitcode[32767 + j] = bitString;
}
num <<= 1;
num2 <<= 1;
}
}
public byte[] GetBytes()
{
if (!isDone)
{
Debug.LogError("JPEGEncoder not complete, cannot get bytes!");
return new byte[1];
}
return byteout.GetAllBytes();
}
private void writeBits(BitString bs)
{
int val = bs.val;
int num = bs.len - 1;
while (num >= 0)
{
if (((uint)val & Convert.ToUInt32(1 << num)) != 0)
{
bytenew |= (int)Convert.ToUInt32(1 << bytepos);
}
num--;
bytepos--;
if (bytepos < 0)
{
if (bytenew == 255)
{
writeByte(byte.MaxValue);
writeByte(0);
}
else
{
writeByte((byte)bytenew);
}
bytepos = 7;
bytenew = 0;
}
}
}
private void writeByte(byte value)
{
byteout.writeByte(value);
}
private void writeWord(int value)
{
writeByte((byte)((value >> 8) & 0xFF));
writeByte((byte)(value & 0xFF));
}
private float[] fDCTQuant(float[] data, float[] fdtbl)
{
int num = 0;
for (int i = 0; i < 8; i++)
{
float num2 = data[num] + data[num + 7];
float num3 = data[num] - data[num + 7];
float num4 = data[num + 1] + data[num + 6];
float num5 = data[num + 1] - data[num + 6];
float num6 = data[num + 2] + data[num + 5];
float num7 = data[num + 2] - data[num + 5];
float num8 = data[num + 3] + data[num + 4];
float num9 = data[num + 3] - data[num + 4];
float num10 = num2 + num8;
float num11 = num2 - num8;
float num12 = num4 + num6;
float num13 = num4 - num6;
data[num] = num10 + num12;
data[num + 4] = num10 - num12;
float num14 = (num13 + num11) * 0.70710677f;
data[num + 2] = num11 + num14;
data[num + 6] = num11 - num14;
num10 = num9 + num7;
num12 = num7 + num5;
num13 = num5 + num3;
float num15 = (num10 - num13) * 0.38268343f;
float num16 = 0.5411961f * num10 + num15;
float num17 = 1.306563f * num13 + num15;
float num18 = num12 * 0.70710677f;
float num19 = num3 + num18;
float num20 = num3 - num18;
data[num + 5] = num20 + num16;
data[num + 3] = num20 - num16;
data[num + 1] = num19 + num17;
data[num + 7] = num19 - num17;
num += 8;
}
num = 0;
for (int i = 0; i < 8; i++)
{
float num2 = data[num] + data[num + 56];
float num3 = data[num] - data[num + 56];
float num4 = data[num + 8] + data[num + 48];
float num5 = data[num + 8] - data[num + 48];
float num6 = data[num + 16] + data[num + 40];
float num7 = data[num + 16] - data[num + 40];
float num8 = data[num + 24] + data[num + 32];
float num9 = data[num + 24] - data[num + 32];
float num10 = num2 + num8;
float num11 = num2 - num8;
float num12 = num4 + num6;
float num13 = num4 - num6;
data[num] = num10 + num12;
data[num + 32] = num10 - num12;
float num14 = (num13 + num11) * 0.70710677f;
data[num + 16] = num11 + num14;
data[num + 48] = num11 - num14;
num10 = num9 + num7;
num12 = num7 + num5;
num13 = num5 + num3;
float num15 = (num10 - num13) * 0.38268343f;
float num16 = 0.5411961f * num10 + num15;
float num17 = 1.306563f * num13 + num15;
float num18 = num12 * 0.70710677f;
float num19 = num3 + num18;
float num20 = num3 - num18;
data[num + 40] = num20 + num16;
data[num + 24] = num20 - num16;
data[num + 8] = num19 + num17;
data[num + 56] = num19 - num17;
num++;
}
for (int i = 0; i < 64; i++)
{
data[i] = Mathf.Round(data[i] * fdtbl[i]);
}
return data;
}
private void writeAPP0()
{
writeWord(65504);
writeWord(16);
writeByte(74);
writeByte(70);
writeByte(73);
writeByte(70);
writeByte(0);
writeByte(1);
writeByte(1);
writeByte(0);
writeWord(1);
writeWord(1);
writeByte(0);
writeByte(0);
}
private void writeSOF0(int width, int height)
{
writeWord(65472);
writeWord(17);
writeByte(8);
writeWord(height);
writeWord(width);
writeByte(3);
writeByte(1);
writeByte(17);
writeByte(0);
writeByte(2);
writeByte(17);
writeByte(1);
writeByte(3);
writeByte(17);
writeByte(1);
}
private void writeDQT()
{
writeWord(65499);
writeWord(132);
writeByte(0);
for (int i = 0; i < 64; i++)
{
writeByte((byte)YTable[i]);
}
writeByte(1);
for (int i = 0; i < 64; i++)
{
writeByte((byte)UVTable[i]);
}
}
private void writeDHT()
{
writeWord(65476);
writeWord(418);
writeByte(0);
for (int i = 0; i < 16; i++)
{
writeByte((byte)std_dc_luminance_nrcodes[i + 1]);
}
for (int i = 0; i <= 11; i++)
{
writeByte((byte)std_dc_luminance_values[i]);
}
writeByte(16);
for (int i = 0; i < 16; i++)
{
writeByte((byte)std_ac_luminance_nrcodes[i + 1]);
}
for (int i = 0; i <= 161; i++)
{
writeByte((byte)std_ac_luminance_values[i]);
}
writeByte(1);
for (int i = 0; i < 16; i++)
{
writeByte((byte)std_dc_chrominance_nrcodes[i + 1]);
}
for (int i = 0; i <= 11; i++)
{
writeByte((byte)std_dc_chrominance_values[i]);
}
writeByte(17);
for (int i = 0; i < 16; i++)
{
writeByte((byte)std_ac_chrominance_nrcodes[i + 1]);
}
for (int i = 0; i <= 161; i++)
{
writeByte((byte)std_ac_chrominance_values[i]);
}
}
private void writeSOS()
{
writeWord(65498);
writeWord(12);
writeByte(3);
writeByte(1);
writeByte(0);
writeByte(2);
writeByte(17);
writeByte(3);
writeByte(17);
writeByte(0);
writeByte(63);
writeByte(0);
}
private float processDU(float[] CDU, float[] fdtbl, float DC, BitString[] HTDC, BitString[] HTAC)
{
BitString bs = HTAC[0];
BitString bs2 = HTAC[240];
float[] array = fDCTQuant(CDU, fdtbl);
for (int i = 0; i < 64; i++)
{
DU[ZigZag[i]] = (int)array[i];
}
int num = (int)((float)DU[0] - DC);
DC = DU[0];
if (num == 0)
{
writeBits(HTDC[0]);
}
else
{
writeBits(HTDC[category[32767 + num]]);
writeBits(bitcode[32767 + num]);
}
int num2 = 63;
while (num2 > 0 && DU[num2] == 0)
{
num2--;
}
if (num2 == 0)
{
writeBits(bs);
return DC;
}
for (int i = 1; i <= num2; i++)
{
int num3 = i;
for (; DU[i] == 0 && i <= num2; i++)
{
}
int num4 = i - num3;
if (num4 >= 16)
{
for (int j = 1; j <= num4 / 16; j++)
{
writeBits(bs2);
}
num4 &= 0xF;
}
writeBits(HTAC[num4 * 16 + category[32767 + DU[i]]]);
writeBits(bitcode[32767 + DU[i]]);
}
if (num2 != 63)
{
writeBits(bs);
}
return DC;
}
private void RGB2YUV(BitmapData img, int xpos, int ypos)
{
int num = 0;
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
Color pixelColor = img.getPixelColor(xpos + j, img.height - (ypos + i));
float num2 = pixelColor.r * 255f;
float num3 = pixelColor.g * 255f;
float num4 = pixelColor.b * 255f;
YDU[num] = 0.299f * num2 + 0.587f * num3 + 0.114f * num4 - 128f;
UDU[num] = -0.16874f * num2 + -0.33126f * num3 + 0.5f * num4;
VDU[num] = 0.5f * num2 + -0.41869f * num3 + -0.08131f * num4;
num++;
}
}
}
public void doEncoding()
{
isDone = false;
initHuffmanTbl();
initCategoryfloat();
initQuantTables(sf);
encode();
isDone = true;
image = null;
}
private void encode()
{
byteout = new ByteArray();
bytenew = 0;
bytepos = 7;
writeWord(65496);
writeAPP0();
writeDQT();
writeSOF0(image.width, image.height);
writeDHT();
writeSOS();
float dC = 0f;
float dC2 = 0f;
float dC3 = 0f;
bytenew = 0;
bytepos = 7;
for (int i = 0; i < image.height; i += 8)
{
for (int j = 0; j < image.width; j += 8)
{
RGB2YUV(image, j, i);
dC = processDU(YDU, fdtbl_Y, dC, YDC_HT, YAC_HT);
dC2 = processDU(UDU, fdtbl_UV, dC2, UVDC_HT, UVAC_HT);
dC3 = processDU(VDU, fdtbl_UV, dC3, UVDC_HT, UVAC_HT);
}
}
if (bytepos >= 0)
{
BitString bitString = new BitString();
bitString.len = bytepos + 1;
bitString.val = (1 << bytepos + 1) - 1;
writeBits(bitString);
}
writeWord(65497);
isDone = true;
}
}