/* ******************************************************************************
* Copyright (c) 2006-2012 XMind Ltd. and others.
*
* This file is a part of XMind 3. XMind releases 3 and
* above are dual-licensed under the Eclipse Public License (EPL),
* which is available at http://www.eclipse.org/legal/epl-v10.html
* and the GNU Lesser General Public License (LGPL),
* which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details.
*
* Contributors:
* XMind Ltd. - initial API and implementation
*******************************************************************************/
package org.xmind.gef.internal.image;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.swt.graphics.RGB;
/**
* @author Frank Shaka
*/
class MinRiskColorReplacingPolicy implements IColorReplacingPolicy {
private static class ColorReplacing {
RGB source;
RGB replacement;
int risk;
public ColorReplacing(RGB source, RGB replacement, int risk) {
this.source = source;
this.replacement = replacement;
this.risk = risk;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "source=" + source + ",replacement=" + replacement + ",risk=" + risk; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
private Map<RGB, ColorReplacing> replacings;
// private Map<RGB, Map<RGB, Integer>> riskCache;
private int[][] riskCache;
private Set<RGB> retainedColors;
/**
* @see cn.brainy.gef.image.IColorReplacingPolicy#getReplacingColors(int,
* java.util.Map)
*/
public RGB[] getReplacingColors(int numMaxColors,
final Map<RGB, Integer> colorOccurrences) {
/* Sort colors by occurrences */
Set<RGB> sorter = new TreeSet<RGB>(new Comparator<RGB>() {
public int compare(RGB o1, RGB o2) {
int x = colorOccurrences.get(o2) - colorOccurrences.get(o1);
return x == 0 ? 1 : x;
}
});
sorter.addAll(colorOccurrences.keySet());
List<RGB> sortedColors = new ArrayList<RGB>(sorter);
replacings = new HashMap<RGB, ColorReplacing>();
int t = 0;
for (int i = 0; i < sortedColors.size(); i++) {
RGB c1 = sortedColors.get(i);
ColorReplacing rep = createMinRiskReplacing(c1,
sortedColors.subList(0, i));
replacings.put(c1, rep);
if ((i >> 10) > t) {
t = i >> 10;
}
}
Set<RGB> sorter2 = new TreeSet<RGB>(new Comparator<RGB>() {
/**
* @see java.util.Comparator#compare(java.lang.Object,
* java.lang.Object)
*/
public int compare(RGB o1, RGB o2) {
int delta = replacings.get(o2).risk
* (int) Math.sqrt(colorOccurrences.get(o2))
- replacings.get(o1).risk
* (int) Math.sqrt(colorOccurrences.get(o1));
return delta == 0 ? 1 : delta;
}
});
sorter2.addAll(sortedColors);
sortedColors = new ArrayList<RGB>(sorter2);
List<RGB> results = sortedColors.subList(0, numMaxColors);
for (RGB c : results) {
replacings.put(c, new ColorReplacing(c, c, 0));
}
for (RGB c : sortedColors.subList(numMaxColors, sortedColors.size())) {
replacings.put(c, createMinRiskReplacing(c, results));
}
retainedColors = new HashSet<RGB>(results);
return results.toArray(new RGB[results.size()]);
}
/**
* @see cn.brainy.gef.image.IColorReplacingPolicy#getReplacedColor(org.eclipse.swt.graphics.RGB)
*/
public RGB getReplacedColor(RGB source) {
ColorReplacing replacing = replacings.get(source);
RGB result = replacing.replacement;
if (!retainedColors.contains(result)) {
result = getReplacedColor(result);
replacing.replacement = result;
}
return result;
}
public ColorReplacing createMinRiskReplacing(RGB src, List<RGB> colors) {
RGB resultColor = src;
int minRisk = Integer.MAX_VALUE;
for (RGB toTest : colors) {
int risk = getColorReplacingRisk2(src, toTest);
if (risk < minRisk) {
minRisk = risk;
resultColor = toTest;
}
}
return new ColorReplacing(src, resultColor, minRisk);
}
protected int getRisk(RGB src, RGB dest) {
// Map<RGB, Integer> riskMap = getRiskMap( src );
// Integer risk = riskMap.get( dest );
// if ( risk == null ) {
// risk = getInteger( getColorReplacingRisk( src, dest ) );
// riskMap.put( dest, risk );
// }
// return risk;
int[] rc = getRiskCache(src);
int index = dest.hashCode();
int risk = rc[index];
if (risk < 0) {
risk = getColorReplacingRisk2(src, dest);
rc[index] = risk;
}
return risk;
}
private int[] getRiskCache(RGB src) {
int index = src.hashCode();
int[] rc = getRiskCache()[index];
if (rc == null) {
rc = new int[16777215];
for (int i = 0; i < rc.length; i++) {
rc[i] = -1;
}
getRiskCache()[index] = rc;
}
return rc;
}
private int[][] getRiskCache() {
if (riskCache == null)
riskCache = new int[16777215][];
return riskCache;
}
// private Map<RGB, Integer> getRiskMap( RGB src ) {
// Map<RGB, Integer> map = getRiskCache().get( src );
// if ( map == null ) {
// map = new HashMap<RGB, Integer>();
// getRiskCache().put( src, map );
// }
// return map;
// }
// private Map<RGB, Map<RGB, Integer>> getRiskCache() {
// if ( riskCache == null )
// riskCache = new HashMap<RGB, Map<RGB, Integer>>();
// return riskCache;
// }
public static int getColorReplacingRisk(RGB c1, RGB c2) {
int deltaRed = c1.red - c2.red;
int deltaGreen = c1.green - c2.green;
int deltaBlue = c1.blue - c2.blue;
return deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue
* deltaBlue;
}
public static int getColorReplacingRisk2(RGB c1, RGB c2) {
int deltaRed = c1.red - c2.red;
int deltaGreen = c1.green - c2.green;
int deltaBlue = c1.blue - c2.blue;
return Math.abs(deltaRed) + Math.abs(deltaGreen) + Math.abs(deltaBlue);
}
}