We help IT Professionals succeed at work.

Convert Java Image Object to Byte Array

adamretter
adamretter asked
on
Medium Priority
5,288 Views
Last Modified: 2008-01-09
I need to take a java Image object (java.awt.Image) and convert it to a byte array. I need to preserve all of the image information not just the pixels!

Basically I have a database, and I have read the image from the database into a byte array, I have then constructed an Image object from this byte array - this all works fine, I can render the image, manipulate it etc.
But now I need to go the other way and convert the Image object back to a byte array - this doesnt appear to be so easy!

The solution MUST work for both Sun JDK 1.4+ and 1.5+ and MUST NOT rely on any 3rd party libraries unless they are absolutely tiny and open source, although 3rd party libraries are not the prefered method!

The code I had originally found to do this (below) throws an exception at g,drawimage(...), and to be honset I dont understand enough about Java to fix it myself (ths solution does not have to include this code)-

private byte[] convertImageToByteArray(Image img, String MIMEType)
{
            try
              {
                  Iterator iter = ImageIO.getImageWritersByMIMEType(MIMEType);
                  ImageWriter writer = iter.hasNext() ? (ImageWriter) iter.next() : null;
                  ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
                  writer.setOutput(ios);
                  BufferedImage rendImage = null;
                  if(img instanceof BufferedImage)
                  {
                      rendImage = (BufferedImage) img;
                  }
                  else
                  {
                      MediaTracker tracker = new MediaTracker(this);
                      tracker.addImage(img, 0);
                      tracker.waitForAll();
                      rendImage = new BufferedImage(img.getWidth(null), img.getHeight(null), 1);
                      Graphics g = rendImage.createGraphics();
                      g.drawImage(img, 0, 0, null);
                  }
                  writer.write(new IIOImage(rendImage, null, null));
                  writer.dispose();
                  return baos.toByteArray();
              }
            catch(Exception e)
            {
                  e.printStackTrace();//temp
                  return null;
            }
}

Comment
Watch Question

CERTIFIED EXPERT
Top Expert 2016

Commented:
Please post the exception stack trace
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
> I need to preserve all of the image information not just the pixels!

what other information specifically do u need?
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
try:

                     MediaTracker tracker = new MediaTracker(this);
                     tracker.addImage(img, 0);
                     tracker.waitForAll();
                     rendImage = new BufferedImage(img.getWidth(null), img.getHeight(null), 1);
                     Graphics g = rendImage.createGraphics();
                     g.drawImage(img, 0, 0, null);
                     tracker.addImage(rendImage, 1);
                     tracker.waitForAll();
CERTIFIED EXPERT
Top Expert 2016

Commented:
You needn't worry about that. It *will* be preserved (otherwise it wouldn't be possible to reconstitute the image from a file)
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
And close baos.

Author

Commented:
FAO CEHJ, here is the exception -

java.lang.ClassCastException: [I
      at java.awt.image.ColorModel.getAlpha(ColorModel.java:814)
      at java.awt.image.ColorModel.getRGB(ColorModel.java:859)
      at sun.awt.image.ImageRepresentation.convertToRGB(ImageRepresentation.java:271)
      at sun.awt.image.ImageRepresentation.setPixels(ImageRepresentation.java:485)
      at java.awt.image.AreaAveragingScaleFilter.accumPixels(AreaAveragingScaleFilter.java:196)
      at java.awt.image.AreaAveragingScaleFilter.setPixels(AreaAveragingScaleFilter.java:235)
      at sun.awt.image.OffScreenImageSource.sendPixels(OffScreenImageSource.java:84)
      at sun.awt.image.OffScreenImageSource.produce(OffScreenImageSource.java:169)
      at sun.awt.image.OffScreenImageSource.addConsumer(OffScreenImageSource.java:48)
      at sun.awt.image.OffScreenImageSource.startProduction(OffScreenImageSource.java:62)
      at java.awt.image.FilteredImageSource.startProduction(FilteredImageSource.java:166)
      at sun.awt.image.ImageRepresentation.startProduction(ImageRepresentation.java:647)
      at sun.awt.image.ImageRepresentation.drawToBufImage(ImageRepresentation.java:722)
      at sun.java2d.pipe.DrawImage.copyImage(DrawImage.java:883)
      at sun.java2d.pipe.ValidatePipe.copyImage(ValidatePipe.java:168)
      at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2847)
      at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2832)
      at org.exist.xquery.modules.image.ScaleFunction$ImageConversion.convertImageToByteArray(ScaleFunction.java:266)

Author

Commented:
FAO objects,

