Save ReadableByteChannel as PNG - java

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
}

Related

Image size increases after processing in Graphics2D

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 to compress image with PNG extension [duplicate]

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"));

Converting byte array to jpg image file throughing exception

Hi I have a byte array that I am converting to jpg image but that is giving exception as below please explain me wht is the problem with this.
ByteArrayInputStream bis = new ByteArrayInputStream(someByteArray);
Iterator<?> readers = ImageIO.getImageReadersByFormatName("jpg");
//ImageIO is a class containing static methods for locating ImageReaders
//and ImageWriters, and performing simple encoding and decoding.
ImageReader reader = (ImageReader) readers.next();
Object source = bis;
ImageInputStream iis = ImageIO.createImageInputStream(source);
reader.setInput(iis, true);
ImageReadParam param = reader.getDefaultReadParam();
BufferedImage image = reader.read(0, param);
//got an image file
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
//bufferedImage is the RenderedImage to be written
Graphics2D g2 = bufferedImage.createGraphics();
g2.drawImage(image, null, null);
File imageFile = new File("D:\\newrose2.jpg");
ImageIO.write(bufferedImage, "jpg", imageFile);
Exception:
javax.imageio.IIOException: Invalid JPEG file structure: SOS before SOF
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImageHeader(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readNativeHeader(JPEGImageReader.java:550)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readNativeHeader(JPEGImageReader.java:550)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.checkTablesOnly(JPEGImageReader.java:295)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.gotoImage(JPEGImageReader.java:427)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readHeader(JPEGImageReader.java:543)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:986)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:966)
at Trnsport.writejpegfile(Trnsport.java:398)
at Trnsport.getData(Trnsport.java:107)
at Trnsport.run(Trnsport.java:63)
at java.lang.Thread.run(Thread.java:722)
Edit:
FileOutputStream fos = new FileOutputStream("image" + new Date().getTime() + ".jpg");
fos.write(someByteArray);
fos.close();
If your byte array already contains valid JPEG data, you do not need to invoke the JPEG reader or writer -- you can write the bytes to the file using ordinary file I/O.
If the byte array actually contains some format of raw pixel data, you will need to load it into a BufferedImage directly (such as via setRGB) and encode that as a JPEG.
The fact that you're getting an exception trying to decode it implies it is not JPEG data, but raw pixel data. Or, perhaps it is a different type of image altogether, or it has an image at some offset into the array instead of at the start the array, or it is not an image at all.

BufferedImage Raster Data to BufferedImage

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.

Write CMYK image in PDF

I need to add a CMYK Image (java.awt.BufferedImage) to a Pdf-Document with iText.
I'm trying to do it with:
com.lowagie.text.Image img = Image.getInstance(BufferedImage, bgColor);
This produces an RGB image in the resulting PDF. (and I suppose it's a bug, because it just ignores ColorModel). However I could use:
com.lowagie.text.Image img = Image.getInstance(byte[] rawData);
And it produces a correct CMYK-Image in PDF. But for the second case I need to convert java.awt.BufferedImage in ByteArray. I cannot do it with ImageIO.write(ByteArrayOutputStream). I also cannot do it with com.sun.image.codec.jpeg.JPEGImageEncoder because I must use OpenJDK.
Any ideas how can I achieve the correct behavior to write a CMYK image in PDF using iText?
So basically what you're asking is how to convert a BufferedImage to a byte[] to print to PDF?
BufferedImage img; // your image to be printed
String formatName; // name of the image format (see ImageIO docs)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write( img, formatName, baos);
byte[] rawData = baos.toByteArray();
You should be able to use that for the CMYK-image as you had in your original post:
com.lowagie.text.Image img = Image.getInstance(byte[] rawData);

Categories

Resources