Bitmap to byte[] to Bitmap without compression - java

I am trying to encrypt an image in Android. What I would love to do is the following:
1. select image from gallery
2. convert image to byte array
3. encrypt the byte array
4. store the encrypted byte array as an image
5. retrieve the byte array from an encrypted image.
6. decrypt the byte array
7. restore the image
I have completed steps 1, 3 and 6. I have a problem with steps 2, 4, 5 and 7.
Original attempt:
// imgDecodableString is the String with the image file path
Bitmap imageBitmap = BitmapFactory.decodeFile(imgDecodableString);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
final byte[] byteArray = stream.toByteArray();
/* skip encryption/decryption for now */
Bitmap source = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
Just doing the above returns the original image without problems.
However, I would like to store that encrypted byte array as an image. I planned to do +128 on each byte element (so that the range is 0..255 instead of -128..127) and create a new bitmap with RGB(byteArray[i],byteArray[i],byteArray[i]).
But there is a big problem... The size of the byte array that I get from compressing the image holds less elements than there are pixels in an image, which I guess what compression implies. With that being the case, I cannot create an image because the array size could be odd, and I need to preserve all of the bytes. So I tried the following:
// imgDecodableString is the String with the image file path
Bitmap imageBitmap = BitmapFactory.decodeFile(imgDecodableString);
ByteBuffer buffer = ByteBuffer.allocate(imageBitmap.getByteCount()); //Create a new buffer
imageBitmap.copyPixelsToBuffer(buffer); //Move the byte data to the buffer
final byte[] byteArray = buffer.array(); //Get the underlying array containing the data.
/* skip encryption/decryption for now */
Bitmap source = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
But now source is null...
Given a Bitmap, can I transform it into a byte array that has as many elements as the image has pixels (or a factor of)?

The size of the byte array that I get from compressing the image holds less elements than there are pixels in an image, which I guess what compression implies. With that being the case, I cannot create an image because the array size could be odd, and I need to preserve all of the bytes.
I don't really see the problem other than your steps could do with a few changes:
select image from gallery
convert image to byte array (via PNG compression)
encrypt the byte array (via +128)
store the encrypted byte array as a file (you can't store it as an image now, because it's not an image)
retrieve the byte array from an encrypted file.
decrypt the byte array (-128)
restore the image
Alternatively if you want to scramble the image, but keep it as an image, then I would avoid manipulating it as a byte array:
select image from gallery
modify image bytes (akin to the encryption)
convert image to byte array (via PNG compression)
store the byte array as an image
retrieve the byte array from the image
restore the image
descramble the image bytes

Related

Working with images and file handling in Java

