feat: 完成jpeg读取后端

This commit is contained in:
2025-08-15 21:04:50 +08:00
parent 774c9575d4
commit 3644c75304
3 changed files with 236 additions and 31 deletions

View File

@@ -72,7 +72,7 @@ public class Image
var b8 = (byte)((b5 * 255) / 31); // 5位扩展到8位
// 存储到 RGB24 数组
var rgb24Index = (i%2 == 0)?((i+1) * 3):((i-1) * 3);
var rgb24Index = (i % 2 == 0) ? ((i + 1) * 3) : ((i - 1) * 3);
rgb24Data[rgb24Index] = r8; // R
rgb24Data[rgb24Index + 1] = g8; // G
rgb24Data[rgb24Index + 2] = b8; // B
@@ -255,13 +255,169 @@ public class Image
return Encoding.ASCII.GetBytes("\r\n");
}
/// <summary>
/// 将原始 JPEG 数据补全 JPEG 头部,生成完整的 JPEG 图片
/// </summary>
/// <param name="jpegData">原始 JPEG 数据(可能缺少完整头部)</param>
/// <param name="width">图像宽度</param>
/// <param name="height">图像高度</param>
/// <param name="quality">JPEG质量1-100默认80</param>
/// <returns>完整的 JPEG 图片数据</returns>
public static Result<byte[]> CompleteJpegData(byte[] jpegData, int width, int height, int quality = 80)
{
if (jpegData == null)
return new(new ArgumentNullException(nameof(jpegData)));
if (width <= 0 || height <= 0)
return new(new ArgumentException("Width and height must be positive"));
if (quality < 1 || quality > 100)
return new(new ArgumentException("Quality must be between 1 and 100"));
try
{
// 检查是否已经是完整的 JPEG 文件(以 FFD8 开头FFD9 结尾)
if (jpegData.Length >= 4 &&
jpegData[0] == 0xFF && jpegData[1] == 0xD8 &&
jpegData[jpegData.Length - 2] == 0xFF && jpegData[jpegData.Length - 1] == 0xD9)
{
// 已经是完整的 JPEG 文件,直接返回
return jpegData;
}
// 创建一个临时的 RGB24 图像用于生成 JPEG 头部
using var tempImage = new SixLabors.ImageSharp.Image<Rgb24>(new Configuration
{
}, width, height);
// 填充临时图像(使用简单的渐变色作为占位符)
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
tempImage[x, y] = new Rgb24((byte)(x % 256), (byte)(y % 256), 128);
}
}
using var stream = new MemoryStream();
tempImage.SaveAsJpeg(stream, new JpegEncoder { Quality = quality });
var completeJpeg = stream.ToArray();
// 如果原始数据看起来是 JPEG 扫描数据,尝试替换扫描数据部分
if (jpegData.Length > 0)
{
// 查找 JPEG 扫描数据开始位置SOS 标记 0xFFDA 后)
int sosIndex = -1;
for (int i = 0; i < completeJpeg.Length - 1; i++)
{
if (completeJpeg[i] == 0xFF && completeJpeg[i + 1] == 0xDA)
{
// 跳过 SOS 段头部,找到实际扫描数据开始位置
i += 2; // 跳过 FF DA
if (i < completeJpeg.Length - 1)
{
int segmentLength = (completeJpeg[i] << 8) | completeJpeg[i + 1];
sosIndex = i + segmentLength;
break;
}
}
}
// 查找 EOI 标记位置0xFFD9
int eoiIndex = -1;
for (int i = completeJpeg.Length - 2; i >= 0; i--)
{
if (completeJpeg[i] == 0xFF && completeJpeg[i + 1] == 0xD9)
{
eoiIndex = i;
break;
}
}
if (sosIndex > 0 && eoiIndex > sosIndex)
{
// 替换扫描数据部分
var headerLength = sosIndex;
var footerStart = eoiIndex;
var footerLength = completeJpeg.Length - footerStart;
var newJpegLength = headerLength + jpegData.Length + footerLength;
var newJpegData = new byte[newJpegLength];
// 复制头部
Array.Copy(completeJpeg, 0, newJpegData, 0, headerLength);
// 复制原始扫描数据
Array.Copy(jpegData, 0, newJpegData, headerLength, jpegData.Length);
// 复制尾部
Array.Copy(completeJpeg, footerStart, newJpegData, headerLength + jpegData.Length, footerLength);
return newJpegData;
}
}
// 如果无法智能合并,返回完整的模板 JPEG
return completeJpeg;
}
catch (Exception ex)
{
return new(ex);
}
}
/// <summary>
/// 从 JPEG 数据生成 MJPEG 帧数据
/// </summary>
/// <param name="jpegData">完整的 JPEG 数据</param>
/// <param name="boundary">边界字符串(默认为"--boundary"</param>
/// <returns>MJPEG 帧数据</returns>
public static Result<(byte[] header, byte[] footer, byte[] data)> CreateMjpegFrameFromJpeg(
byte[] jpegData, string boundary = "--boundary")
{
if (jpegData == null)
return new(new ArgumentNullException(nameof(jpegData)));
// 验证是否为有效的 JPEG 数据
if (jpegData.Length < 4 || jpegData[0] != 0xFF || jpegData[1] != 0xD8)
{
return new(new ArgumentException("Invalid JPEG data: missing JPEG header"));
}
try
{
var header = CreateMjpegFrameHeader(jpegData.Length, boundary);
var footer = CreateMjpegFrameFooter();
var totalLength = header.Length + jpegData.Length + footer.Length;
var frameData = new byte[totalLength];
var offset = 0;
Array.Copy(header, 0, frameData, offset, header.Length);
offset += header.Length;
Array.Copy(jpegData, 0, frameData, offset, jpegData.Length);
offset += jpegData.Length;
Array.Copy(footer, 0, frameData, offset, footer.Length);
return (header, footer, frameData);
}
catch (Exception ex)
{
return new(ex);
}
}
/// <summary>
/// 创建完整的 MJPEG 帧数据
/// </summary>
/// <param name="jpegData">JPEG数据</param>
/// <param name="boundary">边界字符串(默认为"--boundary"</param>
/// <returns>完整的MJPEG帧数据</returns>
public static Result<byte[]> CreateMjpegFrame(byte[] jpegData, string boundary = "--boundary")
public static Result<(byte[] header, byte[] footer, byte[] data)> CreateMjpegFrame(
byte[] jpegData, string boundary = "--boundary")
{
if (jpegData == null)
return new(new ArgumentNullException(nameof(jpegData)));
@@ -283,7 +439,7 @@ public class Image
Array.Copy(footer, 0, frameData, offset, footer.Length);
return frameData;
return (header, footer, frameData);
}
catch (Exception ex)
{