/* DitherFloydSteinbergMono.java (c) 2016 Edward Swartz All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ package v9t9.video.imageimport; import java.awt.image.BufferedImage; import org.ejs.gui.images.ColorMapUtils; import org.ejs.gui.images.IPaletteColorMapper; import org.ejs.gui.images.IPaletteMapper; import v9t9.video.imageimport.ImageImportOptions.Dither; /** * @author ejs * */ public class DitherFloydSteinbergMono implements IDither { private byte[][] thePalette; private Dither ditherType; public DitherFloydSteinbergMono(byte[][] thePalette, Dither ditherType) { this.thePalette = thePalette; this.ditherType = ditherType; } private void ditherFSPixelMono(BufferedImage img, IPaletteColorMapper mapColor, int x, int y) { int pixel = img.getRGB(x, y); int lum = ColorMapUtils.getPixelLum(pixel); int newC = mapColor.getClosestPaletteEntry(pixel); int newPixel = ColorMapUtils.rgb8ToPixel(thePalette[newC]); int newLum = ColorMapUtils.getPixelLum(newPixel); img.setRGB(x, y, newPixel | 0xff000000); int error = lum - newLum; if (ditherType == Dither.FSR) { // reduce bleed by ignoring some error error = reduceBleed(error); } if (error != 0) { if (x + 1 < img.getWidth()) { // x+1, y ditherFSMonoApplyError(img, x + 1, y, 7, error); } if (y + 1 < img.getHeight()) { if (x > 0) { ditherFSMonoApplyError(img, x - 1, y + 1, 3, error); } ditherFSMonoApplyError(img, x, y + 1, 5, error); if (x + 1 < img.getWidth()) { ditherFSMonoApplyError(img, x + 1, y + 1, 1, error); } } } } private int reduceBleed(int v) { if (v < 0) return -(-v / 3); else return v / 3; } private final int clamp(int i) { return i < 0 ? 0 : i > 255 ? 255 : i; } private void ditherFSMonoApplyError(BufferedImage img, int x, int y, int sixteenths, int error) { int offs = sixteenths * error / 16; if (offs == 0) return; int pixel = img.getRGB(x, y); int r = clamp(((pixel >> 16) & 0xff) + offs); int g = clamp(((pixel >> 8) & 0xff) + offs); int b = clamp(((pixel >> 0) & 0xff) + offs); img.setRGB(x, y, (r << 16) | (g << 8) | b | 0xff000000); } /* (non-Javadoc) * @see v9t9.video.imageimport.IDither#run(java.awt.image.BufferedImage, org.ejs.gui.images.IPaletteMapper, org.ejs.gui.images.Histogram) */ @Override public void run(BufferedImage img, IPaletteMapper mapColor) { int h = img.getHeight(); int w = img.getWidth(); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { ditherFSPixelMono(img, mapColor, x, y); } } } }