Java bitmap reading [duplicate] - java

This question already has answers here:
Java - get pixel array from image
(7 answers)
Closed 4 years ago.
I want to read in a bitmap so that I have an array of the 256-RGB values for each pixel.
Currently my code is:
File image = serverConfig.get(map.bmp);
BufferedImage buffer = ImageIO.read(image);
dimX = buffer.getWidth();
dimY = buffer.getHeight();
byte[] pixlesB = (byte[]) buffer.getRaster().getDataElements(0, 0, buffer.getWidth(), buffer.getHeight(), null);
This produces a byte array of the bitmap e.g.
[pixel1Red,pixel1Green,pixel1Blue,pixel2Red,pixel2Green,pixel2Blue,...]
My problem is that when I load a large bitmap (currently the one I'm trying is about 706,000 pixles^2) the bitmap lossless compresses the file and I just get a string of semi-meaningless numbers.
Is there any way to force java to read out the RGB values for all bitmaps, like it does for small ones?
EDIT:
To clarify, I am getting back a [pixel1Red,pixel1Green,pixel1Blue,pixel2Red,pixel2Green,pixel2Blue,...] style list, but the values in there aren't the 0-255 bytes I'm expecting, they're just random, compressed numbers. I need to actual 0-255 values for RGB (or better yet just a byte array of all the hex values) in order for the rest of my code to reliably work.

Try this method:
File image = serverConfig.get(map.bmp);
BufferedImage buffer = ImageIO.read(image);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(buffer, "bmp", baos );
baos.flush();
byte[] pixlesB = baos.toByteArray();
baos.close();

Related

Compressing a multi-page tiff image with lossy jpeg

I need to compress a tif file that has several gray 16bit images (multi-page). I have tried working with ImageIO as here: Tiff compression using Java ImageIO Initially, each image that will be in the tif file comes from another tiff file. When I want to use the compressors, I have the following options:
CCITT RLE, CCITT T.4, CCITT T.6: They give me the error: "javax.imageio.IIOException: I/O error writing TIFF file!"
LZW. I cannot use it. My images are 16bit and LZW increases the size of 16bit images
JPEG. Not possible for 16bit images.
ZLIB. It only reduces 10% even if I specify setCompressionQuality(0.0f);
PackBits. Does not compress.
Deflate. Like ZLIB.
EXIF JPEG. It gives me the error: "javax.imageio.IIOException: Old JPEG compression not supported!"
Does any know any other alternative? I saw an apache imaging library but the tif compression only support the above or less options. Does anyone know about JPEG2000 compressor? Any other kind of alternative?
PNG compresses 16-bit images losslessly. Libraries and utilities are widely available. JPEG2000 has a lossy 16-bit mode, but you'd have to find some software that supports it. Open JPEG might.
However I'd have to ask: what are your criteria for when you have acceptable image quality and when you do not? If it is visual, then you likely end up at normal JPEG anyway, with a good bit less than 8 bits per pixel effective.
Reducing the image 16 bit to 8 bit. Consider that you have a byte[] variable plane16 where you have all the pixels of your image.
Note: My byte[] plane16 gets the data from a 16bit image but byte is 8bit=1byte. Therefore, 2 elements in row of this array are 2byte = 16bit. That is why I convert it to a short[] before operating. If you start from a short[], ommit "ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);"
byte[] plane16; //Fill it with your image!!!
//Do stuff with imageIO. Set writer and compresion method
ImageIO.scanForPlugins();
TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
javax.imageio.ImageWriter writerIO = tiffspi.createWriterInstance();
ImageWriteParam param = writerIO.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("ZLib");
param.setCompressionQuality(0.5f);
File fOutputFile = new File(route+".tif");
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writerIO.setOutput(ios);
//Reducing 16bit to 8bit
short[] shorts = new short[plane16.length/2];
ByteBuffer.wrap(plane16).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
int max = 0;
int min = 999999;
for (int v = 0; v<shorts.length;v++){
if (max<shorts[v]) max = shorts[v];
if (min>shorts[v]) min = shorts[v];
}
double range = 255./(max-min);
byte[] plane8 = new byte[shorts.length];
for (int v = 0; v<plane8.length;v++){
plane8[v] = (byte) ((shorts[v]+min)*range - 128);
}
//16bit:
/*BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_USHORT_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, shorts);*/
//8bit:
BufferedImage convertedGrayscale = new BufferedImage(width,
heigth, BufferedImage.TYPE_BYTE_GRAY);
convertedGrayscale.getRaster().setDataElements(0, 0, width,
heigth, plane8);
//Save image
//If you have a stack of images in tiff, do this trick. "image" is the image number you are setting inside the tiff. If you only have 1 image, remove the if and take the expression from the else.
if (image!=0){
writerIO.writeInsert(image, new IIOImage(convertedGrayscale, null, null), param);
}else{
writerIO.write(null, new IIOImage(convertedGrayscale, null, null), param);
}
//do the next only after the last image to be saved
writerIO.dispose();
ios.flush();
ios.close();

Convert OpenCV Mat object to BufferedImage

I am trying to create a helper function using OpenCV Java API that would process an input image and return the output byte array. The input image is a jpg file saved in the computer. The input and output image are displayed in the Java UI using Swing.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
// Load image from file
Mat rgba = Highgui.imread(filePath);
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0);
// Convert back to byte[] and return
byte[] return_buff = new byte[(int) (rgba.total() * rgba.channels())];
rgba.get(0, 0, return_buff);
return return_buff;
When the return_buff is returned and converted to BufferedImage I get NULL back. When I comment out the Imgproc.cvtColor function, the return_buff is properly converted to a BufferedImage that I can display. It seems like the Imgproc.cvtColor is returning a Mat object that I couldn't display in Java.
Here's my code to convert from byte[] to BufferedImage:
InputStream in = new ByteArrayInputStream(inputByteArray);
BufferedImage outputImage = ImageIO.read(in);
In above code, outputImage is NULL
Does anybody have any suggestions or ideas?
ImageIO.read(...) (and the javax.imageio package in general) is for reading/writing images from/to file formats. What you have is an array containing "raw" pixels. It's impossible for ImageIO to determine file format from this byte array. Because of this, it will return null.
Instead, you should create a BufferedImage from the bytes directly. I don't know OpenCV that well, but I'm assuming that the result of Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0) will be an image in grayscale (8 bits/sample, 1 sample/pixel). This is the same format as BufferedImage.TYPE_BYTE_GRAY. If this assumption is correct, you should be able to do:
// Read image to Mat as before
Mat rgba = ...;
Imgproc.cvtColor(rgba, rgba, Imgproc.COLOR_RGB2GRAY, 0);
// Create an empty image in matching format
BufferedImage gray = new BufferedImage(rgba.width(), rgba.height(), BufferedImage.TYPE_BYTE_GRAY);
// Get the BufferedImage's backing array and copy the pixels directly into it
byte[] data = ((DataBufferByte) gray.getRaster().getDataBuffer()).getData();
rgba.get(0, 0, data);
Doing it this way, saves you one large byte array allocation and one byte array copy as a bonus. :-)
I used this kind of code to convert Mat object to Buffered Image.
static BufferedImage Mat2BufferedImage(Mat matrix)throws Exception {
MatOfByte mob=new MatOfByte();
Imgcodecs.imencode(".jpg", matrix, mob);
byte ba[]=mob.toArray();
BufferedImage bi=ImageIO.read(new ByteArrayInputStream(ba));
return bi;
}