I have a full red image I made using MS Paint (red = 255, blue = 0, green = 0)
I read that image into a File object file
Then I extracted the bytes using Files.readAllBytes(file.toPath()) into a byte array byteArray
Now my expectation is that :
a) byteArray[0], when converted to bitstream, should be all 1
b) byteArray[1], when converted to bitstream, should be all 0
c) byteArray[2], when converted to bitstream, should be all 0
because, as I understand, the pixels values are stored in the order RGB with 8 bits for each color.
When I run my code, I don't get expected outcome. byteArray[0] is all 1 alright, but the other 2 aren't 0s.
Where am I going wrong?
Edit
As requested, I'm including image size, saved format and code used to read it.
Size = 1920p x 1080p
Format = JPG
Code:
File file = new File("image_path.jpg");
byte byteArray[]= new byte[(int) file.length()];
try {
byteArray = Files.readAllBytes(file.toPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int bits[] = new int[8];
for(int j=0; j<8; j++)
{
bits[j] = (b[0] & (1 << j))==0 ? 0:1 ;
//System.out.println("bitsb :"+bitsb[j]);
}
Update
Unfortunately I am unable to make use of other questions containing ImageIO library functions. I'm here partly trying to understand how the image itself is stored, and how I can write my own logic for retrieving and manipulating the image files.
JPEG is a complex image format.
It does not hold the raw image pixel data, but instead has a header, optional metadata and compressed image data.
The algorithm to decompress it to raw pixel values is quite complex, but there are libraries that will do the work for you.
Here is a short tutorial:
https://docs.oracle.com/javase/tutorial/2d/images/loadimage.html
Here is the documentation of the BufferedImage class which will hold the image data:
https://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html
You will need to use one of the getRGB functions to access the raw pixel data.
Make sure to check that your image is in 24 bit color format, if you want each color component to take 1 byte exactly!
JPEG supports other formats such as 32 and 16 bits!
Alternatively, save your image as 24 bit uncompressed BMP.
The file will be much larger, but reading it is much simpler so you don't have to use a library.
Just skip the header, then read raw bytes.
An even simpler image format to work with would be PBM/PPM.

Efficient access to image pixels in Java

I need to write a resampling function that takes an input image and generates an output image in Java.
The image type is TYPE_BYTE_GRAY.
As all pixels will be read and written, I need an efficient method to access the image buffer(s).
I don't trust that methods like getRGB/setRGB will be appropriate as they will perform conversions. I am after functions that will allow me the most direct access to the stored buffer, with efficient address computation, no image copy and minimum overhead.
Can you help me ? I have found examples of many kinds, for instance using a WritableRaster, but nothing sufficiently complete.
Update:
As suggested by #FiReTiTi, the trick is to get a WritableRaster from the image and get its associated buffer as a DataBufferByte object.
DataBufferByte SrcBuffer= (DataBufferByte)Src.getRaster().getDataBuffer();
Then you have the option to directly access the buffer using its getElem/setElem methods
SrcBuffer.setElem(i, getElem(i) + 1);
or to extract an array of bytes
byte [] SrcBytes= SrcBuffer.getData();
SrcBytes[i]= SrcBytes[i] + 1;
Both methods work. I don't know yet it there's a difference in performance...
The easiest way (but not the fastest) is to use the Raster myimage.getRaster(), and then use the methods getSample(x,y,c) and setSample(x,y,c,v) to access and modify the pixels values.
The fastest way to do it is to access the DataBuffer (direct access to the array representing the image), so for a TYPE_BYTE_GRAY BufferedImage, it would be byte[] buffer = ((DataBufferByte)myimage.getRaster().getDataBuffer()).getData(). Just be careful that the pixels are encoded on byte and not unsigned byte, so every time you want to read a pixel value, you have to do buffer[x] & 0xFF.
Here is a simple test:
BufferedImage image = new BufferedImage(256, 256, BufferedImage.TYPE_BYTE_GRAY) ;
byte[] buffer = ((DataBufferByte)image.getRaster().getDataBuffer()).getData() ;
System.out.println("buffer[0] = " + (buffer[0] & 0xFF)) ;
buffer[0] = 1 ;
System.out.println("buffer[0] = " + (buffer[0] & 0xFF)) ;
And here is the outputs:
buffer[0] = 0
buffer[0] = 1
It is possible to get the underlying buffer yourimage.getData().getDataBuffer() but it will require some conversion since this is one long array. You could find order of pixels by setting some elements to a extreme value and render the picture to see how the pixels are affected.

Slicing byte arrays in Java

I'm trying to slice a byte array to prune the first part of the array. I'm using ByteBuffer but it does not behave like I would expect.
byte[] myArray = new byte[10];
ByteBuffer buf = ByteBuffer.wrap(myArray);
buf.position(5);
ByteBuffer slicedBuf = buf.slice();
byte[] newArray = slicedBuf.array();
I would expect the size of newArray to be 5, containing only the last portion of my ByteBuffer. Instead, the full byte array is returned. I understand that this is because the "backing buffer" is the same all along.
How can I slice to have only the desired part of the array?
EDIT: Added context
The bytes are received from network. The buffer is formed like this :
[ SHA1 hash ] [ data... lots of it ]
I already have a function that takes a byte array as a parameter and calculate the SHA1 hash. What I want is to slice the full buffer to pass only the data without the expected hash.
You can use the Arrays.copyOfRange method. For example:
// slice from index 5 to index 9
byte[] slice = Arrays.copyOfRange(myArray, 5, 10);
The ByteBuffer you created is being backed by that array. When you call slice() you effectively receive a specific view of that data:
Creates a new byte buffer whose content is a shared subsequence of this buffer's content.
So calling array() on that returned ByteBuffer returns the backing array in its entirety.
To extract all the bytes from that view, you could do:
byte[] bytes = new byte[slicedBuf.remaining()];
slicedBuf.read(bytes);
The bytes from that view would be copied to the new array.
Edit to add from comments below: It's worth noting that if all you're interested in doing is copying bytes from one byte[] to another byte[], there's no reason to use a ByteBuffer; simply copy the bytes.

Generate a md5 sum from an Android Bitmap object

I've spent several hours trying to figure out how to do this. I've read post after post here on stackoverflow and the documentation.
I have a android.graphics.Bitmap object and I need to get it's md5 sum. At the point that I want to verify the sum it has not been saved to the file system. I've seen several ways of doing this for java.io.File objects. I just need a function that receives a Bitmap object and returns the hex md5 sum as a String.
This might have been addressed somewhere but if it has been I have been unable to understand it or deduce how to do it from it.
The less resource heavy the method is the better it is of course.
Get bitmap's bytes to calculate md5.
Bitmap bm = ... // your bitmap
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos); //bm is the bitmap object
byte[] bitmapBytes = baos.toByteArray();
So you have byte array now. You can find how to get md5 hash of byte array in android here.
I'm not Android developer, but I see in the API reference (http://developer.android.com/reference/android/graphics/Bitmap.html) that there are methods for:
getting size of the bitmap: getWidth, getHeight
getting the pixels as an array of integers: getPixels
So you could just create an array of needed size, then read all the pixels, and convert the array to byte[].
Then it should be not a problem to calculate md5 sum from it.

Image conversion to byte array in Java

Hi I have a model testing question for a object recognition project i am working on. I want to be able to take .jpeg files I have in my eclipse project folder and reduce them to very sparse byte arrays in Java. For example if I had a picture of a ball I would like to be able to convert it to the following byte 2-D array:
00000000000000000
00000001110000000
00001100001110000
00010000000001000
00010000000001000
00001000000010000
00000011111000000
00000000000000000
If someone could be so kind as to explain how I can do this most efficiently I would greatly appreciate it. I am fairly new to programming and do not understand much more than oop so if you could describe the process in simple programming terms without any jargon I would really appreciate it.
First to get byte array of image you need to convert image to BufferedImage. See ths link to convert image to BuffredImage. http://www.dzone.com/snippets/converting-images
After you get BufferedImage convert t into bytearray using bufferedImageToByteArray function.
BufferedImage buf_image; // this is BufferedImage reference you got after converting it from Image
byte[] imageByteArray = bufferedImageToByteArray(buf_image,"jpg");
public static byte[] bufferedImageToByteArray(BufferedImage image, String format) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, format, baos);
return baos.toByteArray();
}

Categories

Resources