What type of array required in WritableRaster method setPixels()?

3.3k views Asked by At

I don't understand how WritableRaster class of Java works. I tried looking at the documentation but don't understand how it takes values from an array of pixels. Plus, I am not sure what the array of pixels consists.

Here I explain.

What I want to do is : Shamir's Secret Sharing on images. For that I need to fetch an image in BuferedImage image. I take a secret image. Create shares by running a 'function' on each pixel of the image. (basically changing the pixel values by something)

Snippet:

int w = image.getWidth();
int h = image.getHeight();
for (int i = 0; i < h; i++) 
    {
    for (int j = 0; j < w; j++) 
        {
        int pixel = image.getRGB(j, i);

        int red = (pixel >> 16) & 0xFF;
        int green = (pixel >> 8) & 0xFF;
        int blue = (pixel) & 0xFF;

        pixels[j][i] = share1(red, green, blue);

// Now taking those rgb values. I change them using some function and return an int value. Something like this:

public int share1 (r, g, b)
{
a1 = rand.nextInt(primeNumber);
total1 = r+g+b+a1;
new_pixel = total1 % primeNumber;
return new_pixel;
}

// This 2d array pixels has all the new color values, right? But now I want to build an image using this new values. So what I did is. First converted this pixels array to a list. Now this list has pixel values of the new image. But to build an image using RasterObj.setPixels() method, I need an array with RGB values [I MIGHT BE WRONG HERE!] So I take individual values of a list and find rgb values and put it consecutively in a new 1D array pixelvector..something like this (r1,g1,b1,r2,g2,b2,r3,g3,b3...)

Size of the list is wh because it contains single pixel value of each pixel. BUT, Size of the new array pixelvector will become wh*3 since it contains r,g,b values of each pixel..

Then to form image I do this: Snippet

BufferedImage image_share1 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
WritableRaster rast = (WritableRaster) image_share1.getData();
rast.setPixels(0, 0, w, h, pixelvector);
image_share1.setData(rast);
ImageIO.write(image_share1,"JPG",new File("share1.jpg"));

If I put an array with just single pixel values in setPixels() method, it does not return from that function! But if I put an array with separate r,g,b values, it returns from the function. But doing the same thing for share1 , share 2 etc.. I am getting nothing but shades of blue. So, I am not even sure I will be able to reconstruct the image..

PS - This might look like a very foolish code I know. But I had just one day to do this and learn about images in Java. So I am doing the best I can.

Thanks..

1

There are 1 answers

4
Harald K On BEST ANSWER

A Raster (like WriteableRaster and its subclasses) consists of a SampleModel and a DataBuffer. The SampleModel describes the sample layout (is it pixel packed, pixel interleaved, band interleaved? how many bands? etc...) and dimensions, while the DataBuffer describes the actual storage (are the samples bytes, short, ints, signed or unsigned? single array or array per band? etc...).

For BufferedImage.TYPE_INT_RGB the samples will be pixel packed (all 3 R, G and B samples packed into a single int for each pixel), and data/transfer type DataBuffer.TYPE_INT.

Sorry for not answering your question regarding WritableRaster.setPixels(...) directly, but I don't think it's the method you are looking for (in most cases, it's not). :-)

For your goal, I think what you should do is something like:

// Pixels in TYPE_INT_RGB format 
// (ie. 0xFFrrggbb, where rr is two bytes red, gg two bytes green etc)
int[] pixelvector = new int[w * h]; 

BufferedImage image_share1 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
WritableRaster rast = image_share1.getRaster(); // Faster! No copy, and live updated
rast.setDataElements(0, 0, w, h, pixelvector);
// No need to call setData, as we modified image_share1 via it's raster

ImageIO.write(image_share1,"JPG",new File("share1.jpg"));

I'm assuming the rest of your code for modifying each pixel value is correct. :-)

But just a tip: You'll make it easier for yourself (and faster due to less conversion) if you use a 1D array instead of a 2D array. I.e.:

int[] pixels = new int[w * h]; // instead of int[][] pixels = new int[w][h];

// ...

for (int y = 0; y < h; y++) {
    for (int x = 0; x < w; x++) {

        // ...

        pixels[y * w + x] = share1(red, green, blue); // instead of pixels[x][y];
     }
 }