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; using OpenAuth.Repository.Domain; namespace OpenAuth.WebApi.boot; public class TestAbc { //[Test] public void TestDser() { var json = @" {""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; 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() { var minio = new MinioService(); long? picSize = 0; int width = 0, height = 0, focalLength = 0; int offset = 0, length = 0; 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://" + minio.endPoint + "/" + minio._bucketName + "/" + "/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) { picSize = contentRange.Length; Console.WriteLine($"获取范围:{contentRange.From}-{contentRange.To}/{contentRange.Length}"); } // 成功获取部分内容 var y = response.Content.ReadAsByteArrayAsync().Result; MemoryStream ms = new MemoryStream(y); var directories = ImageMetadataReader.ReadMetadata(ms); foreach (var directory in directories) { if (directory is ExifDirectoryBase) { foreach (var directoryTag in directory.Tags) { Console.WriteLine( $"{directoryTag.Name}: {directoryTag.Description} : {directoryTag.DirectoryName}"); } if (directory.Name.Equals("Exif SubIFD")) { foreach (var tag in directory.Tags) { if (tag.Name.Equals("Exif Image Width")) { width = int.Parse(tag.Description.Replace("pixels", "") .Trim()); } if (tag.Name.Equals("Exif Image Height")) { height = int.Parse(tag.Description.Replace("pixels", "") .Trim()); } if (tag.Name.Equals("Focal Length 35")) { focalLength = int.Parse(tag.Description.Replace("mm", "") .Trim()); } } } //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()); } } } } } var fileUpload = new LasaMediaFile() { Id = Guid.NewGuid().ToString(), Width = width, Height = height, Size = picSize, ShowOnMap = 1, display = 1, FocalLength = focalLength }; Console.WriteLine("是否有错呢:" + JsonConvert.SerializeObject(fileUpload)); 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:/abbbbbb.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); } } } }