public CacheView(ImageCache cache) { this.cache = cache; InitializeComponent(); this.Icon = Properties.Resources.Icon1; this.entryInfoBindingSource.DataSource = new BindingSource(this.entries, null); this.toolStripButtonEnableSwap.Checked = Program.EnableSwap; this.toolStripButtonEnableSwap.CheckedChanged += ToolStripButtonEnableSwap_CheckedChanged; }
public static void Main(string[] args) { try { if ((args.Length >= 1) && String.Equals(args[0], "-waitdebugger")) { while (!Debugger.IsAttached) { Thread.Sleep(250); } ShiftArgs(ref args, 1); } if ((args.Length == 2) && String.Equals(args[0], "-server")) { Environment.ExitCode = ImageServer.RunServer(args[1]); return; } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); bool showLogOnStart = false; while (args.Length >= 1) { switch (args[0]) { default: goto Break; case "-profile": ProfileMode = true; ShiftArgs(ref args, 1); break; case "-showlog": showLogOnStart = true; ShiftArgs(ref args, 1); break; case "-swap": EnableSwap = true; ShiftArgs(ref args, 1); break; case "-noswap": EnableSwap = false; ShiftArgs(ref args, 1); break; } } Break: if (args.Length == 0) { // HACK: based on what WinMerge does - usability is suspect but still much better than FolderBrowserDialog. // See: http://www.codeproject.com/Articles/44914/Select-file-or-folder-from-the-same-dialog using (OpenFileDialog dialog = new OpenFileDialog()) { dialog.ValidateNames = false; dialog.CheckFileExists = false; dialog.CheckPathExists = false; dialog.Title = "Select a Folder"; dialog.FileName = "Select Folder."; if (dialog.ShowDialog() != DialogResult.OK) { return; } args = new string[] { Path.GetDirectoryName(dialog.FileName) }; } } if (args.Length != 1) { MessageBox.Show("Program must take one argument which is the path to a directory containing images to adjust."); return; } Window window; ImageCache cache = new ImageCache(); string directory = Path.GetFullPath(args[0]); string scanDirectory = GetScanDirectoryFromTargetDirectory(directory); if (!Directory.Exists(directory)) { MessageBox.Show(String.Format("Specified directory does not exist: \"{0}\"", directory)); return; } XmlDocument settings = new XmlDocument(); { string settingsPath = Path.Combine(scanDirectory, SettingsFile); if (File.Exists(settingsPath)) { settings.Load(settingsPath); } } GlobalOptions options = new GlobalOptions(settings.CreateNavigator().SelectSingleNode("/*/options")); { using (GlobalOptionsDialog dialog = new GlobalOptionsDialog(options, directory)) { Application.Run(dialog); if (dialog.DialogResult != DialogResult.OK) { return; } } } if (showLogOnStart) { logWindow = new LoggingWindow(); logWindow.Show(); } // scan items List <Item> items = new List <Item>(); foreach (string filePath in Directory.GetFiles(scanDirectory)) { string fileName = Path.GetFileName(filePath); if (String.Equals(fileName, SettingsFile, StringComparison.OrdinalIgnoreCase)) { continue; } bool extUpper = String.Equals(Path.GetExtension(fileName), Path.GetExtension(fileName).ToUpper()); //fileName = Path.ChangeExtension(fileName, extUpper ? ".JPG" : ".jpg"); Item item = new Item(Path.Combine(directory, fileName), options, cache); items.Add(item); XPathNavigator itemNav = settings.CreateNavigator().SelectSingleNode(String.Format("/*/items/item[file=\"{0}\"]", fileName)); if (itemNav != null) { item.ReadXml(itemNav); } } window = new Window(directory, items, cache, options); window.Show(); window.LastAnalysisTask = BatchAnalyzerQueue.BeginAnalyzeBatch(items); Application.Run(window); LoggingWindow logw = logWindow; if (logw != null) { logw.Close(); } window.LastAnalysisTask.Wait(); // allow any unfinished actions to cancel and dispose state cache.Dispose(); SerializationManager.Manager.Dispose(); ImageClient.Close(); } catch (Exception exception) { Debugger.Log(0, null, exception.ToString()); MessageBox.Show(exception.ToString()); } }
public void StartSwapOut(ImageCache cache) { lock (this) { Debug.Assert(Program.EnableSwap); if (this.outTask != null) { return; } if (this.holders.Count != 0) { return; } Stopwatch elapsed = Stopwatch.StartNew(); #if true // TODO: remove hack EventWaitHandle swapOutDelay = new EventWaitHandle(false, EventResetMode.AutoReset); #endif Task <bool> serializationTask = null; Task <ManagedBitmap> oldBitmap = this.bitmap; // 'this' is not locked at the time 'cache' is used below in the task delegates this.outTask = new Task <bool>( delegate() { Profile profile = new Profile("SwapOut {0}", this.id); #if true // TODO: remove hack profile.Push("Hack delay for swapins"); // HACK: wait a little to allow swapins to start before swapouts EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) // race: swapin can grab and clear this before we get here { localSwapOutDelay.WaitOne(100); } profile.Pop(); // #endif profile.Push("WaitSwapOutGate"); cache.WaitSwapOutGate(); // defer to in-flight swapins profile.Pop(); lock (this) { Debug.Assert(this.swapFilePath == null); Debug.Assert(this.swapFileStream == null); this.swapFilePath = Path.GetTempFileName(); this.swapFileStream = new FileStream(this.swapFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.DeleteOnClose); } profile.Push("oldBitmap.Wait()"); oldBitmap.Wait(); // wait for an old in-flight creation to complete profile.Pop(); profile.Push("Serialize"); serializationTask = new Task <bool>( delegate() { SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintLow); ManagedBitmap.Serialize(this.swapFileStream, oldBitmap.Result); SetIOPriority(this.swapFileStream, PRIORITY_HINT.IoPriorityHintNormal); return(false); }); SerializationManager.Manager.EnqueueWriteTask(serializationTask); serializationTask.Wait(); profile.Pop(); profile.Push("Enqueue oldBitmap"); lock (this) { this.oldBitmaps.Add(oldBitmap.Result); // remove current bitmap and enqueue for destruction upon zero refs } profile.Pop(); profile.Push("Epilog"); cache.Trace("swapout", this, elapsed); cache.PurgeDisposeList(); profile.Pop(); profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); return(false); }); this.bitmap = new Task <ManagedBitmap>( delegate() { Profile profile = new Profile("SwapIn {0}", this.id); profile.Push("outTask.Wait()"); #if true // TODO: remove hack // HACK: release delay immediately if swapin is requested EventWaitHandle localSwapOutDelay = Interlocked.Exchange(ref swapOutDelay, null); if (localSwapOutDelay != null) { localSwapOutDelay.Set(); } // #endif SerializationManager.Manager.Prioritize(serializationTask); Debug.Assert(this.outTask != null); this.outTask.Wait(); // ensure in-progress swapout finishes profile.Pop(); profile.Push("cache.BeginSwapIn()"); cache.BeginSwapIn(); profile.Pop(); try { Stopwatch elapsed2 = Stopwatch.StartNew(); Debug.Assert(this.swapFilePath != null); Debug.Assert(this.swapFileStream != null); profile.Push("Deserialize"); ManagedBitmap bitmap = null; Task <bool> deserializationTask = new Task <bool>( delegate() { bitmap = ManagedBitmap.Deserialize(this.swapFileStream); return(false); }); SerializationManager.Manager.EnqueueReadTask(deserializationTask); deserializationTask.Wait(); this.swapFilePath = null; Stream localSwapFileStream = this.swapFileStream; this.swapFileStream = null; localSwapFileStream.Dispose(); this.outTask = null; profile.Pop(); profile.Push("Epilog"); cache.Trace("swapin", this, elapsed2); cache.PurgeDisposeList(); StartBitmapCompleteWaiter(); return(bitmap); } finally { cache.EndSwapIn(); #if true // TODO: remove hack if (localSwapOutDelay != null) { localSwapOutDelay.Dispose(); } #endif profile.Pop(); // Epilog - here to include cache.EndSwapIn() profile.End(); //Program.Log(LogCat.Perf, profile.ToString()); } }); this.outTask.Start(); } }
public static void Main(string[] args) { try { if ((args.Length >= 1) && String.Equals(args[0], "-waitdebugger")) { while (!Debugger.IsAttached) { Thread.Sleep(250); } ShiftArgs(ref args, 1); } if ((args.Length == 2) && String.Equals(args[0], "-server")) { Environment.ExitCode = ImageServer.RunServer(args[1]); return; } Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); bool showLogOnStart = false; while (args.Length >= 1) { switch (args[0]) { default: goto Break; case "-profile": ProfileMode = true; ShiftArgs(ref args, 1); break; case "-showlog": showLogOnStart = true; ShiftArgs(ref args, 1); break; case "-swap": EnableSwap = true; ShiftArgs(ref args, 1); break; case "-noswap": EnableSwap = false; ShiftArgs(ref args, 1); break; } } Break: if (args.Length == 0) { // HACK: based on what WinMerge does - usability is suspect but still much better than FolderBrowserDialog. // See: http://www.codeproject.com/Articles/44914/Select-file-or-folder-from-the-same-dialog using (OpenFileDialog dialog = new OpenFileDialog()) { dialog.ValidateNames = false; dialog.CheckFileExists = false; dialog.CheckPathExists = false; dialog.Title = "Select a Folder"; dialog.FileName = "Select Folder."; if (dialog.ShowDialog() != DialogResult.OK) { return; } args = new string[] { Path.GetDirectoryName(dialog.FileName) }; } } if (args.Length != 1) { MessageBox.Show("Program must take one argument which is the path to a directory containing images to adjust."); return; } Window window = null; ImageCache cache = new ImageCache(); string directory = Path.GetFullPath(args[0]); string scanDirectory = GetScanDirectoryFromTargetDirectory(directory); if (!Directory.Exists(directory)) { MessageBox.Show(String.Format("Specified directory does not exist: \"{0}\"", directory)); return; } // load xml file XPathNavigator settingsNav; { XmlDocument settings = new XmlDocument(); string settingsPath = Path.Combine(scanDirectory, SettingsFile); if (File.Exists(settingsPath)) { settings.Load(settingsPath); } settingsNav = settings.CreateNavigator(); } GlobalOptions options = new GlobalOptions(settingsNav.SelectSingleNode("/*/options")); { using (GlobalOptionsDialog dialog = new GlobalOptionsDialog(options, directory)) { Application.Run(dialog); if (dialog.DialogResult != DialogResult.OK) { return; } } } if (showLogOnStart) { logWindow = new LoggingWindow(); logWindow.Show(); } // read saved items from xml List <Item> items = new List <Item>(); Dictionary <string, bool> filesWithItems = new Dictionary <string, bool>(); foreach (XPathNavigator itemNav in settingsNav.Select("/*/items/item")) { string fileName = itemNav.SelectSingleNode("file").Value; string filePath = Path.Combine(directory, fileName); if (File.Exists(filePath)) // drop item records for which file no longer exists { Item item = new Item(Path.Combine(directory, fileName), options, cache); item.ReadXml(itemNav); items.Add(item); filesWithItems[fileName.ToLowerInvariant()] = false; } } // add new records for any files that don't have a record foreach (string filePath in Directory.GetFiles(scanDirectory)) { string fileName = Path.GetFileName(filePath); if (String.Equals(fileName, SettingsFile, StringComparison.OrdinalIgnoreCase)) { continue; } if (!filesWithItems.ContainsKey(fileName.ToLowerInvariant())) { Item item = new Item(Path.Combine(directory, fileName), options, cache); items.Add(item); item.SettingsNav = settingsNav; // no match; try after hash has been computed } } // timestamp actions if (options.Timestamps.HasValue) { Parallel.ForEach( items, GetProcessorConstrainedParallelOptions2(CancellationToken.None), delegate(Item item) { if (options.Timestamps.Value) { if (!options.TimestampsOverwriteExisting) { DateTime existingTimestamp; if (TryParseFilenameTimestamp(Path.GetFileName(item.TargetPath), out existingTimestamp)) { return; } } DateTime fsCreated, fsModified, exifCreated; bool found = TryGetTimestamps( item.SourcePath, out fsCreated, out fsModified, out exifCreated); string created = fsCreated.ToString("s").Replace("T", "."); string modified = fsModified.ToString("s").Replace("T", "."); string exif = found ? exifCreated.ToString("s").Replace("T", ".") : "<no data>"; string newName = StripFilenameTimestamp(Path.GetFileName(item.TargetPath)); string text = FormatFilenameTimestamp( found ? exifCreated : (!options.TimestampsExifMissingModifiedInsteadOfCreated ? fsCreated : fsModified)); newName = String.Concat(text, " ", newName); item.RenamedFileName = newName; } else { item.RenamedFileName = StripFilenameTimestamp(Path.GetFileName(item.TargetPath)); } }); // ensure no duplicate names Dictionary <string, bool> usedName = new Dictionary <string, bool>(); foreach (Item item in items) { if (usedName.ContainsKey(item.RenamedFileName)) { int suffix = 0; while (true) { string newName = String.Concat(Path.GetFileNameWithoutExtension(item.RenamedFileName), "-", ++suffix, Path.GetExtension(item.RenamedFileName)); if (!usedName.ContainsKey(newName)) { item.RenamedFileName = newName; break; } } } usedName.Add(item.RenamedFileName, false); } } if (items.Count != 0) { window = new Window(directory, items, cache, options); window.Show(); window.LastAnalysisTask = BatchAnalyzerQueue.BeginAnalyzeBatch(items); Application.Run(window); } else { MessageBox.Show(String.Format("The specified folder \"{0}\" contains no images.", scanDirectory)); } LoggingWindow logw = logWindow; if (logw != null) { logw.Close(); } if (window != null) { window.LastAnalysisTask.Wait(); // allow any unfinished actions to cancel and dispose state } cache.Dispose(); SerializationManager.Manager.Dispose(); ImageClient.Close(); } catch (Exception exception) { Debugger.Log(0, null, exception.ToString()); MessageBox.Show(exception.ToString()); } }