diff options
Diffstat (limited to 'libjava/classpath/java/awt/image/ConvolveOp.java')
-rw-r--r-- | libjava/classpath/java/awt/image/ConvolveOp.java | 178 |
1 files changed, 83 insertions, 95 deletions
diff --git a/libjava/classpath/java/awt/image/ConvolveOp.java b/libjava/classpath/java/awt/image/ConvolveOp.java index 1f73f75b233..ffb834874fa 100644 --- a/libjava/classpath/java/awt/image/ConvolveOp.java +++ b/libjava/classpath/java/awt/image/ConvolveOp.java @@ -1,5 +1,5 @@ /* ConvolveOp.java -- - Copyright (C) 2004, 2005 Free Software Foundation -- ConvolveOp + Copyright (C) 2004, 2005, 2006, Free Software Foundation -- ConvolveOp This file is part of GNU Classpath. @@ -42,7 +42,6 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -import java.util.Arrays; /** * Convolution filter. @@ -190,112 +189,101 @@ public class ConvolveOp implements BufferedImageOp, RasterOp * @see java.awt.image.RasterOp#filter(java.awt.image.Raster, * java.awt.image.WritableRaster) */ - public final WritableRaster filter(Raster src, WritableRaster dest) { + public final WritableRaster filter(Raster src, WritableRaster dest) + { if (src == dest) - throw new IllegalArgumentException(); - if (src.getWidth() < kernel.getWidth() || - src.getHeight() < kernel.getHeight()) - throw new ImagingOpException(null); - + throw new IllegalArgumentException("src == dest is not allowed."); + if (kernel.getWidth() > src.getWidth() + || kernel.getHeight() > src.getHeight()) + throw new ImagingOpException("The kernel is too large."); if (dest == null) dest = createCompatibleDestRaster(src); - else if (src.numBands != dest.numBands) - throw new ImagingOpException(null); + else if (src.getNumBands() != dest.getNumBands()) + throw new ImagingOpException("src and dest have different band counts."); - // Deal with bottom edge - if (edge == EDGE_ZERO_FILL) - { - float[] zeros = new float[src.getNumBands() * src.getWidth() - * (kernel.getYOrigin() - 1)]; - Arrays.fill(zeros, 0); - dest.setPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, zeros); - } - else - { - float[] vals = new float[src.getNumBands() * src.getWidth() - * (kernel.getYOrigin() - 1)]; - src.getPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, vals); - dest.setPixels(src.getMinX(), src.getMinY(), src.getWidth(), - kernel.getYOrigin() - 1, vals); - } + // calculate the borders that the op can't reach... + int kWidth = kernel.getWidth(); + int kHeight = kernel.getHeight(); + int left = kernel.getXOrigin(); + int right = Math.max(kWidth - left - 1, 0); + int top = kernel.getYOrigin(); + int bottom = Math.max(kHeight - top - 1, 0); - // Handle main section + // process the region that is reachable... + int regionW = src.width - left - right; + int regionH = src.height - top - bottom; float[] kvals = kernel.getKernelData(null); + float[] tmp = new float[kWidth * kHeight]; - float[] tmp = new float[kernel.getWidth() * kernel.getHeight()]; - for (int y = src.getMinY() + kernel.getYOrigin(); - y < src.getMinY() + src.getHeight() - kernel.getYOrigin() / 2; y++) - { - // Handle unfiltered edge pixels at start of line - float[] t1 = new float[(kernel.getXOrigin() - 1) * src.getNumBands()]; - if (edge == EDGE_ZERO_FILL) - Arrays.fill(t1, 0); - else - src.getPixels(src.getMinX(), y, kernel.getXOrigin() - 1, 1, t1); - dest.setPixels(src.getMinX(), y, kernel.getXOrigin() - 1, 1, t1); - - for (int x = src.getMinX(); x < src.getWidth() + src.getMinX(); x++) + for (int x = 0; x < regionW; x++) { - // FIXME: This needs a much more efficient implementation - for (int b = 0; b < src.getNumBands(); b++) - { - float v = 0; - src.getSamples(x, y, kernel.getWidth(), kernel.getHeight(), b, tmp); - for (int i=0; i < tmp.length; i++) - v += tmp[i] * kvals[i]; - dest.setSample(x, y, b, v); - } + for (int y = 0; y < regionH; y++) + { + // FIXME: This needs a much more efficient implementation + for (int b = 0; b < src.getNumBands(); b++) + { + float v = 0; + src.getSamples(x, y, kWidth, kHeight, b, tmp); + for (int i = 0; i < tmp.length; i++) + v += tmp[tmp.length - i - 1] * kvals[i]; + // FIXME: in the above line, I've had to reverse the order of + // the samples array to make the tests pass. I haven't worked + // out why this is necessary. + dest.setSample(x + kernel.getXOrigin(), y + kernel.getYOrigin(), + b, v); + } + } } - - // Handle unfiltered edge pixels at end of line - float[] t2 = new float[(kernel.getWidth() / 2) * src.getNumBands()]; - if (edge == EDGE_ZERO_FILL) - Arrays.fill(t2, 0); - else - src.getPixels(src.getMinX() + src.getWidth() - - (kernel.getWidth() / 2), - y, kernel.getWidth() / 2, 1, t2); - dest.setPixels(src.getMinX() + src.getWidth() - (kernel.getWidth() / 2), - y, kernel.getWidth() / 2, 1, t2); - } - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x< src.getWidth() + src.getMinX(); x++) + + // fill in the top border + fillEdge(src, dest, 0, 0, src.width, top, edge); + + // fill in the bottom border + fillEdge(src, dest, 0, src.height - bottom, src.width, bottom, edge); + + // fill in the left border + fillEdge(src, dest, 0, top, left, regionH, edge); + + // fill in the right border + fillEdge(src, dest, src.width - right, top, right, regionH, edge); + + return dest; + } + + /** + * Fills a range of pixels (typically at the edge of a raster) with either + * zero values (if <code>edgeOp</code> is <code>EDGE_ZERO_FILL</code>) or the + * corresponding pixel values from the source raster (if <code>edgeOp</code> + * is <code>EDGE_NO_OP</code>). This utility method is called by the + * {@link #fillEdge(Raster, WritableRaster, int, int, int, int, int)} method. + * + * @param src the source raster. + * @param dest the destination raster. + * @param x the x-coordinate of the top left pixel in the range. + * @param y the y-coordinate of the top left pixel in the range. + * @param w the width of the pixel range. + * @param h the height of the pixel range. + * @param edgeOp indicates how to determine the values for the range + * (either {@link #EDGE_ZERO_FILL} or {@link #EDGE_NO_OP}). + */ + private void fillEdge(Raster src, WritableRaster dest, int x, int y, int w, + int h, int edgeOp) + { + if (w <= 0) + return; + if (h <= 0) + return; + if (edgeOp == EDGE_ZERO_FILL) // fill region with zeroes { - + float[] zeros = new float[src.getNumBands() * w * h]; + dest.setPixels(x, y, w, h, zeros); } - for (int y = src.getMinY(); y < src.getHeight() + src.getMinY(); y++) - for (int x = src.getMinX(); x< src.getWidth() + src.getMinX(); x++) + else // copy pixels from source { - + float[] pixels = new float[src.getNumBands() * w * h]; + src.getPixels(x, y, w, h, pixels); + dest.setPixels(x, y, w, h, pixels); } - - // Handle top edge - if (edge == EDGE_ZERO_FILL) - { - float[] zeros = new float[src.getNumBands() * src.getWidth() * - (kernel.getHeight() / 2)]; - Arrays.fill(zeros, 0); - dest.setPixels(src.getMinX(), - src.getHeight() + src.getMinY() - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, zeros); - } - else - { - float[] vals = new float[src.getNumBands() * src.getWidth() * - (kernel.getHeight() / 2)]; - src.getPixels(src.getMinX(), - src.getHeight() + src.getMinY() - - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, vals); - dest.setPixels(src.getMinX(), - src.getHeight() + src.getMinY() - - (kernel.getHeight() / 2), - src.getWidth(), kernel.getHeight() / 2, vals); - } - - return dest; } /* (non-Javadoc) |