Steganography Lsb information hold capacity - java

I know that using LSB means that u can store messages at around 12% of the image carrier size.
I made a java program that splits a message into n fragments and fills the image carrier with these fragments until the 12 % are all occupied.I do this so that by cropping the image,the message wouldn't get lost.
The problem is that the resulting image is distorted and different from the original image.I thought that if I fill only 12% of the image,more exactly the LSB of the image,the image wouldn't get distorted.
int numHides = imLen/(totalLen*DATA_SIZE); // the number of messages I can store in the image
int offset = 0;
for(int h=0; h < numHides; h++) //hide all frags, numHides times
for(int i=0; i < NUM_FRAGS; i++) {//NUM_FRAGS ..the number of fragments
hideStegoFrag(imBytes, stegoFrags[i], offset);//the method that hides the fragment into the picture starting at the offset position
offset += stegoFrags[i].length*DATA_SIZE;
}
private static boolean hideStegoFrag(byte[] imBytes,byte[] stego,int off){
int offset=off;
for (int i = 0; i < stego.length; i++) { // loop through stego
int byteVal = stego[i];
for(int j=7; j >= 0; j--) { // loop through 8 bits of stego byte
int bitVal = (byteVal >>> j) & 1;
// change last bit of image byte to be the stego bit
imBytes[offset] = (byte)((imBytes[offset] & 0xFE) | bitVal);
offset++;
}
}
return true;
}
The code for transforming the Buffered Image into bits
private static byte[] accessBytes(BufferedImage image)
{
WritableRaster raster = image.getRaster();
DataBufferByte buffer = (DataBufferByte) raster.getDataBuffer();
return buffer.getData();
}
The code that creates the new image with a provided name and the buffered image of the source image
public static boolean writeImageToFile(String imFnm , BufferedImage im){
try {
ImageIO.write(im, "png", new File(imFnm));
} catch (IOException ex) {
Logger.getLogger(MultiSteg.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}

The output image you have posted is a 16-color paletted image.
The data I am seeing shows that you have actually applied your changes to the palette index, not to the colors of the image. The reason you are seeing the distortion is because of the way the palette is organized, you aren't modifying the LSB of the color, you're modifying the LSB of the index, which could change it to a completely different (and very noticeable, as you can see) color. (Actually, you're modifying the LSB of every other index, the 16-color form is 4 bits per pixel, 2 pixels per byte.)
It looks like you loaded raw image data and didn't decode it in to RGB color information. Your algorithm will only work on raw RGB (or raw grayscale) data; 3 bytes (or 1 for grayscale) per pixel. You need to convert your image to RGB888 or something similar before you operate on it. When you save it, you need to save it in a lossless, full color (unless you actually can fit all your colors in a palette) format too, otherwise you risk losing your information.
Your problem actually doesn't lie in the steganography portion of your program, but in the loading and saving of the image data itself.
When you load the image data, you need to convert it to an RGB format. The most convenient format for your application will be BufferedImage.TYPE_3BYTE_BGR, which stores each pixel as three bytes in blue, green, red order (so your byte array will be B,G,R,B,G,R,B,G,R,...). You can do that like so:
public static BufferedImage loadRgbImage (String filename) {
// load the original image
BufferedImage originalImage = ImageIO.read(filename);
// create buffer for converted image in RGB format
BufferedImage rgbImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
// render original image into buffer, changes to destination format
rgbImage.getGraphics().drawImage(originalImage, 0, 0, null);
return rgbImage;
}
If you are frequently working with source images that are already in BGR format anyways, you can make one easy optimization to not convert the image if it's already in the format you want:
public static BufferedImage loadRgbImage (String filename) {
BufferedImage originalImage = ImageIO.read(filename);
BufferedImage rgbImage;
if (originalImage.getType() == BufferedImage.TYPE_3BYTE_BGR) {
rgbImage = originalImage; // no need to convert, just return original
} else {
rgbImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
rgbImage.getGraphics().drawImage(originalImage, 0, 0, null);
}
return rgbImage;
}
You can then just use the converted image for all of your operations. Note that the byte array from the converted image will contain 3 * rgbImage.getWidth() * rgbImage.getHeight() bytes.
You shouldn't have to make any changes to your current image saving code; ImageIO will detect that the image is RGB and will write a 24-bit PNG.

Related

How to efficiently display raw rgb int array in javafx?

I have an int array where each value stores a bitpacked rgb value (8 bits per channel) and alpha is always 255(opaque) and i want to display that in javafx.
My current approach is using a canvas like this:
GraphicsContext graphics = canvas.getGraphicsContext2D();
PixelWriter pw = graphics.getPixelWriter();
pw.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), pixels, 0, width);
However before that i actually have to set the alpha component of each pixel by iterating each pixel and OR'ing it with a mask that turns the pixel from rgb to argb like this:
for (int i = 0; i < pixels.length; i++) {
pixels[i] = 0xFF000000 | pixels[i];
}
Is there a more efficient to do this (as the pixels array is updated many times every second)?
I was hoping there's a IntRgbInstance but unfortunately there isn't (only ByteRgbInstance)
Other approaches i've tested:
Approach 1: Creating a IntBuffer that is filled up like this:
IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
for (int pixel : pixels) {
buffer.put(0xFF000000 | pixel);
}
And then generating a PixelBuffer that uses this buffer, the pixel buffer is then used as an input to this WritableImage constructor: https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/WritableImage.html#%3Cinit%3E(javafx.scene.image.PixelBuffer)
and then i display that WritableImage using a ImageView
This however still didn't speed up anything(rather made it a bit slower) and im guessing that because i have to construct a new WritableImage instance each time the pixels int array is updated.
Approach 2 (that didn't work for some reason, i.e. it displayed nothing in the screen): Creating a buffer the same way as above and using that in one of the setPixels() methods that takes in a buffer:
IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
for (int pixel : pixels) {
buffer.put(0xFF000000 | pixel);
}
pw.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), buffer, width);
After a bit of more research i found out that i don't need to create a new WritableImage instance each time the pixels array is updated but i can just use the updateBuffer method here: https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/PixelBuffer.html#updateBuffer(javafx.util.Callback)
So the code currently looks like this:
pb.updateBuffer(callback -> {
buffer.clear();
for (int pixel : pixels) {
buffer.put(0xFF000000 | pixel);
}
return null;
});
Where pb, buffer is only created once like this:
IntBuffer buffer = IntBuffer.allocate(pixels.length * 4);
PixelBuffer<IntBuffer> pb = new PixelBuffer<>(width, height, buffer, PixelFormat.getIntArgbPreInstance());
view.setImage(new WritableImage(pb));
and this did indeed result in a nice speedup (close to 2x compared to my initial approach)
Maybe this https://openjfx.io/javadoc/17/javafx.graphics/javafx/scene/image/WritableImage.html#%3Cinit%3E(javafx.scene.image.PixelBuffer) is what you are looking for. You could create a PixelBuffer from an IntBuffer of your data.

