package jogamp.opengl.util.pngj; /** * Manages the writer strategy for selecting the internal png predictor filter */ class FilterWriteStrategy { private static final int COMPUTE_STATS_EVERY_N_LINES = 8; final ImageInfo imgInfo; public final FilterType configuredType; // can be negative (fin dout) private FilterType currentType; // 0-4 private int lastRowTested = -1000000; // performance of each filter (less is better) (can be negative) private final double[] lastSums = new double[5]; // performance of each filter (less is better) (can be negative) private final double[] lastEntropies = new double[5]; // a priori preference (NONE SUB UP AVERAGE PAETH) private double[] preference = new double[] { 1.1, 1.1, 1.1, 1.1, 1.2 }; private int discoverEachLines = -1; private final double[] histogram1 = new double[256]; FilterWriteStrategy(final ImageInfo imgInfo, final FilterType configuredType) { this.imgInfo = imgInfo; this.configuredType = configuredType; if (configuredType.val < 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; } boolean shouldTestAll(final int rown) { if (discoverEachLines > 0 && lastRowTested + discoverEachLines <= rown) { currentType = null; return true; } else return false; } public void setPreference(final double none, final double sub, final double up, final double ave, final double paeth) { preference = new double[] { none, sub, up, ave, paeth }; } public boolean computesStatistics() { return (discoverEachLines > 0); } void fillResultsForFilter(final int rown, final FilterType type, final double sum, final int[] histo, final boolean tentative) { lastRowTested = rown; lastSums[type.val] = 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[type.val] = (-e); } } FilterType gimmeFilterType(final int rown, final boolean useEntropy) { if (currentType == null) { // get better if (rown == 0) currentType = FilterType.FILTER_SUB; else { double bestval = Double.MAX_VALUE; 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.getByVal(i); } } } } if (configuredType == FilterType.FILTER_CYCLIC) { currentType = FilterType.getByVal((currentType.val + 1) % 5); } return currentType; } }