// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO; using System.Data; using System.Drawing; using System.Drawing.Imaging; namespace Spludlow.MetSat { /// /// Back end code for http://metsat.spludlow.co.uk/ /// /// A functioning "Spludlow MetSat" database & store must be available /// /// These methods are ran from the Spludlow Scheduler to periodically query the Spludlow MetSat database & store to produce the bitmaps for the web /// /// Each implimented product has its own method and output directory. /// /// The web works from the output directories only /// public class WebImagesBack { public static string _ImageRootDirectory = Spludlow.Config.Get("MetSatWeb.FilePath"); public static string _MetSatStoreDireectory = Spludlow.Config.Get("MetSat.Store"); public static string _ConnectionString = "@MetSat"; public static bool _TestMode = false; public static int _DaysBack = 14; public static string _LogoFilename = @"C:\ProgramData\SpludlowV1\Data\MetSat\SpludlowLogo40mm300dpi.png"; // // Back End Wrapper methods for the scheduler to call // public static void StartDailyProcesses() { Spludlow.Call.Queue(Environment.MachineName, "Spludlow.MetSat", "Spludlow.MetSat.WebImagesBack", "CleanUp"); string[] methods = new string[] { "CloudMaskDaySheet", "ChannelsDaySheet", "IndianOceanCloudMaskDaySheet", "IndianOceanChannelsDaySheet" }; foreach (string method in methods) Spludlow.Call.Queue(Environment.MachineName, "Spludlow.MetSat", "Spludlow.MetSat.WebImagesBack", method); } public static void StartRegularProcesses() { string[] methods = new string[] { "FalseColour", "FalseColourCrop", "WaterVapour", "IndianOceanFalseColour", "IndianOceanFalseColourCrop", "IndianOceanWaterVapour" }; foreach (string method in methods) Spludlow.Call.Queue(Environment.MachineName, "Spludlow.MetSat", "Spludlow.MetSat.WebImagesBack", method); } public static void CloudMaskDaySheet() { CloudMaskSheets(_ImageRootDirectory + @"\CloudMaskDaySheet", "EO_EUM_DAT_MSG_CLM", "Spludlow - EUMETSAT - Meteosat 11 - 0 Degrees - SEVIRI - Cloud Mask Day Sheet - "); } public static void ChannelsDaySheet() { ChannelsSheets(_ImageRootDirectory + @"\ChannelsDaySheet", "EO_EUM_DAT_MSG_HRSEVIRI", "Spludlow - EUMETSAT - Meteosat 11 - 0 Degrees - SEVIRI - Channels Day Sheet - "); } public static void FalseColour() { FalseColourBitmap(_ImageRootDirectory + @"\FalseColour", "EO_EUM_DAT_MSG_HRSEVIRI", "Spludlow - EUMETSAT - Meteosat 11 - 0 Degrees - SEVIRI - False Colour - ", false, false); } public static void FalseColourCrop() { FalseColourBitmap(_ImageRootDirectory + @"\FalseColourCrop", "EO_EUM_DAT_MSG_HRSEVIRI", "Spludlow - EUMETSAT - Meteosat 11 - 0 Degrees - SEVIRI - HRV False Colour Crop - ", true, false); } public static void WaterVapour() { ChannelBitmap(_ImageRootDirectory + @"\WaterVapour", "EO_EUM_DAT_MSG_HRSEVIRI", "WV_062", "Spludlow - EUMETSAT - Meteosat 11 - 0 Degrees - SEVIRI - Water Vapour"); } public static void IndianOceanCloudMaskDaySheet() { CloudMaskSheets(_ImageRootDirectory + @"\IndianOceanCloudMaskDaySheet", "EO_EUM_DAT_MSG_CLM-IODC", "Spludlow - EUMETSAT - Meteosat 11 - 41.5 Degrees - SEVIRI - Cloud Mask Day Sheet - "); } public static void IndianOceanChannelsDaySheet() { ChannelsSheets(_ImageRootDirectory + @"\IndianOceanChannelsDaySheet", "EO_EUM_DAT_MSG_HRSEVIRI-IODC", "Spludlow - EUMETSAT - Meteosat 11 - 41.5 Degrees - SEVIRI - Channels Day Sheet - "); } public static void IndianOceanFalseColour() { FalseColourBitmap(_ImageRootDirectory + @"\IndianOceanFalseColour", "EO_EUM_DAT_MSG_HRSEVIRI-IODC", "Spludlow - EUMETSAT - Meteosat 11 - 41.5 Degrees - SEVIRI - False Colour - ", false, true); } public static void IndianOceanFalseColourCrop() { FalseColourBitmap(_ImageRootDirectory + @"\IndianOceanFalseColourCrop", "EO_EUM_DAT_MSG_HRSEVIRI-IODC", "Spludlow - EUMETSAT - Meteosat 11 - 41.5 Degrees - SEVIRI - HRV False Colour Crop - ", true, true); } public static void IndianOceanWaterVapour() { ChannelBitmap(_ImageRootDirectory + @"\IndianOceanWaterVapour", "EO_EUM_DAT_MSG_HRSEVIRI-IODC", "WV_062", "Spludlow - EUMETSAT - Meteosat 11 - 41.5 Degrees - SEVIRI - Water Vapour - "); } /// /// Create PDFs of each days 96 cloud mask bitmaps placed into a grid on an A3 document /// Thumbnails also generated /// Run once daily using the Spludlow Scheduler /// public static void CloudMaskSheets(string targetDirectory, string productId, string fullText) { if (Directory.Exists(targetDirectory) == false) Directory.CreateDirectory(targetDirectory); string filenamePrefix = fullText.Replace(" ", ""); int placedImageDPI = 300; // Query the database DateTime startDate = DateTime.Now.Date.AddDays(-_DaysBack); Spludlow.Data.IDAL database = Spludlow.Data.DAL.Create(_ConnectionString); DataTable table = database.Select( "SELECT DataItems.CaptureTime, DataItemFiles.* FROM DataItems INNER JOIN DataItemFiles ON DataItems.DataItemId = DataItemFiles.DataItemId " + "WHERE((DataItems.DataProductId = @DataProductId) AND (DataItemFiles.DataItemFileTypeId = 'CH') AND (DataItems.CaptureTime >= @CaptureTime)) " + "ORDER BY DataItems.CaptureTime", productId, startDate); table = SetKeyRemovingDupRows(table, new string[] { "CaptureTime" }, true); // Page geometry float xOffset = 3; float yOffset = 18; float thumbSize = 32; float thumbBoarder = 1.25F; float boxSize = thumbSize + thumbBoarder * 2; int pixels = Spludlow.Printing.PageSizes.MillimetersToPixels(thumbSize, placedImageDPI); Size size = new Size(pixels, pixels); // For each date in the data foreach (DateTime captureDate in GetCaptureDates(table)) { // Skip today as will be incomplete if (captureDate.Date == DateTime.Now.Date) continue; // Name things string pdfFilename = targetDirectory + @"\" + filenamePrefix + captureDate.ToString("yyyy-MM-dd") + ".pdf"; // Skip if done already if (File.Exists(pdfFilename) == true) continue; using (Spludlow.TempDirectory tempDir = new Spludlow.TempDirectory()) { // Create a Print doc Spludlow.Printing.PrintDoc doc = new Spludlow.Printing.PrintDoc("A3*"); // Print hte titla doc.Text(fullText + captureDate.ToShortDateString(), "Arial, 24, Bold, Underline", 4, 4); for (int index = 0; index < 96; ++index) { // Do the maths for bitmap placment int xIndex = index % 12; int yIndex = index / 12; float x = xOffset + thumbBoarder + xIndex * boxSize; float y = yOffset + thumbBoarder + yIndex * boxSize; // Find the date's row DateTime itemDateTime = captureDate.AddMinutes(index * 15); DataRow row = table.Rows.Find(itemDateTime); if (row != null) { // Get the store filename string extention = (string)row["StoreExtention"]; string storeFilename = Spludlow.Io.FileStore.FilePath((long)row["DataItemFileId"], _MetSatStoreDireectory, extention, false); // Res-size to temp file string tempFilename = tempDir.Path + @"\" + Spludlow.Text.TimeStamp(itemDateTime) + extention; Spludlow.Drawing.Bitmaps.Resize(storeFilename, size, tempFilename, ImageFormat.Png, PixelFormat.Format24bppRgb, placedImageDPI); // Place the re-sized image in the print doc doc.Place(tempFilename, x, y, 1, 1); } else { doc.Rectangle(x, y, thumbSize, thumbSize, 0, Color.Empty, Color.Black); } // Draw a boarder rounf the bitmap doc.Rectangle(x - thumbBoarder, y - thumbBoarder, boxSize, boxSize, 1.0F, Color.Red, Color.Empty); } // Print the PDF Spludlow.Printing.Printer.Print(doc, "pdf", pdfFilename, true); File.SetLastWriteTime(pdfFilename, captureDate); // Print the thumbnail bitmaps SaveThumbnalsFromDocument(doc, pdfFilename, captureDate); } if (_TestMode == true) break; } } /// /// Generate daily HRIT Sheets as a PDF with low res placed bitmaps and a JPEG Thumbnail /// public static void ChannelsSheets(string targetDirectory, string productId, string fullText) { if (Directory.Exists(targetDirectory) == false) Directory.CreateDirectory(targetDirectory); int placedImageDPI = 300; string filenamePrefix = fullText.Replace(" ", ""); // Query the database DateTime startDate = DateTime.Now.Date.AddDays(-_DaysBack); Spludlow.Data.IDAL database = Spludlow.Data.DAL.Create(_ConnectionString); DataTable table = database.Select( "SELECT DataItems.CaptureTime, DataItemFiles.* FROM DataItems INNER JOIN DataItemFiles ON DataItems.DataItemId = DataItemFiles.DataItemId " + "WHERE((DataItems.DataProductId = @DataProductId) AND (DataItemFiles.DataItemFileTypeId = 'CH') AND (DataItems.CaptureTime >= @CaptureTime)) " + "ORDER BY DataItems.CaptureTime, DataItemFiles.Channel", productId, startDate); table = SetKeyRemovingDupRows(table, new string[] { "CaptureTime", "Channel" }, true); DateTime[] captureDates = GetCaptureDates(table); string[] channels = new string[] { "IR_016", "IR_039", "IR_087", "IR_097", "IR_108", "IR_120", "IR_134", "VIS006", "VIS008", "WV_062", "WV_073" }; float xOffset = 20; float yOffset = 18; float thumbSize = 32; float thumbBoarder = 1.25F; float boxSize = thumbSize + thumbBoarder * 2; int pixels = Spludlow.Printing.PageSizes.MillimetersToPixels(thumbSize, placedImageDPI); Size size = new Size(pixels, pixels); foreach (DateTime captureDate in captureDates) { if (captureDate.Date == DateTime.Now.Date) continue; string pdfFilename = targetDirectory + @"\" + filenamePrefix + captureDate.ToString("yyyy-MM-dd") + ".pdf"; if (File.Exists(pdfFilename) == true) continue; using (Spludlow.TempDirectory tempDir = new Spludlow.TempDirectory()) { Spludlow.Printing.PrintDoc doc = new Spludlow.Printing.PrintDoc("A3*"); doc.Text(fullText + captureDate.ToShortDateString(), "Arial, 24, Bold, Underline", 4, 4); for (int timeIndex = 0; timeIndex < 8; ++timeIndex) { for (int channelIndex = 0; channelIndex < channels.Length; ++channelIndex) { string channel = channels[channelIndex]; float x = xOffset + thumbBoarder + channelIndex * boxSize; float y = yOffset + thumbBoarder + timeIndex * boxSize; DateTime itemDateTime = captureDate.AddHours(timeIndex * 3); DataRow row = table.Rows.Find(new object[] { itemDateTime, channel }); if (row != null) { string extention = (string)row["StoreExtention"]; string storeFilename = Spludlow.Io.FileStore.FilePath((long)row["DataItemFileId"], _MetSatStoreDireectory, extention, false); string tempFilename = tempDir.Path + @"\" + Spludlow.Text.TimeStamp(itemDateTime) + "-" + channel + extention; Spludlow.Drawing.Bitmaps.Resize(storeFilename, size, tempFilename, ImageFormat.Png, PixelFormat.Format24bppRgb, placedImageDPI); doc.Place(tempFilename, x, y, 1, 1); } else { doc.Rectangle(x, y, thumbSize, thumbSize, 0, Color.Empty, Color.Black); } doc.Rectangle(x - thumbBoarder, y - thumbBoarder, boxSize, boxSize, 1.0F, Color.Red, Color.Empty); } } // Print the PDF Spludlow.Printing.Printer.Print(doc, "pdf", pdfFilename, true); File.SetLastWriteTime(pdfFilename, captureDate); // Print the thumbnail bitmaps SaveThumbnalsFromDocument(doc, pdfFilename, captureDate); } if (_TestMode == true) break; } } /// /// Create the High Res Visable Full Earth & Western Europe Bitmaps with thumbnails /// /// Run on Scheduler on the hour just after Spludlow MetSat Process /// /// Query all "EO_EUM_DAT_MSG_HRSEVIRI" "Source Archive Records" in the Spludlow MetSat Database (3 hourly XRIT) /// For interested hours only, 6am -> 6pm, day time /// If file has not all ready been processed /// Process "Source Archive" into PNG Crop /// Stamp on the logo and info /// Save out JPEG full size and JPEG thumnail for the web server /// public static int FalseColourBitmap(string targetDirectory, string productId, string fullText, bool cropHrv, bool indian) { if (Directory.Exists(targetDirectory) == false) Directory.CreateDirectory(targetDirectory); int[] hours; if (indian == false) hours = new int[] { 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; else hours = new int[] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; string filenamePrefix = fullText.Replace(" ", ""); // Query metsat database for all interested product files DateTime startDate = DateTime.Now.Date.AddDays(-_DaysBack); Spludlow.Data.IDAL database = Spludlow.Data.DAL.Create(_ConnectionString); DataTable table = database.Select( "SELECT DataItems.CaptureTime, DataItemFiles.* FROM DataItems INNER JOIN DataItemFiles ON DataItems.DataItemId = DataItemFiles.DataItemId " + "WHERE((DataItems.DataProductId = @DataProductId) AND (DataItemFiles.DataItemFileTypeId = 'SA') AND (DataItems.CaptureTime >= @CaptureTime)) " + "ORDER BY DataItems.CaptureTime", productId, startDate); table = SetKeyRemovingDupRows(table, new string[] { "CaptureTime" }, true); DateTime[] captureDates = GetCaptureDates(table); int count = 0; if (cropHrv == false) fullText = ""; foreach (DateTime captureDate in captureDates) { foreach (int hour in hours) { // Find the data row DateTime itemDateTime = captureDate.AddHours(hour); DataRow row = table.Rows.Find(new object[] { itemDateTime }); if (row == null) continue; string name = filenamePrefix + itemDateTime.ToString("yyyy-MM-dd-HH"); string stampText = fullText + itemDateTime.ToString(); // Get the store filename string extention = (string)row["StoreExtention"]; string storeFilename = Spludlow.Io.FileStore.FilePath((long)row["DataItemFileId"], _MetSatStoreDireectory, extention, false); string masterFilename = targetDirectory + @"\" + name + ".master.png"; // Cropped Xrit2Pic output string stampFilename = targetDirectory + @"\" + name + ".png"; // Stamped with log and text string imageFilename = targetDirectory + @"\" + name + ".jpg"; // Full size JPEG // Already processed if (File.Exists(imageFilename) == true) continue; // The composite source image moves around depending on time of day, these numbers seem to work int xCrop = 0; if (indian == false) { if (hour == 15) xCrop = 946; if (hour == 18) xCrop = 946 * 4; } else { if (hour == 15) xCrop = 946 * 3; } try { // Process and crop the original "SA" (Source Archive) files FalseColourProcess(storeFilename, masterFilename, xCrop, cropHrv); // Stamp on the logo and info StampImage(masterFilename, stampFilename, _LogoFilename, stampText, Color.DeepSkyBlue); Size originalSize = Spludlow.Drawing.Bitmaps.Dimensions(stampFilename); // Save out a Full JPEG Spludlow.Drawing.Bitmaps.Resize(stampFilename, originalSize, imageFilename, ImageFormat.Jpeg, PixelFormat.Format24bppRgb, 300); File.SetLastWriteTime(imageFilename, itemDateTime); // Save out a Thumbs JPEG SaveTumbnailsFromBitmap(stampFilename, itemDateTime); } catch (Exception ee) { Spludlow.Log.Error("FalseColourBitmap: " + itemDateTime + ", " + storeFilename, ee); } // Delete intimediate files if (File.Exists(masterFilename) == true) File.Delete(masterFilename); if (File.Exists(stampFilename) == true) File.Delete(stampFilename); if (_TestMode == true) return count; } } return count; } /// /// Extract an XRIT "Source Archive" from the Spludlow MetSat Store /// Run Xrti2pic against the files to create a High Res Visable PGM bitmap /// Convert to PNG /// Crop image for Western Europe /// Save out target PNG /// private static void FalseColourProcess(string sourceArchiveFilename, string targetFilename, int x, bool hrvlum) { int dpi = 600; using (Spludlow.TempDirectory tempDir = new Spludlow.TempDirectory()) { string sourceArchiveDirectory = tempDir + @"\source"; Directory.CreateDirectory(sourceArchiveDirectory); string processedDirectory = tempDir + @"\processed"; Directory.CreateDirectory(processedDirectory); string imageDirectory = tempDir + @"\image"; Directory.CreateDirectory(imageDirectory); // Extract archive and get result filenames Spludlow.Archive.Extract(sourceArchiveFilename, sourceArchiveDirectory); string[] subDirs = Directory.GetDirectories(sourceArchiveDirectory); if (subDirs.Length != 1) throw new ApplicationException("Not one sub Directory"); sourceArchiveDirectory = subDirs[0]; string[] files = Directory.GetFiles(sourceArchiveDirectory); string imageFilename; // Run XRIT2PIC to make the false colour image string xritArguments = "-compose"; if (hrvlum == true) xritArguments += " -hrvlum"; Spludlow.MetSat.Xrit2Pic.Run(Directory.GetFiles(sourceArchiveDirectory), processedDirectory, xritArguments); // Get result filename, there should only be one string[] resultFilenames = Directory.GetFiles(processedDirectory); if (resultFilenames.Length != 1) throw new ApplicationException("Not one result file: " + resultFilenames.Length); string filename = resultFilenames[0]; // Convert to PNG imageFilename = imageDirectory + @"\" + Path.GetFileNameWithoutExtension(filename) + ".png"; Spludlow.Drawing.PGM.Convert(filename, imageFilename, ImageFormat.Png, dpi); if (_TestMode == true && hrvlum == true) File.Copy(imageFilename, targetFilename + ".FULL.png"); // Crop or copy to target if (hrvlum == true) Spludlow.Drawing.Bitmaps.Crop(imageFilename, targetFilename, x, 0, 3840, 2160, dpi); else File.Copy(imageFilename, targetFilename); } } /// /// Use a previously processed channel bitmap from the Spludlow MetSat Store /// public static int ChannelBitmap(string targetDirectory, string productId, string channel, string fullText) { if (Directory.Exists(targetDirectory) == false) Directory.CreateDirectory(targetDirectory); string filenamePrefix = fullText.Replace(" ", ""); // Query metsat database for all interested product files DateTime startDate = DateTime.Now.Date.AddDays(-_DaysBack); Spludlow.Data.IDAL database = Spludlow.Data.DAL.Create(_ConnectionString); DataTable table = database.Select( "SELECT DataItems.CaptureTime, DataItemFiles.* FROM DataItems INNER JOIN DataItemFiles ON DataItems.DataItemId = DataItemFiles.DataItemId " + "WHERE((DataItems.DataProductId = @DataProductId) AND (DataItemFiles.Channel = @Channel) AND (DataItems.CaptureTime >= @CaptureTime)) " + "ORDER BY DataItems.CaptureTime", productId, channel, startDate); table = SetKeyRemovingDupRows(table, new string[] { "CaptureTime" }, true); DateTime[] captureDates = GetCaptureDates(table); int count = 0; int[] hours = new int[] { 0, 3, 6, 9, 12, 15, 18, 21 }; foreach (DateTime captureDate in captureDates) { foreach (int hour in hours) { // Find the data row DateTime itemDateTime = captureDate.AddHours(hour); DataRow row = table.Rows.Find(new object[] { itemDateTime }); if (row == null) continue; string name = filenamePrefix + itemDateTime.ToString("yyyy-MM-dd-HH"); string stampText = itemDateTime.ToString(); // Get the store filename string extention = (string)row["StoreExtention"]; string storeFilename = Spludlow.Io.FileStore.FilePath((long)row["DataItemFileId"], _MetSatStoreDireectory, extention, false); string stampFilename = targetDirectory + @"\" + name + ".png"; // Stamped with log and text string imageFilename = targetDirectory + @"\" + name + ".jpg"; // Full size JPEG // Already processed if (File.Exists(imageFilename) == true) continue; Size originalSize = Spludlow.Drawing.Bitmaps.Dimensions(storeFilename); // Stamp on the logo and info StampImage(storeFilename, stampFilename, _LogoFilename, stampText, Color.Yellow); // Save out a Full JPEG Spludlow.Drawing.Bitmaps.Resize(stampFilename, originalSize, imageFilename, ImageFormat.Jpeg, PixelFormat.Format24bppRgb, 300); File.SetLastWriteTime(imageFilename, itemDateTime); // Save out a Thumbs JPEG SaveTumbnailsFromBitmap(stampFilename, itemDateTime); // Delete intimediate files File.Delete(stampFilename); if (_TestMode == true) return count; } } return count; } /// /// Stamp logo and right aligned text /// /// Using the PrintDoc(bitmap, standardWidth) overload specifically designed for drawing onto bitmaps /// /// A standard page width of 210mm (A4) is used for drawing operations reguardless of the bitmap size and dpi to make page geometry easy /// public static void StampImage(string sourceFilename, string targetFilename, string logoFilename, string text, Color colour) { int targetDpi = 600; // Create Print Doc from source bitmap file placed with a familiar width (A4) Spludlow.Printing.PrintDoc doc = new Spludlow.Printing.PrintDoc(sourceFilename, 210); float boarder = 2.5F; // Place the logo (40mm wide) doc.Place(logoFilename, boarder, boarder, 1.0F, 1); // Print the info in textbox so we can right alight and handle overflow doc.TextBox(text, "Rockwell, 12", 45, boarder, 210 - (45 + boarder), 50, colour, StringAlignment.Far); // Save out target bitmap, "Ignore History" flag set to true as not required Spludlow.Printing.Printer.Print(doc, "bitmap", targetFilename + ", " + targetDpi, true); } /// /// Create thumbnail bitmaps from PrintDoc. Used when doing PDF Sheets /// public static void SaveThumbnalsFromDocument(Spludlow.Printing.PrintDoc doc, string filename, DateTime lastWriteTime) { int[] pixelWidths = new int[] { 960, 480 }; string name = filename.Substring(0, filename.LastIndexOf(".")); foreach (int pixelWidth in pixelWidths) { string thumbFilename = name + ".thumb" + pixelWidth + ".jpg"; float dpi = Spludlow.Printing.PageSizes.MillimetersToDpi(doc.Width, pixelWidth); Spludlow.Printing.Printer.Print(doc, "bitmap", thumbFilename + ", " + dpi, true); File.SetLastWriteTime(thumbFilename, lastWriteTime); } } /// /// Create thumbnail bitmaps from bitmap. /// public static void SaveTumbnailsFromBitmap(string filename, DateTime lastWriteTime) { int[] pixelWidths = new int[] { 960, 480 }; string name = filename.Substring(0, filename.LastIndexOf(".")); Size originalPixelSize = Spludlow.Drawing.Bitmaps.Dimensions(filename); foreach (int pixelWidth in pixelWidths) { decimal height = originalPixelSize.Height * (pixelWidth / originalPixelSize.Width); Size thumbSize = new Size(pixelWidth, (int)Math.Round(height, 0)); string thumbFilename = name + ".thumb" + pixelWidth + ".jpg"; Spludlow.Drawing.Bitmaps.Resize(filename, thumbSize, thumbFilename, ImageFormat.Jpeg, PixelFormat.Format24bppRgb, 72); File.SetLastWriteTime(thumbFilename, lastWriteTime); } } /// /// Get the dates in the data /// public static DateTime[] GetCaptureDates(DataTable table) { List captureDates = new List(); foreach (DataRow row in table.Rows) { DateTime captureDate = ((DateTime)row["CaptureTime"]).Date; if (captureDates.Contains(captureDate) == false) captureDates.Add(captureDate); } captureDates.Sort(); return captureDates.ToArray(); } /// /// Occoationaly see duplicate rows in the data, probibly from re-starting running processes /// Should fix further back but this will solve the problem for now /// Done in reverse order as the last one will be most likly be complete /// public static DataTable SetKeyRemovingDupRows(DataTable table, string[] keyColumnNames, bool importRowsFromEnd) { DataTable resultTable = table.Clone(); DataColumn[] keyColumns = new DataColumn[keyColumnNames.Length]; for (int index = 0; index < keyColumnNames.Length; ++index) keyColumns[index] = resultTable.Columns[keyColumnNames[index]]; resultTable.PrimaryKey = keyColumns; List rows = new List(); foreach (DataRow row in table.Rows) rows.Add(row); if (importRowsFromEnd == true) rows.Reverse(); object[] key = new object[keyColumnNames.Length]; foreach (DataRow row in rows) { for (int keyIndex = 0; keyIndex < key.Length; ++keyIndex) key[keyIndex] = row[keyColumnNames[keyIndex]]; if (resultTable.Rows.Find(key) == null) resultTable.ImportRow(row); } // Maybe should put back to right order now reversed ? return resultTable; } public static void CleanUp() { DateTime deleteBefore = DateTime.Now.Date.AddDays(-45); int count = 0; foreach (string imageDirectory in Directory.GetDirectories(_ImageRootDirectory)) { DirectoryInfo dirInfo = new DirectoryInfo(imageDirectory); foreach (FileInfo fileInfo in dirInfo.GetFiles()) { if (fileInfo.LastWriteTime < deleteBefore) { fileInfo.Delete(); ++count; } } } Spludlow.Log.Finish("Web Images Back, Clean Up, Deleted: " + count); } } }