here's my code:
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
WritableRaster raster = newImage.getRaster();
raster.setDataElements(0, 0, image.getWidth(), image.getHeight(), pixels);
newImage.setData(raster);
ImageIO.write(newImage, "jpg", new File("newimage.jpg"));
This code looks right to me and should do what I want. It gets the image's pixel data, then uses it to create a new image which should look exactly the same as the original image. However, the image that is saved has different colors than the original. Why?
Eventually, I'll need to manipulate the pixel bytes but for now, I don't know why it's giving me a different image.
This post may be of help java buffered image created with red mask
It seems to be a common problem with ImageIO so its best to use Toolkit instead.
Related
I have a ReadableByteChannel which contains an image (either obtained from an URL or a file). I write the Channel finally into a File with a code like
final FileOutputStream fileOutputStream = new FileOutputStream(outImageName);
fileOutputStream.getChannel().transferFrom(imageByteChannel, 0, Long.MAX_VALUE);
fileOutputStream.close();
Since it is unclear if the image is a png or a jpeg or ... I want to make sure and save it as png. I know I can use the ImageIO.write(buffImg, outImageName, "png");
But somehow this requires that the buffImg is a RenderedImage which raises the question how to obtain it?
Is there a simpler solution than reading the file from the file system with ImageIO and than write it as png? Can I convert it directly within the memory?
Plus an additional question: Is there a way to tell ImageIO to get rid of the AlphaChannel (=transparent)?
If you can, I suggest getting the InputStream or the underlying File or URL objects instead of a ReadableByteChannel, as ImageIO.read(..) supports all those types as input directly.
If not possible, you can use Channels.newInputStream(..) to get an InputStream from the byte channel, to pass on to ImageIO.read(...). There's no need to write to a file first.
Code:
ReadableByteChannel channel = ...; // You already have this
BufferedImage image = ImageIO.read(Channels.newInputStream(channel))
To get rid of any unwanted transparency, you could do:
BufferedImage opaque = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
Graphics2D g = opaque.createGraphics();
try {
g.setColor(Color.WHITE); // Or any other bg color you like
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.drawImage(image, 0, 0, null);
}
finally {
g.dispose();
}
You can now write the image in PNG format, either to a file or stream:
if (!ImageIO.write(opaque, "PNG", new File(outputFile)) {
// TODO: Handle odd case where the image could not be written
}
The following code results an image of higher size. My original image 200x200 was 6 KB. After the this I got an out put of 100KB.
When I resupply the output as input again, it is not changing the size
File imageFile = "path to image"
BufferedImage subImage= ImageIO.read(new FileInputStream(imageFile));
BufferedImage dest = new BufferedImage(200, 200, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(subImage, 0, 0, 200, 200, null);
g2.dispose();
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(dest, "png", out);
Image size varies depending on the format, compression and channels chosen.
PNG usually uses more size because it offers an alpha channel (which you used here) and does lossless compression, compared to JPEG.
Try chosing "JPEG" when writing the image, and check if the size and quality suits your needs better.
How can I save BufferedImage with TYPE_INT_ARGB to jpg?
Program generates me that image:
And it's OK, but when I save it in that way:
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(byteStream);
try {
ImageIO.write(buffImg, "jpg", bos);
// argb
byteStream.flush();
byte[] newImage = byteStream.toByteArray();
OutputStream out = new BufferedOutputStream(new FileOutputStream("D:\\test.jpg"));
out.write(newImage);
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The result is:
Understand that this is due to the alpha layer, but don't know how to fix it. Png format does not suit me, need jpg.
OK!
I've solved it.
Everything was pretty easy. Don't know is it a good decision and how fast it is. I have not found any other.
So.. everything we need is define new BufferedImage.
BufferedImage buffImg = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = buffImg.createGraphics();
// ... other code we need
BufferedImage img= new BufferedImage(buffImg.getWidth(), buffImg.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.drawImage(buffImg, 0, 0, null);
g2d.dispose();
If there any ideas to improve this method, please, your welcome.
Images having 4 color channels should not be written to a jpeg file. We can convert between ARGB and RGB images without duplicating pixel values. This comes in handy for large images. An example:
int a = 10_000;
BufferedImage im = new BufferedImage(a, a, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = im.createGraphics();
g.setColor(Color.RED);
g.fillRect(a/10, a/10, a/5, a*8/10);
g.setColor(Color.GREEN);
g.fillRect(a*4/10, a/10, a/5, a*8/10);
g.setColor(Color.BLUE);
g.fillRect(a*7/10, a/10, a/5, a*8/10);
//preserve transparency in a png file
ImageIO.write(im, "png", new File("d:/rgba.png"));
//pitfall: in a jpeg file 4 channels will be interpreted as CMYK... this is no good
ImageIO.write(im, "jpg", new File("d:/nonsense.jpg"));
//we need a 3-channel BufferedImage to write an RGB-colored jpeg file
//we can make up a new image referencing part of the existing raster
WritableRaster ras = im.getRaster().createWritableChild(0, 0, a, a, 0, 0, new int[] {0, 1, 2}); //0=r, 1=g, 2=b, 3=alpha
ColorModel cm = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).getColorModel(); //we need a proper ColorModel
BufferedImage imRGB = new BufferedImage(cm, ras, cm.isAlphaPremultiplied(), null);
//this image we can encode to jpeg format
ImageIO.write(imRGB, "jpg", new File("d:/rgb1.jpg"));
So I make a bitmap from a blob with the next code:
byte[] blob = contact.getMP();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Bitmap scalen = Bitmap.createScaledBitmap(bitmap, 320, 240, false);
and it gives back the next output, which is good
Then I do the following to make the bitmap into a Mat, but then my colors just change...
//Mat ImageMat = new Mat();
Mat ImageMat = new Mat(320, 240, CvType.CV_32F);
Utils.bitmapToMat(scalen, ImageMat);
I have no idea why, nor another way to make the bitmap into a Mat. What is wrong?
The format of color channels in Android Bitmap are RGB
But in opencv Mat, the channels are BGR by default.
So when you do Utils.bitmapToMat(), [B,G,R] values are stored in [R,G,B] channels. The red and blue channels are interchanged.
One possible solution is to apply cvtcolor on the opencv Mat you got as below:
Imgproc.cvtColor(ImageMat, ImageMat, Imgproc.COLOR_BGR2RGB);
It worked for me.
I have a byte[] I captured from Kinect using OpenKinect and it's Java JNA wrapper. I'm wondering if there's any existing library I can use to convert the byte[] of RGB data into a image I can display/store?
Java's BufferedImage is a great candidate.
I would find out the color encoding scheme of your byte[] and transform it to an int[] acceptable for setting the RGB array of a BufferedImage with setRGB()javadoc. Then you can save the image to disk in a variety of formats, or render for display.
Writing/Saving an Imageoracle
You can convert the byte[] RGB data into an int[]where each int encodes an ARGB pixel (alpha, red, green, blue). Then use the following code to create a BufferedImage
int[] pixels = new int[width * height];
// do the conversion byte[] => int[]
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
img.setRGB(0, 0, width, height, pixels, 0, width);
You can then use ImageIO to save the image:
File outputFile = new File("image.png");
ImageIO.write(img, "png", outputFile);
Or draw the image for example in a JComponent's paint method:
public void paint(Graphics graphics){
Graphics2D g = (Graphics2D)graphics;
g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), null);
}
Consult the related JavaDoc for details. BufferedImage.TYPE_INT_ARGBis usually the fastest image encoding (at least it was a while ago on Mac OS X and Windows) even if you don't use any alpha at all.
Disclaimer: Code examples have not been tested.