int array to BufferedImage - java

I'm making with the Robot class a printscreen and I convert the BufferedImage into an int array. Then I want to convert the int array back to a bufferedimage but that gives an error. This is my code:
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage printscreen = robot.createScreenCapture(new Rectangle(screen));
int[] pixels = ((DataBufferInt) printscreen.getRaster().getDataBuffer()).getData();
BufferedImage image = new BufferedImage(screen.width, screen.height, BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();
raster.setPixels(0, 0, screen.width, screen.height, pixels);
But I get the error: ArrayIndexOutOfBoundsException: 2073600 but why?
I'm getting the exception on this line:
raster.setPixels(0, 0, screen.width, screen.height, pixels);
EDIT: It is working if I change the second bufferedimage type to TYPE_BYTE_GRAY.

int[] bitMasks = new int[]{0xFF0000, 0xFF00, 0xFF, 0xFF000000};
SinglePixelPackedSampleModel sm = new SinglePixelPackedSampleModel(
DataBuffer.TYPE_INT, width, height, bitMasks);
DataBufferInt db = new DataBufferInt(pixels, pixels.length);
WritableRaster wr = Raster.createWritableRaster(sm, db, new Point());
BufferedImage image = new BufferedImage(ColorModel.getRGBdefault(), wr, false, null);

Changed to:
getRaster().getPixels(0, 0, screen.width, screen.height, pixels)
and it works! Thanks for help anyway

The ArrayIndexOutOfBounds exception occurs as and when you try to access an element at index which is beyond the size of the array. In this case, you're passing the array to setPixels method, which accordingly to its javadocs doesn't explicitly check for the bounds or size of the array. So you should be doing that explicitly before calling that method. e.g.
if(x >= 0 && x < arr.length) {
// some code
}
This is the relevant code from SampleModel class used by WritableRaster.
public int[] getPixels(int x, int y, int w, int h,
int iArray[], DataBuffer data) {
int pixels[];
int Offset=0;
if (iArray != null)
pixels = iArray;
else
pixels = new int[numBands * w * h];
for (int i=y; i<(h+y); i++) {
for (int j=x; j<(w+x); j++) {
for(int k=0; k<numBands; k++) {
pixels[Offset++] = getSample(j, i, k, data);
}
}
}
return pixels;
}

The size of pixels in raster.setPixels(0, 0, screen.width, screen.height, pixels); should be width*height*3 when you set BufferedImage.TYPE_INT_RGB.

BufferedImage image = new BufferedImage(screen.width*3, screen.height,BufferedImage.TYPE_INT_RGB);
WritableRaster raster = (WritableRaster) image.getRaster();
raster.setPixels(0, 0, screen.width*3, screen.height, pixels);

Related

Drawing new image over old image java

I need to draw a new image over old image. I first opened both images in BufferedImage and changed their white background to transparent. Then I got a Graphics2D object from the bufferedImage of old image and called drawImage method of Graphics2D class. I then saved the old image to disk. When I open the saved image I find only the old image with white background changed to transparent. Can anyone suggest me what is error with my code or how can I get to fix my error ?
BufferedImage newImage = ImageIO.read(new File("new.png"));
BufferedImage oldImage = ImageIO.read(new File("old.png"));
newImage = makeWhiteTransparent(newImage);
oldImage = makeWhiteTransparent(oldImage);
Graphics2D graphics = (Graphics2D) oldImage.getGraphics();
graphics.drawImage(newImage,null, 0,0);
File outputImage = new File("merged.png");
ImageIO.write(oldImage, "png", outputImage);
My makeWhiteTransparent method goes like this:
public static BufferedImage makeWhiteTransparent(BufferedImage img){
BufferedImage dst = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
dst.getGraphics().drawImage(img, 0, 0, null);
int markerRGB = Color.WHITE.getRGB() | 0xFF000000;
int width = dst.getWidth();
int height = dst.getHeight();
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
int rgb = dst.getRGB(x, y);
if ( ( rgb | 0xFF000000 ) == markerRGB ) {
int value = 0x00FFFFFF & rgb;
dst.setRGB(x, y, value);
}
}
}
return dst;
}
I tried changing graphics.drawImage(newImage, null,0,0) to graphics.drawImage(newImage, 0,0, null) and also changing TYPE_4BYTE_ABGR to TYPE_INT_ARGB as suggested but it did nothing. The error still exists.
This needs to be changed:
graphics.drawImage(newImage,null, 0,0);
to
graphics.drawImage(newImage, 0,0, null);
you are using the wrong version of drawImage - check http://docs.oracle.com/javase/7/docs/api/java/awt/Graphics2D.html
--
Change also the type TYPE_4BYTE_ABGR to TYPE_INT_ARGB
--
Here's how it works for me:
public BufferedImage makeWhiteTransparent(BufferedImage img){
BufferedImage dst = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
dst.getGraphics().drawImage(img, 0, 0, null);
int markerRGB = 0x00ffffff; // Color.WHITE.getRGB() | 0xFF000000;
int width = dst.getWidth();
int height = dst.getHeight();
for(int x = 0; x < width; x++){
for(int y = 0; y < height; y++){
int rgb = dst.getRGB(x, y)&0x00ffffff;
if ( rgb == markerRGB ) {
int value = 0x00FFFFFF & rgb;
dst.setRGB(x, y, value);
}
}
}
return dst;
}
bim = makeWhiteTransparent(bim);
bim2 = makeWhiteTransparent(bim2);
Graphics2D graphics = (Graphics2D) bim.getGraphics();
graphics.drawImage(bim2,0,0, null);
g2.drawImage(bim, w/2-wc/2, h/2-hc/2, null);
I got the answer to my question finally. All I had to do was create a new BufferedImage and draw two images over it. Below is the code that works as expected:
BufferedImage newImage = ImageIO.read(new File("new.png"));
BufferedImage oldImage = ImageIO.read(new File("old.png"));
oldImage = makeWhiteTransparent(oldImage);
newImage = makeWhiteTransparent(newImage);
int width = Math.max(newImage.getWidth(), oldImage.getWidth());
int height = Math.max(newImage.getHeight(), oldImage.getHeight());
BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = combined.getGraphics();
graphics.drawImage(oldImage, 0, 0, null);
graphics.drawImage(newImage, 0, 0, null);
File outputImage = new File("merged.png");
ImageIO.write(combined, "PNG", outputImage);

