I'm trying to get a BufferedImage from raw samples, but I get exceptions about trying to read past the available data range which I just don't understand. What I'm trying to do is:
val datasize = image.width * image.height
val imgbytes = image.data.getIntArray(0, datasize)
val datamodel = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, image.width, image.height, Array(image.red_mask.intValue, image.green_mask.intValue, image.blue_mask.intValue))
val buffer = datamodel.createDataBuffer
val raster = Raster.createRaster(datamodel, buffer, new Point(0,0))
datamodel.setPixels(0, 0, image.width, image.height, imgbytes, buffer)
val newimage = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB)
newimage.setData(raster)
Unfortunately I get:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 32784
at java.awt.image.SinglePixelPackedSampleModel.setPixels(SinglePixelPackedSampleModel.java:689)
at screenplayer.Main$.ximage_to_swt(Main.scala:40)
at screenplayer.Main$.main(Main.scala:31)
at screenplayer.Main.main(Main.scala)
The data is standard RGB with 1 byte padding (so that 1 pixel == 4 bytes) and the image size is 1366x24 px.
I finally got the code to run with the suggestion below. The final code is:
val datasize = image.width * image.height
val imgbytes = image.data.getIntArray(0, datasize)
val raster = Raster.createPackedRaster(DataBuffer.TYPE_INT, image.width, image.height, 3, 8, null)
raster.setDataElements(0, 0, image.width, image.height, imgbytes)
val newimage = new BufferedImage(image.width, image.height, BufferedImage.TYPE_INT_RGB)
newimage.setData(raster)
If it can be improved, I'm open to suggestions of course, but in general it works as expected.
setPixels assumes that the image data is not packed. So it's looking for an input of length image.width*image.height*3, and running off the end of the array.
Here are three options for how to fix the problem.
(1) Unpack imgbytes so it is 3x longer, and do it the same way as above.
(2) Manually load the buffer from imgbytes instead of using setPixels:
var i=0
while (i < imgbytes.length) {
buffer.setElem(i, imgbytes(i))
i += 1
}
(3) Don't use createDataBuffer; if you already know that your data has the proper formatting you can create the appropriate buffer yourself (in this case, a DataBufferInt):
val buffer = new DataBufferInt(imgbytes, imgbytes.length)
(you may need to do imgbytes.clone if your original copy could get mutated by something else).
Related
I'm trying to read a 256x256 image using ImageIO.read, transform it into a ByteArray, then into a BufferedImage, and back into an image file using ImageIO.write. It all seems to work as it should, but the final image is quite corrupted (although clearly still based on the original image. I can't find what's wrong in the process, I am suspicious of the scansize parameter, which I don't completely understand.
The idea is to manipulate pixels in between the reading and writing, but at the moment I can't even recreate the original image back into itself.
I attach the original image and the processed one below:
import java.awt.image.BufferedImage
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.IOException
import javax.imageio.ImageIO
fun main(args: Array<String>) {
val bImage = ImageIO.read(File("original.tiff"))
val bos = ByteArrayOutputStream()
ImageIO.write(bImage, "tiff", bos)
val data = bos.toByteArray()
val width = 256
val height = 256
val bytesPerPixel = 3
val len = width * height * bytesPerPixel
val image = BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
val arr = IntArray(len)
for (i in 0 until len) arr[i] = data.get(i).toInt()
image.setRGB(0, 0, width, height, arr, 0, 256) // Seems like something is wrong here
try {
ImageIO.write(image, "jpg", File("converted-grayscale-002.jpg"))
} catch (e: IOException) {
System.err.println("IOException: $e")
}
}
This line is not returning the RGB image data:
val data = bos.toByteArray()
it is returning the compressed stream of the image in tiff format, surely it is not the correct image.
To get the pixels, use Image.getPixel(), alternatively you can get the buffer of the image directly, but to this you need to know what is the underlying buffer type - this is broad topic.
Take a look at this answer, it should give you idea how to do it: convert a RGB image to grayscale Image reducing the memory in java
I'm looking to send over an Object that has a BufferedImage through a socket. BufferedImage is not serializable, so it needs to be converted to a serializable data type, and then back again. I have looked a lot online, and byte[] seems to be the go to send just a BuffereImage, but I'm trying to send an entire object so I'm leaning more towards int[]. I thought I ran across an answer that explained this on here a few weeks ago, but after 2.5 hours of searching I could not find it. I have tried the Java Oracle, but quickly got lost.
If there is a better way please excuse my ignorance, as I have not really worked a lot with sockets and BufferedImage manipulation.
Basically a BufferedImage is an array. The pixels are stored into the DataBuffer, which is an array.
BufferedImage source = //...
switch ( source.getType() )
{
case BufferedImage.TYPE_BYTE_GRAY :
case BufferedImage.TYPE_3BYTE_BGR :
case BufferedImage.TYPE_4BYTE_ABGR :
final byte[] bb = ((DataBufferByte)source.getRaster().getDataBuffer()).getData() ;
//...
break ;
case BufferedImage.TYPE_USHORT_GRAY :
final short[] sb = ((DataBufferUShort)source.getRaster().getDataBuffer()).getData() ;
//...
break ;
case BufferedImage.TYPE_INT_RGB :
case BufferedImage.TYPE_INT_BGR :
case BufferedImage.TYPE_INT_ARGB :
final int[] ib = ((DataBufferInt)source.getRaster().getDataBuffer()).getData() ;
break ;
// etc.
}
You will also need to send the image dimensions, plus the number of channels.
Send the image across as a PNG:
// BufferedImage -> byte sequence
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "PNG", baos);
byte[] imageData = baos.toByteArray();
// byte sequence -> BufferedImage
ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
BufferedImage img = ImageIO.read(bais);
I am trying to read a image with the following code, I wasn't able to figure it out why its happening. If there is anything I done wrong in the following code, please tell me.
System.out.println("Image Bytes ::"+imageBytes);
InputStream in = new ByteArrayInputStream(imageBytes);
BufferedImage img = ImageIO.read(in);
System.out.println("Buff Image :: "+img);
and the Output is as follows:
Image Bytes ::[B#4554617c
Buff Image :: null
Since the Source of your imageByte is unknown, it's would be hard to say what went wrong. But if your are creating that byteSource, then probably the below code will help you, because From the Javadocs for ImageIO.read()
Returns a BufferedImage as the result of decoding a supplied File with
an ImageReader chosen automatically from among those currently
registered. The File is wrapped in an ImageInputStream. If no
registered ImageReader claims to be able to read the resulting
stream, null is returned.
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
/**
* Created by ankur on 13/7/15.
* The Following program will read an image file.
* convert it into byte array, and then reuse the
* converted byte array, and convert it back to new BufferedImage
*
*/
public class ImageToBuf {
public static void main(String... strings) throws IOException {
byte[] imageInByte;
//read the image
BufferedImage originalImage = ImageIO.read(new File("/home/ankur/Pictures/BlpRb.png"));
//convert BufferedImage to byte array
ByteArrayOutputStream byteOutS = new ByteArrayOutputStream();
ImageIO.write(originalImage, "png", byteOutS);
byteOutS.flush();
imageInByte = byteOutS.toByteArray();
byteOutS.close();
//convert byte array back to BufferedImage
InputStream readedImage = new ByteArrayInputStream(imageInByte);
BufferedImage bfImage = ImageIO.read(readedImage);
System.out.println(bfImage);
}
}
OutPut(on my amchine):
BufferedImage#21b8d17c: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 3 color space = java.awt.color.ICC_ColorSpace#6433a2 transparency = 1 transIndex = -1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 4959 height = 3505 #numDataElements 1 dataOff[0] = 0
I am very new to image encoding and would rather not learn a whole lot about it. Basically I'm taking greyscale byte array where each byte equals one pixel. I'm getting this data from mnist where I get 28x28 byte images. Anyway, bellow is my code, so you understand what I'm trying to accomplish.
private def getImages = {
val filePath = getClass.getResource("/mnist/train-images.idx3-ubyte").getPath
val fis = new FileInputStream(filePath)
var bytes = new Array[Byte](4)
fis.read(bytes)
println((ByteBuffer.wrap(bytes).getInt()))
fis.read(bytes)
println((ByteBuffer.wrap(bytes).getInt()))
fis.read(bytes)
var rows = ByteBuffer.wrap(bytes).getInt()
println("Number of rows: " + rows)
fis.read(bytes)
var cols = ByteBuffer.wrap(bytes).getInt()
println("Number of cols: " + cols)
var imageBytes = new Array[Byte](rows * cols)
fis.read(imageBytes)
imageBytes.foreach(println(_))
// I created a byte array input stream to feed into ImageIO
// which should create my image
val b = new ByteArrayInputStream(imageBytes)
// This is where your helpful answer would be placed
// What is the code to encode this into jpeg, gif, or whatever?
// This returns null because I have not encoded the bytes
// in the proper format
val img = ImageIO.read(b)
// Errors out because img is null
ImageIO.write(img, "gif", new File("/home/dev/woot.gif"))
}
The format is just consecutive pixel bytes laid next to each other. My question is what Java library or function is available to convert these raw bytes into jpeg, gif, or whatever format I need?
Before you write it out with ImageIO, create a BufferedImage first. It can be as simple as using the setRGB methods, and has the added benefit of allowing you to observe the image before writing it out.
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.