I have little experience with java programming, but I know my way around it a little. I want to pick up a project that was left behind by someone else. I was doing well fixing other errors here and there, but this one stumped me. Here it is:
javax.imageio.IIOException: Can't read input file!
at javax.imageio.ImageIO.read(Unknown Source)
at Replacer.main(Replacer.java:19)
To my surprise, the program still opened. However, when I tried to open a picture, this happened, and displayed a picture of 0 x 0 pixels:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException:
2147483647
at ImageEditor.resize(ImageEditor.java:384)
at ImageEditor.resize(ImageEditor.java:308)
at ImageFrame.setImage(ImageFrame.java:438)
at ImageFrame.actionPerformed(ImageFrame.java:765)
at java.awt.Button.processActionEvent(Unknown Source)
at java.awt.Button.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionP
rivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Replacer:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.PrintStream;
import javax.imageio.ImageIO;
public class Replacer
{
public static void main(String[] args)
{
BufferedImage i = null;
BufferedImage i2 = null;
Color[][] blockColors = new Color[16][16];
ImageFrame b = new ImageFrame(i);
try
{
i2 = ImageIO.read(new File("terrain.png"));
int blockSize = i2.getWidth(b) / 16;
System.out.println("Analyzing terrain.png");
int[] buffer = ImageEditor.returnBuffer(i2, b);
int width = i2.getWidth(b);
for (int j = 0; j < 16; j++) {
for (int k = 0; k < 16; k++) {
if ((j <= 2) || (k <= 8))
{
int[] i3 = ImageEditor.crop(buffer, width, width, b, j * blockSize, k * blockSize, blockSize, blockSize);
blockColors[j][k] = ImageEditor.getAverageColor(i3, b);
}
}
}
Color[] c2 = new Color[100];
c2[0] = blockColors[1][8];
c2[1] = blockColors[2][10];
c2[2] = blockColors[1][11];
c2[3] = blockColors[1][9];
c2[4] = blockColors[1][7];
c2[5] = blockColors[0][4];
c2[6] = blockColors[2][13];
c2[7] = blockColors[1][13];
c2[8] = blockColors[1][12];
c2[9] = blockColors[2][7];
c2[10] = blockColors[2][11];
c2[11] = blockColors[2][8];
c2[12] = blockColors[2][9];
c2[13] = blockColors[2][12];
c2[14] = blockColors[1][14];
c2[15] = blockColors[1][10];
c2[16] = blockColors[1][0];
c2[17] = blockColors[2][0];
c2[18] = blockColors[2][1];
c2[19] = blockColors[3][1];
c2[20] = blockColors[8][4];
c2[21] = blockColors[5][2];
c2[22] = blockColors[4][2];
c2[23] = blockColors[6][7];
c2[24] = blockColors[4][0];
c2[25] = blockColors[0][1];
c2[26] = blockColors[0][11];
c2[27] = blockColors[7][0];
c2[28] = blockColors[6][1];
c2[29] = blockColors[7][1];
c2[30] = blockColors[8][1];
c2[31] = blockColors[0][9];
c2[32] = blockColors[10][4];
c2[33] = blockColors[9][6];
c2[34] = blockColors[7][6];
c2[35] = blockColors[8][6];
c2[36] = blockColors[2][4];
c2[37] = blockColors[6][3];
c2[38] = blockColors[1][1];
c2[39] = blockColors[5][1];
c2[40] = blockColors[4][1];
c2[41] = blockColors[4][7];
c2[42] = blockColors[5][7];
c2[43] = blockColors[0][3];
c2[44] = blockColors[3][4];
c2[45] = blockColors[8][8];
c2[46] = blockColors[8][9];
c2[47] = blockColors[8][10];
c2[48] = blockColors[8][11];
c2[49] = blockColors[8][12];
for (int j = 0; j < c2.length / 2; j++)
{
double shadowRed = 0.892D * c2[j].getRed() + 0.5D;
double shadowGreen = 0.892D * c2[j].getGreen() + 0.5D;
double shadowBlue = 0.892D * c2[j].getBlue() + 0.5D;
c2[(50 + j)] = new Color((int)shadowRed, (int)shadowGreen, (int)shadowBlue);
}
for (int j = 0; j < c2.length; j++) {
System.out.println("colors[" + j + "] = new Color(" + c2[j].getRed() + "," + c2[j].getGreen() + "," + c2[j].getBlue() + ");");
}
b.setColors(c2);
System.out.println("Done");
}
catch (Exception e)
{
e.printStackTrace();
}
b.repaint();
}
}
ImageEditor:
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.PrintStream;
public class ImageEditor
{
public static int[] returnBuffer(Image i, Component c)
{
MediaTracker tracker = new MediaTracker(c);
tracker.addImage(i, 0);
try
{
tracker.waitForAll();
}
catch (Exception e)
{
System.out.println("Image loading interrupted");
}
int width = i.getWidth(c);
int height = i.getHeight(c);
int[] buffer = new int[width * height];
PixelGrabber grabber = new PixelGrabber(i, 0, 0, width, height, buffer, 0, width);
try
{
grabber.grabPixels();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return buffer;
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors(width, height, buffer, c, colors, w);
}
public static Image simplifyColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors)
{
double[] w = new double[colors.length];
for (int k = 0; k < w.length; k++) {
w[k] = 1.0D;
}
return simplifyColors2(i, buffer, c, colors, w);
}
public static Image simplifyColors2(Image i, int[] buffer, Component c, Color[] colors, double[] weights)
{
int height = i.getHeight(c);
int width = i.getWidth(c);
int[] simple = new int[buffer.length];
float[] hsb1 = new float[3];
float[] hsb2 = new float[3];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
hsb1 = Color.RGBtoHSB(current.getRed(), current.getGreen(), current.getBlue(), null);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
if (test != null)
{
hsb2 = Color.RGBtoHSB(test.getRed(), test.getGreen(), test.getBlue(), null);
int diff = (int)(Math.pow(hsb1[0] - hsb2[0], 2.0D) + Math.pow(hsb1[1] - hsb2[1], 2.0D) + Math.pow(hsb1[2] - hsb2[2], 2.0D));
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image simplifyColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128) {
simple[j] = col.getRGB();
} else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors(int width, int height, int[] buffer, Component c, Color[] colors, double[] weights)
{
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
k2 = k;
minDiff = diff;
}
}
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image shadowColors3(int width, int height, int[] buffer2, Component c, Color[] colors, double[] weights)
{
int[] buffer = (int[])buffer2.clone();
int[] simple = new int[buffer.length];
double k2 = 0.0D;
for (int j = 0; j < buffer.length; j++)
{
int minDiff = 10000000;
Color current = new Color(buffer[j], true);
Color col = Color.black;
for (int k = 0; k < colors.length; k++)
{
if (current.getAlpha() == 0)
{
col = new Color(255, 255, 255, 0);
break;
}
Color test = colors[k];
double w = weights[k];
if (test != null)
{
int diff = (int)((Math.pow(test.getRed() - current.getRed(), 2.0D) + Math.pow(test.getGreen() - current.getGreen(), 2.0D) + Math.pow(test.getBlue() - current.getBlue(), 2.0D)) / w);
if (diff < minDiff)
{
col = test;
minDiff = diff;
k2 = k;
}
}
}
int quantErrorR = current.getRed() - col.getRed();
int quantErrorG = current.getGreen() - col.getGreen();
int quantErrorB = current.getBlue() - col.getBlue();
if ((j + 1) % width != 0)
{
Color x = new Color(buffer[(j + 1)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 7 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 7 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 7 / 16, 255)), x.getAlpha());
buffer[(j + 1)] = y.getRGB();
}
if (((j - 1) % width != 0) && (j - 1 + width < buffer.length))
{
Color x = new Color(buffer[(j - 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 3 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 3 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 3 / 16, 255)), x.getAlpha());
buffer[(j - 1 + width)] = y.getRGB();
}
if (j + width < buffer.length)
{
Color x = new Color(buffer[(j + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 5 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 5 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 5 / 16, 255)), x.getAlpha());
buffer[(j + width)] = y.getRGB();
}
if (((j + 1) % width != 0) && (j + 1 + width < buffer.length))
{
Color x = new Color(buffer[(j + 1 + width)], true);
Color y = new Color(Math.max(0, Math.min(x.getRed() + col.getAlpha() / 255 * quantErrorR * 1 / 16, 255)), Math.max(0, Math.min(x.getGreen() + col.getAlpha() / 255 * quantErrorG * 1 / 16, 255)), Math.max(0, Math.min(x.getBlue() + col.getAlpha() / 255 * quantErrorB * 1 / 16, 255)), x.getAlpha());
buffer[(j + 1 + width)] = y.getRGB();
}
if (current.getAlpha() >= 128)
{
if (k2 < colors.length / 2) {
simple[j] = Color.WHITE.getRGB();
} else {
simple[j] = Color.BLACK.getRGB();
}
}
else {
simple[j] = new Color(255, 255, 255, 0).getRGB();
}
}
return c.createImage(new MemoryImageSource(width, height, simple, 0, width));
}
public static Image resize(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int getResizedHeight(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return newDim;
}
return (int)(newDim * 1.0D * h / w);
}
public static int getResizedWidth(Image i, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return (int)(newDim * 1.0D * w / h);
}
return newDim;
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resizebuff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resizebuff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize2(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newDim)
{
int h = i.getHeight(c);
int w = i.getWidth(c);
if (w < h) {
return resize2buff(i, buffer, c, newDim, (int)(newDim * 1.0D * w / h));
}
return resize2buff(i, buffer, c, (int)(newDim * 1.0D * h / w), newDim);
}
public static Image resize(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resizebuff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int oldX = (int)(x / wRatio);
int oldY = (int)(y / hRatio);
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
}
}
return resized;
}
public static Image resize2(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return i;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resize(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return c.createImage(new MemoryImageSource(newWidth, newHeight, resized, 0, newWidth));
}
public static int[] resize2buff(Image i, int[] buffer, Component c, int newHeight, int newWidth)
{
if (newHeight < 2) {
newHeight = 2;
}
if (newWidth < 2) {
newWidth = 2;
}
int height = i.getHeight(c);
int width = i.getWidth(c);
if ((height == newHeight) && (width == newWidth)) {
return buffer;
}
int[] resized = new int[newHeight * newWidth];
double hRatio = newHeight / height;
double wRatio = newWidth / width;
if ((hRatio > 1.0D) || (wRatio > 1.0D)) {
return resizebuff(i, buffer, c, newHeight, newWidth);
}
for (int y = 0; y < newHeight; y++) {
for (int x = 0; x < newWidth; x++)
{
int k = 0;
double oldC = 0.0D;
double oldRed = 0.0D;
double oldGreen = 0.0D;
double oldBlue = 0.0D;
double oldAlpha = 0.0D;
for (int q = (int)(x / wRatio); q < (int)((x + 1) / wRatio); q++) {
for (int j = (int)(y / hRatio); j < (int)((y + 1) / hRatio); j++)
{
Color oldColor = new Color(buffer[(j * width + q)], true);
oldRed = (oldRed * k + oldColor.getRed()) / (k + 1);
oldGreen = (oldGreen * k + oldColor.getGreen()) / (k + 1);
oldBlue = (oldBlue * k + oldColor.getBlue()) / (k + 1);
oldAlpha = (oldAlpha * k + oldColor.getAlpha()) / (k + 1);
k++;
}
}
resized[(y * newWidth + x)] = new Color((int)oldRed, (int)oldGreen, (int)oldBlue, (int)oldAlpha).getRGB();
}
}
return resized;
}
public static int[] countColors(int[] buffer, Component c, Color[] colors)
{
int[] count = new int[colors.length];
for (int k = 0; k < count.length; k++) {
count[k] = 0;
}
Color col = Color.BLACK;
for (int j = 0; j < buffer.length; j++)
{
col = new Color(buffer[j]);
for (int k = 0; k < colors.length; k++) {
if ((colors[k] != null) && (colors[k].getRGB() == col.getRGB())) {
count[k] += 1;
}
}
}
return count;
}
(Had to cut it off b/c of character limit)
EDIT: Turns out the first error doesn't matter. The program tries to run textures from a separate file. If it isn't found, it skips it.
Any help is appreciated.
Addressing your second issue with the stack trace:
This line is your issue:
resized[(y * newWidth + x)] = buffer[(oldY * width + oldX)];
Specifically this part resized[(y * newWidth + x)] because [y * newWidth + x] can be far bigger than what resized allows.
Let's assume the image is 100x50 (WxH), this means that int[] resized = new int[newHeight * newWidth]; will create a new array that is 5000 long.
However the for loops will create something much higher:
for (int y = 0; y < newHeight; y++) in this instance y will go as high as newHeight or 100
vfor (int x = 0; x < newWidth; x++)in this instanceywill go as high asnewWidth` or 50
So:
resized[(y * newWidth + x)] = something; will be an issue because 100 * 100 + 50 can be as large as 10050, that is far bigger than 5000.
The solution is to make a larger resized array, or to rethink your for loops.
a want to test this function. Can you please write a test for one of those methods? I already read about JUnit testing but i really have no clue how to test this.
public class SomeClass {
#Override
public void render(Screen screen)
{
int xTile = playerLook[0];
int yTile = playerLook[1];
int walkingSpeed = 4;
int flipTop = (numSteps >> walkingSpeed) & 1;
int flipBottom = (numSteps >> walkingSpeed) & 1;
if (movingDir == 1) {
xTile += 2;
}
else if (movingDir > 1) {
xTile += 4 + ((numSteps >> walkingSpeed) & 1) * 2;
flipTop = (movingDir - 1) % 2;
}
int modifier = 8 * scale;
int xOffset = x - modifier / 2;
int yOffset = y - modifier / 2 - 4;
if (isSwimming) {
int waterColor = 0;
yOffset += 4;
if (tickCount % 60 < 15) {
waterColor = Colors.get(-1, -1, 225, -1);
} else if ((15 <= tickCount % 60) && (tickCount % 60 < 30)) {
yOffset -= 1;
waterColor = Colors.get(-1, 225, 115, -1);
} else if ((30 <= tickCount % 60) && (tickCount % 60 < 45)) {
waterColor = Colors.get(-1, 115, -1, 225);
} else {
yOffset -= 1;
waterColor = Colors.get(-1, 225, 115, -1);
}
screen.render(xOffset, yOffset + 3, 0 + 27 * MAP_TILE_SIZE, waterColor, 0x00, 1);
screen.render(xOffset + 8, yOffset + 3, 0 + 27 * MAP_TILE_SIZE, waterColor, 0x01, 1);
}
screen.render(xOffset + (modifier * flipTop), yOffset, xTile + yTile * MAP_TILE_SIZE, color, flipTop, scale);
screen.render(xOffset + modifier - (modifier * flipTop), yOffset, (xTile + 1) + yTile * MAP_TILE_SIZE, color, flipTop, scale);
if (!isSwimming) {
screen.render(xOffset + (modifier * flipBottom), yOffset + modifier, xTile + (yTile + 1) * MAP_TILE_SIZE, color, flipBottom, scale);
screen.render(xOffset + modifier - (modifier * flipBottom), yOffset + modifier, (xTile + 1) + (yTile + 1) * MAP_TILE_SIZE, color, flipBottom, scale);
}
}
#Override
public boolean hasCollided(int xa, int ya)
{
int xMin = 0;
int xMax = 7;
int yMin = 3;
int yMax = 7;
for (int x = xMin; x < xMax; x++) {
if (isSolidTile(xa, ya, x, yMin)) {
return true;
}
}
for (int x = xMin; x < xMax; x++) {
if (isSolidTile(xa, ya, x, yMax)) {
return true;
}
}
for (int y = yMin; y < yMax; y++) {
if (isSolidTile(xa, ya, xMin, y)) {
return true;
}
}
for (int y = yMin; y < yMax; y++) {
if (isSolidTile(xa, ya, xMax, y)) {
return true;
}
}
return false;
}
}
would really appreciate some help.
Thank you guys
I found some code that draws the histogram but I am not sure how to make it show the histogram of _tempBitmaps[0] once the user clicks on a ShowRGB Histogram Button
I want the graphs to be displayed on top of ImageView once the user clicks the button display_RGB and when the user clicks the button again the graphs disappear.
I have also attached a mockup of the layout and the graphs that I wish to achieve.
Mockup:
Below is the sample code I found for histogram and it works but currently some of the variables arent initialised and thats what I need help with :
class DrawOnTop extends View {
Bitmap mBitmap;
Paint mPaintBlack;
Paint mPaintYellow;
Paint mPaintRed;
Paint mPaintGreen;
Paint mPaintBlue;
byte[] mYUVData;
int[] mRGBData;
int mImageWidth, mImageHeight;
int[] mRedHistogram;
int[] mGreenHistogram;
int[] mBlueHistogram;
double[] mBinSquared;
public DrawOnTop(Context context) {
super(context);
mPaintBlack = new Paint();
mPaintBlack.setStyle(Paint.Style.FILL);
mPaintBlack.setColor(Color.BLACK);
mPaintBlack.setTextSize(25);
mPaintYellow = new Paint();
mPaintYellow.setStyle(Paint.Style.FILL);
mPaintYellow.setColor(Color.YELLOW);
mPaintYellow.setTextSize(25);
mPaintRed = new Paint();
mPaintRed.setStyle(Paint.Style.FILL);
mPaintRed.setColor(Color.RED);
mPaintRed.setTextSize(25);
mPaintGreen = new Paint();
mPaintGreen.setStyle(Paint.Style.FILL);
mPaintGreen.setColor(Color.GREEN);
mPaintGreen.setTextSize(25);
mPaintBlue = new Paint();
mPaintBlue.setStyle(Paint.Style.FILL);
mPaintBlue.setColor(Color.BLUE);
mPaintBlue.setTextSize(25);
mBitmap = null;
mYUVData = null;
mRGBData = null;
mRedHistogram = new int[256];
mGreenHistogram = new int[256];
mBlueHistogram = new int[256];
mBinSquared = new double[256];
for (int bin = 0; bin < 256; bin++)
{
mBinSquared[bin] = ((double)bin) * bin;
} // bin
}
#Override
protected void onDraw(Canvas canvas) {
if (mBitmap != null)
{
int canvasWidth = canvas.getWidth();
int canvasHeight = canvas.getHeight();
int newImageWidth = canvasWidth;
int newImageHeight = canvasHeight;
int marginWidth = (canvasWidth - newImageWidth)/2;
// Convert from YUV to RGB
decodeYUV420SP(mRGBData, mYUVData, mImageWidth, mImageHeight);
// Draw bitmap
mBitmap.setPixels(mRGBData, 0, mImageWidth, 0, 0,
mImageWidth, mImageHeight);
Rect src = new Rect(0, 0, mImageWidth, mImageHeight);
Rect dst = new Rect(marginWidth, 0,
canvasWidth-marginWidth, canvasHeight);
canvas.drawBitmap(mBitmap, src, dst, mPaintBlack);
// Draw black borders
canvas.drawRect(0, 0, marginWidth, canvasHeight, mPaintBlack);
canvas.drawRect(canvasWidth - marginWidth, 0,
canvasWidth, canvasHeight, mPaintBlack);
// Calculate histogram
calculateIntensityHistogram(mRGBData, mRedHistogram,
mImageWidth, mImageHeight, 0);
calculateIntensityHistogram(mRGBData, mGreenHistogram,
mImageWidth, mImageHeight, 1);
calculateIntensityHistogram(mRGBData, mBlueHistogram,
mImageWidth, mImageHeight, 2);
// Calculate mean
double imageRedMean = 0, imageGreenMean = 0, imageBlueMean = 0;
double redHistogramSum = 0, greenHistogramSum = 0, blueHistogramSum = 0;
for (int bin = 0; bin < 256; bin++)
{
imageRedMean += mRedHistogram[bin] * bin;
redHistogramSum += mRedHistogram[bin];
imageGreenMean += mGreenHistogram[bin] * bin;
greenHistogramSum += mGreenHistogram[bin];
imageBlueMean += mBlueHistogram[bin] * bin;
blueHistogramSum += mBlueHistogram[bin];
} // bin
imageRedMean /= redHistogramSum;
imageGreenMean /= greenHistogramSum;
imageBlueMean /= blueHistogramSum;
// Calculate second moment
double imageRed2ndMoment = 0, imageGreen2ndMoment = 0, imageBlue2ndMoment = 0;
for (int bin = 0; bin < 256; bin++)
{
imageRed2ndMoment += mRedHistogram[bin] * mBinSquared[bin];
imageGreen2ndMoment += mGreenHistogram[bin] * mBinSquared[bin];
imageBlue2ndMoment += mBlueHistogram[bin] * mBinSquared[bin];
} // bin
imageRed2ndMoment /= redHistogramSum;
imageGreen2ndMoment /= greenHistogramSum;
imageBlue2ndMoment /= blueHistogramSum;
double imageRedStdDev = Math.sqrt( imageRed2ndMoment - imageRedMean*imageRedMean );
double imageGreenStdDev = Math.sqrt( imageGreen2ndMoment - imageGreenMean*imageGreenMean );
double imageBlueStdDev = Math.sqrt( imageBlue2ndMoment - imageBlueMean*imageBlueMean );
// Draw mean
String imageMeanStr = "Mean (R,G,B): " + String.format("%.4g", imageRedMean) + ", " + String.format("%.4g", imageGreenMean) + ", " + String.format("%.4g", imageBlueMean);
canvas.drawText(imageMeanStr, marginWidth+10-1, 30-1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10+1, 30-1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10+1, 30+1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10-1, 30+1, mPaintBlack);
canvas.drawText(imageMeanStr, marginWidth+10, 30, mPaintYellow);
// Draw standard deviation
String imageStdDevStr = "Std Dev (R,G,B): " + String.format("%.4g", imageRedStdDev) + ", " + String.format("%.4g", imageGreenStdDev) + ", " + String.format("%.4g", imageBlueStdDev);
canvas.drawText(imageStdDevStr, marginWidth+10-1, 60-1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10+1, 60-1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10+1, 60+1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10-1, 60+1, mPaintBlack);
canvas.drawText(imageStdDevStr, marginWidth+10, 60, mPaintYellow);
// Draw red intensity histogram
float barMaxHeight = 3000;
float barWidth = ((float)newImageWidth) / 256;
float barMarginHeight = 2;
RectF barRect = new RectF();
barRect.bottom = canvasHeight - 200;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
float prob = (float)mRedHistogram[bin] / (float)redHistogramSum;
barRect.top = barRect.bottom -
Math.min(80,prob*barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintRed);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw green intensity histogram
barRect.bottom = canvasHeight - 100;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
barRect.top = barRect.bottom - Math.min(80, ((float)mGreenHistogram[bin])/((float)greenHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintGreen);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
// Draw blue intensity histogram
barRect.bottom = canvasHeight;
barRect.left = marginWidth;
barRect.right = barRect.left + barWidth;
for (int bin = 0; bin < 256; bin++)
{
barRect.top = barRect.bottom - Math.min(80, ((float)mBlueHistogram[bin])/((float)blueHistogramSum) * barMaxHeight) - barMarginHeight;
canvas.drawRect(barRect, mPaintBlack);
barRect.top += barMarginHeight;
canvas.drawRect(barRect, mPaintBlue);
barRect.left += barWidth;
barRect.right += barWidth;
} // bin
} // end if statement
super.onDraw(canvas);
} // end onDraw method
static public void decodeYUV420SP(int[] rgb, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
for (int j = 0, yp = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xff & ((int) yuv420sp[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) - 128;
u = (0xff & yuv420sp[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);
}
}
}
static public void decodeYUV420SPGrayscale(int[] rgb, byte[] yuv420sp, int width, int height)
{
final int frameSize = width * height;
for (int pix = 0; pix < frameSize; pix++)
{
int pixVal = (0xff & ((int) yuv420sp[pix])) - 16;
if (pixVal < 0) pixVal = 0;
if (pixVal > 255) pixVal = 255;
rgb[pix] = 0xff000000 | (pixVal << 16) | (pixVal << 8) | pixVal;
} // pix
}
static public void calculateIntensityHistogram(int[] rgb, int[] histogram, int width, int height, int component)
{
for (int bin = 0; bin < 256; bin++)
{
histogram[bin] = 0;
} // bin
if (component == 0) // red
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 16) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else if (component == 1) // green
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = (rgb[pix] >> 8) & 0xff;
histogram[ pixVal ]++;
} // pix
}
else // blue
{
for (int pix = 0; pix < width*height; pix += 3)
{
int pixVal = rgb[pix] & 0xff;
histogram[ pixVal ]++;
} // pix
}
}
}
This is the class where I wish to create the button which will create the histogram:
public class testrgb extends Activity {
/************************
* PROPERTIES
**********************/
/* Tag for Log */
public static final String TAG = "PiccaFinal.EditPicturesActivity";
/* Images Path */
private String[] _imagesPath;
/* Original Images */
private Bitmap[] _originalBitmaps = new Bitmap[2];
/* Final Filtered Images */
private Bitmap[] _filteredBitmaps = new Bitmap[2];
/* Image View */
private ImageView _filterImageView;
private Preview mPreview;
private DrawOnTop mDrawOnTop;
int[] pixels;
/************************
* ANDROID METHODS
**********************/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_edit_pictures);
Intent intent = getIntent();
_imagesPath = intent.getStringArrayExtra(MainActivity.IMAGES_PATH);
for (int i = MainActivity.LEFT_IMAGE; i <= MainActivity.RIGHT_IMAGE; i++) {
_originalBitmaps[i] = BitmapFactory.decodeFile(_imagesPath[i]);
}
_filterImageView = (ImageView) findViewById(R.id.filter_image_view);
_filterImageView
.setImageBitmap(_originalBitmaps[MainActivity.LEFT_IMAGE]);
// --------------------------------------------------------------------------------
// display_RGB
Button display_RGBButton = (Button) findViewById(R.id.display_RGB);
display_RGBButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//what should I do here
});
}
}
So I'm trying to blur an image as fast as possible(instant feel like),
as the activity needs to be updated as I press the Blur button.
The problem I am having is that, I cannot find a Blur that works quick enough...
Note: The blur, preferably a Gaussian blur, doesn't need to be the best quality at all..
I tried out the following, but it takes a few seconds, is there anyway this code could be made to run quicker in sacrifice of quality ? Or are there any other alternatives?
I would look into GPU stuff, but this blur is really just an effect related to the UI and only happens when I press open a transparent activity sized as a small box...
Any Ideas?
static Bitmap fastblur(Bitmap sentBitmap, int radius, int fromX, int fromY,
int width, int height) {
// Stack Blur v1.0 from
// http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
//
// Java Author: Mario Klingemann <mario at quasimondo.com>
// http://incubator.quasimondo.com
// created Feburary 29, 2004
// Android port : Yahel Bouaziz <yahel at kayenko.com>
// http://www.kayenko.com
// ported april 5th, 2012
// This is a compromise between Gaussian Blur and Box blur
// It creates much better looking blurs than Box Blur, but is
// 7x faster than my Gaussian Blur implementation.
//
// I called it Stack Blur because this describes best how this
// filter works internally: it creates a kind of moving stack
// of colors whilst scanning through the image. Thereby it
// just has to add one new block of color to the right side
// of the stack and remove the leftmost color. The remaining
// colors on the topmost layer of the stack are either added on
// or reduced by one, depending on if they are on the right or
// on the left side of the stack.
//
// If you are using this algorithm in your code please add
// the following line:
//
// Stack Blur Algorithm by Mario Klingemann <mario#quasimondo.com>
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = width;
int h = height;
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, fromX, fromY, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
int originRadius = radius;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
radius = originRadius;
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
pix[yi] = 0xff000000 | (dv[rsum] << 16) | (dv[gsum] << 8)
| dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, fromX, fromY, w, h);
return (bitmap);
}
Try to scale down the image 2, 4, 8, ... times and then scale it up again. That is fast. Otherwise implement it in renderscript.
If you want more than the scaling you can look at this code snippet in renderscript. It does the same kind of bluring as given in another answer. The same algorithm can be implemented in Java and is an optimization of the other answer. This code blurs one line. To blur a bitmap you should invoke this for all lines and then the same for all columns (you need to reimplement it to handle columns). To get a quick blur just do this once. If you want a better looking blur do it several times. I usually only do it twice.
The reason for doing one line is that I tried to parallelize the algorithm, that gave some improvement and is really simple in renderscript. I invoked the below code for all lines in parallel, and then the same for all columns.
int W = 8;
uchar4 *in;
uchar4 *out;
int N;
float invN;
uint32_t nx;
uint32_t ny;
void init_calc() {
N = 2*W+1;
invN = 1.0f/N;
nx = rsAllocationGetDimX(rsGetAllocation(in));
ny = rsAllocationGetDimY(rsGetAllocation(in));
}
void root(const ushort *v_in) {
float4 sum = 0;
uchar4 *head = in + *v_in * nx;
uchar4 *tail = head;
uchar4 *p = out + *v_in * nx;
uchar4 *hpw = head + W;
uchar4 *hpn = head + N;
uchar4 *hpx = head + nx;
uchar4 *hpxmw = head + nx - W - 1;
while (head < hpw) {
sum += rsUnpackColor8888(*head++);
}
while (head < hpn) {
sum += rsUnpackColor8888(*head++);
*p++ = rsPackColorTo8888(sum*invN);
}
while (head < hpx) {
sum += rsUnpackColor8888(*head++);
sum -= rsUnpackColor8888(*tail++);
*p++ = rsPackColorTo8888(sum*invN);
}
while (tail < hpxmw) {
sum -= rsUnpackColor8888(*tail++);
*p++ = rsPackColorTo8888(sum*invN);
}
}
Here is for the vertical bluring:
int W = 8;
uchar4 *in;
uchar4 *out;
int N;
float invN;
uint32_t nx;
uint32_t ny;
void init_calc() {
N = 2*W+1;
invN = 1.0f/N;
nx = rsAllocationGetDimX(rsGetAllocation(in));
ny = rsAllocationGetDimY(rsGetAllocation(in));
}
void root(const ushort *v_in) {
float4 sum = 0;
uchar4 *head = in + *v_in;
uchar4 *tail = head;
uchar4 *hpw = head + nx*W;
uchar4 *hpn = head + nx*N;
uchar4 *hpy = head + nx*ny;
uchar4 *hpymw = head + nx*(ny-W-1);
uchar4 *p = out + *v_in;
while (head < hpw) {
sum += rsUnpackColor8888(*head);
head += nx;
}
while (head < hpn) {
sum += rsUnpackColor8888(*head);
*p = rsPackColorTo8888(sum*invN);
head += nx;
p += nx;
}
while (head < hpy) {
sum += rsUnpackColor8888(*head);
sum -= rsUnpackColor8888(*tail);
*p = rsPackColorTo8888(sum*invN);
head += nx;
tail += nx;
p += nx;
}
while (tail < hpymw) {
sum -= rsUnpackColor8888(*tail);
*p = rsPackColorTo8888(sum*invN);
tail += nx;
p += nx;
}
}
And here is the Java code that calls into the rs code:
private RenderScript mRS;
private ScriptC_horzblur mHorizontalScript;
private ScriptC_vertblur mVerticalScript;
private ScriptC_blur mBlurScript;
private Allocation alloc1;
private Allocation alloc2;
private void hblur(int radius, Allocation index, Allocation in, Allocation out) {
mHorizontalScript.set_W(radius);
mHorizontalScript.bind_in(in);
mHorizontalScript.bind_out(out);
mHorizontalScript.invoke_init_calc();
mHorizontalScript.forEach_root(index);
}
private void vblur(int radius, Allocation index, Allocation in, Allocation out) {
mHorizontalScript.set_W(radius);
mVerticalScript.bind_in(in);
mVerticalScript.bind_out(out);
mVerticalScript.invoke_init_calc();
mVerticalScript.forEach_root(index);
}
Bitmap blur(Bitmap org, int radius) {
Bitmap out = Bitmap.createBitmap(org.getWidth(), org.getHeight(), org.getConfig());
blur(org, out, radius);
return out;
}
private Allocation createIndex(int size) {
Element element = Element.U16(mRS);
Allocation allocation = Allocation.createSized(mRS, element, size);
short[] rows = new short[size];
for (int i = 0; i < rows.length; i++) rows[i] = (short)i;
allocation.copyFrom(rows);
return allocation;
}
private void blur(Bitmap src, Bitmap dst, int r) {
Allocation alloc1 = Allocation.createFromBitmap(mRS, src);
Allocation alloc2 = Allocation.createTyped(mRS, alloc1.getType());
Allocation hIndexAllocation = createIndex(alloc1.getType().getY());
Allocation vIndexAllocation = createIndex(alloc1.getType().getX());
// Iteration 1
hblur(r, hIndexAllocation, alloc1, alloc2);
vblur(r, vIndexAllocation, alloc2, alloc1);
// Iteration 2
hblur(r, hIndexAllocation, alloc1, alloc2);
vblur(r, vIndexAllocation, alloc2, alloc1);
// Add more iterations if you like or simply make a loop
alloc1.copyTo(dst);
}
Gaussian blur is expensive to do accurately. A much faster approximation can be done by just iteratively averaging the pixels. It's still expensive to blur the image a lot but you can redraw between each iteration to at least give instant feedback and a nice animation of the image blurring.
static void blurfast(Bitmap bmp, int radius) {
int w = bmp.getWidth();
int h = bmp.getHeight();
int[] pix = new int[w * h];
bmp.getPixels(pix, 0, w, 0, 0, w, h);
for(int r = radius; r >= 1; r /= 2) {
for(int i = r; i < h - r; i++) {
for(int j = r; j < w - r; j++) {
int tl = pix[(i - r) * w + j - r];
int tr = pix[(i - r) * w + j + r];
int tc = pix[(i - r) * w + j];
int bl = pix[(i + r) * w + j - r];
int br = pix[(i + r) * w + j + r];
int bc = pix[(i + r) * w + j];
int cl = pix[i * w + j - r];
int cr = pix[i * w + j + r];
pix[(i * w) + j] = 0xFF000000 |
(((tl & 0xFF) + (tr & 0xFF) + (tc & 0xFF) + (bl & 0xFF) + (br & 0xFF) + (bc & 0xFF) + (cl & 0xFF) + (cr & 0xFF)) >> 3) & 0xFF |
(((tl & 0xFF00) + (tr & 0xFF00) + (tc & 0xFF00) + (bl & 0xFF00) + (br & 0xFF00) + (bc & 0xFF00) + (cl & 0xFF00) + (cr & 0xFF00)) >> 3) & 0xFF00 |
(((tl & 0xFF0000) + (tr & 0xFF0000) + (tc & 0xFF0000) + (bl & 0xFF0000) + (br & 0xFF0000) + (bc & 0xFF0000) + (cl & 0xFF0000) + (cr & 0xFF0000)) >> 3) & 0xFF0000;
}
}
}
bmp.setPixels(pix, 0, w, 0, 0, w, h);
}