public int[] blendPixels(int x, int y, int w, int h, int[] pixels, int off, int stride) { int[] newPixels = new int[w * h]; int edge = 8; int i = 0; for (int row = 0; row < h; row++) { for (int col = 0; col < w; col++) { if (row < edge || col < edge) { int row2 = row < edge ? h - edge - 1 + row : row; int col2 = col < edge ? w - edge - 1 + col : col; if (row < edge && col < edge) { float frow = (float) row / (float) edge; float fcol = (float) col / (float) edge; int i2 = row2 * w + col2; int i3 = row * w + col2; int i4 = row2 * w + col; int left = ImageMath.mixColors(frow, pixels[i4], pixels[i]); int right = ImageMath.mixColors(frow, pixels[i2], pixels[i3]); newPixels[i] = ImageMath.mixColors(fcol, right, left); } else { float f = (float) Math.min(row, col) / (float) edge; int i2 = row2 * w + col2; newPixels[i] = ImageMath.mixColors(f, pixels[i2], pixels[i]); } } else newPixels[i] = pixels[i]; i++; } } return newPixels; }
/** * Set a knot color. * * @param n the knot index * @param color the color */ @Override public void setColor(int n, int color) { int firstColor = map[0]; int lastColor = map[256 - 1]; if (n > 0) for (int i = 0; i < n; i++) map[i] = ImageMath.mixColors((float) i / n, firstColor, color); if (n < 256 - 1) for (int i = n; i < 256; i++) map[i] = ImageMath.mixColors((float) (i - n) / (256 - n), color, lastColor); }
public int getPixel(int x, int y, int[] inPixels, int width, int height) { float nx = m00 * x + m01 * y; float ny = m10 * x + m11 * y; nx /= scale; ny /= scale * stretch; nx += 1000; ny += 1000; // Reduce artifacts around 0,0 float f = evaluate(nx, ny); float f1 = results[0].distance; float f2 = results[1].distance; int srcx = ImageMath.clamp((int) ((results[0].x - 1000) * scale), 0, width - 1); int srcy = ImageMath.clamp((int) ((results[0].y - 1000) * scale), 0, height - 1); int v = inPixels[srcy * width + srcx]; f = (f2 - f1) / edgeThickness; f = ImageMath.smoothStep(0, edgeThickness, f); if (fadeEdges) { srcx = ImageMath.clamp((int) ((results[1].x - 1000) * scale), 0, width - 1); srcy = ImageMath.clamp((int) ((results[1].y - 1000) * scale), 0, height - 1); int v2 = inPixels[srcy * width + srcx]; v2 = ImageMath.mixColors(0.5f, v2, v); v = ImageMath.mixColors(f, v2, v); } else v = ImageMath.mixColors(f, edgeColor, v); return v; }
@Override protected void transformInverse(int x, int y, float[] out) { float dx = x - icentreX; float dy = y - icentreY; float theta = (float) Math.atan2(-dy, -dx) + angle; float r = (float) Math.sqrt(dx * dx + dy * dy); theta = ImageMath.mod(theta, 2 * (float) Math.PI); out[0] = iWidth * theta / (spreadAngle + 0.00001f); out[1] = iHeight * (1 - (r - radius) / (height + 0.00001f)); }
protected BufferedImage filterPixelsNN( BufferedImage dst, int width, int height, int[] inPixels, Rectangle transformedSpace) { int srcWidth = width; int srcHeight = height; int outWidth = transformedSpace.width; int outHeight = transformedSpace.height; int outX, outY, srcX, srcY; int[] outPixels = new int[outWidth]; outX = transformedSpace.x; outY = transformedSpace.y; int[] rgb = new int[4]; float[] out = new float[2]; for (int y = 0; y < outHeight; y++) { for (int x = 0; x < outWidth; x++) { transformInverse(outX + x, outY + y, out); srcX = (int) out[0]; srcY = (int) out[1]; // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0 if (out[0] < 0 || srcX >= srcWidth || out[1] < 0 || srcY >= srcHeight) { int p; switch (edgeAction) { case ZERO: default: p = 0; break; case WRAP: p = inPixels[ (ImageMath.mod(srcY, srcHeight) * srcWidth) + ImageMath.mod(srcX, srcWidth)]; break; case CLAMP: p = inPixels[ (ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)]; break; case RGB_CLAMP: p = inPixels[ (ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth - 1)] & 0x00ffffff; } outPixels[x] = p; } else { int i = srcWidth * srcY + srcX; rgb[0] = inPixels[i]; outPixels[x] = inPixels[i]; } } setRGB(dst, 0, y, transformedSpace.width, 1, outPixels); } return dst; }
private final int getPixel(int[] pixels, int x, int y, int width, int height) { if (x < 0 || x >= width || y < 0 || y >= height) { switch (edgeAction) { case ZERO: default: return 0; case WRAP: return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)]; case CLAMP: return pixels[ (ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)]; case RGB_CLAMP: return pixels[ (ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)] & 0x00ffffff; } } return pixels[y * width + x]; }
private void rebuildGradient() { xKnots[0] = -1; xKnots[numKnots - 1] = 256; yKnots[0] = yKnots[1]; yKnots[numKnots - 1] = yKnots[numKnots - 2]; for (int i = 1; i < numKnots - 1; i++) { float spanLength = xKnots[i + 1] - xKnots[i]; int end = xKnots[i + 1]; if (i == numKnots - 2) end++; for (int j = xKnots[i]; j < end; j++) { int rgb1 = yKnots[i]; int rgb2 = yKnots[i + 1]; float hsb1[] = Color.RGBtoHSB((rgb1 >> 16) & 0xff, (rgb1 >> 8) & 0xff, rgb1 & 0xff, null); float hsb2[] = Color.RGBtoHSB((rgb2 >> 16) & 0xff, (rgb2 >> 8) & 0xff, rgb2 & 0xff, null); float t = (j - xKnots[i]) / spanLength; int type = getKnotType(i); int blend = getKnotBlend(i); if (j >= 0 && j <= 255) { switch (blend) { case CONSTANT: t = 0; break; case LINEAR: break; case SPLINE: // map[i] = ImageMath.colorSpline(j, numKnots, xKnots, yKnots); t = ImageMath.smoothStep(0.15f, 0.85f, t); break; case CIRCLE_UP: t = t - 1; t = (float) Math.sqrt(1 - t * t); break; case CIRCLE_DOWN: t = 1 - (float) Math.sqrt(1 - t * t); break; } // if (blend != SPLINE) { switch (type) { case RGB: map[j] = ImageMath.mixColors(t, rgb1, rgb2); break; case HUE_CW: case HUE_CCW: if (type == HUE_CW) { if (hsb2[0] <= hsb1[0]) hsb2[0] += 1.0f; } else { if (hsb1[0] <= hsb2[1]) hsb1[0] += 1.0f; } float h = ImageMath.lerp(t, hsb1[0], hsb2[0]) % (ImageMath.TWO_PI); float s = ImageMath.lerp(t, hsb1[1], hsb2[1]); float b = ImageMath.lerp(t, hsb1[2], hsb2[2]); map[j] = 0xff000000 | Color.HSBtoRGB(h, s, b); // FIXME-alpha break; } // } } } } }
/** * Set a knot position. * * @param n the knot index * @param x the knot position * @see #setKnotPosition */ public void setKnotPosition(int n, int x) { xKnots[n] = ImageMath.clamp(x, 0, 255); sortKnots(); rebuildGradient(); }
public BufferedImage filter(BufferedImage src, BufferedImage dst) { int width = src.getWidth(); int height = src.getHeight(); int type = src.getType(); WritableRaster srcRaster = src.getRaster(); originalSpace = new Rectangle(0, 0, width, height); transformedSpace = new Rectangle(0, 0, width, height); transformSpace(transformedSpace); if (dst == null) { ColorModel dstCM = src.getColorModel(); dst = new BufferedImage( dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null); } WritableRaster dstRaster = dst.getRaster(); int[] inPixels = getRGB(src, 0, 0, width, height, null); if (interpolation == NEAREST_NEIGHBOUR) return filterPixelsNN(dst, width, height, inPixels, transformedSpace); int srcWidth = width; int srcHeight = height; int srcWidth1 = width - 1; int srcHeight1 = height - 1; int outWidth = transformedSpace.width; int outHeight = transformedSpace.height; int outX, outY; int index = 0; int[] outPixels = new int[outWidth]; outX = transformedSpace.x; outY = transformedSpace.y; float[] out = new float[2]; for (int y = 0; y < outHeight; y++) { for (int x = 0; x < outWidth; x++) { transformInverse(outX + x, outY + y, out); int srcX = (int) Math.floor(out[0]); int srcY = (int) Math.floor(out[1]); float xWeight = out[0] - srcX; float yWeight = out[1] - srcY; int nw, ne, sw, se; if (srcX >= 0 && srcX < srcWidth1 && srcY >= 0 && srcY < srcHeight1) { // Easy case, all corners are in the image int i = srcWidth * srcY + srcX; nw = inPixels[i]; ne = inPixels[i + 1]; sw = inPixels[i + srcWidth]; se = inPixels[i + srcWidth + 1]; } else { // Some of the corners are off the image nw = getPixel(inPixels, srcX, srcY, srcWidth, srcHeight); ne = getPixel(inPixels, srcX + 1, srcY, srcWidth, srcHeight); sw = getPixel(inPixels, srcX, srcY + 1, srcWidth, srcHeight); se = getPixel(inPixels, srcX + 1, srcY + 1, srcWidth, srcHeight); } outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se); } setRGB(dst, 0, y, transformedSpace.width, 1, outPixels); } return dst; }