The code that you propose wont make any difference, because as I mentioned the exception is thrown at g.drawImage() which happends before your suggested changes...
CERTIFIED EXPERT
Top Expert 2016

Commented:
>>FAO CEHJ, here is the exception -

Is that *all* of it?

Author

Commented:
It goes lower but there is no point posting that, as it is just the code in existing modules of a collaborative open source project that are known to work. All the code I have written for this is in org.exist.xquery.modules.image.ScaleFunction, everything below can be safely ignored I believe.
CERTIFIED EXPERT
Top Expert 2016

Commented:
Are there any exceptions lower down?
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Check the color model of your original image, and set the color model of your BufferedImage to match it.
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
for example if it's rgb with transparency (which it looks like) use:

 rendImage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_ARGB);

Author

Commented:
FAO CEHJ - no there are no exceptions further down

Author

Commented:
FAO objects -

There is no BufferedImage.TYPE_ARGB, so I have tried -

TYPE_INT_ARGB
TYPE_INT_ARGB_PRE
TYPE_4BYTE_ABGR
TYPE_4BYTE_ABGR_PRE

They still seem to cause the same exception as before.

This function has to work on any image type, be it PNG, JPEG, GIF or BMP etc...
So hardcoding something like that probably wont work for me.

Whats next?
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Problem you're going to have is that you cannot determine things like the ColorModel from Image class.
So preserviing all the details of the original image will be difficult. In fact how you are converting the image you're going to lose details of the original image aren't you.

to get the original images color model try:

PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
pg.grabPixels();
ColorModel cm = pg.getColorModel();

you can then use that when creating the new image
or use it to determine whether the image uhas transparency

boolean transparent = cm.hasAlpha();

Author

Commented:
FAO Objects -

I think you are going to hold my hand a bit more,

The constructor of BufferedImage will take a ColorModel but it also wants an ImageType, where do I get this imageType from?

Rather than these piecemeal suggestions, What I would really like is a full tested solution here for converting an java.awt.Image to a byte array without loosing any of the image information. Basically I am trying to store a java.awt.Image in a db.

Do I need to increase the points for this? I can offer double the points (1000) for the correct fully working solution...
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
What exactly is it you don't want to lose, other than the array of pixel values?
Why not just use PixelGrabber to grab the image pixel values as an array.

http://java.sun.com/j2se/1.5.0/docs/api/java/awt/image/PixelGrabber.html

Providing complete solutions is beyond the scope of this site sorry.

Author

Commented:
I dont want to loose any data about the image.

I need to be able to store the image in a db, so later I can get it out the db and reconstruct it from a byte array. I have sucessfully written and tested the code for getting an image from a byte array stored in the db, I can retreive the image from the db into an java.awt.Image object and view the Image, no problem.

Now I need the other end of the process, to take a java.awt.Image and convert it in its entirety to a byte array so i can then store if back to the db.

"Providing complete solutions is beyond the scope of this site sorry" - Why? This site is about asking questions and gettings answers,  I think I have had solutions given for previous questions I have asked on this site in the past. All you need do is post the java code in one of these comment boxes that will do the job.

Im offering 1000 points.
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
Then it sounds like PixelGrabber will meet your needs

int[] pixels = new int[w * h];
PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
pg.grabPixels();

pixels will now contain the value of all pixels in the image.

Author

Commented:
What about the metadata of the image, I know that at least JPEG's can contain metadata?
Mick BarryJava Developer
CERTIFIED EXPERT
Top Expert 2010

Commented:
> What about the metadata of the image, I know that at least JPEG's can contain metadata?

You've already lost that when u converted to Image class.
If you don't want to lose it then you'll need to store the original image.

Author

Commented:
Okay so I have the original image in its entirely stored in the db, I can retreive this from the db as a byte array.

Now the bigger picture is this, I am retreiving this image so that i can Scale it, which is why I was using the java.awt.Image Object, I then want to store the scaled Image back to the db, which is why I was asking how to convert an Image to a byte array. I did not realise that converting from the byte array to a java.awt.Image meant that I would loose additional image information, and if this is the case, how come its still possible to call Image.getProperty("comment"...) ?

Whats my best bet then?
Java Developer
CERTIFIED EXPERT
Top Expert 2010
Commented:
I'd suggest using BufferedImage instead of Image, it contains a lot more detail about the image.
And will also get rid of the error you are having above.
Sopunds like you may also want to encode the image to a byte array in its original format so you may need to also store what that format is.

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts

Author

Commented:
I diagree, this issue has not yet been solved. The answers have been very piecemeal and not really what I asked for. I would like this question to remain open.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.