package a2geek.apple2.image.encoder; import java.awt.image.BufferedImage; import a2geek.apple2.image.encoder.util.ProgressListener; /** * Reduces the color depth of an image to one that a IIgs can handle. * It allows up to 16 pallets of 16 colors. Each color has 4 bits. */ public class ColorDepthReducer { private BufferedImage image; private PaletteEntry[][] paletteColors; private int[] paletteNumbers; private ProgressListener progressListener; /** * Prepare to reduce colors for a super hires palette. */ public ColorDepthReducer(BufferedImage image) { this.image = image; paletteColors = new PaletteEntry[16][16]; paletteNumbers = new int[200]; } /** * Prepare to reduce colors for an Apple II standard color palette (typically 16 lores colors). */ public ColorDepthReducer(BufferedImage image, PaletteEntry[] palette) { this.image = image; paletteNumbers = null; paletteColors = new PaletteEntry[1][]; paletteColors[0] = palette; } /** * Begin the color reduction process. */ public void process() { if (paletteNumbers != null) { processSuperHires(); } else { processToPalette(); } } /** * Begin the color reduction process for super hires. * We group the image into 16 bands of color. */ private void processSuperHires() { int bandHeight = (image.getHeight() / paletteColors.length) + 1; int paletteNumber = 0; for (int y=0; y> 8, // red (color & 0x0f0) >> 4, // green color & 0x00f // blue ); image.setRGB(x, y, paletteColors[0][entry].getMergedColor16()); } } } /** * Process a band of the image. This is where the bulk of the work is done. */ private PaletteEntry[] processBand(int paletteNumber, int yStart, int yEnd) { PaletteEntry[] palette = new PaletteEntry[0x1000]; // Setup all starting PaletteEntries for (int c=0; c 16) { if (progressListener != null) { if (progressListener.isCancelled()) return null; progressListener.update(yStart, image.getHeight(), "Palette #" + (paletteNumber+1) + " (" + colors + " colors)"); } // Locate least popular color int leastPopular = -1; double leastPopularFactor = Double.MAX_VALUE; for (int c=0; c> 12 | (color & 0x00f000) >> 8 | (color & 0x0000f0) >> 4; } /** * Locate the closest color to the given PaletteEntry. * Returns with the palette index entry. */ private int getClosestColor(PaletteEntry[] paletteEntries, PaletteEntry paletteEntry) { int r0 = paletteEntry.getRed(); int g0 = paletteEntry.getGreen(); int b0 = paletteEntry.getBlue(); return getClosestColor(paletteEntries, r0, g0, b0); } /** * Locate the closest color to the given R,G,B coordinates in the given palette. * Returns with the palette index entry. */ private int getClosestColor(PaletteEntry[] paletteEntries, int r0, int g0, int b0) { double targetDistance = Double.MAX_VALUE; int closestColor = -1; for (int activeColor=0; activeColor