I am trying to write a method that takes an image, and saves a 100 by 100 thumbnail of that image. However, when I save the file, it comes out as an unreadable 0 byte image (with the error "Error interpreting JPEG image file (Improper call to JPEG library in state 200)") in Ubuntu's ImageViewer. My code is as follows:
public boolean scale(){
String file = filename.substring(filename.lastIndexOf(File.separator)+1);
File out = new File("data"+File.separator+"thumbnails"+File.separator+file);
if( out.exists() ) return false;
BufferedImage bi;
try{
bi = ImageIO.read(new File(filename));
}
catch(IOException e){
return false;
}
Dimension imgSize = new Dimension(bi.getWidth(), bi.getHeight());
Dimension bounds = new Dimension(100, 100);
int newHeight = imgSize.height;
int newWidth = imgSize.width;
if( imgSize.width > bounds.width ){
newWidth = bounds.width;
newHeight = (newWidth*imgSize.height)/imgSize.width;
}
if( imgSize.height > bounds.width ){
newHeight = bounds.height;
newWidth = (newHeight*imgSize.width)/imgSize.height;
}
Image img = bi.getScaledInstance(newWidth, newHeight, BufferedImage.SCALE_SMOOTH);
BufferedImage thumb = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = thumb.createGraphics();
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
try{
ImageIO.write(thumb, "jpg", out);
}
catch(IOException e){
return false;
}
return true;
}
Where "filename" is a global variable for the class housing this method, representing the path to the original image. My main issue is that I do not see why I'm creating a 0 byte image.
So, the issue was this. I'm working in OpenJDK. OpenJDK doesn't have a JPEG encoder, apparently, so while the file was being created by
ImageIO.write(thumb, "jpg", out);
it wasn't actually creating anything for the file to save; hence the empty 0 byte unreadable file. Changing the ImageIO argument to "png" (and adjusting the new File() extension, appropriately) successfully created the desired image with the above code.
I experienced the same issue even though the JVM had a JPG encoder and it was caused by using an unsupported type of BufferImage underneath. I had used BufferedImage.TYPE_USHORT_GRAY which is evidently not supported and gave no error messages but produced a 0 byte file. When I switched to BufferedImage.TYPE_BYTE_GRAY it worked perfectly.
JPG have no alpha channel, ImageIO.write() will fail silently (just return false) one way is to copy your image into another one
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.getGraphics().drawImage(bufferedImage, 0, 0, null);
boolean write = ImageIO.write(newBufferedImage, extension, outputfile);
if (!write) {
// do something
}
Related
I have a PNG image and I want to resize it. How can I do that? Though I have gone through this I can't understand the snippet.
If you have an java.awt.Image, resizing it doesn't require any additional libraries. Just do:
Image newImage = yourImage.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
Obviously, replace newWidth and newHeight with the dimensions of the specified image.
Notice the last parameter: it tells the runtime the algorithm you want to use for resizing.
There are algorithms that produce a very precise result, however these take a large time to complete.
You can use any of the following algorithms:
Image.SCALE_DEFAULT: Use the default image-scaling algorithm.
Image.SCALE_FAST: Choose an image-scaling algorithm that gives higher priority to scaling speed than smoothness of the scaled image.
Image.SCALE_SMOOTH: Choose an image-scaling algorithm that gives higher priority to image smoothness than scaling speed.
Image.SCALE_AREA_AVERAGING: Use the Area Averaging image scaling algorithm.
Image.SCALE_REPLICATE: Use the image scaling algorithm embodied in the ReplicateScaleFilter class.
See the Javadoc for more info.
We're doing this to create thumbnails of images:
BufferedImage tThumbImage = new BufferedImage( tThumbWidth, tThumbHeight, BufferedImage.TYPE_INT_RGB );
Graphics2D tGraphics2D = tThumbImage.createGraphics(); //create a graphics object to paint to
tGraphics2D.setBackground( Color.WHITE );
tGraphics2D.setPaint( Color.WHITE );
tGraphics2D.fillRect( 0, 0, tThumbWidth, tThumbHeight );
tGraphics2D.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
tGraphics2D.drawImage( tOriginalImage, 0, 0, tThumbWidth, tThumbHeight, null ); //draw the image scaled
ImageIO.write( tThumbImage, "JPG", tThumbnailTarget ); //write the image to a file
Try this:
ImageIcon icon = new ImageIcon(UrlToPngFile);
Image scaleImage = icon.getImage().getScaledInstance(28, 28,Image.SCALE_DEFAULT);
Resize image with high quality:
private static InputStream resizeImage(InputStream uploadedInputStream, String fileName, int width, int height) {
try {
BufferedImage image = ImageIO.read(uploadedInputStream);
Image originalImage= image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
int type = ((image.getType() == 0) ? BufferedImage.TYPE_INT_ARGB : image.getType());
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g2d = resizedImage.createGraphics();
g2d.drawImage(originalImage, 0, 0, width, height, null);
g2d.dispose();
g2d.setComposite(AlphaComposite.Src);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(resizedImage, fileName.split("\\.")[1], byteArrayOutputStream);
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
// Something is going wrong while resizing image
return uploadedInputStream;
}
}
int newHeight = 150;
int newWidth = 150;
holder.iv_arrow.requestLayout();
holder.iv_arrow.getLayoutParams().height = newHeight;
holder.iv_arrow.getLayoutParams().width = newWidth;
holder.iv_arrow.setScaleType(ImageView.ScaleType.FIT_XY);
holder.iv_arrow.setImageResource(R.drawable.video_menu);
Simple way in Java
public void resize(String inputImagePath,
String outputImagePath, int scaledWidth, int scaledHeight)
throws IOException {
// reads input image
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// extracts extension of output file
String formatName = outputImagePath.substring(outputImagePath
.lastIndexOf(".") + 1);
// writes to output file
ImageIO.write(outputImage, formatName, new File(outputImagePath));
}
Design jLabel first:
JLabel label1 = new JLabel("");
label1.setHorizontalAlignment(SwingConstants.CENTER);
label1.setBounds(628, 28, 169, 125);
frame1.getContentPane().add(label1); //frame1 = "Jframe name"
Then you can code below code:
ImageIcon imageIcon1 = new ImageIcon(new ImageIcon("add location url").getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT)); //100, 100 add your own size
label1.setIcon(imageIcon1);
I'm trying to save an image in bmp format, but it doesn't create any file.
If I use "png" instead, everything works fine.
Any ideas?
//This works fine:
ImageIO.write(bi, "png", new File("D:\\MyImage.png"));
//This does not work:
ImageIO.write(bi, "bmp", new File("D:\\MyImage.bmp"));
ImageIO.getWriterFormatNames() gives me "jpg", "bmp", "jpeg" and some others..
Thanks in advance.
Jakob
I just finished debugging a similar problem and I thought I will present my reasoning here, although Jakob has gone ahead with the PNG format.
First, always check the return value of ImageIO.write(...). It will return false if no appropriate writer can be found and that's what should have happened when Jakob tried writing it as a bitmap. This happens when the actual image format of the file does not match what is given in the 'format name' argument. No exception is thrown in this case. Check out the docs at http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage, java.lang.String, java.io.File)
Second, check the image type of the BufferedImage object by using the BufferedImage#getType() method. Check out the possible return values at http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType(). For example, If you get the type as TYPE_INT_ARGB from your BufferedImage object (which represents a PNG with a alpha component) you wont have success using ImageIO.write(bi, "BMP", new File("D:\\test.bmp")) and the method would return false, even though you can see BMP/bmp in the list of entries obtained using ImageIO.getWriterFormatNames(). You might have to work on the encoding and transform your image to the desired format.
Third, when facing such problems which can be a pain sometimes, it always helps to use an image editor such as GIMP to check out your image properties in detail.
#Green arrow, a minor note... you can use either "bmp" or "BMP" as the image format value. The same applies for other formats as well. It does not matter.
As #bincob says, if write returns false, you can redraw the source image like this
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
And then you can write again.
Using BufferedImage.TYPE_INT_RGB encoding works for "gif","png","tif" as well as "jpg" and "bmp":
static void saveBufferedImageToFileTest(){
String[] types = new String[] {"gif","png","tif","jpg","bmp"};
//JPEG and BMP needs BufferedImage.TYPE_INT_RGB. See https://mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
//BufferedImage.TYPE_INT_RGB for all `types`
int biType = BufferedImage.TYPE_INT_RGB; // BufferedImage.TYPE_INT_ARGB does not work for "bmp" and "jpeg"
BufferedImage bi = new BufferedImage(200 ,200, biType);
Graphics g = bi.getGraphics();
g.fillRect(50, 50, 100, 100);
g.dispose();
try {
for(String type : types){
boolean success = ImageIO.write(bi,type,new File("test_image."+type));
System.out.println(type + (success ? " file created" : " file NOT created") );
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
didn't try but I think the format should be "BMP" and not "bmp" actually.
Please try with
ImageIO.write(bi, "BMP", new File("D:\\MyImage.bmp"));
and see what happens.
We can't see how your bi is build.
BufferedImage bufferedImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Is the encodingType is set properly ?
I think your bi is corrupted, that's work perfectly for me.
BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB);
Graphics gd = bi.getGraphics();
gd.drawRect(0, 0, 10, 10);
try {
ImageIO.write(bi, "BMP", new File("C:\\test.bmp"));
ImageIO.write(bi, "PNG", new File("C:\\test.png"));
} catch (IOException e) {
System.out.println("error "+e.getMessage());
}
An oldie, but BMPs are still useful occasionally and the answers above all skirt the best solution: do it yourself. That way it works for any type of bitmap.
static void writeBMP(BufferedImage image, File f) throws IOException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
int width = image.getWidth();
int height = image.getHeight();
int row = (width * 3 + 3) / 4 * 4;
out.write('B');
out.write('M');
writeInt(out, 14 + 40 + row * height); // file size
writeInt(out, 0);
writeInt(out, 14 + 40); // bitmap offset
writeInt(out, 40); // size
writeInt(out, width); // width
writeInt(out, height); // weight
writeInt(out, (24<<16) | 1); // planes, bpp
writeInt(out, 0); // compression
writeInt(out, row * height); // bitmap size
writeInt(out, 0); // resx
writeInt(out, 0); // resy
writeInt(out, 0); // used colors
writeInt(out, 0); // important colors
for (int y=height-1;y>=0;y--) {
for (int x=0;x<width;x++) {
int rgba = image.getRGB(x, y);
out.write(rgba & 0xFF); // b
out.write(rgba >> 8); // g
out.write(rgba >> 16); // r
}
for (int x=width*3;x%4!=0;x++) { // pad to 4 bytes
out.write(0);
}
}
out.close();
}
private static void writeInt(OutputStream out, int v) throws IOException {
out.write(v);
out.write(v >> 8);
out.write(v >> 16);
out.write(v >> 24);
}
I have a PNG image and I want to resize it. How can I do that? Though I have gone through this I can't understand the snippet.
If you have an java.awt.Image, resizing it doesn't require any additional libraries. Just do:
Image newImage = yourImage.getScaledInstance(newWidth, newHeight, Image.SCALE_DEFAULT);
Obviously, replace newWidth and newHeight with the dimensions of the specified image.
Notice the last parameter: it tells the runtime the algorithm you want to use for resizing.
There are algorithms that produce a very precise result, however these take a large time to complete.
You can use any of the following algorithms:
Image.SCALE_DEFAULT: Use the default image-scaling algorithm.
Image.SCALE_FAST: Choose an image-scaling algorithm that gives higher priority to scaling speed than smoothness of the scaled image.
Image.SCALE_SMOOTH: Choose an image-scaling algorithm that gives higher priority to image smoothness than scaling speed.
Image.SCALE_AREA_AVERAGING: Use the Area Averaging image scaling algorithm.
Image.SCALE_REPLICATE: Use the image scaling algorithm embodied in the ReplicateScaleFilter class.
See the Javadoc for more info.
We're doing this to create thumbnails of images:
BufferedImage tThumbImage = new BufferedImage( tThumbWidth, tThumbHeight, BufferedImage.TYPE_INT_RGB );
Graphics2D tGraphics2D = tThumbImage.createGraphics(); //create a graphics object to paint to
tGraphics2D.setBackground( Color.WHITE );
tGraphics2D.setPaint( Color.WHITE );
tGraphics2D.fillRect( 0, 0, tThumbWidth, tThumbHeight );
tGraphics2D.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
tGraphics2D.drawImage( tOriginalImage, 0, 0, tThumbWidth, tThumbHeight, null ); //draw the image scaled
ImageIO.write( tThumbImage, "JPG", tThumbnailTarget ); //write the image to a file
Try this:
ImageIcon icon = new ImageIcon(UrlToPngFile);
Image scaleImage = icon.getImage().getScaledInstance(28, 28,Image.SCALE_DEFAULT);
Resize image with high quality:
private static InputStream resizeImage(InputStream uploadedInputStream, String fileName, int width, int height) {
try {
BufferedImage image = ImageIO.read(uploadedInputStream);
Image originalImage= image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
int type = ((image.getType() == 0) ? BufferedImage.TYPE_INT_ARGB : image.getType());
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g2d = resizedImage.createGraphics();
g2d.drawImage(originalImage, 0, 0, width, height, null);
g2d.dispose();
g2d.setComposite(AlphaComposite.Src);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(resizedImage, fileName.split("\\.")[1], byteArrayOutputStream);
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
// Something is going wrong while resizing image
return uploadedInputStream;
}
}
int newHeight = 150;
int newWidth = 150;
holder.iv_arrow.requestLayout();
holder.iv_arrow.getLayoutParams().height = newHeight;
holder.iv_arrow.getLayoutParams().width = newWidth;
holder.iv_arrow.setScaleType(ImageView.ScaleType.FIT_XY);
holder.iv_arrow.setImageResource(R.drawable.video_menu);
Simple way in Java
public void resize(String inputImagePath,
String outputImagePath, int scaledWidth, int scaledHeight)
throws IOException {
// reads input image
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth,
scaledHeight, inputImage.getType());
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// extracts extension of output file
String formatName = outputImagePath.substring(outputImagePath
.lastIndexOf(".") + 1);
// writes to output file
ImageIO.write(outputImage, formatName, new File(outputImagePath));
}
Design jLabel first:
JLabel label1 = new JLabel("");
label1.setHorizontalAlignment(SwingConstants.CENTER);
label1.setBounds(628, 28, 169, 125);
frame1.getContentPane().add(label1); //frame1 = "Jframe name"
Then you can code below code:
ImageIcon imageIcon1 = new ImageIcon(new ImageIcon("add location url").getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT)); //100, 100 add your own size
label1.setIcon(imageIcon1);
I'm trying to save an image in bmp format, but it doesn't create any file.
If I use "png" instead, everything works fine.
Any ideas?
//This works fine:
ImageIO.write(bi, "png", new File("D:\\MyImage.png"));
//This does not work:
ImageIO.write(bi, "bmp", new File("D:\\MyImage.bmp"));
ImageIO.getWriterFormatNames() gives me "jpg", "bmp", "jpeg" and some others..
Thanks in advance.
Jakob
I just finished debugging a similar problem and I thought I will present my reasoning here, although Jakob has gone ahead with the PNG format.
First, always check the return value of ImageIO.write(...). It will return false if no appropriate writer can be found and that's what should have happened when Jakob tried writing it as a bitmap. This happens when the actual image format of the file does not match what is given in the 'format name' argument. No exception is thrown in this case. Check out the docs at http://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#write(java.awt.image.RenderedImage, java.lang.String, java.io.File)
Second, check the image type of the BufferedImage object by using the BufferedImage#getType() method. Check out the possible return values at http://docs.oracle.com/javase/7/docs/api/java/awt/image/BufferedImage.html#getType(). For example, If you get the type as TYPE_INT_ARGB from your BufferedImage object (which represents a PNG with a alpha component) you wont have success using ImageIO.write(bi, "BMP", new File("D:\\test.bmp")) and the method would return false, even though you can see BMP/bmp in the list of entries obtained using ImageIO.getWriterFormatNames(). You might have to work on the encoding and transform your image to the desired format.
Third, when facing such problems which can be a pain sometimes, it always helps to use an image editor such as GIMP to check out your image properties in detail.
#Green arrow, a minor note... you can use either "bmp" or "BMP" as the image format value. The same applies for other formats as well. It does not matter.
As #bincob says, if write returns false, you can redraw the source image like this
BufferedImage newBufferedImage = new BufferedImage(bufferedImage.getWidth(),
bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0, Color.WHITE, null);
And then you can write again.
Using BufferedImage.TYPE_INT_RGB encoding works for "gif","png","tif" as well as "jpg" and "bmp":
static void saveBufferedImageToFileTest(){
String[] types = new String[] {"gif","png","tif","jpg","bmp"};
//JPEG and BMP needs BufferedImage.TYPE_INT_RGB. See https://mkyong.com/java/convert-png-to-jpeg-image-file-in-java/
//BufferedImage.TYPE_INT_RGB for all `types`
int biType = BufferedImage.TYPE_INT_RGB; // BufferedImage.TYPE_INT_ARGB does not work for "bmp" and "jpeg"
BufferedImage bi = new BufferedImage(200 ,200, biType);
Graphics g = bi.getGraphics();
g.fillRect(50, 50, 100, 100);
g.dispose();
try {
for(String type : types){
boolean success = ImageIO.write(bi,type,new File("test_image."+type));
System.out.println(type + (success ? " file created" : " file NOT created") );
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
didn't try but I think the format should be "BMP" and not "bmp" actually.
Please try with
ImageIO.write(bi, "BMP", new File("D:\\MyImage.bmp"));
and see what happens.
We can't see how your bi is build.
BufferedImage bufferedImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
Is the encodingType is set properly ?
I think your bi is corrupted, that's work perfectly for me.
BufferedImage bi = new BufferedImage(50,50,BufferedImage.TYPE_INT_RGB);
Graphics gd = bi.getGraphics();
gd.drawRect(0, 0, 10, 10);
try {
ImageIO.write(bi, "BMP", new File("C:\\test.bmp"));
ImageIO.write(bi, "PNG", new File("C:\\test.png"));
} catch (IOException e) {
System.out.println("error "+e.getMessage());
}
An oldie, but BMPs are still useful occasionally and the answers above all skirt the best solution: do it yourself. That way it works for any type of bitmap.
static void writeBMP(BufferedImage image, File f) throws IOException {
OutputStream out = new BufferedOutputStream(new FileOutputStream(f));
int width = image.getWidth();
int height = image.getHeight();
int row = (width * 3 + 3) / 4 * 4;
out.write('B');
out.write('M');
writeInt(out, 14 + 40 + row * height); // file size
writeInt(out, 0);
writeInt(out, 14 + 40); // bitmap offset
writeInt(out, 40); // size
writeInt(out, width); // width
writeInt(out, height); // weight
writeInt(out, (24<<16) | 1); // planes, bpp
writeInt(out, 0); // compression
writeInt(out, row * height); // bitmap size
writeInt(out, 0); // resx
writeInt(out, 0); // resy
writeInt(out, 0); // used colors
writeInt(out, 0); // important colors
for (int y=height-1;y>=0;y--) {
for (int x=0;x<width;x++) {
int rgba = image.getRGB(x, y);
out.write(rgba & 0xFF); // b
out.write(rgba >> 8); // g
out.write(rgba >> 16); // r
}
for (int x=width*3;x%4!=0;x++) { // pad to 4 bytes
out.write(0);
}
}
out.close();
}
private static void writeInt(OutputStream out, int v) throws IOException {
out.write(v);
out.write(v >> 8);
out.write(v >> 16);
out.write(v >> 24);
}
I am trying to write out a png file from a java.awt.image.BufferedImage. Everything works fine but the resulting png is a 32-bit file.
Is there a way to make the png file be 8-bit? The image is grayscale, but I do need transparency as this is an overlay image. I am using java 6, and I would prefer to return an OutputStream so that I can have the calling class deal with writing out the file to disk/db.
Here is the relevant portion of the code:
public static ByteArrayOutputStream createImage(InputStream originalStream)
throws IOException {
ByteArrayOutputStream oStream = null;
java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream);
int imgWidth = newImg.getWidth(null);
int imgHeight = newImg.getHeight(null);
java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth,
imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);
Color bckgrndColor = new Color(0x80, 0x80, 0x80);
Graphics2D gf = (Graphics2D)bim.getGraphics();
// set transparency for fill image
gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
gf.setColor(bckgrndColor);
gf.fillRect(0, 0, imgWidth, imgHeight);
oStream = new ByteArrayOutputStream();
javax.imageio.ImageIO.write(bim, "png", oStream);
oStream.close();
return oStream;
}
The build in imageio png writer will write 32bit png files on all the platforms I have used it on, no matter what the source image is. You should also be aware that many people have complained that the resulting compression is much lower than what is possible with the png format. There are several independent png libraries available that allow you to specify the exact format, but I don't actually have any experience with any of them.
I found the answer as to how to convert RGBA to Indexed here: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html
However, the resulting 8-bit png file only has 100% or 0% transparency. You could probably tweak the IndexColorModel arrays, but we have decided to make the generated file (what was an overlay mask) into an underlay jpg and use what was the static base as the transparent overlay.
It is an interesting question... It is late, I will experiment tomorrow. I will first try and use a BufferedImage.TYPE_BYTE_INDEXED (perhaps after drawing) to see if Java is smart enough to generate an 8bit PNG.
Or perhaps some image library can allow that.
[EDIT] Some years later... Actually, I made the code at the time, but forgot to update this thread... I used the code pointed at by Kat, with a little refinement on the handling of transparency, and saving in PNG format instead of Gif format. It works in making a 8-bit PNG file with all-or-nothing transparency.
You can find a working test file at http://bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.java
using my ImageUtil class.
Since the code isn't that big, for posterity sake, I post it here, without the JavaDoc to save some lines.
public class ImageUtil
{
public static int ALPHA_BIT_MASK = 0xFF000000;
public static BufferedImage imageToBufferedImage(Image image, int width, int height)
{
return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
}
public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type)
{
BufferedImage dest = new BufferedImage(width, height, type);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
g2.dispose();
return dest;
}
public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage)
{
// Create a non-transparent palletized image
Image flattenedImage = transformTransparencyToMagenta(srcImage);
BufferedImage flatImage = imageToBufferedImage(flattenedImage,
srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
BufferedImage destImage = makeColorTransparent(flatImage, 0, 0);
return destImage;
}
private static Image transformTransparencyToMagenta(BufferedImage image)
{
ImageFilter filter = new RGBImageFilter()
{
#Override
public final int filterRGB(int x, int y, int rgb)
{
int pixelValue = 0;
int opacity = (rgb & ALPHA_BIT_MASK) >>> 24;
if (opacity < 128)
{
// Quite transparent: replace color with transparent magenta
// (traditional color for binary transparency)
pixelValue = 0x00FF00FF;
}
else
{
// Quite opaque: get pure color
pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK;
}
return pixelValue;
}
};
ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y)
{
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image; // No transparency added as we don't have an indexed image
IndexColorModel originalICM = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM'
// Number of indexed colors
int size = originalICM.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
originalICM.getReds(reds);
originalICM.getGreens(greens);
originalICM.getBlues(blues);
IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex);
return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null);
}
}
Thanks for responding, I was going to try an TYPE_BYTE_INDEXED with an IndexColorModel and may still but if ImageIO writes out 32-bit regardless it appears that I may be wasting my time there.
The image I am trying to write out can be very large (up to 8000x4000) but is just a simple mask for the image underneath, so will only have a ~30% transparent gray and a 100% transparent cutout. I would use a GIF but IE6 seems to have trouble with displaying one that large.
It only gets generated once and in an internal set-up type screen, so performance isn't an issue either, but it does have to be done within the java code and not by an offline utility.
The libraries that you specified might be used to transform it while writing... I am going to go check that out.
If anyone has a better way, please let me know!!
Thanks!