Convert byte array of data type TYPE_4BYTE_ABGR to BufferedImage

I have a byte array with type TYPE_4BYTE_ABGR, and I know its width and height, I want to change it to BufferedImage, any ideas?
The fastest way to create a BufferedImage from a byte array in TYPE_4BYTE_ABGR form, is to wrap the array in a DataBufferByte and create an interleaved WritableRaster from that. This will make sure there are no additional byte array allocations. Then create the BufferedImage from the raster, and a matching color model:
public static void main(String[] args) {
int width = 300;
int height = 200;
int samplesPerPixel = 4; // This is the *4BYTE* in TYPE_4BYTE_ABGR
int[] bandOffsets = {3, 2, 1, 0}; // This is the order (ABGR) part in TYPE_4BYTE_ABGR
byte[] abgrPixelData = new byte[width * height * samplesPerPixel];
DataBuffer buffer = new DataBufferByte(abgrPixelData, abgrPixelData.length);
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
System.out.println("image: " + image); // Should print: image: BufferedImage#<hash>: type = 6 ...
}
Note however, that this image will be "unmanaged" (some HW accelerations will be disabled), because you have direct access to the pixel array.
To avoid this, create the WritableRaster without the pixels, and copy the pixels into it. This will use twice as much memory, but will keep the image "managed" and thus possible better display performance:
// Skip creating the data buffer
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
raster.setDataElements(0, 0, width, height, abgrPixelData);
// ...rest of code as above.
You could even do this (which might be more familiar):
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
WritableRaster raster = image.getRaster();
raster.setDataElements(0, 0, width, height, abgrPixelData);
Might not be very efficient, but a BufferedImage can be converted to another type this way:
public static BufferedImage convertToType(BufferedImage image, int type) {
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
Graphics2D graphics = newImage.createGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
return newImage;
}
About the method you want to be implemented, you would have to know the width or height of the image to convert a byte[] to a BufferedImage.
Edit:
One way is converting the byte[] to int[] (data type TYPE_INT_ARGB) and using setRGB:
int[] dst = new int[width * height];
for (int i = 0, j = 0; i < dst.length; i++) {
int a = src[j++] & 0xff;
int b = src[j++] & 0xff;
int g = src[j++] & 0xff;
int r = src[j++] & 0xff;
dst[i] = (a << 24) | (r << 16) | (g << 8) | b;
}
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, dst, 0, width);

Create a WritableRaster based on int array

