缩略图读取测试

main
陈伟 1 month ago
parent 8094bfc7fd
commit 913f3d40c9

@ -14,7 +14,9 @@
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="DocXCore.Standard" Version="1.0.1" />
<PackageReference Include="EnyimMemcachedCore" Version="2.6.4" />
<PackageReference Include="ExifLib" Version="1.7.0" />
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="MetadataExtractor" Version="2.8.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Minio" Version="6.0.4" />

@ -1,19 +1,507 @@
using System.Dynamic;
using System.Drawing;
using System.Drawing.Imaging;
using Infrastructure.CloudSdk.minio;
using Infrastructure.CloudSdk.wayline;
using Infrastructure.Extensions;
using Infrastructure.Utilities;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
namespace OpenAuth.WebApi.boot;
public class TestAbc
{
[Test]
//[Test]
public void TestDser()
{
var json =
@"{""bid"":""e62da5f5-acaa-442a-8134-38ea56f88347"",""data"":{""result"":319003},""method"":""flighttask_execute"",""tid"":""6d638f18-20d7-4625-ac58-3cca1e5d100e"",""timestamp"":1750379532217}";
@" {""bid"":""67fea48d-d350-45c4-babb-df5256907172"",""data"":{""result"":0},""method"":""flighttask_prepare"",""tid"":""dc89588c-0f68-4d5e-91e2-a5d678efd429"",""timestamp"":1750406045000}
";
var result = JsonConvert.DeserializeObject<TopicServicesRequest<dynamic>>(json);
long code = result.data.result;
long code = result.data.result;
Console.WriteLine(code);
}
//[Test]
public void TestGetSuffix()
{
var fileName = "test.jpg";
var suffix = Path.GetExtension(fileName);
Console.WriteLine(suffix);
}
//[Test]
public async Task TestTempLink()
{
MinioService minioService = new MinioService();
// 76382c23-8c63-44b7-acb7-c9b69e85b526/3893eb7c-7f24-4ae0-8291-01c13a39ebc6/DJI_202506301510_002_3893eb7c-7f24-4ae0-8291-01c13a39ebc6/
string url = await minioService.GetObjectUrl("test",
"76382c23-8c63-44b7-acb7-c9b69e85b526/3893eb7c-7f24-4ae0-8291-01c13a39ebc6/DJI_202506301510_002_3893eb7c-7f24-4ae0-8291-01c13a39ebc6/DJI_20250630151113_0001_V.jpeg");
Console.Write(url);
}
//[Test]
public void TestSubstring()
{
var str1 = "2025-07-04"; //
var str2 = "dev/2025-07-04/abc/";
var index = str2.IndexOf(str1) + str1.Length;
Console.WriteLine(index);
Console.WriteLine(str2.Substring(index));
}
//[Test]
public void TestJson()
{
var json =
"{\n \"bid\": \"1d988af7-aa93-4141-9d9b-b29e437f2338\",\n \"data\": {\n \"file\": {\n \"cloud_to_cloud_id\": \"DEFAULT\",\n \"ext\": {\n \"drone_model_key\": \"0-100-1\",\n \"flight_id\": \"9ab67dc0-6e6f-4c58-a178-bef76f7e0b15\",\n \"is_original\": true,\n \"media_index\": 525705,\n \"payload_model_key\": \"1-99-0\"\n },\n \"metadata\": {\n \"absolute_altitude\": 157.967,\n \"created_time\": \"2025-07-11T11:15:02+08:00\",\n \"gimbal_yaw_degree\": -44.7,\n \"relative_altitude\": 76.584,\n \"shoot_position\": {\n \"lat\": 35.13427,\n \"lng\": 118.29459541666667\n }\n },\n \"name\": \"DJI_20250711111502_0088_V.jpeg\",\n \"object_key\": \"6196fb6b-3753-4885-a085-1b91713349f3/9ab67dc0-6e6f-4c58-a178-bef76f7e0b15/DJI_202507111111_002_9ab67dc0-6e6f-4c58-a178-bef76f7e0b15/DJI_20250711111502_0088_V.jpeg\",\n \"path\": \"\"\n },\n \"flight_task\": {\n \"expected_file_count\": 91,\n \"flight_type\": 0,\n \"uploaded_file_count\": 91\n },\n \"progress\": 0,\n \"result\": 0\n },\n \"method\": \"file_upload_callback\",\n \"need_reply\": 1,\n \"tid\": \"80803634-94c5-4cac-92fe-8a36e09c9a00\",\n \"timestamp\": 1752203903285,\n \"gateway\": \"8UUXN5400A079H\"\n}";
var result = JsonConvert.DeserializeObject<TopicServicesRequest<dynamic>>(json);
var data = result.data;
Console.WriteLine(data.flight_task.flight_type);
Console.WriteLine(data.file.ext.drone_model_key);
Console.WriteLine(data.file.ext.flight_id);
Console.WriteLine(data.file.ext.media_index);
Console.WriteLine(data.file.ext.payload_model_key);
Console.WriteLine(data.file.metadata.absolute_altitude);
Console.WriteLine(data.file.metadata.created_time);
Console.WriteLine(data.file.metadata.gimbal_yaw_degree);
Console.WriteLine(data.file.metadata.relative_altitude);
Console.WriteLine(data.file.metadata.shoot_position.lat);
Console.WriteLine(data.file.metadata.shoot_position.lng);
Console.WriteLine(data.file.name);
Console.WriteLine(data.file.object_key);
Console.WriteLine(data.file.path);
if (result.need_reply.Equals(1))
{
Console.WriteLine("需要回复");
}
Console.WriteLine(result.need_reply);
string createdTime = data.file.metadata.created_time;
Console.WriteLine(createdTime.ToDateTime());
}
//[Test]
public void TestCombi()
{
string tempPath = Path.GetTempPath();
Console.WriteLine(tempPath);
}
// [Test]
public void TestTimeZone()
{
long[] times =
{
1753146586552,
1753146587621,
1753146587744,
1753146588532,
1753146588822,
1753146588959,
1753146590022,
1753146590155,
1753146590533,
1753146591251,
1753146591376,
1753146592452,
1753146592582,
1753146593668,
1753146593792,
};
var y = times[0];
foreach (var time in times)
{
var x = DateTimeOffset.FromUnixTimeMilliseconds(time);
Console.WriteLine(x.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss:fff") + $" {time - y}");
y = time;
}
}
//[Test]
public void Test()
{
var content =
"{\"cityid\":\"101120911\",\"date\":\"2025-08-01\",\"week\":\"星期五\",\"update_time\":\"10:18\",\"city\":\"兰山\",\"cityEn\":\"lanshan\",\"country\":\"中国\",\"countryEn\":\"China\",\"wea\":\"多云\",\"wea_img\":\"yun\",\"tem\":\"27.8\",\"tem1\":\"30\",\"tem2\":\"26\",\"win\":\"东北风\",\"win_speed\":\"3级\",\"win_meter\":\"12km/h\",\"humidity\":\"87%\",\"visibility\":\"16km\",\"pressure\":\"987\",\"air\":\"27\",\"air_pm25\":\"17\",\"air_level\":\"优\",\"air_tips\":\"各类人群可多参加户外活动,多呼吸一下清新的空气。\",\"alarm\":{\"alarm_type\":\"暴雨\",\"alarm_level\":\"蓝色\",\"alarm_title\":\"山东省发布暴雨蓝色预警\",\"alarm_content\":\"山东省气象台于8月1日06时00分继续发布暴雨蓝色预警预计1日白天到夜间临沂和枣庄有小到中雨局部暴雨并伴有雷电日照、青岛、威海和烟台有雷雨或阵雨局部大雨或暴雨鲁西北地区天气多云其他地区局部有雷雨或阵雨雷雨地区雷雨时阵风7\uff5e9级。预警信息来源国家预警信息发布中心\"},\"rain_pcpn\":\"3.8\",\"uvIndex\":\"2\",\"uvDescription\":\"低\",\"wea_day\":\"中雨\",\"wea_day_img\":\"yu\",\"wea_night\":\"小雨\",\"wea_night_img\":\"yu\",\"sunrise\":\"05:15\",\"sunset\":\"19:10\",\"aqi\":{\"update_time\":\"08:05\",\"air\":\"27\",\"air_level\":\"优\",\"air_tips\":\"各类人群可多参加户外活动,多呼吸一下清新的空气。\",\"pm25\":\"17\",\"pm25_desc\":\"优\",\"pm10\":\"27\",\"pm10_desc\":\"优\",\"o3\":\"21\",\"o3_desc\":\"\",\"no2\":\"14\",\"no2_desc\":\"\",\"so2\":\"9\",\"so2_desc\":\"\",\"co\":\"0.4\",\"co_desc\":\"\",\"kouzhao\":\"不用佩戴口罩\",\"yundong\":\"适宜运动\",\"waichu\":\"适宜外出\",\"kaichuang\":\"适宜开窗\",\"jinghuaqi\":\"不需要打开\"},\"nums\":14}";
var weather = JsonConvert.DeserializeObject<JObject>(content);
var win_meter = weather.GetValue("win_mete")?.Value<string>(); // 风速
Console.WriteLine(win_meter);
}
static void ReadExifData(string filePath)
{
if (!File.Exists(filePath))
{
Console.WriteLine("文件不存在!");
return;
}
try
{
// 读取所有元数据目录
var directories = ImageMetadataReader.ReadMetadata(filePath);
Console.WriteLine("所有元数据目录:");
foreach (var dir in directories)
{
Console.WriteLine($"- {dir.GetType().Name}");
}
// 更通用的方式获取所有EXIF相关标签
Console.WriteLine("\nEXIF 数据:");
Console.WriteLine("====================");
// 查找所有包含EXIF标签的目录
foreach (var directory in directories)
{
// 检查目录是否包含EXIF标签
if (directory is ExifDirectoryBase)
{
foreach (var tag in directory.Tags)
{
Console.WriteLine($"{tag.Name}: {tag.Description}");
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
Console.WriteLine($"堆栈跟踪: {ex.StackTrace}");
}
}
// 获取属性名称
static string GetPropertyName(int id)
{
// 常见的EXIF属性ID映射
var propertyNames = new System.Collections.Generic.Dictionary<int, string>
{
{ 0x010F, "制造商" },
{ 0x0110, "相机型号" },
{ 0x0132, "日期时间" },
{ 0x829A, "曝光时间" },
{ 0x829D, "光圈值" },
{ 0x8822, "自动曝光、光圈优先、快门优先、M 档等" },
{ 0x8827, "ISO速度" },
{ 0x9003, "拍摄日期" },
{ 0x9204, "曝光程序" },
{ 0x9207, "测光模式" },
{ 0x9209, "闪光灯" },
{ 0x920A, "物理焦距" },
{ 0xA000, "EXIF版本" },
{ 0xA001, "镜头型号" },
{ 0x010E, "主题" },
{ 0x0131, "程序名称" },
{ 0x0112, "镜头方向" },
{ 0x9202, "最大光圈" },
};
return propertyNames.TryGetValue(id, out string name) ? name : $"属性 ID: 0x{id:X4}";
}
// 获取属性值
static string GetPropertyValue(PropertyItem prop)
{
// 根据属性类型解析值
switch (prop.Type)
{
case 1: // 字节型
return BitConverter.ToString(prop.Value);
case 2: // 字符串
return System.Text.Encoding.ASCII.GetString(prop.Value).Trim('\0');
case 3: // 16位整数
return BitConverter.ToInt16(prop.Value, 0).ToString();
case 4: // 32位整数
return BitConverter.ToInt32(prop.Value, 0).ToString();
case 5: // rational (两个32位整数的比值)
int numerator = BitConverter.ToInt32(prop.Value, 0);
int denominator = BitConverter.ToInt32(prop.Value, 4);
if (denominator != 0)
return ((double)numerator / denominator).ToString("0.00");
return numerator.ToString();
case 10: // signed rational
int num = BitConverter.ToInt32(prop.Value, 0);
int den = BitConverter.ToInt32(prop.Value, 4);
if (den != 0)
return ((double)num / den).ToString("0.00");
return num.ToString();
default:
return $"({prop.Type}) {BitConverter.ToString(prop.Value)}";
}
}
//[Test]
public void TestGetExif()
{
ReadExifData("f:/DJI_20250805014002_0001_V.jpeg");
}
//[Test]
public void TestMem()
{
var client = new MinioService();
var y = client.GetObjectAsStream("test",
"f9443fba-5ba9-4d9e-aea0-5238bdb73f72/15a21693-3d05-4923-b46d-90fc18ef312e/DJI_202508050138_002_15a21693-3d05-4923-b46d-90fc18ef312e/DJI_20250805014002_0001_V.jpeg");
var directories = ImageMetadataReader.ReadMetadata(y.Result);
// 查找所有包含EXIF标签的目录
foreach (var directory in directories)
{
// 检查目录是否包含EXIF标签
if (directory is ExifDirectoryBase)
{
foreach (var tag in directory.Tags)
{
Console.WriteLine($"{tag.Name}: {tag.Description} {tag.DirectoryName}");
}
}
}
}
// [Test]
public void TestPi()
{
var client = new MinioService();
var y = client.GetObjectAsStream("test",
"f9443fba-5ba9-4d9e-aea0-5238bdb73f72/15a21693-3d05-4923-b46d-90fc18ef312e/DJI_202508050138_002_15a21693-3d05-4923-b46d-90fc18ef312e/DJI_20250805014002_0001_V.jpeg");
using (Image image = Image.FromStream(y.Result))
{
Console.WriteLine("图片基本信息:");
Console.WriteLine($"尺寸: {image.Width} x {image.Height}");
Console.WriteLine($"格式: {image.RawFormat.Guid}");
Console.WriteLine();
Console.WriteLine("图片详细属性:");
int x = 0;
// 遍历所有属性
foreach (PropertyItem prop in image.PropertyItems)
{
x = x + prop.Len;
try
{
string value = GetPropertyValue(prop);
Console.WriteLine($"{GetPropertyName(prop.Id)}: {value}");
}
catch
{
// 有些属性可能无法解析,直接跳过
continue;
}
}
}
}
// [Test]
public void TestGetEx()
{
var client = new MinioService();
var y = client.GetObjectAsStream("test",
"f9443fba-5ba9-4d9e-aea0-5238bdb73f72/15a21693-3d05-4923-b46d-90fc18ef312e/DJI_202508050138_002_15a21693-3d05-4923-b46d-90fc18ef312e/DJI_20250805014002_0001_V.jpeg");
var first64Kb = new byte[64 * 1024];
var bytesRead = y.Result.ReadAsync(first64Kb, 0, first64Kb.Length).Result;
var stream = new MemoryStream(first64Kb, 0, bytesRead);
stream.Position = 0;
y.Result.Position = 0;
// 从有限流中读取EXIF信息
var directories = ImageMetadataReader.ReadMetadata(y.Result);
int offset = 0, length = 0;
foreach (var directory in directories)
{
// 检查目录是否包含EXIF标签
if (directory is ExifDirectoryBase)
{
//Console.WriteLine(directory.Name);
if (directory.Name.Equals("Exif Thumbnail"))
{
foreach (var tag in directory.Tags)
{
if (tag.Name.Equals("Thumbnail Offset"))
{
offset = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
if (tag.Name.Equals("Thumbnail Length"))
{
length = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
}
}
/*foreach (var tag in directory.Tags)
{
if (tag.Name.Equals("Exif Thumbnail"))
{
offset = tag.Description;
}
Console.WriteLine($"{tag.Name}: {tag.Description} { tag.DirectoryName}");
}*/
}
}
// todo 读取缩略图
// 提取缩略图数据
byte[] thumbnailData = new byte[length];
y.Result.Position = 0;
bytesRead = y.Result.ReadAsync(first64Kb, 0, first64Kb.Length).Result;
Console.WriteLine("读取的字节长度: " + bytesRead);
Array.Copy(first64Kb, offset + 6, thumbnailData, 0, length);
// 保存缩略图文件
File.WriteAllBytes("f:/ab.jpeg", thumbnailData);
}
// todo 完整图片尝试读取图片缩略图
// [Test]
public void TestGetThumbnail()
{
var picStr = "f:/DJI_20250805002929_0003_V.jpeg";
var directories = ImageMetadataReader.ReadMetadata(picStr);
int offset = 0, length = 0;
foreach (var directory in directories)
{
if (directory is ExifDirectoryBase)
{
//Console.WriteLine(directory.Name);
if (directory.Name.Equals("Exif Thumbnail"))
{
foreach (var tag in directory.Tags)
{
if (tag.Name.Equals("Thumbnail Offset"))
{
offset = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
if (tag.Name.Equals("Thumbnail Length"))
{
length = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
}
}
}
}
using (FileStream fileStream = new FileStream(picStr, FileMode.Open, FileAccess.Read))
{
fileStream.Seek(offset + 6, SeekOrigin.Begin);
byte[] buffer = new byte[length];
int bytesRead = fileStream.Read(buffer, 0, length);
var x = IsValidImageFormat(buffer);
Console.WriteLine("是否为有效图片:" + x);
Console.WriteLine("读取的字节长度: " + bytesRead);
File.WriteAllBytes("f:/ab.jpeg", buffer);
}
}
// [Test]
public void SaveTub()
{
var picStr = "f:/DJI_20250801170827_0082_V.jpeg";
var directories = ImageMetadataReader.ReadMetadata(picStr);
int offset = 0, length = 0;
}
//[Test]
public void ExtraceJpeg()
{
var picStr = "f:/DJI_20250801170827_0082_V.jpeg";
var extractor = new ExifThumbnailExtractor();
extractor.Extract(picStr, "f:/abc.jpeg");
}
private bool IsValidImageFormat(byte[] data)
{
if (data.Length < 2)
return false;
// JPEG以0xFFD8开头TIFF以"II"或"MM"开头
bool isJpeg = data[0] == 0xFF && data[1] == 0xD8;
bool isTiff = (data[0] == 0x49 && data[1] == 0x49) || (data[0] == 0x4D && data[1] == 0x4D);
return isJpeg || isTiff;
}
[Test]
public void DownloadRange()
{
using (var httpClient = new HttpClient())
{
var total = 0L;
// 添加Range请求头
httpClient.DefaultRequestHeaders.Range = new System.Net.Http.Headers.RangeHeaderValue(0, 65535);
try
{
var response = httpClient
.GetAsync(
"http://175.27.168.120:6013/test/640aea27-2dd3-4081-933c-fcef432fcec0/71924889-540d-4362-aeb1-9ee787a655a7/DJI_202508050906_002_71924889-540d-4362-aeb1-9ee787a655a7/DJI_20250805090809_0001_V.jpeg",
HttpCompletionOption.ResponseHeadersRead).Result;
if (response.StatusCode == System.Net.HttpStatusCode.PartialContent)
{
//Focal Length 35: 24 mm
//Exif Image Width: 4032 pixels : Exif SubIFD
//Exif Image Height: 3024 pixels : Exif SubIFD
// 3.1 解析Content-Range头格式bytes start-end/total
var contentRange = response.Content.Headers.ContentRange;
if (contentRange != null)
{
Console.WriteLine($"获取范围:{contentRange.From}-{contentRange.To}/{contentRange.Length}");
}
// 成功获取部分内容
var y = response.Content.ReadAsByteArrayAsync().Result;
MemoryStream ms = new MemoryStream(y);
var directories = ImageMetadataReader.ReadMetadata(ms);
int offset = 0, length = 0;
foreach (var directory in directories)
{
if (directory is ExifDirectoryBase)
{
foreach (var directoryTag in directory.Tags)
{
Console.WriteLine($"{directoryTag.Name}: {directoryTag.Description} : { directoryTag.DirectoryName}");
}
//Console.WriteLine(directory.Name);
if (directory.Name.Equals("Exif Thumbnail"))
{
foreach (var tag in directory.Tags)
{
if (tag.Name.Equals("Thumbnail Offset"))
{
offset = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
if (tag.Name.Equals("Thumbnail Length"))
{
length = int.Parse(tag.Description.Replace("bytes", "").Trim());
}
}
}
}
}
ms.Seek(offset + 6, SeekOrigin.Begin);
byte[] buffer = new byte[length];
int bytesRead = ms.Read(buffer, 0, length);
var x = IsValidImageFormat(buffer);
Console.WriteLine("是否为有效图片:" + x);
Console.WriteLine("读取的字节长度: " + bytesRead);
File.WriteAllBytes("f:/abcccc.jpeg", buffer);
}
else if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
// 服务器不支持Range请求返回完整内容
throw new InvalidOperationException("服务器不支持Range请求");
}
else
{
throw new HttpRequestException($"请求失败: {response.StatusCode}");
}
}
catch (Exception ex)
{
throw new Exception($"下载Range数据失败: {ex.Message}", ex);
}
}
}
}
Loading…
Cancel
Save