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"));
Related
I have a function generateImageOutput below to write BufferedImage to jpeg file.
public boolean generateImageOutput(BufferedImage image, String filename){
//The image is written to the file by the writer
File file = new File( projectFolder+"/data/"+filename+".jpg");
//Iterator containing all ImageWriter (JPEG)
Iterator encoder = ImageIO.getImageWritersByFormatName("JPEG");
ImageWriter writer = (ImageWriter) encoder.next();
//Compression parameter (best quality)
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1.0f);
//Try to write the image
try{
ImageOutputStream outputStream = ImageIO.createImageOutputStream(file);
writer.setOutput(outputStream);
writer.write(null, new IIOImage(image, null, null), param);
outputStream.flush();
writer.dispose();
outputStream.close();
}catch(IOException e){
e.printStackTrace();
System.out.println(e.toString());
return false;
}
return true;
}
It works for some, but it fails for a BufferedImage converted from base64 string:
String encodedString = JSON.parseObject(string).getString("image");
byte[] decodedBytes = Base64.getDecoder().decode(encodedString);
ByteArrayInputStream bis = new ByteArrayInputStream(decodedBytes);
buffered_image = ImageIO.read(bis);
When writing the above buffered_image to jpeg using generateImageOutput, it raises exception :
javax.imageio.IIOException: Bogus input colorspace
at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeImage(Native Method)
at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeOnThread(JPEGImageWriter.java:1007)
at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:371)
The string encodedString has no issue, I have sucessfully converted it to an image online.
How can I resolve the exception ?
According to #J.doe Alpha channel must be remove. I have a code that removes the Alpha channel. The code below was to determine whether or not the image has alpha channel. If the image has alpha channel it will create an image without alpha channel.
private static BufferedImage removeAlphaChannel(BufferedImage img) {
if (!img.getColorModel().hasAlpha()) {
return img;
}
BufferedImage target = createImage(img.getWidth(), img.getHeight(), false);
Graphics2D g = target.createGraphics();
// g.setColor(new Color(color, false));
g.fillRect(0, 0, img.getWidth(), img.getHeight());
g.drawImage(img, 0, 0, null);
g.dispose();
return target;
}
private static BufferedImage createImage(int width, int height, boolean hasAlpha) {
return new BufferedImage(width, height, hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
}
Finally I find that the reason is the image has an ALPHA channel.
Looks like JPEG doesn't handle the alpha channel correctly in this context. For me saving the image as PNG did the trick.
I have raw grayscale image pixels represented by short[]. I would like to create BufferedImage from it and save it as PNG.
Since there is no TYPE_SHORT_GRAY defined for BufferedImage I'm creating one myself this way:
short[] myRawImageData;
// Create signed 16 bit data buffer, and compatible sample model
DataBuffer dataBuffer = new DataBufferShort(myRawImageData, w * h);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_SHORT, w, h, 1, w, new int[] {0});
// Create a raster from sample model and data buffer
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
// Create a 16 bit signed gray color model
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_SHORT);
// Finally create the signed 16 bit image
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
try (FileOutputStream fos = new FileOutputStream("/tmp/tst.png")) {
ImageIO.write(image, "png", fos);// <--- Here goes the exception
} catch (Exception ex) {
ex.printStackTrace();
}
So far so good but when I'm trying to use ImageIO.write to save it as PNG I'm getting ArrayIndexOutOfBoundsException.
Your code works fine for me, the only way I got your error was when I changed the bandOffsets. Could you give us more of your code?
EDIT
If you have negative data in your dataset, you should probably be using ushort instead of short.
int h = 64, w = 64;
short[] myRawImageData = new short[4096];
for (int i = 0; i < 4096; i++){
//this rolls over into negative numbers
myRawImageData[i] = (short) (i * 14);
}
// Create signed 16 bit data buffer, and compatible sample model
DataBuffer dataBuffer = new DataBufferUShort(myRawImageData, w * h);
SampleModel sampleModel = new ComponentSampleModel(DataBuffer.TYPE_USHORT, w, h, 1, w, new int[] {0});
// Create a raster from sample model and data buffer
WritableRaster raster = Raster.createWritableRaster(sampleModel, dataBuffer, null);
// Create a 16 bit signed gray color model
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorModel colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
// Finally create the signed 16 bit image
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
try (FileOutputStream fos = new FileOutputStream("/tmp/tst.png")) {
ImageIO.write(image, "png", fos);// <--- Here goes the exception
} catch (Exception ex) {
ex.printStackTrace();
}
This is assuming you expect negative values to be the brighter half of the gamut.
I have an image captured by a camera, in RAW BGRA format (byte array).
How can I save it to disk, as a JPG/PNG file?
I've tried with ImageIO.write from Java API, but I got error IllegalArgumentException (image = null)
CODE:
try
{
InputStream input = new ByteArrayInputStream(img);
BufferedImage bImageFromConvert = ImageIO.read(input);
String path = "D:/image.jpg";
ImageIO.write(bImageFromConvert, "jpg", new File(path));
}
catch(Exception ex)
{
System.out.println(ex.toString());
}
Note that "img" is the RAW byte array, and that is NOT null.
The problem is that ImageIO.read does not support raw RGB (or BGRA in your case) pixels. It expects a file format, like BMP, PNG or JPEG, etc.
In your code above, this causes bImageFromConvert to become null, and this is the reason for the error you see.
If you have a byte array in BGRA format, try this:
// You need to know width/height of the image
int width = ...;
int height = ...;
int samplesPerPixel = 4;
int[] bandOffsets = {2, 1, 0, 3}; // BGRA order
byte[] bgraPixelData = new byte[width * height * samplesPerPixel];
DataBuffer buffer = new DataBufferByte(bgraPixelData, bgraPixelData.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 = 0 ...
ImageIO.write(image, "PNG", new File(path));
Note that JPEG is not a good format for storing images with alpha channel. While it is possible, most software will not display it properly. So I suggest using PNG instead.
Alternatively, you could remove the alpha channel, and use JPEG.
With Matlab you can convert all types of images with 2 lines of code:
img=imread('example.CR2');
imwrite(img,'example.JPG');
I want to send ImageIcon to database using jdbc.
I need to File object to do that.
How to convert ImageIcon to File wihout saving it into disk?
File fBlob = new File(imageIcon.getImage());
FileInputStream is = new FileInputStream ( fBlob );
preparedStatement.setBinaryStream (3, is, (int) fBlob.length() );
May be you could try to get a byte array from the imageIcon and then write it to the database. Something like this :
BufferedImage bi = getBufferedImage(imageIcon.getImage());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(bi, formatType, baos);
byte[] byteArray= baos.toByteArray();
preparedStatement.setBytes(1, byteArray);
EDIT :
Use this method to convert the Image to a BufferedImage :
public static BufferedImage getBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null),
img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
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.