// If defaultNewIsNull is true, then newIsNull is ignored and it should behave as
 // if newIsNull were false.
 private void runTest(
     WritableRaster source,
     double sourceNoData,
     double newValue,
     boolean defaultNewIsNull,
     boolean newIsNull) {
   ColorModel cm1 = RasterUtils.createColorModel(source);
   java.util.Hashtable<String, Object> arg1Properties = new java.util.Hashtable<String, Object>();
   arg1Properties.put(OpImageUtils.NODATA_PROPERTY, sourceNoData);
   BufferedImage s1 = new BufferedImage(cm1, source, false, arg1Properties);
   RenderedOp op = null;
   if (defaultNewIsNull) {
     op = ReplaceNullDescriptor.create(s1, newValue, null);
   } else {
     op = ReplaceNullDescriptor.create(s1, newValue, newIsNull, null);
   }
   Raster r = op.getData();
   if (!defaultNewIsNull && newIsNull) {
     Assert.assertEquals(newValue, OpImageUtils.getNoData(op, Double.NaN), EPSILON);
   } else {
     Assert.assertTrue(Double.isNaN(OpImageUtils.getNoData(op, Double.NaN)));
   }
   Assert.assertEquals(width, r.getWidth());
   Assert.assertEquals(height, r.getHeight());
   for (int x = 0; x < width; x++) {
     for (int y = 0; y < height; y++) {
       double v = r.getSampleDouble(x, y, 0);
       int pixelId = getPixelId(x, y, width);
       Assert.assertEquals(pixelId, v, EPSILON);
     }
   }
 }
  private static BufferedImage convolveICOL(
      RenderedOp source, KernelJAI gaussKernel, KernelJAI distKernel) {
    final int m = gaussKernel.getWidth();
    final int n = m / 2 + 1;

    float[] weights = new float[n];
    float wSum = 0;
    for (int k = 0; k < n; k++) {
      weights[k] = gaussKernel.getElement(distKernel.getXOrigin() + k, distKernel.getYOrigin());
      wSum += weights[k];
    }
    for (int k = 0; k < n; k++) {
      weights[k] /= wSum;
    }

    dumpArray("Weights", weights);

    int width = source.getWidth();
    int height = source.getHeight();
    Raster aRaster = source.getData(new Rectangle(0, 0, width, height));
    BufferedImage cImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    byte[] aData = ((DataBufferByte) aRaster.getDataBuffer()).getData();
    byte[] cData = ((DataBufferByte) cImage.getRaster().getDataBuffer()).getData();
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        float[] sums = new float[n];
        int[] counts = new int[n];
        for (int j = 0; j < m; j++) {
          for (int i = 0; i < m; i++) {
            int k = (int) distKernel.getElement(i, j);
            if (k > 0) {
              int xx = x + i - distKernel.getXOrigin();
              int yy = y + j - distKernel.getYOrigin();
              if (xx >= 0 && xx < width && yy >= 0 && yy < height) {
                int a = (aData[yy * width + xx] & 0xff);
                if (a > 0) { // = if (not no-data)
                  sums[k] += a;
                  counts[k]++;
                }
              }
            }
          }
        }

        int a = aData[y * width + x] & 0xff;

        float c = weights[0] * a;
        for (int k = 1; k < n; k++) {
          if (counts[k] > 0) {
            c += (weights[k] * sums[k]) / counts[k];
          }
        }

        if (a == 0) {
          cData[y * width + x] = (byte) c;
        } else {
          cData[y * width + x] = aData[y * width + x];
        }
      }
    }
    return cImage;
  }