private async Task OptimizeImageAsync(bool lossy, EventArgs e)
        {
            _isProcessing = true;

            IEnumerable <string> files = null;

            // Check command parameters first
            if (e is OleMenuCmdEventArgs cmdArgs && cmdArgs.InValue is string arg)
            {
                string filePath = arg.Trim('"', '\'');

                if (Compressor.IsFileSupported(filePath) && File.Exists(filePath))
                {
                    files = new[] { filePath };
                }
            }

            // Then check selected items
            if (files == null)
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                files = ProjectHelpers.GetSelectedFilePaths(_dte).Where(f => Compressor.IsFileSupported(f)).ToArray();
            }

            if (!files.Any())
            {
                _isProcessing = false;

                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                _dte.StatusBar.Text = "No images found to optimize";
                return;
            }

            var list      = new CompressionResult[files.Count()];
            var stopwatch = Stopwatch.StartNew();
            int count     = files.Count();

            await Task.Run(async() =>
            {
                try
                {
                    string text = count == 1 ? " image" : " images";
                    _dte.StatusBar.Progress(true, "Optimizing " + count + text + "...", AmountCompleted: 1, Total: count + 1);

                    var compressor = new Compressor();
                    var cache      = new Cache(_dte.Solution.FullName, lossy);
                    int nCompleted = 0;
                    var options    = new ParallelOptions {
                        MaxDegreeOfParallelism = Environment.ProcessorCount
                    };

                    Parallel.For(0, count, options, i =>
                    {
                        string file = files.ElementAt(i);

                        // Don't process if file has been fully optimized already
                        if (cache.IsFullyOptimized(file))
                        {
                            var bogus = new CompressionResult(file, file, TimeSpan.Zero)
                            {
                                Processed = false
                            };
                            HandleResult(bogus, nCompleted + 1);
                        }
                        else
                        {
                            CompressionResult result = compressor.CompressFile(file, lossy);
                            HandleResult(result, nCompleted + 1);

                            if (result.Saving > 0 && result.ResultFileSize > 0 && !string.IsNullOrEmpty(result.ResultFileName))
                            {
                                list[i] = result;
                            }
                            else
                            {
                                cache.AddToCache(file);
                            }
                        }

                        Interlocked.Increment(ref nCompleted);
                    });
                }
                finally
                {
                    _dte.StatusBar.Progress(false);
                    stopwatch.Stop();
                    await DisplayEndResultAsync(list, stopwatch.Elapsed);
                    _isProcessing = false;
                }
            });
        }
        private async void OptimizeImageAsync(bool lossy)
        {
            _isProcessing = true;

            IEnumerable <string> files = ProjectHelpers.GetSelectedFilePaths(_dte).Where(f => Compressor.IsFileSupported(f));

            if (!files.Any())
            {
                _dte.StatusBar.Text = "No images found to optimize";
                _isProcessing       = false;
                return;
            }

            var list      = new CompressionResult[files.Count()];
            var stopwatch = Stopwatch.StartNew();
            int count     = files.Count();

            await Task.Run(async() =>
            {
                try
                {
                    string text = count == 1 ? " image" : " images";
                    _dte.StatusBar.Progress(true, "Optimizing " + count + text + "...", AmountCompleted: 1, Total: count + 1);

                    var compressor = new Compressor();
                    var cache      = new Cache(_dte.Solution, lossy);
                    int nCompleted = 0;
                    var options    = new ParallelOptions {
                        MaxDegreeOfParallelism = Environment.ProcessorCount
                    };

                    Parallel.For(0, count, options, i =>
                    {
                        string file = files.ElementAt(i);

                        // Don't process if file has been fully optimized already
                        if (cache.IsFullyOptimized(file))
                        {
                            var bogus = new CompressionResult(file, file, TimeSpan.Zero)
                            {
                                Processed = false
                            };
                            HandleResult(bogus, nCompleted + 1);
                        }
                        else
                        {
                            CompressionResult result = compressor.CompressFileAsync(file, lossy);
                            HandleResult(result, nCompleted + 1);

                            if (result.Saving > 0 && result.ResultFileSize > 0 && !string.IsNullOrEmpty(result.ResultFileName))
                            {
                                list[i] = result;
                            }
                            else
                            {
                                cache.AddToCache(file);
                            }
                        }

                        Interlocked.Increment(ref nCompleted);
                    });
                }
                finally
                {
                    _dte.StatusBar.Progress(false);
                    stopwatch.Stop();
                    await DisplayEndResultAsync(list, stopwatch.Elapsed);
                    _isProcessing = false;
                }
            });
        }