From d027935eb9a3060e5e3aa4247c86f587c10e7cd3 Mon Sep 17 00:00:00 2001 From: Shijia Zhou <35678586+DasuberVetLeonidas@users.noreply.github.com> Date: Mon, 5 Jan 2026 12:04:57 +1100 Subject: [PATCH 1/4] Change image source to JAM --- EarthLiveSharp/EarthLiveSharp.csproj | 160 ++------- EarthLiveSharp/Program.cs | 472 ++++++++++++++++----------- 2 files changed, 303 insertions(+), 329 deletions(-) diff --git a/EarthLiveSharp/EarthLiveSharp.csproj b/EarthLiveSharp/EarthLiveSharp.csproj index f19638e..7bd45f9 100644 --- a/EarthLiveSharp/EarthLiveSharp.csproj +++ b/EarthLiveSharp/EarthLiveSharp.csproj @@ -1,155 +1,49 @@  - - + + - Debug - AnyCPU - {5916F0E1-8196-4229-97C8-7DA0AA91AF0E} WinExe - Properties - EarthLiveSharp - EarthLiveSharp - v4.5 - 512 - false - - 发布\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - EarthLive.ico + net48 + true + false + true + + true + - - - - - + + + + + - - - Form - - - settingsForm.cs - - - Form - - - mainForm.cs - - - - - - mainForm.cs - - - mainForm.cs - - - settingsForm.cs - - - mainForm.cs - - + + + + + ResXFileCodeGenerator Resources.Designer.cs - Designer - + + True True Resources.resx - True - - settingsForm.cs - - - settingsForm.cs - - + + SettingsSingleFileGenerator Settings.Designer.cs - - + + + True True Settings.settings - True - - - Designer - - - - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 和 x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - - + \ No newline at end of file diff --git a/EarthLiveSharp/Program.cs b/EarthLiveSharp/Program.cs index 893e7ab..95d599c 100644 --- a/EarthLiveSharp/Program.cs +++ b/EarthLiveSharp/Program.cs @@ -94,230 +94,310 @@ interface IScraper } public class Scraper_himawari8 : IScraper { - private string imageID = ""; - private static string last_imageID = "0"; - private string json_url = "https://himawari8-dl.nict.go.jp/himawari8/img/FULL_24h/latest.json"; + // JMA URL Pattern: https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_HHmm.jpg + private const string JMA_BASE_URL = "https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_"; - private int GetImageID() + public void UpdateImage() { - System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - HttpWebRequest request = WebRequest.Create(json_url) as HttpWebRequest; - try - { - HttpWebResponse response = request.GetResponse() as HttpWebResponse; - if (response.StatusCode != HttpStatusCode.OK) - { - throw new Exception("[himawari8 connection error]"); - } - if (!response.ContentType.Contains("application/json")) - { - throw new Exception("[himawari8 no json recieved. your Internet connection is hijacked]"); - } - StreamReader reader = new StreamReader(response.GetResponseStream()); - string date = reader.ReadToEnd(); - imageID = date.Substring(9,19).Replace("-", "/").Replace(" ", "/").Replace(":", ""); - Trace.WriteLine("[himawari8 get latest ImageID] " + imageID); - reader.Close(); - } - catch (Exception e) - { - Trace.WriteLine(e.Message); - return -1; - } - return 0; - } + InitFolder(); - private int SaveImage() - { - System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - WebClient client = new WebClient(); - string image_source = ""; - if (Cfg.source_selection == 1) - { - image_source = "https://res.cloudinary.com/" + Cfg.cloud_name + "/image/fetch/https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; - } - else - { - image_source = "https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; - } - string url = ""; - string image_path = ""; try { - for (int ii = 0; ii < Cfg.size; ii++) - { - for (int jj = 0; jj < Cfg.size; jj++) - { - url = string.Format("{0}/{1}d/550/{2}_{3}_{4}.png", image_source, Cfg.size, imageID, ii, jj); - image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); // remove the '/' in imageID - client.DownloadFile(url, image_path); - } - } - Trace.WriteLine("[save image] " + imageID); - return 0; - } - catch (Exception e) - { - Trace.WriteLine(e.Message + " " + imageID); - Trace.WriteLine(string.Format("[url]{0} [image_path]{1}", url, image_path)); - return -1; - } - finally - { - client.Dispose(); - } - } + // 1. Get current UTC time + DateTime nowUtc = DateTime.UtcNow; - private void JoinImage() - { - // join & convert the images to wallpaper.bmp - Bitmap bitmap = new Bitmap(550 * Cfg.size, 550 * Cfg.size); - Image[,] tile = new Image[Cfg.size, Cfg.size]; - Graphics g = Graphics.FromImage(bitmap); - for (int ii = 0; ii < Cfg.size; ii++) - { - for (int jj = 0; jj < Cfg.size; jj++) - { - tile[ii,jj] = Image.FromFile(string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj)); - g.DrawImage(tile[ii, jj], 550 * ii, 550 * jj); - tile[ii, jj].Dispose(); - } - } - g.Save(); - g.Dispose(); - if (Cfg.zoom == 100) - { - bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - } - else if (1 < Cfg.zoom & Cfg.zoom <100) - { - int new_size = bitmap.Height * Cfg.zoom /100; - Bitmap zoom_bitmap = new Bitmap(new_size, new_size); - Graphics g_2 = Graphics.FromImage(zoom_bitmap); - g_2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - g_2.DrawImage(bitmap, 0, 0, new_size, new_size); - g_2.Save(); - g_2.Dispose(); - zoom_bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - zoom_bitmap.Dispose(); - } - else - { - Trace.WriteLine("[himawari8 zoom error]"); - } + // 2. Subtract 10 minutes to avoid fetching an image that hasn't been uploaded yet. + // (This also handles the "going back one day" logic automatically via DateTime math) + DateTime adjustedTime = nowUtc.AddMinutes(-10); - bitmap.Dispose(); + // 3. Round down to the nearest 10-minute interval + // Example: 00:19 -> 00:10, 00:05 -> 00:00 + int minute = adjustedTime.Minute; + int roundedMinute = (minute / 10) * 10; - if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") - { - if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) - { - Scrap_wrapper.SequenceCount = 0; - } - try + // 4. Construct the target timestamp + DateTime targetTime = new DateTime( + adjustedTime.Year, + adjustedTime.Month, + adjustedTime.Day, + adjustedTime.Hour, + roundedMinute, + 0, + DateTimeKind.Utc + ); + + // 5. Generate the URL (Format: HHmm, e.g., "2350", "0010") + string timeStr = targetTime.ToString("HHmm"); + string imageUrl = JMA_BASE_URL + timeStr + ".jpg"; + string savePath = Cfg.image_folder + "\\wallpaper.bmp"; + + // 6. Download + // Clean up old file first + if (File.Exists(savePath)) { - File.Copy(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder), Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp", true); - Scrap_wrapper.SequenceCount++; + File.Delete(savePath); } - catch (Exception e) + + using (WebClient client = new WebClient()) { - Trace.WriteLine("[can't save wallpaper to distDirectory]"); - Trace.WriteLine(e.Message); - return; + // Tls12 is required for most government websites now + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + Trace.WriteLine("[JMA Download] Requesting: " + imageUrl); + client.DownloadFile(imageUrl, savePath); + Trace.WriteLine("[JMA Download] Success. Saved to " + savePath); } } + catch (Exception e) + { + Trace.WriteLine("[JMA Download Error] " + e.Message); + } } private void InitFolder() { - if(Directory.Exists(Cfg.image_folder)) + if (!Directory.Exists(Cfg.image_folder)) { - // delete all images in the image folder. - //string[] files = Directory.GetFiles(image_folder); - //foreach (string fn in files) - //{ - // File.Delete(fn); - //} - } - else - { - Trace.WriteLine("[himawari8 create folder]"); Directory.CreateDirectory(Cfg.image_folder); } } - public void UpdateImage() - { - InitFolder(); - if (GetImageID() == -1) - { - return; - } - if (imageID.Equals(last_imageID)) - { - return; - } - if (SaveImage()==0) - { - JoinImage(); - } - last_imageID = imageID; - return; - } + + // --- Interface Stubs (Not needed for direct JMA download) --- public void CleanCDN() { - Cfg.Load(); - if (Cfg.api_key.Length == 0) return; - if (Cfg.api_secret.Length == 0) return; - try - { - HttpWebRequest request = WebRequest.Create("https://api.cloudinary.com/v1_1/" + Cfg.cloud_name + "/resources/image/fetch?prefix=https://himawari8-dl") as HttpWebRequest; - request.Method = "DELETE"; - request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); - string svcCredentials = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(Cfg.api_key + ":" + Cfg.api_secret)); - request.Headers.Add("Authorization", "Basic " + svcCredentials); - HttpWebResponse response = null; - StreamReader reader = null; - string result = null; - for (int i = 0; i < 3;i++ ) // max 3 request each hour. - { - response = request.GetResponse() as HttpWebResponse; - if (response.StatusCode != HttpStatusCode.OK) - { - throw new Exception("[himawari8 clean CND cache connection error]"); - } - if (!response.ContentType.Contains("application/json")) - { - throw new Exception("[himawari8 clean CND cache no json recieved. your Internet connection is hijacked]"); - } - reader = new StreamReader(response.GetResponseStream()); - result = reader.ReadToEnd(); - if (result.Contains("\"error\"")) - { - throw new Exception("[himawari8 clean CND cache request error]\n" + result); - } - if (result.Contains("\"partial\":false")) - { - Trace.WriteLine("[himawari8 clean CDN cache done]"); - break; // end of Clean CDN - } - else - { - Trace.WriteLine("[himawari8 more images to delete]"); - } - } - } - catch (Exception e) - { - Trace.WriteLine("[himawari8 error when delete CDN cache]"); - Trace.WriteLine(e.Message); - return; - } + // Logic removed as we are not using Cloudinary/CDN for this source } + public void ResetState() { - last_imageID = "0"; + // No state tracking needed for direct time-based download } } + // { + // private string imageID = ""; + // private static string last_imageID = "0"; + // private string json_url = "https://himawari8-dl.nict.go.jp/himawari8/img/FULL_24h/latest.json"; + + // private int GetImageID() + // { + // System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + // HttpWebRequest request = WebRequest.Create(json_url) as HttpWebRequest; + // try + // { + // HttpWebResponse response = request.GetResponse() as HttpWebResponse; + // if (response.StatusCode != HttpStatusCode.OK) + // { + // throw new Exception("[himawari8 connection error]"); + // } + // if (!response.ContentType.Contains("application/json")) + // { + // throw new Exception("[himawari8 no json recieved. your Internet connection is hijacked]"); + // } + // StreamReader reader = new StreamReader(response.GetResponseStream()); + // string date = reader.ReadToEnd(); + // imageID = date.Substring(9,19).Replace("-", "/").Replace(" ", "/").Replace(":", ""); + // Trace.WriteLine("[himawari8 get latest ImageID] " + imageID); + // reader.Close(); + // } + // catch (Exception e) + // { + // Trace.WriteLine(e.Message); + // return -1; + // } + // return 0; + // } + + // private int SaveImage() + // { + // System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + // WebClient client = new WebClient(); + // string image_source = ""; + // if (Cfg.source_selection == 1) + // { + // image_source = "https://res.cloudinary.com/" + Cfg.cloud_name + "/image/fetch/https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; + // } + // else + // { + // image_source = "https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; + // } + // string url = ""; + // string image_path = ""; + // try + // { + // for (int ii = 0; ii < Cfg.size; ii++) + // { + // for (int jj = 0; jj < Cfg.size; jj++) + // { + // url = string.Format("{0}/{1}d/550/{2}_{3}_{4}.png", image_source, Cfg.size, imageID, ii, jj); + // image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); // remove the '/' in imageID + // client.DownloadFile(url, image_path); + // } + // } + // Trace.WriteLine("[save image] " + imageID); + // return 0; + // } + // catch (Exception e) + // { + // Trace.WriteLine(e.Message + " " + imageID); + // Trace.WriteLine(string.Format("[url]{0} [image_path]{1}", url, image_path)); + // return -1; + // } + // finally + // { + // client.Dispose(); + // } + // } + + // private void JoinImage() + // { + // // join & convert the images to wallpaper.bmp + // Bitmap bitmap = new Bitmap(550 * Cfg.size, 550 * Cfg.size); + // Image[,] tile = new Image[Cfg.size, Cfg.size]; + // Graphics g = Graphics.FromImage(bitmap); + // for (int ii = 0; ii < Cfg.size; ii++) + // { + // for (int jj = 0; jj < Cfg.size; jj++) + // { + // tile[ii,jj] = Image.FromFile(string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj)); + // g.DrawImage(tile[ii, jj], 550 * ii, 550 * jj); + // tile[ii, jj].Dispose(); + // } + // } + // g.Save(); + // g.Dispose(); + // if (Cfg.zoom == 100) + // { + // bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); + // } + // else if (1 < Cfg.zoom & Cfg.zoom <100) + // { + // int new_size = bitmap.Height * Cfg.zoom /100; + // Bitmap zoom_bitmap = new Bitmap(new_size, new_size); + // Graphics g_2 = Graphics.FromImage(zoom_bitmap); + // g_2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + // g_2.DrawImage(bitmap, 0, 0, new_size, new_size); + // g_2.Save(); + // g_2.Dispose(); + // zoom_bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); + // zoom_bitmap.Dispose(); + // } + // else + // { + // Trace.WriteLine("[himawari8 zoom error]"); + // } + + // bitmap.Dispose(); + + // if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") + // { + // if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) + // { + // Scrap_wrapper.SequenceCount = 0; + // } + // try + // { + // File.Copy(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder), Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp", true); + // Scrap_wrapper.SequenceCount++; + // } + // catch (Exception e) + // { + // Trace.WriteLine("[can't save wallpaper to distDirectory]"); + // Trace.WriteLine(e.Message); + // return; + // } + // } + // } + + // private void InitFolder() + // { + // if(Directory.Exists(Cfg.image_folder)) + // { + // // delete all images in the image folder. + // //string[] files = Directory.GetFiles(image_folder); + // //foreach (string fn in files) + // //{ + // // File.Delete(fn); + // //} + // } + // else + // { + // Trace.WriteLine("[himawari8 create folder]"); + // Directory.CreateDirectory(Cfg.image_folder); + // } + // } + // public void UpdateImage() + // { + // InitFolder(); + // if (GetImageID() == -1) + // { + // return; + // } + // if (imageID.Equals(last_imageID)) + // { + // return; + // } + // if (SaveImage()==0) + // { + // JoinImage(); + // } + // last_imageID = imageID; + // return; + // } + // public void CleanCDN() + // { + // Cfg.Load(); + // if (Cfg.api_key.Length == 0) return; + // if (Cfg.api_secret.Length == 0) return; + // try + // { + // HttpWebRequest request = WebRequest.Create("https://api.cloudinary.com/v1_1/" + Cfg.cloud_name + "/resources/image/fetch?prefix=https://himawari8-dl") as HttpWebRequest; + // request.Method = "DELETE"; + // request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); + // string svcCredentials = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(Cfg.api_key + ":" + Cfg.api_secret)); + // request.Headers.Add("Authorization", "Basic " + svcCredentials); + // HttpWebResponse response = null; + // StreamReader reader = null; + // string result = null; + // for (int i = 0; i < 3;i++ ) // max 3 request each hour. + // { + // response = request.GetResponse() as HttpWebResponse; + // if (response.StatusCode != HttpStatusCode.OK) + // { + // throw new Exception("[himawari8 clean CND cache connection error]"); + // } + // if (!response.ContentType.Contains("application/json")) + // { + // throw new Exception("[himawari8 clean CND cache no json recieved. your Internet connection is hijacked]"); + // } + // reader = new StreamReader(response.GetResponseStream()); + // result = reader.ReadToEnd(); + // if (result.Contains("\"error\"")) + // { + // throw new Exception("[himawari8 clean CND cache request error]\n" + result); + // } + // if (result.Contains("\"partial\":false")) + // { + // Trace.WriteLine("[himawari8 clean CDN cache done]"); + // break; // end of Clean CDN + // } + // else + // { + // Trace.WriteLine("[himawari8 more images to delete]"); + // } + // } + // } + // catch (Exception e) + // { + // Trace.WriteLine("[himawari8 error when delete CDN cache]"); + // Trace.WriteLine(e.Message); + // return; + // } + // } + // public void ResetState() + // { + // last_imageID = "0"; + // } + // } public static class Autostart { From 7c21b2458d9ee31c1006889d3d0f8238f41d3847 Mon Sep 17 00:00:00 2001 From: Shijia Zhou <35678586+DasuberVetLeonidas@users.noreply.github.com> Date: Mon, 12 Jan 2026 06:52:01 +1100 Subject: [PATCH 2/4] Modified JoinImage so that it focuses on Australia --- EarthLiveSharp/Program.cs | 634 ++++++++++++++++++++++---------------- 1 file changed, 361 insertions(+), 273 deletions(-) diff --git a/EarthLiveSharp/Program.cs b/EarthLiveSharp/Program.cs index 95d599c..4d6fb68 100644 --- a/EarthLiveSharp/Program.cs +++ b/EarthLiveSharp/Program.cs @@ -93,312 +93,400 @@ interface IScraper void ResetState(); } public class Scraper_himawari8 : IScraper - { - // JMA URL Pattern: https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_HHmm.jpg - private const string JMA_BASE_URL = "https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_"; - public void UpdateImage() - { - InitFolder(); + // // New URL from JMA + // { + // // JMA URL Pattern: https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_HHmm.jpg + // private const string JMA_BASE_URL = "https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_"; - try - { - // 1. Get current UTC time - DateTime nowUtc = DateTime.UtcNow; - - // 2. Subtract 10 minutes to avoid fetching an image that hasn't been uploaded yet. - // (This also handles the "going back one day" logic automatically via DateTime math) - DateTime adjustedTime = nowUtc.AddMinutes(-10); - - // 3. Round down to the nearest 10-minute interval - // Example: 00:19 -> 00:10, 00:05 -> 00:00 - int minute = adjustedTime.Minute; - int roundedMinute = (minute / 10) * 10; - - // 4. Construct the target timestamp - DateTime targetTime = new DateTime( - adjustedTime.Year, - adjustedTime.Month, - adjustedTime.Day, - adjustedTime.Hour, - roundedMinute, - 0, - DateTimeKind.Utc - ); - - // 5. Generate the URL (Format: HHmm, e.g., "2350", "0010") - string timeStr = targetTime.ToString("HHmm"); - string imageUrl = JMA_BASE_URL + timeStr + ".jpg"; - string savePath = Cfg.image_folder + "\\wallpaper.bmp"; - - // 6. Download - // Clean up old file first - if (File.Exists(savePath)) - { - File.Delete(savePath); - } + // public void UpdateImage() + // { + // InitFolder(); - using (WebClient client = new WebClient()) - { - // Tls12 is required for most government websites now - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + // try + // { + // // 1. Get current UTC time + // DateTime nowUtc = DateTime.UtcNow; - Trace.WriteLine("[JMA Download] Requesting: " + imageUrl); - client.DownloadFile(imageUrl, savePath); - Trace.WriteLine("[JMA Download] Success. Saved to " + savePath); - } - } - catch (Exception e) - { - Trace.WriteLine("[JMA Download Error] " + e.Message); - } - } + // // 2. Subtract 10 minutes to avoid fetching an image that hasn't been uploaded yet. + // // (This also handles the "going back one day" logic automatically via DateTime math) + // DateTime adjustedTime = nowUtc.AddMinutes(-10); - private void InitFolder() - { - if (!Directory.Exists(Cfg.image_folder)) - { - Directory.CreateDirectory(Cfg.image_folder); - } - } + // // 3. Round down to the nearest 10-minute interval + // // Example: 00:19 -> 00:10, 00:05 -> 00:00 + // int minute = adjustedTime.Minute; + // int roundedMinute = (minute / 10) * 10; - // --- Interface Stubs (Not needed for direct JMA download) --- - public void CleanCDN() - { - // Logic removed as we are not using Cloudinary/CDN for this source - } + // // 4. Construct the target timestamp + // DateTime targetTime = new DateTime( + // adjustedTime.Year, + // adjustedTime.Month, + // adjustedTime.Day, + // adjustedTime.Hour, + // roundedMinute, + // 0, + // DateTimeKind.Utc + // ); - public void ResetState() - { - // No state tracking needed for direct time-based download - } - } - // { - // private string imageID = ""; - // private static string last_imageID = "0"; - // private string json_url = "https://himawari8-dl.nict.go.jp/himawari8/img/FULL_24h/latest.json"; + // // 5. Generate the URL (Format: HHmm, e.g., "2350", "0010") + // string timeStr = targetTime.ToString("HHmm"); + // string imageUrl = JMA_BASE_URL + timeStr + ".jpg"; + // string savePath = Cfg.image_folder + "\\wallpaper.bmp"; - // private int GetImageID() - // { - // System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - // HttpWebRequest request = WebRequest.Create(json_url) as HttpWebRequest; - // try - // { - // HttpWebResponse response = request.GetResponse() as HttpWebResponse; - // if (response.StatusCode != HttpStatusCode.OK) - // { - // throw new Exception("[himawari8 connection error]"); - // } - // if (!response.ContentType.Contains("application/json")) + // // 6. Download + // // Clean up old file first + // if (File.Exists(savePath)) // { - // throw new Exception("[himawari8 no json recieved. your Internet connection is hijacked]"); + // File.Delete(savePath); // } - // StreamReader reader = new StreamReader(response.GetResponseStream()); - // string date = reader.ReadToEnd(); - // imageID = date.Substring(9,19).Replace("-", "/").Replace(" ", "/").Replace(":", ""); - // Trace.WriteLine("[himawari8 get latest ImageID] " + imageID); - // reader.Close(); - // } - // catch (Exception e) - // { - // Trace.WriteLine(e.Message); - // return -1; - // } - // return 0; - // } - // private int SaveImage() - // { - // System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - // WebClient client = new WebClient(); - // string image_source = ""; - // if (Cfg.source_selection == 1) - // { - // image_source = "https://res.cloudinary.com/" + Cfg.cloud_name + "/image/fetch/https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; - // } - // else - // { - // image_source = "https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; - // } - // string url = ""; - // string image_path = ""; - // try - // { - // for (int ii = 0; ii < Cfg.size; ii++) + // using (WebClient client = new WebClient()) // { - // for (int jj = 0; jj < Cfg.size; jj++) - // { - // url = string.Format("{0}/{1}d/550/{2}_{3}_{4}.png", image_source, Cfg.size, imageID, ii, jj); - // image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); // remove the '/' in imageID - // client.DownloadFile(url, image_path); - // } + // // Tls12 is required for most government websites now + // ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + + // Trace.WriteLine("[JMA Download] Requesting: " + imageUrl); + // client.DownloadFile(imageUrl, savePath); + // Trace.WriteLine("[JMA Download] Success. Saved to " + savePath); // } - // Trace.WriteLine("[save image] " + imageID); - // return 0; // } // catch (Exception e) // { - // Trace.WriteLine(e.Message + " " + imageID); - // Trace.WriteLine(string.Format("[url]{0} [image_path]{1}", url, image_path)); - // return -1; - // } - // finally - // { - // client.Dispose(); - // } - // } - - // private void JoinImage() - // { - // // join & convert the images to wallpaper.bmp - // Bitmap bitmap = new Bitmap(550 * Cfg.size, 550 * Cfg.size); - // Image[,] tile = new Image[Cfg.size, Cfg.size]; - // Graphics g = Graphics.FromImage(bitmap); - // for (int ii = 0; ii < Cfg.size; ii++) - // { - // for (int jj = 0; jj < Cfg.size; jj++) - // { - // tile[ii,jj] = Image.FromFile(string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj)); - // g.DrawImage(tile[ii, jj], 550 * ii, 550 * jj); - // tile[ii, jj].Dispose(); - // } - // } - // g.Save(); - // g.Dispose(); - // if (Cfg.zoom == 100) - // { - // bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - // } - // else if (1 < Cfg.zoom & Cfg.zoom <100) - // { - // int new_size = bitmap.Height * Cfg.zoom /100; - // Bitmap zoom_bitmap = new Bitmap(new_size, new_size); - // Graphics g_2 = Graphics.FromImage(zoom_bitmap); - // g_2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - // g_2.DrawImage(bitmap, 0, 0, new_size, new_size); - // g_2.Save(); - // g_2.Dispose(); - // zoom_bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - // zoom_bitmap.Dispose(); - // } - // else - // { - // Trace.WriteLine("[himawari8 zoom error]"); - // } - - // bitmap.Dispose(); - - // if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") - // { - // if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) - // { - // Scrap_wrapper.SequenceCount = 0; - // } - // try - // { - // File.Copy(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder), Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp", true); - // Scrap_wrapper.SequenceCount++; - // } - // catch (Exception e) - // { - // Trace.WriteLine("[can't save wallpaper to distDirectory]"); - // Trace.WriteLine(e.Message); - // return; - // } + // Trace.WriteLine("[JMA Download Error] " + e.Message); // } // } // private void InitFolder() // { - // if(Directory.Exists(Cfg.image_folder)) - // { - // // delete all images in the image folder. - // //string[] files = Directory.GetFiles(image_folder); - // //foreach (string fn in files) - // //{ - // // File.Delete(fn); - // //} - // } - // else + // if (!Directory.Exists(Cfg.image_folder)) // { - // Trace.WriteLine("[himawari8 create folder]"); // Directory.CreateDirectory(Cfg.image_folder); // } // } - // public void UpdateImage() - // { - // InitFolder(); - // if (GetImageID() == -1) - // { - // return; - // } - // if (imageID.Equals(last_imageID)) - // { - // return; - // } - // if (SaveImage()==0) - // { - // JoinImage(); - // } - // last_imageID = imageID; - // return; - // } + + // // --- Interface Stubs (Not needed for direct JMA download) --- // public void CleanCDN() // { - // Cfg.Load(); - // if (Cfg.api_key.Length == 0) return; - // if (Cfg.api_secret.Length == 0) return; - // try - // { - // HttpWebRequest request = WebRequest.Create("https://api.cloudinary.com/v1_1/" + Cfg.cloud_name + "/resources/image/fetch?prefix=https://himawari8-dl") as HttpWebRequest; - // request.Method = "DELETE"; - // request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); - // string svcCredentials = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(Cfg.api_key + ":" + Cfg.api_secret)); - // request.Headers.Add("Authorization", "Basic " + svcCredentials); - // HttpWebResponse response = null; - // StreamReader reader = null; - // string result = null; - // for (int i = 0; i < 3;i++ ) // max 3 request each hour. - // { - // response = request.GetResponse() as HttpWebResponse; - // if (response.StatusCode != HttpStatusCode.OK) - // { - // throw new Exception("[himawari8 clean CND cache connection error]"); - // } - // if (!response.ContentType.Contains("application/json")) - // { - // throw new Exception("[himawari8 clean CND cache no json recieved. your Internet connection is hijacked]"); - // } - // reader = new StreamReader(response.GetResponseStream()); - // result = reader.ReadToEnd(); - // if (result.Contains("\"error\"")) - // { - // throw new Exception("[himawari8 clean CND cache request error]\n" + result); - // } - // if (result.Contains("\"partial\":false")) - // { - // Trace.WriteLine("[himawari8 clean CDN cache done]"); - // break; // end of Clean CDN - // } - // else - // { - // Trace.WriteLine("[himawari8 more images to delete]"); - // } - // } - // } - // catch (Exception e) - // { - // Trace.WriteLine("[himawari8 error when delete CDN cache]"); - // Trace.WriteLine(e.Message); - // return; - // } + // // Logic removed as we are not using Cloudinary/CDN for this source // } + // public void ResetState() // { - // last_imageID = "0"; + // // No state tracking needed for direct time-based download // } // } + // Old url from NICT + { + private string imageID = ""; + private static string last_imageID = "0"; + private string json_url = "https://himawari8-dl.nict.go.jp/himawari8/img/FULL_24h/latest.json"; + + private int GetImageID() + { + System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + HttpWebRequest request = WebRequest.Create(json_url) as HttpWebRequest; + try + { + HttpWebResponse response = request.GetResponse() as HttpWebResponse; + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception("[himawari8 connection error]"); + } + if (!response.ContentType.Contains("application/json")) + { + throw new Exception("[himawari8 no json recieved. your Internet connection is hijacked]"); + } + StreamReader reader = new StreamReader(response.GetResponseStream()); + string date = reader.ReadToEnd(); + imageID = date.Substring(9,19).Replace("-", "/").Replace(" ", "/").Replace(":", ""); + Trace.WriteLine("[himawari8 get latest ImageID] " + imageID); + reader.Close(); + } + catch (Exception e) + { + Trace.WriteLine(e.Message); + return -1; + } + return 0; + } + + private int SaveImage() + { + System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + WebClient client = new WebClient(); + string image_source = ""; + if (Cfg.source_selection == 1) + { + image_source = "https://res.cloudinary.com/" + Cfg.cloud_name + "/image/fetch/https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; + } + else + { + image_source = "https://himawari8-dl.nict.go.jp/himawari8/img/D531106"; + } + string url = ""; + string image_path = ""; + try + { + for (int ii = 0; ii < Cfg.size; ii++) + { + for (int jj = 0; jj < Cfg.size; jj++) + { + url = string.Format("{0}/{1}d/550/{2}_{3}_{4}.png", image_source, Cfg.size, imageID, ii, jj); + image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); // remove the '/' in imageID + client.DownloadFile(url, image_path); + } + } + Trace.WriteLine("[save image] " + imageID); + return 0; + } + catch (Exception e) + { + Trace.WriteLine(e.Message + " " + imageID); + Trace.WriteLine(string.Format("[url]{0} [image_path]{1}", url, image_path)); + return -1; + } + finally + { + client.Dispose(); + } + } + + // Original FullDisk JoinImage + // private void JoinImage() + // { + // // join & convert the images to wallpaper.bmp + // Bitmap bitmap = new Bitmap(550 * Cfg.size, 550 * Cfg.size); + // Image[,] tile = new Image[Cfg.size, Cfg.size]; + // Graphics g = Graphics.FromImage(bitmap); + // for (int ii = 0; ii < Cfg.size; ii++) + // { + // for (int jj = 0; jj < Cfg.size; jj++) + // { + // tile[ii,jj] = Image.FromFile(string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj)); + // g.DrawImage(tile[ii, jj], 550 * ii, 550 * jj); + // tile[ii, jj].Dispose(); + // } + // } + // g.Save(); + // g.Dispose(); + // if (Cfg.zoom == 100) + // { + // bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); + // } + // else if (1 < Cfg.zoom & Cfg.zoom <100) + // { + // int new_size = bitmap.Height * Cfg.zoom /100; + // Bitmap zoom_bitmap = new Bitmap(new_size, new_size); + // Graphics g_2 = Graphics.FromImage(zoom_bitmap); + // g_2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; + // g_2.DrawImage(bitmap, 0, 0, new_size, new_size); + // g_2.Save(); + // g_2.Dispose(); + // zoom_bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); + // zoom_bitmap.Dispose(); + // } + // else + // { + // Trace.WriteLine("[himawari8 zoom error]"); + // } + + // bitmap.Dispose(); + + // if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") + // { + // if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) + // { + // Scrap_wrapper.SequenceCount = 0; + // } + // try + // { + // File.Copy(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder), Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp", true); + // Scrap_wrapper.SequenceCount++; + // } + // catch (Exception e) + // { + // Trace.WriteLine("[can't save wallpaper to distDirectory]"); + // Trace.WriteLine(e.Message); + // return; + // } + // } + // } + + // New Australia focused JoinImage + private void JoinImage() + { + // 1. Setup dimensions for the Full Disk + int fullWidth = 550 * Cfg.size; + int fullHeight = 550 * Cfg.size; + + // 2. Create the full disk in memory first + using (Bitmap fullDisk = new Bitmap(fullWidth, fullHeight)) + { + using (Graphics g = Graphics.FromImage(fullDisk)) + { + // Draw all downloaded tiles onto the full disk canvas + for (int ii = 0; ii < Cfg.size; ii++) + { + for (int jj = 0; jj < Cfg.size; jj++) + { + string tilePath = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); + if (File.Exists(tilePath)) + { + using (Image tile = Image.FromFile(tilePath)) + { + g.DrawImage(tile, 550 * ii, 550 * jj); + } + } + } + } + } + + // 3. DEFINE CROP: Focus on Australia / Bass Strait / East Coast + // Himawari-8 Center is 140.7E (approx. mid-Australia longitude). + // + // Settings below are percentages (0.0 to 1.0) of the full image. + // Adjust these numbers to zoom in tighter or pan around. + + // X=0.25: Starts a bit West of WA. + // Y=0.55: Starts around Northern Territory (south of Equator). + // W=0.45: Wide enough to include NZ. + // H=0.35: Tall enough to include Tasmania/Bass Strait and Southern Ocean. + + int cropX = (int)(fullWidth * 0.25); + int cropY = (int)(fullHeight * 0.55); + int cropW = (int)(fullWidth * 0.45); + int cropH = (int)(fullHeight * 0.35); + + // Safety check to prevent crashing if bounds are wrong + if (cropX + cropW > fullWidth) cropW = fullWidth - cropX; + if (cropY + cropH > fullHeight) cropH = fullHeight - cropY; + + Rectangle cropRect = new Rectangle(cropX, cropY, cropW, cropH); + + // 4. Crop the image and Save as wallpaper.bmp + // We use Clone to extract the specific rectangle + using (Bitmap croppedBitmap = fullDisk.Clone(cropRect, fullDisk.PixelFormat)) + { + // Save the Main Wallpaper + string wallpaperPath = string.Format("{0}\\wallpaper.bmp", Cfg.image_folder); + croppedBitmap.Save(wallpaperPath, System.Drawing.Imaging.ImageFormat.Bmp); + + // 5. Save to Archive Directory (if enabled in settings) + if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") + { + if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) + { + Scrap_wrapper.SequenceCount = 0; + } + try + { + string archivePath = Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp"; + croppedBitmap.Save(archivePath, System.Drawing.Imaging.ImageFormat.Bmp); + Scrap_wrapper.SequenceCount++; + } + catch (Exception e) + { + Trace.WriteLine("[can't save wallpaper to distDirectory]"); + Trace.WriteLine(e.Message); + } + } + } + } + // 'using' blocks automatically dispose of fullDisk to free memory + } + + private void InitFolder() + { + if(Directory.Exists(Cfg.image_folder)) + { + // delete all images in the image folder. + //string[] files = Directory.GetFiles(image_folder); + //foreach (string fn in files) + //{ + // File.Delete(fn); + //} + } + else + { + Trace.WriteLine("[himawari8 create folder]"); + Directory.CreateDirectory(Cfg.image_folder); + } + } + public void UpdateImage() + { + InitFolder(); + if (GetImageID() == -1) + { + return; + } + if (imageID.Equals(last_imageID)) + { + return; + } + if (SaveImage()==0) + { + JoinImage(); + } + last_imageID = imageID; + return; + } + public void CleanCDN() + { + Cfg.Load(); + if (Cfg.api_key.Length == 0) return; + if (Cfg.api_secret.Length == 0) return; + try + { + HttpWebRequest request = WebRequest.Create("https://api.cloudinary.com/v1_1/" + Cfg.cloud_name + "/resources/image/fetch?prefix=https://himawari8-dl") as HttpWebRequest; + request.Method = "DELETE"; + request.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); + string svcCredentials = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(Cfg.api_key + ":" + Cfg.api_secret)); + request.Headers.Add("Authorization", "Basic " + svcCredentials); + HttpWebResponse response = null; + StreamReader reader = null; + string result = null; + for (int i = 0; i < 3;i++ ) // max 3 request each hour. + { + response = request.GetResponse() as HttpWebResponse; + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception("[himawari8 clean CND cache connection error]"); + } + if (!response.ContentType.Contains("application/json")) + { + throw new Exception("[himawari8 clean CND cache no json recieved. your Internet connection is hijacked]"); + } + reader = new StreamReader(response.GetResponseStream()); + result = reader.ReadToEnd(); + if (result.Contains("\"error\"")) + { + throw new Exception("[himawari8 clean CND cache request error]\n" + result); + } + if (result.Contains("\"partial\":false")) + { + Trace.WriteLine("[himawari8 clean CDN cache done]"); + break; // end of Clean CDN + } + else + { + Trace.WriteLine("[himawari8 more images to delete]"); + } + } + } + catch (Exception e) + { + Trace.WriteLine("[himawari8 error when delete CDN cache]"); + Trace.WriteLine(e.Message); + return; + } + } + public void ResetState() + { + last_imageID = "0"; + } + } + public static class Autostart { static string key = "EarthLiveSharp"; From b51931533551d7a480233b698475c9bc90f7c2bb Mon Sep 17 00:00:00 2001 From: Shijia Zhou Date: Tue, 13 Jan 2026 14:27:53 +1100 Subject: [PATCH 3/4] Cleaned up Program.cs cleaned up program.cs --- EarthLiveSharp/Program.cs | 145 -------------------------------------- 1 file changed, 145 deletions(-) diff --git a/EarthLiveSharp/Program.cs b/EarthLiveSharp/Program.cs index 4d6fb68..5aa2012 100644 --- a/EarthLiveSharp/Program.cs +++ b/EarthLiveSharp/Program.cs @@ -93,90 +93,6 @@ interface IScraper void ResetState(); } public class Scraper_himawari8 : IScraper - - // // New URL from JMA - // { - // // JMA URL Pattern: https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_HHmm.jpg - // private const string JMA_BASE_URL = "https://www.data.jma.go.jp/mscweb/data/himawari/img/aus/aus_tre_"; - - // public void UpdateImage() - // { - // InitFolder(); - - // try - // { - // // 1. Get current UTC time - // DateTime nowUtc = DateTime.UtcNow; - - // // 2. Subtract 10 minutes to avoid fetching an image that hasn't been uploaded yet. - // // (This also handles the "going back one day" logic automatically via DateTime math) - // DateTime adjustedTime = nowUtc.AddMinutes(-10); - - // // 3. Round down to the nearest 10-minute interval - // // Example: 00:19 -> 00:10, 00:05 -> 00:00 - // int minute = adjustedTime.Minute; - // int roundedMinute = (minute / 10) * 10; - - // // 4. Construct the target timestamp - // DateTime targetTime = new DateTime( - // adjustedTime.Year, - // adjustedTime.Month, - // adjustedTime.Day, - // adjustedTime.Hour, - // roundedMinute, - // 0, - // DateTimeKind.Utc - // ); - - // // 5. Generate the URL (Format: HHmm, e.g., "2350", "0010") - // string timeStr = targetTime.ToString("HHmm"); - // string imageUrl = JMA_BASE_URL + timeStr + ".jpg"; - // string savePath = Cfg.image_folder + "\\wallpaper.bmp"; - - // // 6. Download - // // Clean up old file first - // if (File.Exists(savePath)) - // { - // File.Delete(savePath); - // } - - // using (WebClient client = new WebClient()) - // { - // // Tls12 is required for most government websites now - // ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; - - // Trace.WriteLine("[JMA Download] Requesting: " + imageUrl); - // client.DownloadFile(imageUrl, savePath); - // Trace.WriteLine("[JMA Download] Success. Saved to " + savePath); - // } - // } - // catch (Exception e) - // { - // Trace.WriteLine("[JMA Download Error] " + e.Message); - // } - // } - - // private void InitFolder() - // { - // if (!Directory.Exists(Cfg.image_folder)) - // { - // Directory.CreateDirectory(Cfg.image_folder); - // } - // } - - // // --- Interface Stubs (Not needed for direct JMA download) --- - // public void CleanCDN() - // { - // // Logic removed as we are not using Cloudinary/CDN for this source - // } - - // public void ResetState() - // { - // // No state tracking needed for direct time-based download - // } - // } - - // Old url from NICT { private string imageID = ""; private static string last_imageID = "0"; @@ -252,67 +168,6 @@ private int SaveImage() } } - // Original FullDisk JoinImage - // private void JoinImage() - // { - // // join & convert the images to wallpaper.bmp - // Bitmap bitmap = new Bitmap(550 * Cfg.size, 550 * Cfg.size); - // Image[,] tile = new Image[Cfg.size, Cfg.size]; - // Graphics g = Graphics.FromImage(bitmap); - // for (int ii = 0; ii < Cfg.size; ii++) - // { - // for (int jj = 0; jj < Cfg.size; jj++) - // { - // tile[ii,jj] = Image.FromFile(string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj)); - // g.DrawImage(tile[ii, jj], 550 * ii, 550 * jj); - // tile[ii, jj].Dispose(); - // } - // } - // g.Save(); - // g.Dispose(); - // if (Cfg.zoom == 100) - // { - // bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - // } - // else if (1 < Cfg.zoom & Cfg.zoom <100) - // { - // int new_size = bitmap.Height * Cfg.zoom /100; - // Bitmap zoom_bitmap = new Bitmap(new_size, new_size); - // Graphics g_2 = Graphics.FromImage(zoom_bitmap); - // g_2.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - // g_2.DrawImage(bitmap, 0, 0, new_size, new_size); - // g_2.Save(); - // g_2.Dispose(); - // zoom_bitmap.Save(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder),System.Drawing.Imaging.ImageFormat.Bmp); - // zoom_bitmap.Dispose(); - // } - // else - // { - // Trace.WriteLine("[himawari8 zoom error]"); - // } - - // bitmap.Dispose(); - - // if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") - // { - // if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) - // { - // Scrap_wrapper.SequenceCount = 0; - // } - // try - // { - // File.Copy(string.Format("{0}\\wallpaper.bmp", Cfg.image_folder), Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp", true); - // Scrap_wrapper.SequenceCount++; - // } - // catch (Exception e) - // { - // Trace.WriteLine("[can't save wallpaper to distDirectory]"); - // Trace.WriteLine(e.Message); - // return; - // } - // } - // } - // New Australia focused JoinImage private void JoinImage() { From 554b27615f95990f5b56b2a87d322273e37880cd Mon Sep 17 00:00:00 2001 From: Shijia Zhou Date: Tue, 13 Jan 2026 16:08:00 +1100 Subject: [PATCH 4/4] Mark city locations and superimpose a crop over Shanghai Region --- EarthLiveSharp/Program.cs | 279 +++++++++++++++++++++++++------------- 1 file changed, 185 insertions(+), 94 deletions(-) diff --git a/EarthLiveSharp/Program.cs b/EarthLiveSharp/Program.cs index 5aa2012..defff58 100644 --- a/EarthLiveSharp/Program.cs +++ b/EarthLiveSharp/Program.cs @@ -1,14 +1,30 @@ using System; using System.Windows.Forms; using System.Net; -using System.Net.Cache; +using System.Net.Cache; using System.IO; using System.Diagnostics; using Microsoft.Win32; using System.Drawing; +using System.Drawing.Drawing2D; +using System.Collections.Generic; namespace EarthLiveSharp { + // Helper struct for City Data + public struct City + { + public string Name; + public double Lat; + public double Lon; + public City(string name, double lat, double lon) + { + Name = name; + Lat = lat; + Lon = lon; + } + } + static class Program { [System.Runtime.InteropServices.DllImport("user32.dll")] @@ -36,7 +52,7 @@ static void Main(string[] args) { return; } - if (Cfg.source_selection ==0 & Cfg.cloud_name.Equals("demo")) + if (Cfg.source_selection == 0 & Cfg.cloud_name.Equals("demo")) { #if DEBUG @@ -48,10 +64,7 @@ static void Main(string[] args) } #endif } - //if (Cfg.language.Equals("en")| Cfg.language.Equals("zh-Hans")| Cfg.language.Equals("zh-Hant")) - //{ - // System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(Cfg.language); - //} + Cfg.image_folder = Application.StartupPath + @"\images"; Cfg.Save(); Scrap_wrapper.set_scraper(); @@ -92,12 +105,24 @@ interface IScraper void CleanCDN(); void ResetState(); } - public class Scraper_himawari8 : IScraper + +public class Scraper_himawari8 : IScraper { private string imageID = ""; private static string last_imageID = "0"; private string json_url = "https://himawari8-dl.nict.go.jp/himawari8/img/FULL_24h/latest.json"; + // Cities List + private List cities = new List() + { + new City("Shanghai", 31.23, 121.47), + new City("Sydney", -33.86, 151.21), + new City("Adelaide", -34.93, 138.60), + new City("Perth", -31.95, 115.86), + new City("Brisbane", -27.47, 153.03), + new City("Melbourne", -37.81, 144.96) + }; + private int GetImageID() { System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; @@ -149,7 +174,7 @@ private int SaveImage() for (int jj = 0; jj < Cfg.size; jj++) { url = string.Format("{0}/{1}d/550/{2}_{3}_{4}.png", image_source, Cfg.size, imageID, ii, jj); - image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); // remove the '/' in imageID + image_path = string.Format("{0}\\{1}_{2}.png", Cfg.image_folder, ii, jj); client.DownloadFile(url, image_path); } } @@ -168,19 +193,105 @@ private int SaveImage() } } - // New Australia focused JoinImage + // --- FIXED PROJECTION GEOMETRY --- + private Point GetPixelCoordinates(double lat, double lon, int width, int height) + { + // Himawari-8/9 Sub-satellite Point + double satLon = 140.7; + + double radLat = lat * Math.PI / 180.0; + double radLon = lon * Math.PI / 180.0; + double radSatLon = satLon * Math.PI / 180.0; + double radLonDiff = radLon - radSatLon; + + // Perspective constants + // P = distance_satellite / radius_earth = 42164 / 6378 + double P = 6.610689; + + // Geocentric coords + double x_g = Math.Cos(radLat) * Math.Cos(radLonDiff); + double y_g = Math.Cos(radLat) * Math.Sin(radLonDiff); + double z_g = Math.Sin(radLat); + + // Visibility check (hide if on the back side) + if (x_g < 0.155) // approximate limb limit + { + return new Point(-100, -100); + } + + // Vertical Perspective Projection (View from P looking at 0) + // The mapping factor K maps the geometric projection to the normalized plane + double K = (P - 1) / (P - x_g); + + double x_proj = K * y_g; + double y_proj = K * z_g; + + // CALIBRATION FIX: + // At the limb (edge of earth), x_proj is approx 0.858. + // We want the limb to be at the edge of the image (0.5 coordinates). + // Scale = 0.5 / 0.858 = ~0.582 + double scale = 0.582; + + int pixelX = (int)((0.5 + x_proj * scale) * width); + int pixelY = (int)((0.5 - y_proj * scale) * height); + + return new Point(pixelX, pixelY); + } + + private void DrawCityMarkers(Bitmap bmp) + { + // Dynamic Sizing + int refSize = bmp.Width; + int fontSize = Math.Max(14, refSize / 65); + int dotSize = Math.Max(8, refSize / 180); + int padding = dotSize / 2; + + using (Graphics g = Graphics.FromImage(bmp)) + { + g.SmoothingMode = SmoothingMode.AntiAlias; + g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; + + using (Brush brushRed = new SolidBrush(Color.Red)) + using (Pen penWhite = new Pen(Color.White, 2)) + using (Font font = new Font("Arial", fontSize, FontStyle.Bold)) + using (GraphicsPath path = new GraphicsPath()) + { + foreach (var city in cities) + { + Point p = GetPixelCoordinates(city.Lat, city.Lon, bmp.Width, bmp.Height); + + // Skip if off-screen (e.g. hidden side) + if (p.X < 0 || p.Y < 0) continue; + + // Draw Dot + Rectangle dotRect = new Rectangle(p.X - padding, p.Y - padding, dotSize, dotSize); + g.FillEllipse(brushRed, dotRect); + g.DrawEllipse(penWhite, dotRect); + + // Draw Text with Outline + string text = city.Name; + PointF textPos = new PointF(p.X + dotSize, p.Y - (fontSize / 2)); + + path.Reset(); + path.AddString(text, font.FontFamily, (int)font.Style, font.Size, textPos, StringFormat.GenericDefault); + + g.DrawPath(new Pen(Color.Black, 3), path); + g.FillPath(Brushes.White, path); + } + } + } + } + private void JoinImage() { - // 1. Setup dimensions for the Full Disk int fullWidth = 550 * Cfg.size; int fullHeight = 550 * Cfg.size; - // 2. Create the full disk in memory first using (Bitmap fullDisk = new Bitmap(fullWidth, fullHeight)) { + // 1. Reconstruct Full Disk using (Graphics g = Graphics.FromImage(fullDisk)) { - // Draw all downloaded tiles onto the full disk canvas for (int ii = 0; ii < Cfg.size; ii++) { for (int jj = 0; jj < Cfg.size; jj++) @@ -197,37 +308,60 @@ private void JoinImage() } } - // 3. DEFINE CROP: Focus on Australia / Bass Strait / East Coast - // Himawari-8 Center is 140.7E (approx. mid-Australia longitude). - // - // Settings below are percentages (0.0 to 1.0) of the full image. - // Adjust these numbers to zoom in tighter or pan around. - - // X=0.25: Starts a bit West of WA. - // Y=0.55: Starts around Northern Territory (south of Equator). - // W=0.45: Wide enough to include NZ. - // H=0.35: Tall enough to include Tasmania/Bass Strait and Southern Ocean. - - int cropX = (int)(fullWidth * 0.25); - int cropY = (int)(fullHeight * 0.55); - int cropW = (int)(fullWidth * 0.45); - int cropH = (int)(fullHeight * 0.35); - - // Safety check to prevent crashing if bounds are wrong - if (cropX + cropW > fullWidth) cropW = fullWidth - cropX; - if (cropY + cropH > fullHeight) cropH = fullHeight - cropY; - - Rectangle cropRect = new Rectangle(cropX, cropY, cropW, cropH); - - // 4. Crop the image and Save as wallpaper.bmp - // We use Clone to extract the specific rectangle - using (Bitmap croppedBitmap = fullDisk.Clone(cropRect, fullDisk.PixelFormat)) + // 2. MARK CITIES on the Full Disk + DrawCityMarkers(fullDisk); + + // 3. Prepare Crops + // Crop A: Australia (Main) + int auX = (int)(fullWidth * 0.25); + int auY = (int)(fullHeight * 0.55); + int auW = (int)(fullWidth * 0.45); + int auH = (int)(fullHeight * 0.35); + if (auX + auW > fullWidth) auW = fullWidth - auX; + if (auY + auH > fullHeight) auH = fullHeight - auY; + Rectangle rectAu = new Rectangle(auX, auY, auW, auH); + + // Crop B: Shanghai Area (Inset) + int shX = (int)(fullWidth * 0.15); + int shY = (int)(fullHeight * 0.15); + int shW = (int)(fullWidth * 0.30); + int shH = (int)(fullHeight * 0.30); + if (shX + shW > fullWidth) shW = fullWidth - shX; + if (shY + shH > fullHeight) shH = fullHeight - shY; + Rectangle rectSh = new Rectangle(shX, shY, shW, shH); + + // 4. Composition + using (Bitmap wallpaper = fullDisk.Clone(rectAu, fullDisk.PixelFormat)) { - // Save the Main Wallpaper + using (Bitmap shanghaiImg = fullDisk.Clone(rectSh, fullDisk.PixelFormat)) + { + // Resize Shanghai Inset to 35% of wallpaper width + int insetWidth = (int)(wallpaper.Width * 0.35); + int insetHeight = (int)((double)shanghaiImg.Height / shanghaiImg.Width * insetWidth); + + using (Bitmap shanghaiSmall = new Bitmap(insetWidth, insetHeight)) + { + using (Graphics gSmall = Graphics.FromImage(shanghaiSmall)) + { + gSmall.InterpolationMode = InterpolationMode.HighQualityBicubic; + gSmall.DrawImage(shanghaiImg, 0, 0, insetWidth, insetHeight); + } + + // Draw Inset + using (Graphics gFinal = Graphics.FromImage(wallpaper)) + { + int padding = 20; + // White border around inset + gFinal.DrawRectangle(new Pen(Color.White, 3), padding, padding, insetWidth, insetHeight); + gFinal.DrawImage(shanghaiSmall, padding, padding, insetWidth, insetHeight); + } + } + } + + // Save string wallpaperPath = string.Format("{0}\\wallpaper.bmp", Cfg.image_folder); - croppedBitmap.Save(wallpaperPath, System.Drawing.Imaging.ImageFormat.Bmp); + wallpaper.Save(wallpaperPath, System.Drawing.Imaging.ImageFormat.Bmp); - // 5. Save to Archive Directory (if enabled in settings) if (Cfg.saveTexture && Cfg.saveDirectory != "selected Directory") { if (Scrap_wrapper.SequenceCount >= Cfg.saveMaxCount) @@ -237,54 +371,36 @@ private void JoinImage() try { string archivePath = Cfg.saveDirectory + "\\" + "wallpaper_" + Scrap_wrapper.SequenceCount + ".bmp"; - croppedBitmap.Save(archivePath, System.Drawing.Imaging.ImageFormat.Bmp); + wallpaper.Save(archivePath, System.Drawing.Imaging.ImageFormat.Bmp); Scrap_wrapper.SequenceCount++; } catch (Exception e) { - Trace.WriteLine("[can't save wallpaper to distDirectory]"); + Trace.WriteLine("[can't save wallpaper]"); Trace.WriteLine(e.Message); } } } } - // 'using' blocks automatically dispose of fullDisk to free memory } private void InitFolder() { - if(Directory.Exists(Cfg.image_folder)) + if(!Directory.Exists(Cfg.image_folder)) { - // delete all images in the image folder. - //string[] files = Directory.GetFiles(image_folder); - //foreach (string fn in files) - //{ - // File.Delete(fn); - //} - } - else - { - Trace.WriteLine("[himawari8 create folder]"); Directory.CreateDirectory(Cfg.image_folder); } } public void UpdateImage() { InitFolder(); - if (GetImageID() == -1) - { - return; - } - if (imageID.Equals(last_imageID)) - { - return; - } + if (GetImageID() == -1) return; + if (imageID.Equals(last_imageID)) return; if (SaveImage()==0) { JoinImage(); } last_imageID = imageID; - return; } public void CleanCDN() { @@ -301,47 +417,22 @@ public void CleanCDN() HttpWebResponse response = null; StreamReader reader = null; string result = null; - for (int i = 0; i < 3;i++ ) // max 3 request each hour. + for (int i = 0; i < 3;i++ ) { response = request.GetResponse() as HttpWebResponse; - if (response.StatusCode != HttpStatusCode.OK) - { - throw new Exception("[himawari8 clean CND cache connection error]"); - } - if (!response.ContentType.Contains("application/json")) - { - throw new Exception("[himawari8 clean CND cache no json recieved. your Internet connection is hijacked]"); - } + if (response.StatusCode != HttpStatusCode.OK) throw new Exception("Error"); reader = new StreamReader(response.GetResponseStream()); result = reader.ReadToEnd(); - if (result.Contains("\"error\"")) - { - throw new Exception("[himawari8 clean CND cache request error]\n" + result); - } - if (result.Contains("\"partial\":false")) - { - Trace.WriteLine("[himawari8 clean CDN cache done]"); - break; // end of Clean CDN - } - else - { - Trace.WriteLine("[himawari8 more images to delete]"); - } + if (result.Contains("\"partial\":false")) break; } } - catch (Exception e) - { - Trace.WriteLine("[himawari8 error when delete CDN cache]"); - Trace.WriteLine(e.Message); - return; - } + catch (Exception e) { Trace.WriteLine(e.Message); } } public void ResetState() { last_imageID = "0"; } } - public static class Autostart { static string key = "EarthLiveSharp"; @@ -358,7 +449,7 @@ public static bool Set(bool enabled) } else { - runKey.SetValue(key, path); // dirty fix: to avoid exception in next line. + runKey.SetValue(key, path); runKey.DeleteValue(key); } return true; @@ -377,4 +468,4 @@ public static bool Set(bool enabled) } } } -} +} \ No newline at end of file