I want to know how to get the size of an image header. I have been searchin in internet but I have not found information about how to get an image (bitmap) header in java/android.
Anyone has an idea or example?
What I have been trying to do is next but it's not working properly because the image cannot be opened:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
byte[] b_header = new byte[8];
System.arraycopy(b, 0, b_header, 0, 8);
bos.write(b_header);
bos.flush();
bos.close();
I wouldn't suggest writing code to handle PNG manipulation yourself unless that is the main goal of the project. Instead, I'd find a library that would handle the loading of a PNG for you and then scramble the chunks that it can get for you. I found a nice PNG java library here:
PNGJ
Also, I wrote a small code snip based on their examples to get you on the right track to scrambling your images.
public static void encryptPng(File in, File out) {
PngReader pngReader = new PngReader(in);
PngWriter pngWriter = new PngWriter(out, pngReader.imgInfo, false);
pngWriter.copyChunksFrom(pngReader.getChunksList());
for (int row = 0; row < pngReader.imgInfo.rows; row++) {
ImageLineInt lineInt = (ImageLineInt) pngReader.readRow();
adjustLine(lineInt, pngReader.imgInfo);
pngWriter.writeRow(lineInt);
}
pngReader.close();
pngWriter.close();
}
public static void adjustLine(ImageLineInt line, ImageInfo info) {
/*
Scramble the line with some reversable algorithm so that it can't be read
*/
}
Related
I am trying to write a simple server that uses sockets and reads images from disc when it receives http request from browser.
I am able to receive the request, read the image from disc and pass it to the browser (the browser then automatically downloads the image). However, when I try to open the downloaded image, it says:
Could not load image 'img.png'. Fatal error reading PNG image file: Not a PNG file
The same goes for all other types of extensions (jpg, jpeg, gif etc...)
Could you help me out and tell me what am I doing wrong? I suspect that there might be something wrong with the way I read the image or maybe some encoding has to be specified?
Reading the image from disc:
// read image and serve it back to the browser
public byte[] readImage(String path) {
File file = new File(FILE_PATH + path);
try {
BufferedImage image = ImageIO.read(file); // try reading the image first
// get DataBufferBytes from Raster
WritableRaster raster = image.getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
return data.getData();
} catch (IOException ex) {
// handle exception...
}
return ("Could not read image").getBytes();
}
Writing the data via socket:
OutputStream output = clientSocket.getOutputStream();
output.write(result);
In this case, the result contains the byte array produced by the readImage method.
EDIT: second try with reading the image as normal file
FileReader reader = new FileReader(file);
char buf[] = new char[8192];
int len;
StringBuilder s = new StringBuilder();
while ((len = reader.read(buf)) >= 0) {
s.append(buf, 0, len);
byte[] byteArray = s.toString().getBytes();
}
return s.toString().getBytes();
You may use ByteArrayOutputStream, like,
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", byteArrayOutputStream);
and then you can write to socket as,
outputStream.write(byteArrayOutputStream.toByteArray());
I have this following code in my servlet
response.setContentType("image/gif");
String filepath = "PATH//TO//GIF.gif";
OutputStream out = response.getOutputStream();
File f = new File(filepath);
BufferedImage bi = ImageIO.read(f);
ImageIO.write(bi, "gif", out);
out.close();
This code is just returning first frame of the image.
How to achieve returning full GIF image ?
Your GIF does not animate, because you are sending only the first frame to the client. :-)
Actually, you are, because ImageIO.read reads only the first frame (and a BufferedImage can only contain a single frame/image). You are then writing that single frame to the servlet output stream, and the result will not animate (it should be possible to create animating GIFs using ImageIO, but the code to do so will be quite verbose, see How to encode an animated GIF in Java, using ImageWriter and ImageIO? and Creating animated GIF with ImageIO?).
The good news is, the solution is both simple, and will save you CPU cycles. There's no need to involve ImageIO here, if you just want to send an animated GIF that you have stored on disk. The same technique can be used to send any binary content, really.
Instead, simply do:
response.setContentType("image/gif");
String filepath = "PATH//TO//GIF.gif";
OutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(new File(filepath));
try {
FileUtils.copy(in, out);
finally {
in.close();
}
out.close();
FileUtils.copy can be implemented as:
public void copy(final InputStream in, final OutputStream out) {
byte[] buffer = new byte[1024];
int count;
while ((count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
// Flush out stream, to write any remaining buffered data
out.flush();
}
I am not new to bitmaps nor new to java. I am trying to convert High resolution bitmaps to byte array in a loop. Please find code here:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream);
imageByteArray = stream.toByteArray();
When i am using the above approach I cam able to convert 5 images in 1 second. But I need it to be even faster. I tried ByteBuffer approach also like this:
Bitmap bmp = intent.getExtras().get("data");
int size = bmp.getRowBytes() * bmp.getHeight();
ByteBuffer b = ByteBuffer.allocate(size);
bmp.copyPixelsToBuffer(b);
byte[] bytes = new byte[size];
try {
b.get(bytes, 0, bytes.length);
} catch (BufferUnderflowException e) {
// always happens
}
But this is very slow (Slower then previous) :(
Please, can somebody give a faster method? Guide Me...
The first solution is the right one.
But two things can happen here:
The image is maybe not of JPEG type, so conversion occurs, which takes time
The image is compressed 50%, which takes time
That aside, if it's taking some time, I doubt it could go faster (being the right solution).
You must consider the fact that the speed of processing is tightly tied to the speed of the device you are testing on( since this is tagged android I'm presuming you're using a mobile device ).
You should take a look at android developer on how to handle large bitmaps effectively Android developers . Since processing 5 high resolution images per second is slow to you I can presume you are having some kind of gallery or previews? If that's the case you shouldn't handle the high resolution images and should indeed take a look at the link above.
Also as a side-note your second code can be optimised this way:
int bytes = bmp.getByteCount();
ByteBuffer buffer = ByteBuffer.allocate(bytes);
bmp.copyPixelsToBuffer(buffer);
byte[] array = buffer.array();
Otherwise the most efficient way of copying bytes that I know is copy() taken from Commons-IO:
public static int copy(InputStream input, OutputStream output) throws IOException {
int n, count = 0;
byte[] buffer = new byte[4 * 1024];
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
you can try as follows
Bitmap bitmap = intent.getExtras().get("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap .compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
hope it may work good for you!!
check for line bitmap.compress(Bitmap.CompressFormat.JPEG, 50, stream); it may cause problem..as you are using JPEG format with rate 50.
I am trying to compress a sequence of images in png format. It seems that compression is going well:
FileOutputStream fos = null;
GZIPOutputStream gzip = null;
fos = new FileOutputStream(PATH_SAVE_GZIP);
gzip = new GZIPOutputStream(fos);
for (int i = 0; i < NB_OF_IMAGES; i++) {
BufferedImage im = images.get(i).getBufImg();
ImageIO.write(im, "JPEG", gzip);
}
gzip.finish();
gzip.close();
fos.close();
However I get Exception Nullpointer... when I try to uncompress it with this code.
What am I'm doing wrong?
I've finished my project and now I know the answer. This could be solved by several ways:
One is by using ObjectOutput/Input Stream and write BufferedImages like objects.
The other is to use ByteArrayOutputStream and write images like bytes. Prior to use this you should know the size to be written. So I've solved this writing size before each image. Not efficient way... However works.
fileOutputStream fos = new FileOutputStream(path);
GZIPOutputStream gzip = new GZIPOutputStream(fos);
gzip.write(shortToBytes(numImatges));
gzip.write(shortToBytes((short) 0));
for (int i = 0; i < dates.getNB_OF_IMAGES(); i++) {
if (images != null) {
im = images.get(i).getBufImg();
}
ByteArrayOutputStream byteOstream = new ByteArrayOutputStream();
ImageIO.write(im, "jpeg", byteOstream);
byteOstream.flush();
byteOstream.close();
gzip.write(shortToBytes((short) byteOstream.size()));
gzip.write(byteOstream.toByteArray());
}
//close streams
Your problem is that you write all the images to a single GZIP stream and when reading, ImageIO doesn't know where one image ends and the next begins.
You got two options:
Use ZIP instead of GZIP
Package the files in a TAR file using jtar or Java Tar Package and then GZIP the tar, when reading you will first UnGZIP and then extract the images from the tar file
I am trying to convert an image to byte array and converting back byte array to image in Android Emulator.
First part is working fine but the second part is not creating the image file in Android emulator.
Please suggest me if there is any correction in my second part of the code.
Following is my code.
public String GetQRCode() throws FileNotFoundException, IOException {
/*
* In this function the first part shows how to convert an image file to
* byte array. The second part of the code shows how to change byte array
* back to an image.
*/
Bitmap bitmap = BitmapFactory.decodeFile("sdcard/Download/QR.jpg");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 60, baos);
byte[] byte_img_data = baos.toByteArray();
byte[] buf = new byte[200];
// Second Part: Convert byte array back to an image
Bitmap bitmap2 = BitmapFactory.decodeByteArray(byte_img_data, 0, 200);
ByteArrayOutputStream img= new ByteArrayOutputStream();
Bitmap imageFile= BitmapFactory.decodeFile("sdcard/Download/QR3.jpg");
String abc = buf.toString();
return abc;
}
your call to BitmapFactory.decodeByteArray(..) - this method returns a Bitmap object, but you're not assigning it to anything. You also need to change the call to pass in the actual length of byte_img_data, rather then 200.
Bitmap bitmap2 = BitmapFactory.decodeByteArray(byte_img_data, 0, byte_img_data.length);
However, whether decodeByteArray(..) can handle compressed streams, i don't know