I need to take an int array and turn it into BufferImage. I really don't have any background on this subject and I learn it all from the internet so here's what I'm trying to do:
Create an array from BufferedImage(done), turn this array into IntBuffer(done) - (Later i'll need to do some opertions on the image through the IntBuffer), put the changed values from the IntBuffer in new array(done), and turn this array into WritableRaster.
(If something isn't right in my understading of the process please tell me)
Here's the line where I deal with the WritableRaster:
WritableRaster newRaster= newRaster.setPixels(0, 0, width, height, matrix);
Eclipse marks this as a mistake and says ''Type mismatch:Cannot convert from void to WritableRaster"
Please help! I'm a bit lost.
Also sorry for bad english.
EDIT:
The matrix:
int height=img.getHeight();
int width=img.getWidth();
int[]matrix=new int[width*height];
The part of the code where I try to insert values to the Raster:
BufferedImage finalImg = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
WritableRaster newRaster= (WritableRaster)finalImg.getData();
newRaster.setPixels(0, 0, width, height, matrix);
The error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10769
at java.awt.image.SinglePixelPackedSampleModel.setPixels(Unknown Source)
at java.awt.image.WritableRaster.setPixels(Unknown Source)
You can create a WritableRaster and/or BufferedImage from an int array like this:
int w = 300;
int h = 200;
int[] matrix = new int[w * h];
// ...manipulate the matrix...
DataBufferInt buffer = new DataBufferInt(matrix, matrix.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF, 0xFF000000}; // ARGB (yes, ARGB, as the masks are R, G, B, A always) order
WritableRaster raster = Raster.createPackedRaster(buffer, w, h, w, bandMasks, null);
System.out.println("raster: " + raster);
ColorModel cm = ColorModel.getRGBdefault();
BufferedImage image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
System.err.println("image: " + image);
ColorModel cm = ColorModel.getRGBdefault();
int w = 300;
int h = 200;
WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer();
int[] bufferData = buffer.getData();
int[] array = new int[2400];
Random random = new Random();
for (int i = 0; i < 2400; i++) {
array[i] = random.nextInt(2);
}
System.arraycopy(array, 0, bufferData, 0, (array.length < bufferData.length ? array.length : bufferData.length));
BufferedImage image = new BufferedImage(cm, raster, false, null);
FileOutputStream fos = new FileOutputStream("D:\\abc\\OCR\\" + "LearningRaster" + ".png");
ImageIO.write(image, "PNG", fos);
fos.close();
setPixels returns void:
public static void setPixels(BufferedImage img,
int x, int y, int w, int h, int[] pixels)
so you need to create Raster and than set pixels to it:
WritableRaster newRaster= WritableRaster.createWritableRaster(…);
newRaster.setPixels(0, 0, width, height, matrix);
You need to put 4 int per pixel (it depends on color model, 4 for ARGB). So, matrix size must be
int[] matrix = new int[width * height * 4]
See more about WritableRaster here —
Oracle: WritableRaster
Code examples

How can I get my image to flip?

I'm having a problem getting an image to flip. My program is supposed to show the default image and the flipped image. I thought that if I could replace the (0,0) pixel of the flipped picture with the (width-1,height-1) of the original picture, it would work, but instead of getting the original image, I get this.
Here is my code:
import java.awt.Color;
public class Horizontal {
public static void main(String[] args)
{
Picture source = new Picture(args[0]);//name of picture.
Picture flip = new Picture(source.width(), source.height());//sets the width and height of source
for (int i =0; i < source.width(); i++)
{
int w = 1;
int sw = source.width()-w;
for (int j = 0; j < source.width(); j++)
{
int h=1;
int sh = source.height()-h;
Color SourceColor = source.get(sw,sh);// return the the color pixel of (sw,sh)
flip.set(i, j, SourceColor);//suppose to replace the (i,j) pixel of flip with source's (sw,sh) pixel
h++;
}
w++;
}
source.show();// shows the original image
flip.show(); // shows flipped version of image
}
}
Chceck this site. It has great info about basic image algorithms in java.
You can copy code for flipping an image.
http://www.javalobby.org/articles/ultimate-image/#9
Flipping horizontally:
public static BufferedImage horizontalflip(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = new BufferedImage(w, h, img.getType());
Graphics2D g = dimg.createGraphics();
g.drawImage(img, 0, 0, w, h, w, 0, 0, h, null);
g.dispose();
return dimg;
}
Flipping vertically:
public static BufferedImage verticalflip(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
BufferedImage dimg = dimg = new BufferedImage(w, h, img.getColorModel().getTransparency());
Graphics2D g = dimg.createGraphics();
g.drawImage(img, 0, 0, w, h, 0, h, w, 0, null);
g.dispose();
return dimg;
}

Are there similar android methods of java getData().getPixels()?

I'm trying to use the following code of java to read image data on android. Since ImageIO is not supported, what are some ways I may use getData().getPixels()?
By changing BufferedImage into Bitmap, I can get all other codes working besides bi.getData().getPixels()?
Any method in the android library I may use to replace it?
In android Bitmap class:
public void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
This method supports int[], but not double[]. I'm not familiar with image processing will they be different?
Thank you.
private double[] getImageData(String imageFileName) throws FaceRecError {
BufferedImage bi = null;
double[] inputFace = null;
try{
bi = ImageIO.read(new File(imageFileName));
}catch(IOException ioe){
throw new FaceRecError(ioe.getMessage());
}
if (bi != null){
int imageWidth = bi.getWidth();
int imageHeight = bi.getHeight();
inputFace = new double[imageWidth * imageHeight];
bi.getData().getPixels(0, 0, imageWidth, imageHeight,inputFace);
}
return inputFace;
}
This code is used for getting color of all pixels in Bitmap in android.This return array of color
Bitmap bitmap=BitmapFactory.decodeFile("file path");
int height=bitmap.getHeight();
int width=bitmap.getWidth();
int[] pixel=new int[height*width];
bitmap.getPixels(pixel, 0, width, 0, width, width, height);
So your color will be saved in pixel array. getPixels() have many parameter to customize which pixel color you want
Updated For Casting Integer array to double
public double[] getDoubleNumbers(int[] numbers)
//changed double to double[]
{double[] newNumbers = new double[numbers.length]; //changed 99 to numbers.length
for (int index = 0; index < numbers.length; index++)
newNumbers[index] = (double)numbers[index];
return newNumbers;
}
}

Categories