so I am working on a program in java which creates the a rectangular image (see link below) as a ppm image that would be further written into a ppm file. Creating and writing the image to the file I get. However, I am having difficulty creating the image dynamically such that it works for any width and height specified. From my understanding, a p3 ppm file simply follows the following format for a 4x4 image.
P3
4 4
15
0 0 0 0 0 0 0 0 0 15 0 15
0 0 0 0 15 7 0 0 0 0 0 0
0 0 0 0 0 0 0 15 7 0 0 0
15 0 15 0 0 0 0 0 0 0 0 0
Where the first three numbers are the headings and the rest is simply the rgb values of each pixel. But I am having trouble figuring out how I can create the above matrix for the image below and for any dimensions specified as it does not include solid colors in a straight line?
Image to be created:
I figured I could create an arraylist which holds an array of rgb values such that each index in the list is one rgb set followed by the next rgb set to the right. However, I am quite confused on what the rgb values would be. Here is what I have:
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
for(int i = 0; i <= width; i++){
for(int j = 0; i <= height; j++){
rgb[0] = 255-j; //random values as im not sure what they should be or how to calculate them
rgb[1] = 0+j;
rgb[1] = 0+j;
pic.add(rgb);
}
}
}
Thanks in advance.
EDITED::Updated code
I have managed to fix most of the issues, however, the image generated does not match the one posted above. With this code. I get the following image:
package ppm;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class PPM {
private BufferedImage img;
private static final String imageDir = "Image/rect.ppm";
private final static String filename = "assignment1_q1.ppm";
private static byte bytes[]=null; // bytes which make up binary PPM image
private static double doubles[] = null;
private static int height = 0;
private static int width = 0;
private static ArrayList pic;
private static String matrix="";
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException {
createImage(200, 200);
writeImage(filename);
}
public static void createImage(int width, int height){
pic = new ArrayList();
int[] rgb = new int[3];
matrix +="P3\n" + width + "\n" + height + "\n255\n";
for(int i = 0; i <= height; i++){
for(int j = 0; j <= width; j++){
Color c = getColor(width, height, j, i);
//System.out.println(c);
if(c==Color.red){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = 0;
rgb[2] = 0;
}else if(c==Color.green){
rgb[0] = 0;
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = 0;
}else if(c==Color.blue){
rgb[0] = 0;
rgb[1] = 0;
rgb[2] = (int) (255*factor(width, height, j, i));
}else if(c== Color.white){
rgb[0] = (int) (255*factor(width, height, j, i));
rgb[1] = (int) (255*factor(width, height, j, i));
rgb[2] = (int) (255*factor(width, height, j, i));
}
matrix += ""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " " ;
//System.out.println(""+ rgb[0] + " " + rgb[1] + " " + rgb[2] + " ");
//pic.add(rgb);
}
matrix += "\n";
}
}
public static Color getColor(int width, int height, int a, int b){
double d1 = ((double) width / height) * a;
double d2 = (((double) -width / height) * a + height);
if(d1 > b && d2 > b) return Color.green;
if(d1 > b && d2 < b) return Color.blue;
if(d1 < b && d2 > b) return Color.red;
return Color.white;
}
public static double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
//System.out.println(Math.min(factorX, factorY));
return Math.min(factorX, factorY);
}
public static void writeImage(String fn) throws FileNotFoundException, IOException {
//if (pic != null) {
FileOutputStream fos = new FileOutputStream(fn);
fos.write(new String(matrix).getBytes());
//fos.write(data.length);
//System.out.println(data.length);
fos.close();
// }
}
}
You can use Linear functions to model the diagonals in the picture. Keep in mind though that in the coordinates (0, 0) lie in the top-left corner of the image!
Say you want to create an image with the dimensions width and height, the diagonal from the top-left to bottom-right would cross the points (0, 0) and (width, height):
y = ax + t
0 = a * 0 + t => t = 0
height = a * width + 0 => a = height / width
d1(x) = (height / width) * x
Now we can calculate the function for the second diagonal. This diagonal goes through the points (0, height) and (width, 0), so:
y = ax + t
height = a * 0 + t => t = height
0 = a * width + height => a = -(height/width)
d2(x) = -(height/width) * x + height
From this we can determine whether a certain point in the image lies below or above a diagonal. As an example for the point (a, b):
if d1(a) > b: (a, b) lies above the first diagonal (left-top to right-bottom), thus it must be either blue or green. Otherwise it must be either red or white
if d2(a) > b: (a, b) lies above the second diagonal, thus it must be either red or green. Otherwise it must be white or blue
By applying both relationships it's easy to determine to which of the four colors a certain point belongs:
Color getColor(int width, int height, int a, int b){
double d1 = ((double) height / width) * a;
double d2 = ((double) -height / width) * a + height;
if(d1 > b && d2 > b) return greenColor;
if(d1 > b && d2 < b) return blueColor;
if(d1 < b && d2 > b) return redColor;
return whiteColor;
}
Now there's one last thing that we need to take into account: the image darkens towards it's borders.
A darker version of a color can be created by multiplying each channel with a factor. The lower the factor the darker the resulting the color. For the sake of simplicity I'll assume the change in brightness is linear from the center of the image.
Since the brightness changes along two axis independently, we need to model this by calculating the change alongside both axis and using the maximum.
The brightness change as a function of the distance of the center can be modeled using the distance to the closer border of the image in relation to the distance to the center (only on one axis):
deltaX = min(a, width - a) / (width / 2)
deltaY = min(b, height - b) / (height / 2)
So we can get the factor to multiply each color-channel by this way:
double factor(int width, int height, int a, int b){
double factorX = (double) Math.min(a, width - a) / width * 2;
double factorY = (double) Math.min(b, height - b) / height * 2;
return Math.min(factorX, factorY);
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I am trying to figure out how to use a nested for loop to produce this pattern below:
Thus far, I have
public class Triangle {
public static final int SIZE = 600;
public static final int INITIAL_X = 300;
public static final int INITIAL_Y = 50;
public static final int SIDE = 100;
/**
*
*
* #param args command line arguments
*/
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
DrawingPanel panel = new DrawingPanel(SIZE, SIZE);
panel.setBackground(Color.WHITE);
System.out.print("Enter number of rows (1-5): " );
int row = console.nextInt();
if(row < 1) {
row = 1;
} else if(row > 5) {
row = 5;
}
System.out.print("Specify red value (0-255): ");
int red = console.nextInt();
if(red < 0) {
red = 0;
} else if(red > 255) {
red = 255;
System.out.print("Specify green value (0-255): ");
int green = console.nextInt();
if(green < 0) {
green = 0;
} else if(green > 255) {
green = 255;
}
System.out.print("Specify blue value (0-255): ");
int blue = console.nextInt();
if(blue < 0) {
blue = 0;
} else if(blue > 255) {
blue = 255;
}
Graphics g = panel.getGraphics(); //Initializes graphics panel.
g.setColor(new Color(red, green, blue));
for (int i = 1; i <= row; i++) {
for (int x = 1; x <= row; x++) {
int lx = sx - SIDE/2;
int rx = sx + SIDE/2;
int ly = (int) (sy + SIDE*Math.sqrt(3)/2);
int ry = ly;
System.out.println("\n*CLOSE the Drawing Panel to exit the program*");
}
/**
* Draws an equilateral triangle with topmost point at (x, y) with the
* given side length and color.
*
* #param g
* #param color
* #param x
* #param y
* #param sideLength
*/
public static void drawTriangle(Graphics g, int sx, int sy, int rows) {
g.drawLine(sx, sy, lx, ly);
g.drawLine(sx, sy, rx, ry);
g.drawLine(lx, ly, rx, ry);
}
This code is definitely not finished. I only want to use the java.awt.* and java.util.* packages to solve this. My trouble is mainly with creating a nested for loop in the main method, but I believe I have a grasp on the scanner part of this assignment. I have used the equilateral triangle formulas below that are derived from the Pythagorean theorem. Each row is supposed to have that many triangles (for instance, the 5th row is supposed to have 5 triangles). The triangles are contiguous and the lower left/right points of each triangle form the uppermost points of the triangles in the row below. The (x, y) coordinates of the topmost point of the triangle in the first row must be (300, 50). Please let me know if anyone can help.
A recursive approach sounds easier than iterative so it could look like this:
private void drawTree(double x, double y, int depth, int maxDepth, Graphics graphics, double sideLength) {
if (depth >= maxDepth) {
return;
}
double leftX = x - sideLength / 2;
double leftY = y + Math.sqrt(sideLength * 3) / 2;
double rightX = x + sideLength / 2;
double rightY = leftY;
//draw line from (x,y) -> (leftX, leftY)
graphics.drawLine(x, y, leftX, leftY);
//draw line from (x,y) -> (rightX, rightY)
graphics.drawLine(x, y, rightX, rightY);
//draw line from (leftX, leftY) -> (rightX, rightY)
graphics.drawLine(leftX, leftX, rightX, rightY);
drawTree(leftX, leftY, depth + 1, maxDepth, graphics, sideLength);
drawTree(rightX, rightY, depth + 1, maxDepth, graphics, sideLength);
}
Does POI-Framwork support to get background color of a XSSFSimpleShape object? I looked around this class but I couldn't find the way to get its background?
Here is my code:
XSSFSimpleShape simpleObj = ...
simpleObj.getCTShape().getSpPr()... get some things named color here
simpleObj.getCTShape().getStyle().getFillRef()... get some things named colors here
This is the opposite of a trivial task. You are on the right way with CTShapeProperties. The next step is CTSolidColorFillProperties and as long we will find a CTSRgbColor all things will be easy because this is simply RGB. But there are much more possible kinds of color types as you see.
One possible color type which Excel is often using is CTSchemeColor. This color is a theme color from ThemesTable but possibly additional determined by given luminescence changing from lumMod and lumOff.
Example XML:
<a:solidFill>
<a:schemeClr val="accent4">
<a:lumMod val="60000"/>
<a:lumOff val="40000"/>
</a:schemeClr>
</a:solidFill>
Problem with this is that those luminescence changings are made in HSL. Javas java.awt.Color is only supporting HSB (aka HSV) but not HSL. So we need additional code for supporting HSL. In my example I have used the code from Rob Camick.
So knowing that all we can do the following:
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSimpleShape;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.model.ThemesTable;
import java.io.InputStream;
import java.io.FileInputStream;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import java.awt.Color;
class ReadExcelShapeFillColors {
//two methods for dealing with the HSL color model
//helper method HueToRGB, see below
private static float HueToRGB(float p, float q, float h) {
if (h < 0) h += 1;
if (h > 1 ) h -= 1;
if (6 * h < 1) {
return p + ((q - p) * 6 * h);
}
if (2 * h < 1 ) {
return q;
}
if (3 * h < 2) {
return p + ( (q - p) * 6 * ((2.0f / 3.0f) - h) );
}
return p;
}
//get a new Color changed by given luminescence from lumMod and lumOff
private static Color getColorLumModandOff(Color color, int lumMod, int lumOff) {
float[] rgb = color.getRGBColorComponents( null );
float r = rgb[0];
float g = rgb[1];
float b = rgb[2];
float min = Math.min(r, Math.min(g, b));
float max = Math.max(r, Math.max(g, b));
float h = 0;
if (max == min) h = 0;
else if (max == r) h = ((60 * (g - b) / (max - min)) + 360) % 360;
else if (max == g) h = (60 * (b - r) / (max - min)) + 120;
else if (max == b) h = (60 * (r - g) / (max - min)) + 240;
float l = (max + min) / 2;
l = l * (float)lumMod/100000f + (float)lumOff/100000f;
float s = 0;
if (max == min) s = 0;
else if (l <= .5f) s = (max - min) / (max + min);
else s = (max - min) / (2 - max - min);
h = h % 360.0f;
h /= 360f;
float q = 0;
if (l < 0.5) q = l * (1 + s);
else q = (l + s) - (s * l);
float p = 2 * l - q;
r = Math.max(0, HueToRGB(p, q, h + (1.0f / 3.0f)));
g = Math.max(0, HueToRGB(p, q, h));
b = Math.max(0, HueToRGB(p, q, h - (1.0f / 3.0f)));
r = Math.min(r, 1.0f);
g = Math.min(g, 1.0f);
b = Math.min(b, 1.0f);
return new Color(r, g, b, 1.0f);
}
public static void main(String[] args) throws Exception {
InputStream inp = new FileInputStream("ExcelWithSimpleShape.xlsx");
Workbook workbook = WorkbookFactory.create(inp);
Sheet sheet = workbook.getSheetAt(0);
Drawing<? extends Shape> drawing = sheet.getDrawingPatriarch();
for (Shape shape : drawing) {
System.out.println(shape.getClass());
System.out.println(shape.getShapeName() + "_________________");
if (shape instanceof XSSFSimpleShape) { //we have a XSSFSimpleShape
XSSFWorkbook xssfworkbook = (XSSFWorkbook)workbook;
ThemesTable themesTable = xssfworkbook.getTheme();
XSSFSimpleShape xssfSimpleShape = (XSSFSimpleShape)shape;
CTShape ctShape = xssfSimpleShape.getCTShape();
CTShapeProperties ctShapeProperties = ctShape.getSpPr();
byte[] bRGB;
if (ctShapeProperties.isSetSolidFill()) { //we have a solid fill defined
CTSolidColorFillProperties ctSolidColorFillProperties = ctShapeProperties.getSolidFill();
if (ctSolidColorFillProperties.isSetSrgbClr()) { //we have a explicit given RGB color
bRGB = ctSolidColorFillProperties.getSrgbClr().getVal();
System.out.println((bRGB[0]&0xFF)+", "+(bRGB[1]&0xFF)+", "+(bRGB[2]&0xFF));
Color color = new Color(bRGB[0]&0xFF, bRGB[1]&0xFF, bRGB[2]&0xFF);
System.out.println("explicit given RGB color: " + color);
} else if (ctSolidColorFillProperties.isSetSchemeClr()) { //we have a scheme color defined in ThemesTable
int iThemeColorIdx = ctSolidColorFillProperties.getSchemeClr().getVal().intValue()-1;
System.out.println("theme color index: " + iThemeColorIdx);
//get luminescence definition
int lumMod = 100000;
int lumOff = 0;
if (ctSolidColorFillProperties.getSchemeClr().getLumModList().size() > 0)
lumMod = ctSolidColorFillProperties.getSchemeClr().getLumModList().get(0).getVal();
if (ctSolidColorFillProperties.getSchemeClr().getLumOffList().size() > 0)
lumOff = ctSolidColorFillProperties.getSchemeClr().getLumOffList().get(0).getVal();
System.out.println("lumMod: " + lumMod);
System.out.println("lumOff: " + lumOff);
XSSFColor xssfColor = themesTable.getThemeColor(iThemeColorIdx);
bRGB = xssfColor.getRGB(); //RGB color from ThemesTable
System.out.println((bRGB[0]&0xFF)+", "+(bRGB[1]&0xFF)+", "+(bRGB[2]&0xFF));
Color color = new Color(bRGB[0]&0xFF, bRGB[1]&0xFF, bRGB[2]&0xFF);
color = getColorLumModandOff(color, lumMod, lumOff); //Color changed by given lumMod and lumOff
System.out.println("scheme color: " + color);
}
} else { //we have accent1 scheme color as fill color
XSSFColor xssfColor = themesTable.getThemeColor(STSchemeColorVal.INT_ACCENT_1-1);
bRGB = xssfColor.getRGB();
System.out.println((bRGB[0]&0xFF)+", "+(bRGB[1]&0xFF)+", "+(bRGB[2]&0xFF));
Color color = new Color(bRGB[0]&0xFF, bRGB[1]&0xFF, bRGB[2]&0xFF);
System.out.println("accent1 scheme color: " + color);
}
}
}
workbook.close();
}
}
This code will get the fill colors of all shapes from first sheet of the XSSFWorkbook file which are instanceof XSSFSimpleShape as long as they are given by solid fill and are either CTSRgbColor or CTSchemeColor.
Why are those pixel rgb values sometimes equal and sometimes not equal? I am learning image processing. It would be great if someone help me out here.
public class ColorTest1 {
Color p1;
Color p2;
ColorTest1() throws IOException, InterruptedException {
BufferedImage bi = ImageIO.read(new File("d:\\x.jpg"));
for (int y = 0; y < bi.getHeight(); y++) {
for (int x = 0; x < bi.getWidth() - 1; x++) {
p1 = new Color(bi.getRGB(x, y));
p2 = new Color(bi.getRGB(x + 1, y));
int a = (p1.getAlpha() + p2.getAlpha()) / 2;
int r = (p1.getRed() + p2.getRed()) / 2;
int g = (p1.getGreen() + p2.getGreen()) / 2;
int b = (p1.getBlue() + p2.getBlue()) / 2;
int x1 = p1.getRGB();
int x2 = p2.getRGB();
int sum1 = (x1 + x2) / 2;
int sum2 = a * 16777216 + r * 65536 + g * 256 + b;
System.out.println(sum1 == sum2);
}
}
}
public static void main(String... areg) throws IOException, InterruptedException {
new ColorTest1();
}
}
This is the image:
Take two pixels. One is black. The other is nearly black but with a slight bit of red in it, just 1/255. Ignore alpha. r will be (0 + 1) / 2 = 0. g and b will be 0 too. x1 will be 0. x2 will be 65536, right? So sum1 will be 65536 / 2 = 32768. sum2 obviously will be 0.
Whenever the sum of either red or green of the two colours is odd, the int division will set the high bit of the next colour in RGB, leading to an unexpected result.
I am trying to implement window level functionality( To apply bone, brain, lung etc on CT) for DICOM images in my application and implemented formula as per the DICOM specification.
I am changing pixel values based on below formula and creating a new image, but images are becoming blank. What am doing wrong and is this correct way to do this. Please help :(:( Thanks
BufferedImage image = input image;
double w = 2500; // Window width
double c = 500; // window Center
double ymin = 0;
double ymax = 255;
double x = 0;
double y = 0;
double slope = dicomObject.get(Tag.RescaleSlope).getFloat(true);
double intercept = dicomObject.get(Tag.RescaleIntercept).getFloat(true);
int width = image.getWidth();
int height = image.getHeight();
double val = c - 0.5 - (w - 1) / 2;
double val2 = c - 0.5 + (w - 1) / 2;
for (int m = 0; m < height; m++) {
for (int n = 0; n < width; n++) {
int rgb = image.getRGB(n, m);
int valrgb = image.getRGB(n, m);
int a = (0xff000000 & valrgb) >>> 24;
int r = (0x00ff0000 & valrgb) >> 16;
int g = (0x0000ff00 & valrgb) >> 8;
int b = (0x000000ff & valrgb);
x = a + r + g + b;
if (x <= val)
y = ymin;
else if (x > val2)
y = ymax;
else {
y = ((x - (c - 0.5)) / (w - 1) + 0.5) * (ymax - ymin)+ ymin;
}
y = y * slope + intercept;
rgb = (int) y;
image.setRGB(n, m, rgb);
}
}
String filePath = "out put fileName";
ImageIO.write(image, "jpeg", new File(filePath));
First of all whats in your BufferedImage image ?
There are three steps you want to take from raw (decopressed) pixel data:
Get stored values - apply BitsAllocated, BitsStored, HighBit transformation. (I guess you image already passed that level)
Get modality values - thats your Slope, Intercept transformation. Ofter this transformation, your data will be in Hounsfield Units for CT.
Then you apply WW/WL (Value Of Interest) transformation, which will transform this window of walues into grayscale color space.
EDIT:
You've got to tell me where did you get "input image" from? After decompression pixel data should be in a byte array of size byte[width*height*2] (for CT Image BitsAllocated is always 16, thus *2). You can get stored values like this:
ushort code = (ushort)((pixel[0] + (pixel[1] << 8)) & (ushort)((1<<bitsStored) - 1));
int value = TwosComplementDecode(code);
I appear to have hit a wall in my most recent project involving wave/ripple generation over an image. I made one that works with basic colors on a grid that works perfectly; heck, I even added shades to the colors depending on the height of the wave.
However, my overall goal was to make this effect work over an image like you would see here. I was following an algorithm that people are calling the Hugo Elias method (though idk if he truly came up with the design). His tutorial can be found here!
When following that tutorial I found his pseudo code challenging to follow. I mean the concept for the most part makes sense until I hit the height map portion over an image. The problem being the x and y offsets throw an ArrayIndexOutOfBoundsException due to him adding the offset to the corresponding x or y. If the wave is too big (i.e. in my case 512) it throws an error; yet, if it is too small you can't see it.
Any ideas or fixes to my attempted implementation of his algorithm?
So I can't really make a compile-able version that is small and shows the issue, but I will give the three methods I'm using in the algorithm. Also keep in mind that the buffer1 and buffer2 are the height maps for the wave (current and previous) and imgArray is a bufferedImage represented by a int[img.getWidth() * img.getHeight()] full of ARGB values.
Anyways here you go:
public class WaveRippleAlgorithmOnImage extends JPanel implements Runnable, MouseListener, MouseMotionListener
{
private int[] buffer1;
private int[] buffer2;
private int[] imgArray;
private int[] movedImgArray;
private static double dampening = 0.96;
private BufferedImage img;
public WaveRippleAlgorithmOnImage(BufferedImage img)
{
this.img = img;
imgArray = new int[img.getHeight()*img.getWidth()];
movedImgArray = new int[img.getHeight()*img.getWidth()];
imgArray = img.getRGB(0, 0,
img.getWidth(), img.getHeight(),
null, 0, img.getWidth());
//OLD CODE
/*for(int y = 0; y < img.getHeight(); y++)
{
for(int x = 0; x < img.getWidth(); x++)
{
imgArray[y][x] = temp[0 + (y-0)*img.getWidth() + (x-0)];
}
}*/
buffer1 = new int[img.getHeight()*img.getWidth()];
buffer2 = new int[img.getHeight()*img.getWidth()];
buffer1[buffer1.length/2] = (img.getWidth() <= img.getHeight() ? img.getWidth() / 3 : img.getHeight() / 3);
//buffer1[25][25] = 10;
back = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
//<editor-fold defaultstate="collapsed" desc="Used Methods">
#Override
public void run()
{
while(true)
{
this.update();
this.repaint();
this.swap();
}
}
//Called from Thread to update movedImgArray prior to being drawn.
private void update()
{
//This is my attempt of trying to convert his code to java.
for (int i=img.getWidth(); i < imgArray.length - 1; i++)
{
if(i % img.getWidth() == 0 || i >= imgArray.length - img.getWidth())
continue;
buffer2[i] = (
((buffer1[i-1]+
buffer1[i+1]+
buffer1[i-img.getWidth()]+
buffer1[i+img.getWidth()]) >> 1)) - buffer2[i];
buffer2[i] -= (buffer2[i] >> 5);
}
//Still my version of his code, because of the int[] instead of int[][].
for (int y = 1; y < img.getHeight() - 2; y++)
{
for(int x = 1; x < img.getWidth() - 2; x++)
{
int xOffset = buffer1[((y)*img.getWidth()) + (x-1)] - buffer1[((y)*img.getWidth()) + (x+1)];
int yOffset = buffer1[((y-1)*img.getWidth()) + (x)] - buffer1[((y+1)*img.getWidth()) + (x)];
int shading = xOffset;
//Here is where the error occurs (after a click or wave started), because yOffset becomes -512; which in turn gets
//multiplied by y... Not good... -_-
movedImgArray[(y*img.getWidth()) + x] = imgArray[((y+yOffset)*img.getWidth()) + (x+xOffset)] + shading;
}
}
//This is my OLD code that kidna worked...
//I threw in here to show you how I was doing it before I switched to images.
/*
for(int y = 1; y < img.getHeight() - 1; y++)
{
for(int x = 1; x < img.getWidth() - 1; x++)
{
//buffer2[y][x] = ((buffer1[y][x-1] +
//buffer1[y][x+1] +
//buffer1[y+1][x] +
//buffer1[y-1][x]) / 4) - buffer2[y][x];
buffer2[y][x] = ((buffer1[y][x-1] +
buffer1[y][x+1] +
buffer1[y+1][x] +
buffer1[y-1][x] +
buffer1[y + 1][x-1] +
buffer1[y + 1][x+1] +
buffer1[y - 1][x - 1] +
buffer1[y - 1][x + 1]) / 4) - buffer2[y][x];
buffer2[y][x] = (int)(buffer2[y][x] * dampening);
}
}*/
}
//Swaps buffers
private void swap()
{
int[] temp;
temp = buffer2;
buffer2 = buffer1;
buffer1 = temp;
}
//This creates a wave upon clicking. It also is where that 512 is coming from.
//512 was about right in my OLD code shown above, but helps to cause the Exeception now.
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getX() > 0 && e.getY() > 0 && e.getX() < img.getWidth() && e.getY() < img.getHeight())
buffer2[((e.getY())*img.getWidth()) + (e.getX())] = 512;
}
private BufferedImage back;
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
back.setRGB(0, 0, img.getWidth(), img.getHeight(), movedImgArray, 0, img.getWidth());
g.drawImage(back, 0, 0, null);
}
}
P.S. Here are two images of the old code working.
Looking at my original pseudocode, I assume the Array Out Of Bounds error is happening when you try to look up the texture based on the offset. The problem happens because the refraction in the water is allowing us to see outside of the texture.
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
t = texture(x+Xoffset, y+Yoffset) // Array out of bounds?
p = t + Shading
plot pixel at (x,y) with colour p
end loop
The way to fix this is simply to either clamp the texture coordinates, or let them wrap. Also, if you find that the amount of refraction is too much, you can reduce it by bit-shifting the Xoffset and Yoffset values a little bit.
int clamp(int x, int min, int max)
{
if (x < min) return min;
if (x > max) return max;
return x;
}
int wrap(int x, int min, int max)
{
while (x<min)
x += (1+max-min);
while (x>max)
x -= (1+max-min);
return x;
}
for every pixel (x,y) in the buffer
Xoffset = buffer(x-1, y) - buffer(x+1, y)
Yoffset = buffer(x, y-1) - buffer(x, y+1)
Shading = Xoffset
Xoffset >>= 1 // Halve the amount of refraction
Yoffset >>= 1 // if you want.
Xcoordinate = clamp(x+Xoffset, 0, Xmax) // Use clamp() or wrap() here
Ycoordinate = clamp(y+Yoffset, 0, Ymax) //
t = texture(Xcoordinate, Ycoordinate)
p = t + Shading
plot pixel at (x,y) with colour p
end loop