-
Notifications
You must be signed in to change notification settings - Fork 0
/
FilterWriteStrategy.cs
101 lines (91 loc) · 3.96 KB
/
FilterWriteStrategy.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
using System;
using System.Collections.Generic;
using System.Text;
namespace Hjg.Pngcs {
/// <summary>
/// Manages the writer strategy for selecting the internal png predictor filter
/// </summary>
internal class FilterWriteStrategy {
private static readonly int COMPUTE_STATS_EVERY_N_LINES = 8;
private readonly ImageInfo imgInfo;
private readonly FilterType configuredType; // can be negative (fin dout)
private FilterType currentType; // 0-4
private int lastRowTested = -1000000;
private double[] lastSums = new double[5];// performance of each filter (less is better) (can be negative)
private double[] lastEntropies = new double[5];
private double[] preference = new double[] { 1.1, 1.1, 1.1, 1.1, 1.2 }; // a priori preference (NONE SUB UP AVERAGE PAETH)
private int discoverEachLines = -1;
private double[] histogram1 = new double[256];
internal FilterWriteStrategy(ImageInfo imgInfo, FilterType configuredType) {
this.imgInfo = imgInfo;
this.configuredType = configuredType;
if (configuredType < 0) { // first guess
if ((imgInfo.Rows < 8 && imgInfo.Cols < 8) || imgInfo.Indexed
|| imgInfo.BitDepth < 8)
currentType = FilterType.FILTER_NONE;
else
currentType = FilterType.FILTER_PAETH;
} else {
currentType = configuredType;
}
if (configuredType == FilterType.FILTER_AGGRESSIVE)
discoverEachLines = COMPUTE_STATS_EVERY_N_LINES;
if (configuredType == FilterType.FILTER_VERYAGGRESSIVE)
discoverEachLines = 1;
}
internal bool shouldTestAll(int rown) {
if (discoverEachLines > 0 && lastRowTested + discoverEachLines <= rown) {
currentType = FilterType.FILTER_UNKNOWN;
return true;
} else
return false;
}
internal void setPreference(double none, double sub, double up, double ave, double paeth) {
preference = new double[] { none, sub, up, ave, paeth };
}
internal bool computesStatistics() {
return (discoverEachLines > 0);
}
internal void fillResultsForFilter(int rown, FilterType type, double sum, int[] histo, bool tentative) {
lastRowTested = rown;
lastSums[(int)type] = sum;
if (histo != null) {
double v, alfa, beta, e;
alfa = rown == 0 ? 0.0 : 0.3;
beta = 1 - alfa;
e = 0.0;
for (int i = 0; i < 256; i++) {
v = ((double)histo[i]) / imgInfo.Cols;
v = histogram1[i] * alfa + v * beta;
if (tentative)
e += v > 0.00000001 ? v * Math.Log(v) : 0.0;
else
histogram1[i] = v;
}
lastEntropies[(int)type] = (-e);
}
}
internal FilterType gimmeFilterType(int rown, bool useEntropy) {
if (currentType == FilterType.FILTER_UNKNOWN) { // get better
if (rown == 0)
currentType = FilterType.FILTER_SUB;
else {
double bestval = Double.MaxValue;
double val;
for (int i = 0; i < 5; i++) {
val = useEntropy ? lastEntropies[i] : lastSums[i];
val /= preference[i];
if (val <= bestval) {
bestval = val;
currentType = (FilterType)i;
}
}
}
}
if (configuredType == FilterType.FILTER_CYCLIC) {
currentType = (FilterType)(((int)currentType + 1) % 5);
}
return currentType;
}
}
}