/// <summary> /// Counts up the ForegroundColor from each entry in _rowResults, then /// combines similar colors to allow for things like antialiasing. /// Candidate colors are evaluated, beginning at the highest contrast /// from backgroundColor, until we find a candidate that seems to occur /// frequently enough that we accept it as the foreground color. /// </summary> private ColorVoteInfo GetForegroundInfo(Color backgroundColor) { CountMap <Color> simpleForegroundColorBallots = new CountMap <Color>(); _rowResults.ForEach(r => { Color foregroundColor = r.ForegroundColor; Color testBackgroundColor = r.BackgroundColor; if (foregroundColor != null && backgroundColor.Equals(testBackgroundColor)) { simpleForegroundColorBallots.Increment(r.ForegroundColor, r.TransitionCount); } }); if (!simpleForegroundColorBallots.Any()) { return(null); } var simpleForegroundBallotsSortedByContrast = simpleForegroundColorBallots.OrderByDescending(x => { ColorPair cp = new ColorPair(backgroundColor, x.Key); return(cp.ColorContrast()); }); CountMap <Color> aggregatedForegroundColorBallots = new CountMap <Color>(); foreach (var pair in simpleForegroundBallotsSortedByContrast) { // Remember counts so we can add them after we iterate the entire list CountMap <Color> rememberedCounts = new CountMap <Color>(); foreach (var aggregateForegroundColorBallot in aggregatedForegroundColorBallots) { if (aggregateForegroundColorBallot.Key.IsSimilarColor(pair.Key)) { rememberedCounts .Increment(aggregateForegroundColorBallot.Key, pair.Value); } } foreach (var countToAdd in rememberedCounts) { aggregatedForegroundColorBallots .Increment(countToAdd.Key, countToAdd.Value); } aggregatedForegroundColorBallots.Increment(pair.Key, pair.Value); } var sortedForegroundColorBallots = aggregatedForegroundColorBallots .OrderByDescending(x => x.Value); return(BuildColorVoteInfo(sortedForegroundColorBallots, GetTotalVoteCountFromAllBallots)); }
/// <summary> /// Counts up the BackgroundColor from each entry in _rowResults, then /// selects the most frequent BackgroundColor as the overall BackgroundColor. /// </summary> private ColorVoteInfo GetBackgroundInfo() { CountMap <Color> backgroundColorBallots = new CountMap <Color>(); _rowResults.ForEach(r => { Color backgroundColor = r.BackgroundColor; if (backgroundColor != null) { backgroundColorBallots.Increment(r.BackgroundColor); } }); var sortedBackgroundColorBallots = backgroundColorBallots.OrderByDescending(x => x.Value); return(BuildColorVoteInfo(sortedBackgroundColorBallots, GetTotalVoteCountFromAllBallots)); }
// Returns true when entries have lead to a confident conclusion about Text and Background color. internal ColorContrastResult OnRowEnd() { ColorContrastResult result = new ColorContrastResult(); CountMap <ColorPair> pairsWithSimilarTextColor = new CountMap <ColorPair>(); foreach (var exactPairOuter in countExactPairs) { foreach (var exactPairInner in countExactPairs) { if (exactPairOuter.Key.backgroundColor.Equals(exactPairInner.Key.backgroundColor)) { if (exactPairOuter.Key.foregroundColor.IsSimilarColor(exactPairInner.Key.foregroundColor)) { pairsWithSimilarTextColor.Increment(exactPairOuter.Key, exactPairInner.Value); } } } } var sortedByValueAndContrast = pairsWithSimilarTextColor.OrderByDescending(x => x.Value) .ThenByDescending(x => x.Key.ColorContrast()); if (!sortedByValueAndContrast.Any()) { return(result); } var resultPairs = new HashSet <ColorPair>(); var firstEntryCount = sortedByValueAndContrast.First().Value; if (firstEntryCount < ColorContrastConfig.MinNumberColorTransitions) { return(result); } var firstEntryCountAdjusted = firstEntryCount / ColorContrastConfig.TransitionCountDominanceFactor; foreach (var entry in sortedByValueAndContrast) { // Only Collect Pairs that have a reasonable occurence count. if (entry.Value < firstEntryCountAdjusted) { break; } resultPairs.Add(entry.Key); } foreach (var colorPair in resultPairs) { result.Add(colorPair); } countExactColors.Clear(); openTransitions.Clear(); return(result); }