Convert Java Image Object to Byte Array

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;
            }
}

adamretterAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
Please post the exception stack trace
Mick BarryJava DeveloperCommented:
> I need to preserve all of the image information not just the pixels!

what other information specifically do u need?
Mick BarryJava DeveloperCommented:
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();
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

CEHJCommented:
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 DeveloperCommented:
And close baos.
adamretterAuthor 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)
adamretterAuthor 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...
CEHJCommented:
>>FAO CEHJ, here is the exception -

Is that *all* of it?
adamretterAuthor 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.
CEHJCommented:
Are there any exceptions lower down?
Mick BarryJava DeveloperCommented:
Check the color model of your original image, and set the color model of your BufferedImage to match it.
Mick BarryJava DeveloperCommented:
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);
adamretterAuthor Commented:
FAO CEHJ - no there are no exceptions further down
adamretterAuthor 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 DeveloperCommented:
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();
adamretterAuthor 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 DeveloperCommented:
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.
adamretterAuthor 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 DeveloperCommented:
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.
adamretterAuthor Commented:
What about the metadata of the image, I know that at least JPEG's can contain metadata?
Mick BarryJava DeveloperCommented:
> 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.
adamretterAuthor 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?
Mick BarryJava DeveloperCommented:
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.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
adamretterAuthor 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.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.