package ika.geo.grid;
import ika.geo.GeoGrid;
import ika.geo.GeoObject;
import ika.geo.GeoPoint;
import ika.geo.GeoSet;
/**
* Floyd-Steinberg error diffusion dithering.
*
* @author Bernie Jenny, Oregon State University
*/
public class GridDitheringOperator implements GridOperator {
// Floyd Steinberg dithering constants
private static final float A = 7f / 16f;
private static final float B = 3f / 16f;
private static final float C = 5f / 16f;
private static final float D = 1f / 16f;
public String getName() {
return "Floyd-Steinberg Error Diffusion Dithering";
}
public GeoObject operate(GeoGrid geoGrid) {
geoGrid = new GridScaleToRangeOperator(0f, 255f).operate(geoGrid);
GeoSet dots = new GeoSet();
final double dist = geoGrid.getCellSize();
int nRows = geoGrid.getRows();
int nCols = geoGrid.getCols();
double y = geoGrid.getNorth();
for (int row = 0; row < nRows; row++) {
double x = geoGrid.getWest();
// traverse the image in zig-zag order. Even rows from left to right
// and odd rows from right to left.
int col = row % 2 == 0 ? 0 : nCols - 1;
final int inc = row % 2 == 0 ? 1 : -1;
for (; row % 2 == 0 ? col < nCols : col >= 0; col += inc) {
final int shadeCol = (int) ((x - geoGrid.getWest()) / dist);
final int shadeRow = (int) ((geoGrid.getNorth() - y) / dist);
// FIXME
if (shadeCol > 0 && shadeRow > 0 && shadeCol < geoGrid.getCols() - 1 && shadeRow < geoGrid.getRows() - 1) {
float shade = geoGrid.getValue(shadeCol, shadeRow);
final float dif;
if (shade < 128) {
dots.add(new GeoPoint(x, y));
dif = shade;
} else {
dif = shade - 255;
}
// Floyd Steinberg error diffusion dithering
// right
float v = geoGrid.getValue(shadeCol + inc, shadeRow);
geoGrid.setValue((short) (v + dif * A), shadeCol + inc, shadeRow);
// left bottom
v = geoGrid.getValue(shadeCol - inc, shadeRow + 1);
geoGrid.setValue((short) (v + dif * B), shadeCol - inc, shadeRow + 1);
// center bottom
v = geoGrid.getValue(shadeCol, shadeRow + 1);
geoGrid.setValue((short) (v + dif * C), shadeCol, shadeRow + 1);
// right bottom
v = geoGrid.getValue(shadeCol + inc, shadeRow + 1);
geoGrid.setValue((short) (v + dif * D), shadeCol + inc, shadeRow + 1);
}
x += dist;
}
y -= dist;
}
return dots;
}
}