Pixel relocation, showing side-by-side

I want to read individual pixels from one image and "relocate" them to another image. I basically want to simulate how it would be if I grabbed pixel by pixel from one image and "move" them to a blank canvas. Turning the pixels I grab from the original image white.
This is what I have right now, I'm able to read the pixels from the image and create a copy (which comes out saturated for some reason) of it.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class ImageTest
{
public static void main(String args[])throws IOException
{
//create buffered image object img
File oldImgFile = new File("/path/to/image/shrek4life.jpg");
BufferedImage oldImg = null;
BufferedImage newImg = null;
try{
oldImg = ImageIO.read(oldImgFile);
}catch(IOException e){}
newImg = new BufferedImage(oldImg.getWidth(), oldImg.getHeight(), BufferedImage.TYPE_INT_ARGB);
File f = null;
try
{
for(int i = 0; i < oldImg.getWidth(); i++){
for(int j = 0; j < oldImg.getHeight(); j++){
//get the rgb color of the old image and store it the new
Color c = new Color(oldImg.getRGB(i, j));
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
int col = (r<<16) | (g<<8) | b;
newImg.setRGB(i, j, col);
}
}
//write image
f = new File("newImg.jpg");
ImageIO.write(newImg, "jpg", f);
}catch(IOException e){
System.out.println("Error: " + e);
}
}//main() ends here
}//class ends here
And I would like to basically slow the process down and display it happening. But I'm not sure how to do that. Would I need to use to accomplish this ? I'm somewhat new to threading but I think I would need multiple threads to handle the painting of both pictures.
First of all, I would like to mention you are working in a very inefficient way. You are creating a Color, decomposing a pixel in its channels, and moving to the new image by a bit-shift. It is easier if you work directly with the integer the whole time (and more efficient).
I will assume the image "/path/to/image/shrek4life.jpg" has ARGB color space. I recommend ensure this, because if the old image does not have this color space you should make a conversion.
When you create the new image, you create it as ARGB color space, so each channel is expressed in a byte of the int, first byte for Alpha, second byte for red, third byte for green and the last one for blue.
I think you forgot the alpha channel when you manipulated the old image pixel to move it into the new image.
With this explanation in mind, I think you can change your code to increase the efficiency, like this:
for(int i = 0; i < oldImg.getWidth(); i++){
for(int j = 0; j < oldImg.getHeight(); j++){
int pixel = oldImg.getRGB(i,j);
newImg.setRGB(i, j, pixel );
//If you like to get more control over the pixels and print
//you can decompose the pixel using Color as you already do
//But when you understand fully the process I recommend erase it
Color c = new Color(pixel);
//Print the color or do whatever you like
}
}
About how to display the process of pixel relocation:
In process:
You can print the changed pixel as a number with its position in image (discouraged). System.out.println("pixel"+pixel+" X:"+i+" Y:"+j);
Use this tutorial in baeldung to print an image. I suggest draw a rectangle with the color of the image and wait for a key press (enter, for example) using Scanner. After the key was press, you can load the next pixel, an so on.
If a single rectangle with just one pixel has little information, I suggest add an array of rectangles to draw several pixels in a time. Even you can print an image, and see the process pixel by pixel, using Scanner to mark each step.
As #haraldK suggest, you can use Swing to display de relocation image. Through swing timer and invokes update()
Post process:
Save the image in a file. To improve the speed of process, I suggest save a few pixels (10 - 100).

