// // WaveletTransformFilter.java // // This filter takes an ordinary image and computes // its simple wavelet transform // // Copyright (c) 1997, Benjamin Nason Lipchak // package benj.awt.image; import java.awt.image.*; public class WaveletTransformFilter extends ImageFilter { private static ColorModel defaultRGB = ColorModel.getRGBdefault(); private int width, height; private int rasterOrig[]; private int rasterSend[]; private int jLevel; public WaveletTransformFilter() { jLevel = -1; } public WaveletTransformFilter(int level) { if (jLevel >= 0) jLevel = level; } public void setDimensions(int width, int height) { this.width = width; this.height = height; rasterOrig = new int[width * height]; rasterSend = new int[width * height]; //Limit jLevel to greatest possible value int n = logBase2(width); if (jLevel > n) jLevel = n; if (jLevel == -1) consumer.setDimensions(width, height); else consumer.setDimensions(width / pow2(jLevel), height / pow2(jLevel)); } public void setColorModel(ColorModel model) { consumer.setColorModel(defaultRGB); } public void setHints(int hintflags) { consumer.setHints(TOPDOWNLEFTRIGHT | COMPLETESCANLINES | SINGLEPASS | (hintflags & SINGLEFRAME)); } public void setPixels(int x, int y, int w, int h, ColorModel model, byte pixels[], int off, int scansize) { int srcoff = off; int dstoff = y * width + x; for (int yc = 0; yc < h; yc++) { for (int xc = 0; xc < w; xc++) { rasterOrig[dstoff++] = model.getRGB(pixels[srcoff++] & 0xff); } srcoff += (scansize - w); dstoff += (width - w); } } public void setPixels(int x, int y, int w, int h, ColorModel model, int pixels[], int off, int scansize) { int srcoff = off; int dstoff = y * width + x; if (model == defaultRGB) { for (int yc = 0; yc < h; yc++) { System.arraycopy(pixels, srcoff, rasterOrig, dstoff, w); srcoff += scansize; dstoff += width; } } else { for (int yc = 0; yc < h; yc++) { for (int xc = 0; xc < w; xc++) { rasterOrig[dstoff++] = model.getRGB(pixels[srcoff++]); } srcoff += (scansize - w); dstoff += (width - w); } } } public void imageComplete(int status) { if (status == IMAGEERROR || status == IMAGEABORTED) { consumer.imageComplete(status); return; } //Check for width (and height) of 1... make sure this gets copied int extent = 0; if (width == 1 || jLevel == 0) { rasterSend = rasterOrig; } else { //Transform data n times, where (2^n == width == height) int pixelA, pixelB, pixelC, pixelD; int average; int n; if (jLevel == -1) n = logBase2(width); else n = jLevel; for (int j = 0; j < n; j++) { extent = width / pow2(j); for (int dy = 0; dy < extent; dy += 2) { for (int dx = 0; dx < extent; dx += 2) { pixelA = rasterOrig[(dy * width) + dx]; pixelB = rasterOrig[(dy * width) + dx + 1]; pixelC = rasterOrig[((dy + 1) * width) + dx]; pixelD = rasterOrig[((dy + 1) * width) + dx + 1]; average = averageColor(pixelA, pixelB, pixelC, pixelD); rasterSend[(dy / 2) * width + (dx / 2)] = average; rasterOrig[(dy / 2) * width + (dx / 2)] = average; rasterSend[(dy / 2) * width + ((dx + extent) / 2)] = pixelB; rasterSend[((dy + extent) / 2) * width + (dx / 2)] = pixelC; rasterSend[((dy + extent) / 2) * width + ((dx + extent) / 2)] = pixelD; } } } } //Red rover, red rover, send data right over if (jLevel == -1 || jLevel == 0) { int pixels[] = new int[width]; for (int dy = 0; dy < height; dy++) { for (int dx = 0; dx < width; dx++) { pixels[dx] = rasterSend[(dy * width) + dx]; } consumer.setPixels(0, dy, width, 1, defaultRGB, pixels, 0, width); } } else { extent /= 2; int pixels[] = new int[extent]; for (int dy = 0; dy < extent; dy++) { for (int dx = 0; dx < extent; dx++) { pixels[dx] = rasterSend[(dy * width) + dx]; } consumer.setPixels(0, dy, extent, 1, defaultRGB, pixels, 0, extent); } } consumer.imageComplete(status); } int pow2(int degree) { if (degree < 0) return -1; int result = 1; while (degree > 0) { result *= 2; degree--; } return result; } int logBase2(int number) { int result = 0; while (pow2(result) != number) { result++; if (result >= number) return -1; } return result; } int averageColor(int colorA, int colorB, int colorC, int colorD) { int redA, redB, redC, redD, redAverage; int greenA, greenB, greenC, greenD, greenAverage; int blueA, blueB, blueC, blueD, blueAverage; int alphaA, alphaB, alphaC, alphaD, alphaAverage; redA = (colorA & 0xff); redB = (colorB & 0xff); redC = (colorC & 0xff); redD = (colorD & 0xff); redAverage = (redA + redB + redC + redD) / 4; greenA = (colorA & 0xff00) >> 8; greenB = (colorB & 0xff00) >> 8; greenC = (colorC & 0xff00) >> 8; greenD = (colorD & 0xff00) >> 8; greenAverage = (greenA + greenB + greenC + greenD) / 4; blueA = (colorA & 0xff0000) >> 16; blueB = (colorB & 0xff0000) >> 16; blueC = (colorC & 0xff0000) >> 16; blueD = (colorD & 0xff0000) >> 16; blueAverage = (blueA + blueB + blueC + blueD) / 4; alphaA = (colorA & 0xff000000) >> 24; alphaB = (colorB & 0xff000000) >> 24; alphaC = (colorC & 0xff000000) >> 24; alphaD = (colorD & 0xff000000) >> 24; alphaAverage = (alphaA + alphaB + alphaC + alphaD) / 4; return ((alphaAverage << 24) | (blueAverage << 16) | (greenAverage << 8) | redAverage); } }