Search code examples
javargbindexoutofboundsexceptionbufferedimage

Coordinate is out of bounds from .setRGB


I'm trying to create a program that generates an image and colors each pixel to the same value, then saves the file to a.PNG. I am currently receiving a Coordinate out of bounds error, and have tried several things to debug it. I think that the issue is linked to some third-party code written by my lecturer, as I have printed the p-value, which is negative, though I believe it needs to be between 0 and 255.

Currently, it is not generating any PNG file.

Can someone advise me on how to fix this code?

import java.util.Scanner;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter; 

public class Lab_Week8_ImageFromText {

    public static void main(String[] args) throws Exception  {  

    int image_width = 3;
    int image_height = 3;
    String output_file_path = ("image.png");
    String input_file_path = "";
    int r = 10;
    int b = 10;
    int g = 10;

    BufferedImage imagetowrite = imageFromText(image_width, image_height, input_file_path, output_file_path, r, g, b); 
    File f = new File (output_file_path);
    ImageIO.write(imagetowrite, "png", f);

    }

    public static BufferedImage imageFromText (int image_width, int image_height, String input_file_path, String output_file_path, int r, int g, int b) throws IOException{

        if(image_width <= 0 || image_height <= 0) {
            System.err.println("Width and Height have to be strictly positive!");
            return null;
        }

        System.out.println("Hello");

        BufferedImage image = new BufferedImage (image_width, image_height, BufferedImage.TYPE_INT_ARGB);

        int x = 1;
        int y = 1;
        for (x = 1; x <= image_width; x++)
        {//System.out.println (x);
        for (y = 1; y <= image_height; y++){//System.out.println(y);
            setPixel(image, x, y, r, g, b);
    }}

        System.out.println("Hello 2" + image);
        return image;
    }

    public static void setPixel(BufferedImage image, int x, int y, int r, int g, int b) {
        /*
         * Test cases for error management
         */
        if(x < 0 || y < 0) {
            System.err.println("Coordinates (x, y) cannot be negative numbers!");
            return;
        }
        if(r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {
            System.err.println("Colour values (r, g, b) have to be between 0 and 255!");
            return;
        }
        /*
         * Set the alpha value for the pixel, i.e. the transparency of the pixel, to its max value
         */
        int a = 255;
        /*
         * Write the different value of the pixel, i.e. the colours red, green, blue and alpha.
         * The different colour values are all stored into a single integer using byte operators.
         * a = x << y means write the value of x as bytes at the address y in the object a.
         * a = o1 | o2 means a will be composed by o1 and o2, where o1 and o2 are binary operators.
         * It is necessary to use this operator because the setRGB method of BufferedImage 
         * take only one integer that have to hold all the colour values for one given pixel.
         */
        int p = (a << 24) | (r << 16) | (g << 8) | b;
        /*
         * Use the setRGB method from BufferedImage to write the new pixel value (i.e. colour) to the image
         */
        image.setRGB(x, y, p);
        System.out.println(p);
    }

}

Here is the output of p and the error message:

Hello
-16119286
-16119286
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Coordinate out of bounds!
        at sun.awt.image.IntegerInterleavedRaster.setDataElements(IntegerInterleavedRaster.java:301)
        at java.awt.image.BufferedImage.setRGB(BufferedImage.java:1016)
        at Lab_Week8_ImageFromText.setPixel(Lab_Week8_ImageFromText.java:79)
        at Lab_Week8_ImageFromText.imageFromText(Lab_Week8_ImageFromText.java:44)
        at Lab_Week8_ImageFromText.main(Lab_Week8_ImageFromText.java:22)

Solution

  • The issue here is a common misconception with array indexing for novice programmers. The majority of modern programming languages (critically including Java) index an array with length size with the first element at index 0, and the last element at size-1.

    In both of your loops in your program quoted below, you permit the index to equal the length/size of the array. This means that at some point, the program will try to access the element at size.

    for (x = 1; x <= image_width; x++){
        //System.out.println (x);
        for (y = 1; y <= image_height; y++){
            //System.out.println(y);
            setPixel(image, x, y, r, g, b);
        }
    }
    

    So, to correct these loops, you'll want to set up the bounds like this:

    for (x = 0; x < image_width; x++){
        //System.out.println (x);
        for (y = 0; y < image_height; y++){
            //System.out.println(y);
            setPixel(image, x, y, r, g, b);
        }
    }
    

    Note that we now start at 0 and end at image_whatever - 1, meaning that the last call inside both of your loops would effectively be something like this:

    setPixel(image, image_width-1, image_height-1, r, g, b);
    

    I hope this helps you understand your mistake.