public ImageCache(FileDatabase fileDatabase) : base(fileDatabase) { this.CurrentDifferenceState = ImageDifference.Unaltered; this.differenceBitmapCache = new Dictionary<ImageDifference, BitmapSource>(); this.mostRecentlyUsedIDs = new MostRecentlyUsedList<long>(Constant.Images.BitmapCacheSize); this.prefetechesByID = new ConcurrentDictionary<long, Task>(); this.unalteredBitmapsByID = new ConcurrentDictionary<long, BitmapSource>(); }
public void MoveToNextStateInPreviousNextDifferenceCycle() { Debug.Assert((this.Current != null) && (this.Current.IsVideo == false), "No current file or current file is an image."); // always go to unaltered from combined difference if (this.CurrentDifferenceState == ImageDifference.Combined) { this.CurrentDifferenceState = ImageDifference.Unaltered; return; } if (!this.Current.IsDisplayable()) { // can't calculate differences for files which aren't displayble this.CurrentDifferenceState = ImageDifference.Unaltered; return; } else { // move to next state in cycle, wrapping around as needed this.CurrentDifferenceState = (this.CurrentDifferenceState >= ImageDifference.Next) ? ImageDifference.Previous : ++this.CurrentDifferenceState; } // unaltered is always displayable; no more checks required if (this.CurrentDifferenceState == ImageDifference.Unaltered) { return; } // can't calculate previous or next difference for the first or last file in the image set, respectively // can't calculate difference if needed file isn't displayable if (this.CurrentDifferenceState == ImageDifference.Previous && this.CurrentRow == 0) { this.MoveToNextStateInPreviousNextDifferenceCycle(); } else if (this.CurrentDifferenceState == ImageDifference.Next && this.CurrentRow == this.Database.CurrentlySelectedFileCount - 1) { this.MoveToNextStateInPreviousNextDifferenceCycle(); } else if (this.CurrentDifferenceState == ImageDifference.Next && !this.Database.IsFileDisplayable(this.CurrentRow + 1)) { this.MoveToNextStateInPreviousNextDifferenceCycle(); } else if (this.CurrentDifferenceState == ImageDifference.Previous && !this.Database.IsFileDisplayable(this.CurrentRow - 1)) { this.MoveToNextStateInPreviousNextDifferenceCycle(); } }
public void MoveToNextStateInCombinedDifferenceCycle() { Debug.Assert((this.Current != null) && (this.Current.IsVideo == false), "No current file or current file is an image."); // if this method and MoveToNextStateInPreviousNextDifferenceCycle() returned bool they'd be consistent MoveNext() and MovePrevious() // however, there's no way for them to fail and there's not value in always returning true if (this.CurrentDifferenceState == ImageDifference.Next || this.CurrentDifferenceState == ImageDifference.Previous || this.CurrentDifferenceState == ImageDifference.Combined) { this.CurrentDifferenceState = ImageDifference.Unaltered; } else { this.CurrentDifferenceState = ImageDifference.Combined; } }
public static JArray Parse(MappedFile file, ImageDifference imageDiff) { if (imageDiff.IsLoad) { return(new JArray(new JObject { ["Action"] = "Load", ["Target"] = file.RelativeMappedPath, ["FromFile"] = Path.Combine("assets", file.RelativeFilePath) })); } JArray changes = new JArray(); foreach (Area change in imageDiff.Differences) { JObject newToken = new JObject { ["Action"] = "EditImage", ["Target"] = file.RelativeMappedPath, ["FromFile"] = Path.Combine("assets", file.RelativeFilePath) }; JObject area = new JObject { ["X"] = change.Left, ["Y"] = change.Top, ["Width"] = change.Width, ["Height"] = change.Height }; newToken["FromArea"] = area; newToken["ToArea"] = area; changes.Add(newToken); } return(changes); }
private void ResetDifferenceState(BitmapSource unalteredImage) { this.CurrentDifferenceState = ImageDifference.Unaltered; this.differenceBitmapCache[ImageDifference.Unaltered] = unalteredImage; this.differenceBitmapCache[ImageDifference.Previous] = null; this.differenceBitmapCache[ImageDifference.Next] = null; this.differenceBitmapCache[ImageDifference.Combined] = null; }
public async Task<ImageDifferenceResult> TryCalculateCombinedDifferenceAsync(byte differenceThreshold) { if (this.CurrentDifferenceState != ImageDifference.Combined) { return ImageDifferenceResult.NotCalculable; } // three valid images are needed: the current one, the previous one, and the next one if (this.Current == null || this.Current.IsVideo || this.Current.IsDisplayable() == false) { this.CurrentDifferenceState = ImageDifference.Unaltered; return ImageDifferenceResult.CurrentImageNotAvailable; } WriteableBitmap previousBitmap = await this.TryGetPreviousBitmapAsWriteableAsync(); if (previousBitmap == null) { return ImageDifferenceResult.PreviousImageNotAvailable; } WriteableBitmap nextBitmap = await this.TryGetNextBitmapAsWriteableAsync(); if (nextBitmap == null) { return ImageDifferenceResult.NextImageNotAvailable; } BitmapSource unalteredBitmap = this.differenceBitmapCache[ImageDifference.Unaltered]; Debug.Assert(unalteredBitmap != null, "Difference cache coherency error: unaltered bitmap is null."); WriteableBitmap unalteredWriteableBitmap = unalteredBitmap.AsWriteable(); this.differenceBitmapCache[ImageDifference.Unaltered] = unalteredWriteableBitmap; // all three images are available, so calculate and cache difference BitmapSource differenceBitmap = await Task.Run(() => { return unalteredWriteableBitmap.Difference(previousBitmap, nextBitmap, differenceThreshold); }); this.differenceBitmapCache[ImageDifference.Combined] = differenceBitmap; return differenceBitmap != null ? ImageDifferenceResult.Success : ImageDifferenceResult.NotCalculable; }
public async Task<ImageDifferenceResult> TryCalculateDifferenceAsync() { if (this.Current == null || this.Current.IsVideo || this.Current.IsDisplayable() == false) { this.CurrentDifferenceState = ImageDifference.Unaltered; return ImageDifferenceResult.CurrentImageNotAvailable; } // determine which image to use for differencing WriteableBitmap comparisonBitmap = null; if (this.CurrentDifferenceState == ImageDifference.Previous) { comparisonBitmap = await this.TryGetPreviousBitmapAsWriteableAsync(); if (comparisonBitmap == null) { return ImageDifferenceResult.PreviousImageNotAvailable; } } else if (this.CurrentDifferenceState == ImageDifference.Next) { comparisonBitmap = await this.TryGetNextBitmapAsWriteableAsync(); if (comparisonBitmap == null) { return ImageDifferenceResult.NextImageNotAvailable; } } else { return ImageDifferenceResult.NotCalculable; } WriteableBitmap unalteredBitmap = this.differenceBitmapCache[ImageDifference.Unaltered].AsWriteable(); this.differenceBitmapCache[ImageDifference.Unaltered] = unalteredBitmap; BitmapSource differenceBitmap = await Task.Run(() => { return unalteredBitmap.Difference(comparisonBitmap); }); this.differenceBitmapCache[this.CurrentDifferenceState] = differenceBitmap; return differenceBitmap != null ? ImageDifferenceResult.Success : ImageDifferenceResult.NotCalculable; }