adamretter
asked on
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(Im age img, String MIMEType)
{
try
{
Iterator iter = ImageIO.getImageWritersByM IMEType(MI METype);
ImageWriter writer = iter.hasNext() ? (ImageWriter) iter.next() : null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputS tream(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;
}
}
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(Im
{
try
{
Iterator iter = ImageIO.getImageWritersByM
ImageWriter writer = iter.hasNext() ? (ImageWriter) iter.next() : null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageOutputStream ios = ImageIO.createImageOutputS
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
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;
}
}
Please post the exception stack trace
> I need to preserve all of the image information not just the pixels!
what other information specifically do u need?
what other information specifically do u need?
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();
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 0);
tracker.waitForAll();
rendImage = new BufferedImage(img.getWidth
Graphics g = rendImage.createGraphics()
g.drawImage(img, 0, 0, null);
tracker.addImage(rendImage
tracker.waitForAll();
You needn't worry about that. It *will* be preserved (otherwise it wouldn't be possible to reconstitute the image from a file)
And close baos.
ASKER
FAO CEHJ, here is the exception -
java.lang.ClassCastExcepti on: [I
at java.awt.image.ColorModel. getAlpha(C olorModel. java:814)
at java.awt.image.ColorModel. getRGB(Col orModel.ja va:859)
at sun.awt.image.ImageReprese ntation.co nvertToRGB (ImageRepr esentation .java:271)
at sun.awt.image.ImageReprese ntation.se tPixels(Im ageReprese ntation.ja va:485)
at java.awt.image.AreaAveragi ngScaleFil ter.accumP ixels(Area AveragingS caleFilter .java:196)
at java.awt.image.AreaAveragi ngScaleFil ter.setPix els(AreaAv eragingSca leFilter.j ava:235)
at sun.awt.image.OffScreenIma geSource.s endPixels( OffScreenI mageSource .java:84)
at sun.awt.image.OffScreenIma geSource.p roduce(Off ScreenImag eSource.ja va:169)
at sun.awt.image.OffScreenIma geSource.a ddConsumer (OffScreen ImageSourc e.java:48)
at sun.awt.image.OffScreenIma geSource.s tartProduc tion(OffSc reenImageS ource.java :62)
at java.awt.image.FilteredIma geSource.s tartProduc tion(Filte redImageSo urce.java: 166)
at sun.awt.image.ImageReprese ntation.st artProduct ion(ImageR epresentat ion.java:6 47)
at sun.awt.image.ImageReprese ntation.dr awToBufIma ge(ImageRe presentati on.java:72 2)
at sun.java2d.pipe.DrawImage. copyImage( DrawImage. java:883)
at sun.java2d.pipe.ValidatePi pe.copyIma ge(Validat ePipe.java :168)
at sun.java2d.SunGraphics2D.d rawImage(S unGraphics 2D.java:28 47)
at sun.java2d.SunGraphics2D.d rawImage(S unGraphics 2D.java:28 32)
at org.exist.xquery.modules.i mage.Scale Function$I mageConver sion.conve rtImageToB yteArray(S caleFuncti on.java:26 6)
java.lang.ClassCastExcepti
at java.awt.image.ColorModel.
at java.awt.image.ColorModel.
at sun.awt.image.ImageReprese
at sun.awt.image.ImageReprese
at java.awt.image.AreaAveragi
at java.awt.image.AreaAveragi
at sun.awt.image.OffScreenIma
at sun.awt.image.OffScreenIma
at sun.awt.image.OffScreenIma
at sun.awt.image.OffScreenIma
at java.awt.image.FilteredIma
at sun.awt.image.ImageReprese
at sun.awt.image.ImageReprese
at sun.java2d.pipe.DrawImage.
at sun.java2d.pipe.ValidatePi
at sun.java2d.SunGraphics2D.d
at sun.java2d.SunGraphics2D.d
at org.exist.xquery.modules.i
ASKER
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...
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...
>>FAO CEHJ, here is the exception -
Is that *all* of it?
Is that *all* of it?
ASKER
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.i mage.Scale Function, everything below can be safely ignored I believe.
Are there any exceptions lower down?
Check the color model of your original image, and set the color model of your BufferedImage to match it.
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);
rendImage = new BufferedImage(img.getWidth
ASKER
FAO CEHJ - no there are no exceptions further down
ASKER
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?
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?
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();
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();
ASKER
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...
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...
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.
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.
ASKER
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.
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.
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.
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.
ASKER
What about the metadata of the image, I know that at least JPEG's can contain metadata?
> 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.
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.
ASKER
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?
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?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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.