1

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..

Samarth Shah
  • 878
  • 8
  • 14
  • rast.setPixels(0, 0, w, h, pixelvector); Based on the doc that function is setting the whole image to the color of 'pixelvector'. Here - http://docs.oracle.com/javase/7/docs/api/java/awt/image/WritableRaster.html – new Objekt Dec 09 '14 at 21:38
  • possible duplicate of [Turn an array of pixels into an Image object with Java's ImageIO?](http://stackoverflow.com/questions/124630/turn-an-array-of-pixels-into-an-image-object-with-javas-imageio) – Vince Dec 09 '14 at 21:38
  • @newObjekt..Yes I know, But as I said I dont understand the documentation. Does it set the entire image by taking 3 values from that array at a time, LIKE: r,g,b or does it take only 1 value .? – Samarth Shah Dec 09 '14 at 21:41
  • @VinceEmigh Yes, but What I dont understand is the array pixelvector..Should it contain 1 value/ pixel or 3 consecutive values/pixel.?? – Samarth Shah Dec 09 '14 at 21:44
  • Retitle yout question to be more specific. What do you mean *3 consecutive pixels*? The array should contain all the pixels in the image. Do you understand how pixels in a singe dimensional array work? You calculate which pixel is being set using `x + (y * width)` (you dont need to use the formula, im just showing you how you'd pick which pixel to access) – Vince Dec 09 '14 at 21:58
  • @VinceEmigh just one last thing: if I want to make an image of w width and h height ..do I need to input an array of size (w*h) in setPixels() method i.e., an array of pixel values. OR do I nee to input an array of size (w*h*3) in setPixels() method..HOW is the method going to take values from array pixelvector? – Samarth Shah Dec 09 '14 at 22:42

1 Answers1

5

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];
     }
 }
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • It works and made my code really short and faster. Thanks a lot. One more thing, can you tell me if my share1 method is correct? What I want to do is get the Red, green, blue values of the original pixel and then call share1..in that, I add and multiple random things and return a new_pixel value..BUT, the old pixel values are like -60000 or so and new pixel values are like 150 or 200..Is it correct? I need to return back a packed RGB pixel value.I am supposed to get back noise-like images!! which I am not!! – Samarth Shah Dec 10 '14 at 10:54
  • Good! :-) I don't know the algorithm you are trying to implement here, so it's hard to say for sure. But it *looks* a little strange for me to just sum up `r`, `g` and `b`. Maybe you should compute each value on its own, and then re-create the packed RGB format using `int newPixel = 0xff000000 | (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff);`? – Harald K Dec 10 '14 at 10:58
  • Well, I am trying to encrypt image (Shamir's Secret Sharing)/ For that I have to run a function which maps R, G, B values to only one value, which is the color of a pixel of encrypted image. (They are supposed to be gray noise-like). The func is = (R + G + B + a) mod prime. [a is a random no]. NOW, this function wants me to sum the RGB values..weird... so I cant do your approach.. – Samarth Shah Dec 10 '14 at 11:08
  • I see... Well, I skimmed the Wikipedia article, but it's too technical for me to understand in 30 seconds... ;-) So I suggest you ask another question on that specifically. But I can't see how this method can create anything but a greenish-blue image (or blue if `prime` is lower than 255). Maybe (`val` = result of func) `int newPixel = 0xff000000 | (val & 0xff) << 16 | (val & 0xff) << 8 | (val & 0xff);` then? This should at least create gray noise. Or you need to make sure that prime is between 255 * 255 and 255 * 255 * 255. That could work – Harald K Dec 10 '14 at 11:22