Changed so it does not modify the source image any longer.
Speed improve.
This commit is contained in:
parent
f6d4aea699
commit
6385a1e0d1
1 changed files with 43 additions and 36 deletions
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Code from com.jhlabs.image.DiffusionFilter, Java Image Processing
|
* DiffusionFilter code from com.jhlabs.image.DiffusionFilter, Java Image Processing
|
||||||
* Copyright (C) Jerry Huxtable 1998
|
* Copyright (C) Jerry Huxtable 1998
|
||||||
* http://www.jhlabs.com/ip/
|
* http://www.jhlabs.com/ip/
|
||||||
*
|
*
|
||||||
|
@ -32,13 +32,13 @@ import java.awt.image.*;
|
||||||
|
|
||||||
public class DiffusionFilterOp implements BufferedImageOp {
|
public class DiffusionFilterOp implements BufferedImageOp {
|
||||||
|
|
||||||
protected final static int[] diffusionMatrix = {
|
protected final static int[] diffusionMatrix = {
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0, 0, 7,
|
0, 0, 7,
|
||||||
3, 5, 1,
|
3, 5, 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
private int[] matrix;
|
private int[] matrix;
|
||||||
private int sum;
|
private int sum;
|
||||||
private boolean serpentine = true;
|
private boolean serpentine = true;
|
||||||
private int[] colorMap;
|
private int[] colorMap;
|
||||||
|
@ -51,7 +51,8 @@ public class DiffusionFilterOp implements BufferedImageOp {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set whether to use a serpentine pattern for return or not. This can reduce 'avalanche' artifacts in the output.
|
* Set whether to use a serpentine pattern for return or not.
|
||||||
|
* This can reduce 'avalanche' artifacts in the output.
|
||||||
* @param serpentine true to use serpentine pattern
|
* @param serpentine true to use serpentine pattern
|
||||||
*/
|
*/
|
||||||
public void setSerpentine(boolean serpentine) {
|
public void setSerpentine(boolean serpentine) {
|
||||||
|
@ -108,32 +109,43 @@ public class DiffusionFilterOp implements BufferedImageOp {
|
||||||
int width = src.getWidth();
|
int width = src.getWidth();
|
||||||
int height = src.getHeight();
|
int height = src.getHeight();
|
||||||
|
|
||||||
DataBufferInt srcBuffer = (DataBufferInt) src.getRaster().getDataBuffer();
|
|
||||||
int srcData[] = srcBuffer.getData();
|
|
||||||
|
|
||||||
// This is the offset into the buffer of the current source pixel
|
// This is the offset into the buffer of the current source pixel
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
// Loop through each pixel
|
// Loop through each pixel
|
||||||
for (int y = 0; y < height; y++) {
|
// create a BufferedImage of only 1 pixel height for fetching the rows
|
||||||
|
// of the image in the correct format (ARGB)
|
||||||
|
// This speeds up things by more than factor 2, compared to the standard
|
||||||
|
// BufferedImage.getRGB solution
|
||||||
|
BufferedImage row = new BufferedImage(width, 1, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
Graphics2D g2d = row.createGraphics();
|
||||||
|
int pixels[] = ((DataBufferInt) row.getRaster().getDataBuffer()).getData();
|
||||||
|
// make sure alpha values do not add up for each row:
|
||||||
|
g2d.setComposite(AlphaComposite.Src);
|
||||||
|
// calculate scanline by scanline in order to safe memory.
|
||||||
|
// It also seems to run faster like that
|
||||||
|
int rowIndex = 0;
|
||||||
|
for (int y = 0; y < height; y++, rowIndex += width) {
|
||||||
|
g2d.drawImage(src, null, 0, -y);
|
||||||
|
// now pixels contains the rgb values of the row y!
|
||||||
boolean reverse = serpentine && (y & 1) == 1;
|
boolean reverse = serpentine && (y & 1) == 1;
|
||||||
int direction;
|
int direction;
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
index = y * width + width - 1;
|
index = width - 1;
|
||||||
direction = -1;
|
direction = -1;
|
||||||
} else {
|
} else {
|
||||||
index = y * width;
|
index = 0;
|
||||||
direction = 1;
|
direction = 1;
|
||||||
}
|
}
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
int rgb1 = srcData[index];
|
int rgb1 = pixels[index];
|
||||||
int a1 = (rgb1 >> 24) & 0xff;
|
int a1 = (rgb1 >> 24) & 0xff;
|
||||||
int r1 = (rgb1 >> 16) & 0xff;
|
int r1 = (rgb1 >> 16) & 0xff;
|
||||||
int g1 = (rgb1 >> 8) & 0xff;
|
int g1 = (rgb1 >> 8) & 0xff;
|
||||||
int b1 = rgb1 & 0xff;
|
int b1 = rgb1 & 0xff;
|
||||||
|
|
||||||
int idx = findIndex(r1, g1, b1, a1);
|
int idx = findIndex(r1, g1, b1, a1);
|
||||||
dstData[index] = (byte) idx;
|
dstData[rowIndex + index] = (byte) idx;
|
||||||
|
|
||||||
int rgb2 = colorMap[idx];
|
int rgb2 = colorMap[idx];
|
||||||
int a2 = (rgb2 >> 24) & 0xff;
|
int a2 = (rgb2 >> 24) & 0xff;
|
||||||
|
@ -159,14 +171,16 @@ public class DiffusionFilterOp implements BufferedImageOp {
|
||||||
w = matrix[(i + 1) * 3 + j + 1];
|
w = matrix[(i + 1) * 3 + j + 1];
|
||||||
if (w != 0) {
|
if (w != 0) {
|
||||||
int k = reverse ? index - j : index + j;
|
int k = reverse ? index - j : index + j;
|
||||||
rgb1 = srcData[k];
|
rgb1 = pixels[k];
|
||||||
a1 = ((rgb1 >> 24) & 0xff) + ea * w / sum;
|
a1 = ((rgb1 >> 24) & 0xff) + ea * w / sum;
|
||||||
r1 = ((rgb1 >> 16) & 0xff) + er * w / sum;
|
r1 = ((rgb1 >> 16) & 0xff) + er * w / sum;
|
||||||
g1 = ((rgb1 >> 8) & 0xff) + eg * w / sum;
|
g1 = ((rgb1 >> 8) & 0xff) + eg * w / sum;
|
||||||
b1 = (rgb1 & 0xff) + eb * w / sum;
|
b1 = (rgb1 & 0xff) + eb * w / sum;
|
||||||
|
pixels[k] =
|
||||||
srcData[k] = ((clamp(a1) << 24) | clamp(r1) << 16)
|
(clamp(a1) << 24) |
|
||||||
| (clamp(g1) << 8) | clamp(b1);
|
(clamp(r1) << 16) |
|
||||||
|
(clamp(g1) << 8) |
|
||||||
|
clamp(b1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,31 +204,24 @@ public class DiffusionFilterOp implements BufferedImageOp {
|
||||||
int findIndex(int r1, int g1, int b1, int a1)
|
int findIndex(int r1, int g1, int b1, int a1)
|
||||||
throws ArrayIndexOutOfBoundsException {
|
throws ArrayIndexOutOfBoundsException {
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
long dist = Long.MAX_VALUE;
|
int dist = Integer.MAX_VALUE;
|
||||||
for (int i = 0; i < colorMap.length; i++) {
|
for (int i = 0; i < colorMap.length; i++) {
|
||||||
int rgb2 = colorMap[i];
|
int rgb2 = colorMap[i];
|
||||||
int a2 = (rgb2 >> 24) & 0xff;
|
int da = a1 - ((rgb2 >> 24) & 0xff);
|
||||||
int r2 = (rgb2 >> 16) & 0xff;
|
int dr = r1 - ((rgb2 >> 16) & 0xff);
|
||||||
int g2 = (rgb2 >> 8) & 0xff;
|
int dg = g1 - ((rgb2 >> 8) & 0xff);
|
||||||
int b2 = rgb2 & 0xff;
|
int db = b1 - (rgb2 & 0xff);
|
||||||
|
int newdist = da * da + dr * dr + dg * dg + db * db;
|
||||||
int da = a1 - a2;
|
|
||||||
int dr = r1 - r2;
|
|
||||||
int dg = g1 - g2;
|
|
||||||
int db = b1 - b2;
|
|
||||||
|
|
||||||
long newdist = da * da + dr * dr + dg * dg + db * db;
|
|
||||||
if (newdist < dist) {
|
if (newdist < dist) {
|
||||||
idx = i;
|
idx = i;
|
||||||
dist = newdist;
|
dist = newdist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This always returns an indexed image
|
// This always returns an indexed image
|
||||||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel destCM) {
|
||||||
ColorModel destCM) {
|
|
||||||
return new BufferedImage(src.getWidth(), src.getHeight(),
|
return new BufferedImage(src.getWidth(), src.getHeight(),
|
||||||
BufferedImage.TYPE_BYTE_INDEXED);
|
BufferedImage.TYPE_BYTE_INDEXED);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue