using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Dasync.Collections; using Microsoft.Extensions.Logging; namespace MaddoShared { [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility")] public class ImageCreationStuff(ILogger logger, PicSettings picSettings, ImageCreatorSharp imageCreatorService) { public class Options { public bool AggiornaSottodirectory { get; set; } public bool CreaSottocartelle { get; set; } public int FilePerCartella { get; set; } public string SuffissoCartelle { get; set; } public int CifreContatore { get; set; } public NumerazioneType NumerazioneType { get; set; } public string SourcePath { get; set; } public string DestinationPath { get; set; } public int MaxThreads { get; set; } public int ChunksSize { get; set; } public bool LinearExecution { get; set; } } public async Task CreaCatalogoParallel(Options options, ConcurrentBag results, EventHandler> updateEvent, CancellationToken cancellationToken = default(CancellationToken)) { var stopwatch = new Stopwatch(); stopwatch.Start(); await ProcessImagesParallel(options, results, updateEvent, cancellationToken); stopwatch.Stop(); return $"{stopwatch.Elapsed.Hours}h {stopwatch.Elapsed.Minutes}m ${stopwatch.Elapsed.Seconds}s ({stopwatch.Elapsed.TotalSeconds}s)"; } public async Task ProcessImagesParallel( Options options, ConcurrentBag results, EventHandler> updateEvent, CancellationToken cancellationToken = default) { var dataToProcess = GetFilesToProcess(options); // int threads = options.MaxThreads == 0 ? Environment.ProcessorCount * 2 : options.MaxThreads; int threads = options.MaxThreads; Bitmap logoBmp = null; // Load Logo if (picSettings.LogoAggiungi & File.Exists(picSettings.LogoNomeFile)) { logoBmp = new Bitmap(picSettings.LogoNomeFile); } Func processFile = async fileData => { using var logoCopy = logoBmp.Clone(new Rectangle(0, 0, logoBmp.Width, logoBmp.Height), logoBmp.PixelFormat); var imgState = new ImageState { WorkFile = fileData.File, DestDir = fileData.Directory, }; await imageCreatorService.CreaImmagineThread(imgState, logoCopy); // using var imgCreator = new ImageCreatorSharp(fileData.File, fileData.Directory, picSettings); // await imgCreator.CreaImmagineThread(fileData.File.Name, logoCopy); results.Add(fileData.File.Name); try { updateEvent?.Invoke(this, new Tuple(fileData.File.Name, dataToProcess.Count)); } catch (Exception e) { logger.LogError(e, "Error in reporting update"); throw; } // finally // { // imgCreator = null; // } }; if (options.LinearExecution) { foreach (var fileData in dataToProcess) await processFile(fileData); } else { var chunks = options.ChunksSize > 0 ? SplitList(dataToProcess, options.ChunksSize) : new List> { dataToProcess }; foreach (var chunk in chunks) { await chunk.ParallelForEachAsync( processFile, maxDegreeOfParallelism: threads, false, cancellationToken); chunk.Clear(); GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: false, compacting: false); } } try { logoBmp?.Dispose(); } catch (Exception e) { logger.LogError(e, "Error in disposing the logo"); } } private List GetFilesToProcess(Options options) { if (options.AggiornaSottodirectory && options.CreaSottocartelle) { var helper = new FileHelperSharp(); return helper.GetFilesRecursive( new DirectoryInfo(options.SourcePath), new DirectoryInfo(options.DestinationPath), "*.jpg", new FileHelperOptions { FilesPerFolder = options.FilePerCartella, Suffix = options.SuffissoCartelle, CounterSize = options.CifreContatore, NumerationType = options.NumerazioneType }); } var files = Directory.EnumerateFiles( options.SourcePath, "*.jpg", options.AggiornaSottodirectory ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); return files.Select(x => { var fInfo = new FileInfo(x); var filePath = fInfo.DirectoryName; var trimmedSourcePath = options.SourcePath.TrimEnd('\\'); var newFilePath = fInfo.FullName.Replace(trimmedSourcePath, "").TrimStart('\\'); newFilePath = Path.Combine(options.DestinationPath, newFilePath); var destFolderPath = new FileInfo(newFilePath).DirectoryName; var destFolderInfo = new DirectoryInfo(destFolderPath); destFolderInfo.EnsureDirectoryExists(); return new FileData(fInfo, new DirectoryInfo(new FileInfo(newFilePath).DirectoryName)); // var destDir = new FileInfo(newFilePath).Directory!; // destDir.Create(); // Ensure exists // // return new FileData(fInfo, destDir); }).ToList(); } private static IEnumerable> SplitList(List bigList, int nSize = 3) { for (int i = 0; i < bigList.Count; i += nSize) { yield return bigList.GetRange(i, Math.Min(nSize, bigList.Count - i)); } } } }