I have a class called Graphic that creates a new BufferedImage, draws a new Graphics2D and returns this image as base64 encoded String:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// Draw background
g2.setColor(Color.decode("#FFFFFF"));
g2.fillRect(0, 0, grafikBreite, grafikHoehe);
g2.setColor(Color.decode("#000000"));
// Draw some rectangles and other stuff...
drawStuff(g2);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] imageInByte = {};
try {
JPEGImageEncoder j = new JPEGImageEncoderImpl(baos);
j.encode(image);
imageInByte = baos.toByteArray();
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
return javax.xml.bind.DatatypeConverter.printBase64Binary(imageInByte);
In my jsp-File I want to display this image using, where graphic is the previously created base64 byte array:
<img src="data:image/jpg;base64,<c:out value="${graphic}"/>"/>
The image is displayed, but the problem is that the image has red background and the other colors used are also wrong. If I save the created base64 string as jpeg-File on hard disk, all colors are displayed correctly.
Has someone an idea why HTML displays the image with strange colors?
Thanks for help
First a bit cleaning up:
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, grafikBreite, grafikHoehe);
g2.setColor(Color.BLACK);
drawStuff(g2);
g2.dispose(); // TODO
Dispose after createGraphics.
Then one could try the more generic, portable ImageIO class. The parametrising for antialiasing and such goes a bit different, but then JPEG is a lossy format anyway. Just to try a different angle.
ImageIO.write(image, "jpg", baos);
baos.close();
imageInByte = baos.toByteArray();
And then I did the closing first. (It has no effect by javadoc.)
One could try .png and a another type, ABGR.
I think ImageIO does the trick, or your code with ABGR.
Related
Long story short I have premultiplied Texture. I grab a FrameBuffer, clear it with (0,0,0,0), set the blend mode to glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA), and render the Texture. Then I grab the pixels glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, byteBufferPixels); and use that:
BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
screenshot.setRGB(0, 0, width, height, argbInts, 0, width);
try {
ImageIO.write(screenshot, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
I also have tried BufferedImage.TYPE_INT_ARGB_PRE with no change.
The result is this:
How do I get a nice transparent PNG file out of premultiplied pixel data in OpenGL?
Thanks!
The JavaDoc for BufferedImage.setRGB(...) says:
Sets an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) and default sRGB color space, into a portion of the image data.
This means that your input data argbInts needs to be in non-premultiplied form, regardless of the destination image type. It's of course possible to un-multiply the input pixel data before passing it to the setRGB method, but it's a bit tedious for an array with packed ints, so I leave that as an exercise for the reader... 😉
Instead, it is much easier to just change the image to TYPE_INT_ARGB_PRE and set the pixel data directly with the original premultiplied pixels, like this:
BufferedImage screenshot = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
// Safe cast for TYPE_INT_*
int[] imageData = ((DataBufferInt) screenshot.getRaster().getDataBuffer()).getData();
System.arraycopy(argbInts, 0, imageData, 0, argbInts.length));
try {
ImageIO.write(screenshot, "PNG", file);
} catch (IOException e) {
e.printStackTrace();
}
This question already has answers here:
Converting transparent gif / png to jpeg using java
(7 answers)
Closed 5 years ago.
I am trying to put two images together using java. So I tried drawing a buffered image on top of another buffered image it worked but it ruined the colors of the image the final image is somewhat green
Here is my code:
try
{
BufferedImage source = ImageIO.read(new File("marker.png"));
BufferedImage logo = ImageIO.read(new File("pic.png"));
Graphics2D g = (Graphics2D) source.getGraphics();
g.drawImage(logo, 20, 50, null);
File outputfile = new File("image.jpg");
ImageIO.write(source, "jpg", outputfile);
}
catch (Exception e)
{
e.printStackTrace();
}
jpg could mess with your data during compression - you could try png as output format.
To make sure you have all the colors you need, I suggest using a dedicated target image with the colordepth you need instead of overwriting on of your source images. Like this:
BufferedImage target = new BufferedImage(source.getWidth(), source.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g = (Graphics2D) target.getGraphics();
g.drawImage(source, 0, 0, null);
g.drawImage(logo, 20, 50, null);
File outputfile = new File("targetimage.png");
ImageIO.write(target, "png", outputfile);
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"));
I'm having an image in Database in bytearray format. I want to display on browser. I don't know how to write Image using OutputStream. Here is my code.
byte[] imageInBytes = (byte[]) obj; // from Database
InputStream in = new ByteArrayInputStream(imageInBytes);
Image img = ImageIO.read(in).getScaledInstance(50, -1, Image.SCALE_SMOOTH);
OutputStream o = resp.getOutputStream(); // HttpServletResponse
o.write(imgByte);
You may try something like this:
File f=new File("image.jpg");
BufferedImage o=ImageIO.read(f);
ByteArrayOutputStream b=new ByteArrayOutputStream();
ImageIO.write(o, "jpg", b);
byte[] img=b.toByteArray();
You have to set the content type of the response to be an image type that you are sending.
Suppose your image was stored when it was a jpeg. then,
OutputStream o = resp.getOutputStream(); // HttpServletResponse
o.setContentType("image/jpeg");
o.write(img.getBytes() /* imgByte */);
would send the browser an image. ( The browser understands from the header information that the following information you just sent it, is a jpeg image. )
You could try using ImageIO.write...
ImageIO.write(img, "jpg", o);
But this will require you to use BufferedImage when reading...
BufferedImage img = ImageIO.read(in);
You could then use AffineTransform to scale the image...
BufferedImage scaled = new BufferedImage(img.getWidth() / 2, img.getHeight() / 2, img.getType());
Graphics2D g2d = scaled.createGraphics();
g2d.setTransform(AffineTransform.getScaledInstance(0.5, 0.5));
g2d.drawImage(img, 0, 0, null);
g2d.dispose();
img = scaled;
This, obviously, only scales the image by 50%, so you'll need to calculate the required scaling factor based on the original size of the image against your desired size...
Take a look at Java: maintaining aspect ratio of JPanel background image for some ideas on scaling images...
I know this is something to do with compositing but I can't work out what. In an earlier section of code, a particular list of pixels in a BufferedImage are set to be transparent black:
for(Pixel p : closed){
Color c = new Color(image.getRGB(p.x, p.y));
Color newC = new Color(0,0,0, 0);
image.setRGB(p.x, p.y, newC.getRGB() & 0x00000000);
}
if(andCrop){
image = image.getSubimage(left, top, right-left, bottom-top);
}
return image;
Then I attempt to write the image out:
try {
BufferedImage out = new BufferedImage(image.getWidth(), image.getHeight(), java.awt.Transparency.TRANSLUCENT);
Graphics2D g2d = out.createGraphics();
g2d.setComposite(AlphaComposite.Clear);
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
g2d.setComposite(AlphaComposite.Src);
g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
g2d.dispose();
File outputfile = new File(file);
ImageIO.write(out, "png", outputfile);
} catch (IOException e) {
}
Now, I know that 'out' is clear before I attempt to draw the image onto it. What I'm not getting is what's wrong with my compositing. Instead of coming out as transparent, I'm getting full-black.
All bufferedimages used are INT_ARGB.
EDIT - This has been solved. The image source was from ImageIO.read and the BufferedImage returned did not support alpha. A quick post-read conversion let the rest of the code run smoothly.
Things that comes to my mind... (thanks to Andrew):
java.awt.Transparency.TRANSLUCENT = 3
TYPE_INT_ARGB = 2
TYPE_INT_ARGB_PRE = 3
public BufferedImage(int width,
int height,
int imageType)
Constructs a BufferedImage of one of the predefined image types. (TYPE_...)
http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html
so it seems as basically it's a mixup.
Besides, what is the effect you want to achieve? you clear an empty image, then draw fully transparent pixels to it... I just don't get it.
Whelp, this has been downvoted now so I'm not sure this will be relevant, but the issue was that the original BufferedImage was being read in by ImageIO, and this image was not supporting ARGB. A quick post-read conversion allowed the rest of the code to work.