Java: BufferedImage to byte array and back

I see that a number of people have had a similar problem, however I'm yet to try find exactly what I'm looking for.
So, I have a method which reads an input image and converts it to a byte array:
File imgPath = new File(ImageName);
BufferedImage bufferedImage = ImageIO.read(imgPath);
WritableRaster raster = bufferedImage .getRaster();
DataBufferByte data = (DataBufferByte) raster.getDataBuffer();
What I now want to do is convert it back into a BufferedImage (I have an application for which I need this functionality). Note that "test" is the byte array.
BufferedImage img = ImageIO.read(new ByteArrayInputStream(test));
File outputfile = new File("src/image.jpg");
ImageIO.write(img,"jpg",outputfile);
However, this returns the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: im == null!
This is because the BufferedImage img is null. I think this has something to do with the fact that in my original conversion from BufferedImage to byte array, information is changed/lost so that the data can no longer be recognised as a jpg.
Does anyone have any suggestions on how to solve this? Would be greatly appreciated.
This is recommended to convert to a byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "jpg", baos);
byte[] bytes = baos.toByteArray();
Note that calling close or flush will do nothing, you can see this for yourself by looking at their source/doc:
Closing a ByteArrayOutputStream has no effect.
The flush method of OutputStream does nothing.
Thus use something like this:
ByteArrayOutputStream baos = new ByteArrayOutputStream(THINK_ABOUT_SIZE_HINT);
boolean foundWriter = ImageIO.write(bufferedImage, "jpg", baos);
assert foundWriter; // Not sure about this... with jpg it may work but other formats ?
byte[] bytes = baos.toByteArray();
Here are a few links concerning the size hint:
Java: Memory efficient ByteArrayOutputStream
jpg bits per pixel
Of course always read the source code and docs of the version you are using, do not rely blindly on SO answers.

How to convert image to byte array and convert back byte array to image

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

How do I convert byte[] to Bitmap?

Let's say I have a byte buffer and how do I get Bitmap?
If you want to manipulate the image, use ImageIO. It creates a format-agnostic image in memory:
BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
If you just want to store in to disk, then simply write the byte array to a file.
Note that the byte array must be already a bitmap image, you can't take any byte array and have it as bitmap.
And you get the byte array from the byte buffer by:
byte[] bytes = new byte[buf.capacity()];
buf.get(bytes, 0, bytes.length);

Categories

Resources