| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- using qdr.app.tools.qfu.Commands.Aspects;
- using Quadarax.Foundation.Core.QConsole;
- using Quadarax.Foundation.Core.QConsole.Argument;
- using Quadarax.Foundation.Core.QConsole.Attributes;
- using Quadarax.Foundation.Core.Value;
- using System.Drawing;
- using System.Drawing.Imaging;
- namespace qdr.app.tools.qfu.Commands
- {
- [CommandDefinition]
- internal class ImgListCmd : BaseCmd
- {
- #region *** Constants ***
- private const string CMD_NAME = "img_list";
- private const string CMD_DESCR = "List all image files from source directory with dimensions, resolution and size information.";
- // Common image file extensions
- private static readonly string[] ImageExtensions = {
- ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".tif",
- ".webp", ".ico", ".svg", ".psd", ".raw", ".cr2", ".nef", ".arw"
- };
- #endregion
- #region *** Properties ***
- public override string Name => CMD_NAME;
- public override string Description => CMD_DESCR;
- protected string Directory { get; private set; } = string.Empty;
- protected bool IncludeSubdirectories { get; private set; } = false;
- protected string[] ExcludePatterns { get; private set; } = Array.Empty<string>();
- #endregion
- #region *** Constructors ***
- public ImgListCmd(Engine engine) : base(engine)
- {
- }
- #endregion
- #region *** Overrides ***
- #region **** EXECUTE ****
- protected override Result OnExecute()
- {
- var subdirText = IncludeSubdirectories ? " and subdirectories" : "";
- var excludeText = ExcludePatterns.Length > 0 ? $" (excluding: {string.Join(", ", ExcludePatterns)})" : "";
-
- WriteCaption($"Listing image files from '{Directory}'{subdirText}{excludeText}...");
- WriteInfo($"{"Dimensions",-12}\t{"Resolution",-15}\t{"Size",-10}\t{"File Path"}");
- WriteInfo($"{new string('-', 12)}\t{new string('-', 15)}\t{new string('-', 10)}\t{new string('-', 50)}");
- var totalFiles = 0;
- var processedFiles = 0;
- var errors = new List<string>();
- try
- {
- var searchOption = IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
- var allImageFiles = new List<string>();
- // Get all files with image extensions
- foreach (var extension in ImageExtensions)
- {
- try
- {
- var files = FileSystem.Directory.GetFiles(Directory, $"*{extension}", searchOption);
- allImageFiles.AddRange(files);
- }
- catch (Exception ex)
- {
- WriteWarning($"Failed to search for {extension} files: {ex.Message}");
- }
- }
- // Remove duplicates and apply exclusion filters
- var uniqueFiles = allImageFiles.Distinct().ToList();
- var filteredFiles = ApplyExcludeFilters(uniqueFiles);
- totalFiles = filteredFiles.Count;
- foreach (var filePath in filteredFiles.OrderBy(f => f))
- {
- processedFiles++;
-
- try
- {
- var relativePath = Path.GetRelativePath(Directory, filePath);
- var imageInfo = GetImageInfo(filePath);
-
- if (imageInfo != null)
- {
- WriteInfo($"{imageInfo.Dimensions,-12}\t{imageInfo.Resolution,-15}\t{imageInfo.Size,-10}\t{relativePath}");
- }
- else
- {
- WriteWarning($"{"N/A",-12}\t{"N/A",-15}\t{GetFileSize(filePath),-10}\t{relativePath} (unsupported format)");
- }
- }
- catch (Exception ex)
- {
- var relativePath = Path.GetRelativePath(Directory, filePath);
- var errorMsg = $"Failed to process '{relativePath}': {ex.Message}";
- errors.Add(errorMsg);
- WriteError($"{"ERROR",-12}\t{"ERROR",-15}\t{GetFileSize(filePath),-10}\t{relativePath}");
- }
- }
- WriteCaption($"Successfully processed: {processedFiles} of {totalFiles} image files.");
-
- if (errors.Count > 0)
- {
- WriteWarning($"Encountered {errors.Count} errors during operation.");
- }
- return errors.Count == 0 ? new Result() : new Result(new Exception($"Failed to process {errors.Count} files."));
- }
- catch (Exception ex)
- {
- WriteError($"Critical error during operation: {ex.Message}");
- return new Result(ex);
- }
- }
- #endregion
- #region **** Arguments ****
- protected override void OnValidateArguments()
- {
- base.OnValidateArguments();
- // Get and validate directory (using Source from BaseCmd)
- Directory = Source;
- if (!FileSystem.Directory.Exists(Directory))
- throw new ArgumentException($"Directory '{Directory}' does not exist.", SourceAspect.ARG_SRC_NAME);
- // Get flags
- IncludeSubdirectories = GetArgumentValueOrDefault<bool>(SubdirsAspect.ARG_SUBDIRS_NAME, false);
- // Get exclude patterns
- ExcludePatterns = ExcludeAspect.GetExcludePatterns(this);
- }
- protected override IEnumerable<AbstractArgument> OnSetupArguments()
- {
- var list = base.OnSetupArguments().ToList();
-
- // Add our specific arguments
- list.AddRange(SubdirsAspect.SetupArguments());
- list.AddRange(ExcludeAspect.SetupArguments());
-
- return list;
- }
- #endregion
- #region **** Private Operations ****
- private ImageInfo? GetImageInfo(string filePath)
- {
- try
- {
- using var fileStream = FileSystem.File.OpenRead(filePath);
- using var image = Image.FromStream(fileStream, false, false);
-
- var width = image.Width;
- var height = image.Height;
- var dimensions = $"{width}x{height}";
-
- // Get resolution (DPI)
- var horizontalRes = image.HorizontalResolution;
- var verticalRes = image.VerticalResolution;
- var resolution = $"{horizontalRes:F0}x{verticalRes:F0} DPI";
-
- // Get file size
- var size = GetFileSize(filePath);
-
- return new ImageInfo(dimensions, resolution, size);
- }
- catch
- {
- // If System.Drawing can't handle the image, try to at least get basic info
- return null;
- }
- }
- private string GetFileSize(string filePath)
- {
- try
- {
- var fileInfo = FileSystem.FileInfo.New(filePath);
- var bytes = fileInfo.Length;
-
- return bytes switch
- {
- < 1024 => $"{bytes} B",
- < 1024 * 1024 => $"{bytes / 1024.0:F1} KB",
- < 1024 * 1024 * 1024 => $"{bytes / (1024.0 * 1024.0):F1} MB",
- _ => $"{bytes / (1024.0 * 1024.0 * 1024.0):F1} GB"
- };
- }
- catch
- {
- return "N/A";
- }
- }
- private List<string> ApplyExcludeFilters(List<string> files)
- {
- if (ExcludePatterns.Length == 0)
- return files;
- var filteredFiles = new List<string>();
- foreach (var file in files)
- {
- var fileName = Path.GetFileName(file);
- var shouldExclude = false;
- foreach (var pattern in ExcludePatterns)
- {
- if (IsMatch(fileName, pattern) || IsMatch(file, pattern))
- {
- shouldExclude = true;
- break;
- }
- }
- if (!shouldExclude)
- {
- filteredFiles.Add(file);
- }
- }
- return filteredFiles;
- }
- private bool IsMatch(string input, string pattern)
- {
- // Simple pattern matching - supports * wildcards
- if (string.IsNullOrEmpty(pattern))
- return false;
- if (pattern == "*")
- return true;
- // Convert pattern to regex-like matching
- var regexPattern = "^" + pattern.Replace("*", ".*").Replace("?", ".") + "$";
- return System.Text.RegularExpressions.Regex.IsMatch(input, regexPattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
- }
- #endregion
- #endregion
- #region *** Helper Classes ***
- private record ImageInfo(string Dimensions, string Resolution, string Size);
- #endregion
- }
- }
|