With javafx, when I read images the PixelFormat is rgb and I want to apply filters on them.I use writableImage.pixelWriter to set the pixels color but the PixelFormat is rgba.
I use ImageIO.write() and it work for .png, but when I try to save this modified image in .jpg or .jpeg, the color change. I find that's because rgba don't work with jpg but i don't know how to change this PixelFormat.
Is there a way to change rgba format in rgb ? Do you know another way to save javafx Image as .jpg/.jpeg ?
Edit : How I save file (it works for png)
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("JPG Files", "*.jpg"));
File outputFile = fileChooser.showSaveDialog(null);
BufferedImage bImage = SwingFXUtils.fromFXImage(modifiedImage.getImage(), null); // getImage() return a javafx.scene.image.Image;
try {
ImageIO.write(bImage, "jpg", outputFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
How I modify image (example)
Image currentImage = modifiedImage.getImage();
WritableImage writableImage = new WritableImage((int) currentImage.getWidth(), (int) currentImage.getHeight());
PixelReader pixelReader = currentImage.getPixelReader();
PixelWriter pixelWriter = writableImage.getPixelWriter();
for (int i = 0; i < (int) currentImage.getWidth(); i++) {
for (int j = 0; j < (int) currentImage.getHeight(); j++) {
pixelWriter.setColor(i, j, new Color(0,0,0,1));
}
}
modifiedImage.setImage(writableImage);
When I get the PixelFormat of the reader it's rgb but for the writer it's rgba. If I save an image without modification it's good, but when I apply a filter on it and I save the image as jpg, the colors change.
On my app the colors are good but if I open the jpg file outside they aren't. With png files there is no problem. I can allow to save only as png but it would be better if i can choose.
Solution :
BufferedImage bImage = SwingFXUtils.fromFXImage(modifiedImage.getImage(), null);
BufferedImage bImage2 = new BufferedImage(bImage.getWidth(), bImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bImage2.getGraphics().drawImage(bImage, 0, 0, null);
try {
ImageIO.write(bImage2, "jpg", outputFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
You are again one of the many people who are hit by this bug https://bugs.openjdk.java.net/browse/JDK-8119048 which is not considered important enough to be fixed. If you read the comments in there you will find a work-arround. Basically the idea is to copy the image after the conversion into a new image without alpha channel.
I'd really like to know how many more people have to waste their time until this bug finally gets enough attention to be fixed.
Related
**I'm using the below code to fetch the multiple failure screenshots from the folder to Bugzilla tool, while uploading the pictures in bugzilla, color of the picture is disorted. [enter image description here][1]. Can any one help me to rectify this issue. ? **
try {
BugzillaConnector conn = new BugzillaConnector();
conn.connectTo("bugzilla.com");
LogIn logIn = new LogIn("username", "password");
conn.executeMethod(logIn);
Bug bug = new BugFactory()
.newBug()
.setProduct("SeleniumFramework")
.setComponent("CoreJavaTestNG")
.setVersion("1.0").setPlatform("PC")
.setOperatingSystem("Windows")
.setDescription("Bug posted from Java Source Code")
.setSummary("Bug posted from Java Source Code")
.createBug();
ReportBug report = new ReportBug(bug);
conn.executeMethod(report);
int bugID = report.getID();
System.out.println("Bug posted and its ID is " + bugID);
GetBug get = new GetBug(bugID);
conn.executeMethod(get);
System.out.println(get.getBug().getID());
System.out.println(get.getBug().getSummary());
System.out.println(get.getBug().getProduct());
System.out.println(get.getBug().getComponent());
System.out.println(get.getBug().getVersion());
System.out.println(get.getBug().getPlatform());
System.out.println(get.getBug().getOperatingSystem());
// Passing txtFileFilter to listFiles() method to retrieve only file start with fail files
File[] files = folder.listFiles(txtFileFilter);
int Count = 0;
for (File file : files) {
BufferedImage bImage = ImageIO.read(new File(FilePath + file.getName()));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ImageIO.write(bImage, "jpg", bos );
byte [] data = bos.toByteArray();
AttachmentFactory attachmentFactory = new AttachmentFactory();
Attachment attachment = attachmentFactory.newAttachment()
. setData(data)
. setMime("image/jpg") //Set the appropriate MIME type for the image format
. setSummary(file.toString()) //Description
. setName(file.toString())//Name of the Screenshot in Bugzilla
. setBugID(bugID)
. createAttachment();
AddAttachment add2 = new AddAttachment(attachment, bugID);
add2.getID();
conn.executeMethod(add2);
Count++;
}
System.out.println(Count + " File Uploded");
}
catch (Exception e) {
e.printStackTrace();
} ```
[1]: https://i.stack.imgur.com/qrIaq.jpg
The pinkish/readish ting your seeing is because the source image contains a alpha channel.
There is a known bug in ImageIO which will include the alpha channel into the output of the JPEG image (or some such thing, you can google it if you're really interested).
The basic solution to your problem is to apply the original image to a BufferedImage using a TYPE_INT_RGB, which will remove the alpha channel, for example see Removing transparency in PNG BufferedImage.
I used the code but am getting blue color background on the image
So, starting with this transparent PNG
And using the below code...
BufferedImage original = ImageIO.read(new File("/Users/shanew/Downloads/transparent.png"));
BufferedImage copy = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = copy.createGraphics();
g2d.setColor(Color.WHITE); // Or what ever fill color you want...
g2d.fillRect(0, 0, copy.getWidth(), copy.getHeight());
g2d.drawImage(original, 0, 0, null);
g2d.dispose();
File dest = new File("Test.jpg");
ImageIO.write(copy, "jpg", dest);
BufferedImage test = ImageIO.read(dest);
JPanel panel = new JPanel();
panel.add(new JLabel(new ImageIcon(original)));
panel.add(new JLabel(new ImageIcon(test)));
JOptionPane.showMessageDialog(null, panel);
I can produce...
If you're still having issues, then you need to do two things:
Update your original question with the code you are using
Provide a sample of the image you are trying to convert
It's not helpful to keep posting code in the comments
I am attempting to perform a basic kernel convolution pass on an image using the BufferedImageOp package in java.awt.image. This is the code I have:
BufferedImage img = null;
File f = null;
//read image
try {
f = new File("keys.JPG");
img = ImageIO.read(f);
} catch (IOException e) {
System.out.println(e);
}
float[] gaussian = {
1/16f, 1/8f, 1/16f,
1/8f, 1/4f, 1/8f,
1/16f, 1/8f, 1/16f,
};
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, gaussian));
BufferedImage dest = op.filter(img, null);
File outputfile = new File("image.jpg");
ImageIO.write(dest, "jpg", outputfile);
My code attempts to load the image keys.JPG and then convolve this image with the Gaussian blur kernel and save the image to the file image.jpg. When I run the code, it processes for a bit then terminates and saves the image successfully but when I compare the original and the new images, they are identical.
Looking online at some code examples, my code should work. Am I missing something?
Thanks
As #haraldK mentioned, my image was too large to notice a difference. The code works as expected.
I am trying to read images from external directory and for that I am using
bufferedImage image=ImageIO.read(new File(imagefile));
jlabel.seticon(new imageicon(image));
and getting a drastic change in colors. I tried many other things like:
bufferedImage image=ImageIO.read(new File(imagefile));
bufferedImage img=new bufferedImage(image.getWidth(),image.getHeight(),bufferedImage.TYPE_INT_RGB);
and I tried:
img.setData(image.getData();
jlabel.seticon(new imageicon(image));
and I tried:
Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
ImageReader reader = null;
while(readers.hasNext()) {
reader = (ImageReader)readers.next();
if(reader.canReadRaster()) {
break;
}
}
ImageInputStream input = ImageIO.createImageInputStream(f);
reader.setInput(input);
Raster raster = reader.readRaster(0, null);
BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
bi.getRaster().setRect(raster);
but result are still same
http://i.stack.imgur.com/jNVm0.jpg
Here is an example of the issue:
The minimal code for viewing is:
bufferedImage image=ImageIO.read(new File(imagefile));
jlabel.seticon(new imageicon(image));
lbitem.setIcon(im);
and for storing
File f = new File(s);
long size=f.length();
FileInputStream fis1=new FileInputStream(f);
FileOutputStream fos2=new FileOutputStream("src/image/"+tfpn.getText()+".jpg");
byte b[]=new byte[1000];
int r=0;
long count=0;
while(true)
{
r=fis1.read(b,0,1000);
fos2.write(b,0,1000);
count = count+r;
if(count==size)
break;
System.out.println(count);
}
What could be causing the bad colors?
This problem is cause by a mismatch between reading/writing (creating/using) an image
that contains alpha (transparency) but you are expecting it to contain no alpha (or the inverse).
For example, if your image is BufferedImage.TYPE_4BYTE_ABGR and you output it
to a file type that does not support alpha (transparency) , or you writer does not
support alpha, it will look like your sample after reading and displaying it.
Use type PNG (supports alpha channel) not JPG (does not support alpha channel)
Ok my problem is simple, after performing AffineTransform, my image is not saving properly (however it is drawn on JPanel properly!). It is really strange, so any hints are really appreciated...
Take a look on code:
public BufferedImage performRotation(BufferedImage bi){
if (angle!=180){
at.translate(0.5*bi.getHeight(), 0.5*bi.getWidth());
if(clockwise){
at.rotate(Math.toRadians(angle));
}else{
at.rotate(Math.toRadians(-angle));
}
at.translate(-0.5*bi.getWidth(), -0.5*bi.getHeight());
}
else if(angle==180){
at.translate(0.5*bi.getWidth(), 0.5*bi.getHeight());
at.rotate(Math.toRadians(angle));
at.translate(-0.5*bi.getWidth(), -0.5*bi.getHeight());
}
AffineTransformOp op = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
BufferedImage bi2 = op.filter(bi, null);
try {
ImageIO.write(bi, "bmp", new File("BEFORE filterORIG.bmp"));
ImageIO.write(bi2, "bmp", new File("AFTER filterNEW.bmp"));
} catch (IOException ex) {
Logger.getLogger(DrawingField.class.getName()).log(Level.SEVERE, null, ex);
}
File BEFORE filterORIG is saved properly -> there is an image, but its pre-rotated.
File AFTER... is saved as blank file.
What is really interesting, is previously mentioned fact that this transformation is poperly shown on JPanel that i use as a display (i can observe effect of desired transformation)
Any help appreciated...
Try writing png images, ie:
ImageIO.write(bi, "png", new File("BEFORE filterORIG.png"));
ImageIO.write(bi2, "png", new File("AFTER filterNEW.png"));
The resulting image (bi2) may have an aplha channel and ImageIO may not allow to encode images with aplha as bmp.
Alternatively, create a destination image with TYPE_INT_RGB color model and use it as a second argument in filter() method.
I'd like to convert gif images to jpeg using Java. It works great for most images, but I have a simple transparent gif image:
Input gif image http://img292.imageshack.us/img292/2103/indexedtestal7.gif
[In case the image is missing: it's a blue circle with transparent pixels around it]
When I convert this image using the following code:
File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
File f = new File("indexed_test.jpg");
ImageIO.write(image, "jpg", f);
This code works without throwing an Exception, but results an invalid jpeg image:
[In case the image is missing: IE cannot show the jpeg, Firefox shows the image with invalid colors.]
I'm using Java 1.5.
I also tried converting the sample gif to png with gimp and using the png as an input for the Java code. The result is the same.
Is it a bug in the JDK? How can I convert images correctly preferably without 3rd party libraries?
UPDATE:
Answers indicate that jpeg conversion cannot handle transparency correctly (I still think that this is a bug) and suggest a workaround for replacing transparent pixels with predefined color. Both of the suggested methods are quite complex, so I've implemented a simpler one (will post as an answer). I accept the first published answer with this workaround (by Markus). I don't know which implementation is the better. I go for the simplest one still I found a gif where it's not working.
For Java 6 (and 5 too, I think):
BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
As already mentioned in the UPDATE of the question I've implemented a simpler way of replacing transparent pixels with predefined color:
public static BufferedImage fillTransparentPixels( BufferedImage image,
Color fillColor ) {
int w = image.getWidth();
int h = image.getHeight();
BufferedImage image2 = new BufferedImage(w, h,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = image2.createGraphics();
g.setColor(fillColor);
g.fillRect(0,0,w,h);
g.drawRenderedImage(image, null);
g.dispose();
return image2;
}
and I call this method before jpeg conversion in this way:
if( inputImage.getColorModel().getTransparency() != Transparency.OPAQUE) {
inputImage = fillTransparentPixels(inputImage, Color.WHITE);
}
The problem (at least with png to jpg conversion) is that the color scheme isn't the same, because jpg doesn't support transparency.
What we've done successfully is something along these lines (this is pulled from various bits of code - so please forgive the crudeness of the formatting):
File file = new File("indexed_test.gif");
BufferedImage image = ImageIO.read(file);
int width = image.getWidth();
int height = image.getHeight();
BufferedImage jpgImage;
//you can probably do this without the headless check if you just use the first block
if (GraphicsEnvironment.isHeadless()) {
if (image.getType() == BufferedImage.TYPE_CUSTOM) {
//coerce it to TYPE_INT_ARGB and cross fingers -- PNGs give a TYPE_CUSTOM and that doesn't work with
//trying to create a new BufferedImage
jpgImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_ARGB);
} else {
jpgImage = new BufferedImage(width, height, image.getType());
}
} else {
jgpImage = GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().getDefaultConfiguration().
createCompatibleImage(width, height, image.getTransparency());
}
//copy the original to the new image
Graphics2D g2 = null;
try {
g2 = jpg.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.drawImage(image, 0, 0, width, height, null);
}
finally {
if (g2 != null) {
g2.dispose();
}
}
File f = new File("indexed_test.jpg");
ImageIO.write(jpgImage, "jpg", f);
This works for png to jpg and gif to jpg. And you will have a white background where the transparent bits were. You can change this by having g2 fill the image with another color before the drawImage call.
3 months late, but I am having a very similar problem (although not even loading a gif, but simply generating a transparent image - say, no background, a colored shape - where when saving to jpeg, all colors are messed up, not only the background)
Found this bit of code in this rather old thread of the java2d-interest list, thought I'd share, because after a quick test, it is much more performant than your solution:
final WritableRaster raster = img.getRaster();
final WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), img.getHeight(), 0, 0, new int[]{0, 1, 2});
// create a ColorModel that represents the one of the ARGB except the alpha channel
final DirectColorModel cm = (DirectColorModel) img.getColorModel();
final DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask());
// now create the new buffer that we'll use to write the image
return new BufferedImage(newCM, newRaster, false, null);
Unfortunately, I can't say I understand exactly what it does ;)
If you create a BufferedImage of type BufferedImage.TYPE_INT_ARGB and save to JPEG weird things will result. In my case the colors are scewed into orange. In other cases the produced image might be invalid and other readers will refuse loading it.
But if you create an image of type BufferedImage.TYPE_INT_RGB then saving it to JPEG works fine.
I think this is therefore a bug in Java JPEG image writer - it should write only what it can without transparency (like what .NET GDI+ does). Or in the worst case thrown an exception with a meaningful message e.g. "cannot write an image that has transparency".
JPEG has no support for transparency. So even when you get the circle color correctly you will still have a black or white background, depending on your encoder and/or renderer.
BufferedImage originalImage = ImageIO.read(getContent());
BufferedImage newImage = new BufferedImage(originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
for (int x = 0; x < originalImage.getWidth(); x++) {
for (int y = 0; y < originalImage.getHeight(); y++) {
newImage.setRGB(x, y, originalImage.getRGB(x, y));
}
}
ImageIO.write(newImage, "jpg", f);
7/9/2020 Edit: added imageIO.write