Java - editing an image

Is it possible to edit a image in java?
I mean to draw a pixel in a certain RGB color in a certain spot and save the image.
I'm working on a game where the objects are loaded by an image and in order to save the current state of the map I need to edit some pixels and load it later.
Any help is appreciated! :)
It is. If you create an instance of BufferedImage, which is an object that stores image data, you will be able to get the pixels and change them. Here is how:
public static void main(String[] args) throws Exception {
BufferedImage originalImage = ImageIO.read(inputFile);
BufferedImage newImage = orgiginalImage;
int[] pixels = ((DataBufferInt)newImage.getRaster().getDataBuffer()).getData();
for(int i = 0; i < pixels.length; i++){
// Code for changing pixel data;
pixels[i] = 0xFFFFFFFF // White
// Syntax for setting pixel color: 0x(HEX COLOR CODE)
// There is no need to set these pixels to the image; they are allerady linked
// For instance, if you create a Canvas object in a JFrame,
// and used graphics.drawImage(newImage, 0, 0,
// newImage.getWidth(), newImage.getHeight(), null), it will be up to date
// Another example is, if you saved newImage to a file, it willallready have
// the white pixels drawn in.
}
}

Why is JPG altered on retrieval? - Java

I am trying to retrieve an jpg image as a BufferedImage then decompose it into a 3D array [RED][GREEN][BLUE] and then turn it back into a BufferedImage and store it under a different file-name. All looks fine to me BUT, when I am trying to reload the 3D array using the new file created I get different values for RGB although the new image looks fine to the naked eye. I did the following.
BufferedImage bi = ImageIO.read(new File("old.jpg"));
int[][][] one = getArray(bi);
save("kite.jpg", one);
BufferedImage bi2 = ImageIO.read(new File("new.jpg"));
int[][][] two = getArray(bi2);
private void save(String destination, int[][][] in) {
try {
BufferedImage out = new BufferedImage(in.length, in[0].length, BufferedImage.TYPE_3BYTE_BGR);
for (int x=0; x<out.getWidth(); x++) {
for (int y = 0; y < out.getHeight(); y++) {
out.setRGB(x, y, new Color(in[x][y][0], in[x][y][1], in[x][y][2]).getRGB());
}
}
File f = new File("name");
ImageIO.write(out, "JPEG", f);
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
so in the example above the values that arrays one and two are holding are different.
I am guessing there is something to do with the different types of retrieving and restoring images? I am trying to figure out what is going on all day but with no luck. Any help appreciated.
Pretty simple:
JPEG is a commonly used method of lossy compression for digital images
(from wikipedia).
Each time the image is compressed, the image is altered to reduce file-size. In fact repeating the steps of decompression and compression for several hundred times alters the image to the point where the entire image turns into a plain gray area in most cases. There are a few compressions that work lossless, but most operation-modes will alter the image.

java - how to make an image using setRGB?

i have 2D array to keep color component value :
p[pixel_value][red]
p[pixel_value][green]
p[pixel_value][blue]
i just dont know how to use them to make an image.
i read about setRGB, what i understand is i should mix all of them to become a RGBArray. then how to make it?
is it any better way to make an image without setRGB ? i need some explanation.
The method setRGB() can be used to set the color of a pixel of an already existing image. You can open an already existing image and set all the pixels of it, using the values stored in your 2D array.
You can do it like this:
BufferedImage img = ImageIO.read(new File("image which you want to change the pixels"));
for(int width=0; width < img.getWidth(); width++)
{
for(int height=0; height < img.getHeight(); height++)
{
Color temp = new Color(p[pixel_value][red], p[pixel_value][green], p[pixel_value][blue]);
img.setRGB(width, height, temp.getRGB());
}
}
ImageIO.write(img, "jpg", new File("where you want to store this new image"));
Like this, you can iterate over all the pixels and set their color accordingly.
NOTE: By doing this, you will lose your original image. This is just a way which I know.
What you need is a BufferedImage. Create a BufferedImage of type TYPE_3BYTE_BGR, if RGB is what you want, with a specified width and height.
QuickFact:
The BufferedImage subclass describes an Image with an accessible
buffer of image data.
Then, call the getRaster() method to get a WritableRaster
QuickFact:
This class extends Raster to provide pixel writing capabilities.
Then, use the setPixel(int x, int y, double[] dArray) method to set the pixels.
Update:
If all you want is to read an image, use the ImageIO.read(File f) method. It will allow you to read an image file in just one method call.
Somewhat SSCCE:
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
}
You want to manually set RGB values?
You need to know that since an int is 32bit it contains all 4 rgb values (1 for the transparency).
xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
^Alpha ^red ^green ^blue
You can accomplish using 4 int values by the use of binary arithmetic:
int rgb = (red << 16) && () (green << 8) & (blue);
bufferedImage.setRGB(x, y, rgb);
IN the above you can add Alpha as well if needed. You just "push" the binary codes into the right places.

Categories

Resources