From 913f3d40c94db6d0711621fcfefbe6ab10c49511 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E4=BC=9F?= <421281095@qq.com> Date: Thu, 7 Aug 2025 16:58:56 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=A9=E7=95=A5=E5=9B=BE=E8=AF=BB=E5=8F=96?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Infrastructure/Infrastructure.csproj | 2 + OpenAuth.WebApi/boot/TestAbc.cs | 496 ++++++++++++++++++++++++++- 2 files changed, 494 insertions(+), 4 deletions(-) diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj index efba1f2..0e81524 100644 --- a/Infrastructure/Infrastructure.csproj +++ b/Infrastructure/Infrastructure.csproj @@ -14,7 +14,9 @@ + + diff --git a/OpenAuth.WebApi/boot/TestAbc.cs b/OpenAuth.WebApi/boot/TestAbc.cs index 7e3bf33..ea55589 100644 --- a/OpenAuth.WebApi/boot/TestAbc.cs +++ b/OpenAuth.WebApi/boot/TestAbc.cs @@ -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>(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>(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(content); + var win_meter = weather.GetValue("win_mete")?.Value(); // 风速 + 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 + { + { 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); + } + } + } } \ No newline at end of file