I'm having problems with image transparency. It's the following:
I have image1 and I need to overlap image2 over it. image2 is png with transparency. I want to create an image with watermark, that would be transparent image2 on top of image1.
When I open image2, that has transparency, and put it in a JFrame just to preview it, it opens with transparency. But when I use a BufferImage object's method getRGB to get image2's pixels and I use setRGB to overlay it over image1, image2 loses transparency and gets white background. Here's the code:
public class Test {
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File("c:/images.jpg"));
BufferedImage image2 = ImageIO.read(new File("c:/images2.png"));
int w = image2.getWidth();
int h = image2.getHeight();
int[] pixels = image2.getRGB(0, 0, w, h, null, 0, w);
image2.setRGB(0, 0, w, h, pixels ,0 ,w);
// here goes the code to show it on JFrame
}
}
Please, can someone tell me what I'm doing wrong? I noticed that this code is losing image2's alpha. How could I make it to not lose alpha?
The problem's that setPixel will use the encoding for the image that receives the pixel in a direct way, without interpreting the graphical context for the original image. That won't happen if you use the graphics object.
Try:
public static void main(String[] args) throws IOException {
BufferedImage image = ImageIO.read(new File("c:/images.jpg"));
BufferedImage image2 = ImageIO.read(new File("c:/images2.png"));
int w = image2.getWidth();
int h = image2.getHeight();
Graphics2D graphics = image.createGraphics();
graphics.drawImage(image2, 0, 0, w, h, null);
graphics.dispose();
// here goes the code to show it on JFrame
}
Related
I just want to place two different images on one canvas and make it a .jpg file in Java. I just want to make a resulting file, not a GUI.
I want to make a result file like below with both images above:
You can use BufferedImage to combine the two images. The following code shows a simple implementation:
public static void combineImages(String imagePath1, String imagePath2, String outputPath) throws IOException {
int intervalWidth = 20; // The interval between two images
BufferedImage image1 = ImageIO.read(new File(imagePath1));
BufferedImage image2 = ImageIO.read(new File(imagePath2));
int combinedWidth = image1.getWidth() + image2.getWidth() + intervalWidth;
int combinedHeight = Math.max(image1.getHeight(), image2.getHeight());
BufferedImage combined = new BufferedImage(combinedWidth, combinedHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D g = combined.createGraphics();
g.setColor(Color.WHITE);
// Fill the background with white
g.fillRect(0, 0, combinedWidth, combinedHeight);
// Draw the two images on the combined image
g.drawImage(image1, 0, 0, null);
g.drawImage(image2, image1.getWidth() + intervalWidth, 0, null);
ImageIO.write(combined, "jpg", new File(outputPath));
}
I've written a program to modify images.
First, I get the image, and get its drawing context like this:
BufferedImage image;
try {
image = ImageIO.read(inputFile);
} catch (IOException ioe) { /* exception handling ... */ }
Graphics g = image.createGraphics();
And then I modify the image like this:
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
g.setColor( /* calculate color ... */ );
g.fillRect(x, y, 1, 1);
}
}
After I've finished modifying the image, I save the image like this:
try {
ImageIO.write(image, "PNG", save.getSelectedFile());
} catch (IOException ioe) { /* exception handling ... */ }
Now most of the time this works just fine.
However, when I tried recoloring this texture
to this
I get this instead:
Inside the debugger, though, the Graphics's color is the shade of pink I want it to be.
The comments seem to suggest that the image the user opens might have some color limitations, and since I'm drawing to the same image I'm reading from, my program has to abide by these limitations. The example image seems to be pretty grayscale-y, and apparently its bit depth is 8 bit. So maybe the pink I'm drawing on it is converted to grayscale, because the image has to stay 8-bit?
As suggested in the comments, the main problem here indeed is the wrong color model. When you load the original image, and print some information about it...
BufferedImage image = ImageIO.read(
new URL("https://i.stack.imgur.com/pSUFR.png"));
System.out.println(image);
it will say
BufferedImage#5419f379: type = 13 IndexColorModel: #pixelBits = 8 numComponents = 3 color space = java.awt.color.ICC_ColorSpace#7dc7cbad transparency = 1 transIndex = -1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 128 height = 128 #numDataElements 1 dataOff[0] = 0
The IndexColorModel does not necessarily support all the colors, but only a subset of them. (Basically, the image supports only the colors that it "needs", which allows for a more compact storage).
The solution here is to convert the image into one that has the appropriate color model. A generic method for this is shown in the following example:
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
public class ImageColors
{
public static void main(String[] args) throws IOException
{
BufferedImage image = ImageIO.read(
new URL("https://i.stack.imgur.com/pSUFR.png"));
// This will show that the image has an IndexColorModel.
// This does not necessarily support all colors.
System.out.println(image);
// Convert the image to a generic ARGB image
image = convertToARGB(image);
// Now, the image has a DirectColorModel, supporting all colors
System.out.println(image);
Graphics2D g = image.createGraphics();
g.setColor(Color.PINK);
g.fillRect(50, 50, 50, 50);
g.dispose();
ImageIO.write(image, "PNG", new File("RightColors.png"));
}
public static BufferedImage convertToARGB(BufferedImage image)
{
BufferedImage newImage = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g = newImage.createGraphics();
g.drawImage(image, 0, 0, null);
g.dispose();
return newImage;
}
}
Right now I have an image and I want to convert it into a BufferedImage...
This is my code -
private BufferedImage toBufferedImage(Image img, int width, int height){
// Create a buffered image with transparency
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics bGr = bimage.getGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
// Return the buffered image
return bimage;
}
But it doesn't work. Can someone explain what's wrong?
Try the new JRE that includes JavaFX.
You could use SwingFXUtils. There is a method which does what you ask for:
BufferedImage image = SwingFXUtils.fromFXImage(fxImage, null);
or
BufferedImage image = ImageIO.read(new File(filename));
BufferedImage extends Image, so you can cast it:
BufferedImage buffered = (BufferedImage) image;
But you must check the type of your image object in runtime, because it can contain other kind of Image.
UPDATE
To convert an Image to a BufferedImage you should check this class and try it:
http://www.dzone.com/snippets/converting-images
Why does combining images where BG is a JPEG cause unexpected results?
This is a follow-up to my answer in Overlaying of 2 images doesnt work properly. The source posted there (using a BG image created in memory) looks like this:
The BG image is on the left.
The FG image (a PNG with transparency) is in the middle.
The combined image is on the right.
So far, so good. But then the person who asked the question commented that if the BG was a JPEG, it failed. Thinking they were mistaken, I altered my example to encode the BG image to a JPEG. Now if I use BufferedImage.TYPE_INT_ARGB or BufferedImage.TYPE_INT_RGB for the final image I get what they were referring to:
TYPE_INT_ARGB
TYPE_INT_RGB
I expected the result to be the same as the original for at least one of those (more so the ARGB variant).
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;
import javax.imageio.ImageIO;
class CombineImages {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
try {
URL urlImage1 =
new URL("http://i.stack.imgur.com/T5uTa.png");
// Load the FG image
Image fgImage = ImageIO.read(urlImage1);
int w = fgImage.getWidth(null);
int h = fgImage.getHeight(null);
// Create a non-trasparent BG image
BufferedImage bgImageTemp =
new BufferedImage(w,h,BufferedImage.TYPE_INT_RGB);
ByteArrayOutputStream baos =
new ByteArrayOutputStream();
ImageIO.write(bgImageTemp, "jpg", baos);
ByteArrayInputStream bais =
new ByteArrayInputStream(baos.toByteArray());
BufferedImage bgImageJpeg = ImageIO.read(bais);
int result = JOptionPane.showConfirmDialog(
null,
"Use a final image with transparency?",
"Transparency",
JOptionPane.YES_NO_OPTION);
int type = (result==JOptionPane.OK_OPTION ?
BufferedImage.TYPE_INT_ARGB :
BufferedImage.TYPE_INT_RGB);
// Create the final image
BufferedImage finalImage =
new BufferedImage(w,h,type);
Graphics2D g = finalImage.createGraphics();
g.drawImage(bgImageJpeg, w, h, null);
g.drawImage(fgImage, w, h, null);
g.dispose();
JPanel gui = new JPanel(new GridLayout(1,0,5,5));
gui.add(new JLabel(new ImageIcon(bgImageJpeg)));
gui.add(new JLabel(new ImageIcon(fgImage)));
gui.add(new JLabel(new ImageIcon(finalImage)));
JOptionPane.showMessageDialog(null, gui);
} catch (Exception e) {
e.printStackTrace();
}
}
};
SwingUtilities.invokeLater(r);
}
}
Looks like this is due to a typo.
In your referenced answer, the code that formed the combined image was
Graphics2D g = finalImage.createGraphics();
g.drawImage(bgImage, 0, 0, null);
g.drawImage(fgImage, 0, 0, null);
But in this question, it's been changed to,
Graphics2D g = finalImage.createGraphics();
g.drawImage(bgImageJpeg, w, h, null);
g.drawImage(fgImage, w, h, null);
The latter begins drawing at the "top-left corner", which happens to be the bottom-right corner of the images, so nothing is really drawn. The former, however, draws the entire images, as expected.
gui.repaint();
Try that after since you effectively painted the panel and components while constructing the joptionpane, but, even then because construction threading matching visibility invocation will not hold truth you should invoke the g.drawImage in a paint override method after joptionpane invocation anyhow.
It cannot draw something that does not yet actually exist onscreen, however there is tolerance for the call because it theoretically exists as a set of objects enough for the method.
I have generated the barcode using barbecue and now I want to resize the barcode as per my need. I tried with BufferedImage and then I got barcode with different size but then I get an additional black line under the barcode.
public class GenerateBarcode {
public static void main(String[] args) throws Exception {
String initialString = JOptionPane.showInputDialog("Enter the text here");
Barcode barcode = BarcodeFactory.createCode128(initialString);
BufferedImage bi = BarcodeImageHandler.getImage(barcode);
}
}
Here I want to resize "bi".
To resize any BufferedImage, you can create a new one and draw your old one on top of it with a scaling applied. For example:
double scale = 2;
BufferedImage scaledBi = new BufferedImage((int)(bi.getWidth()*scale), (int) (bi.getHeight()*scale), bi.getType());
Graphics2D g2 = scaledBi.createGraphics();
g2.drawImage(bi, 0, 0, scaledBi.getWidth(), scaledBi.getHeight(), 0, 0, bi.getWidth(), bi.getHeight(), null);
scaledBi now contains your scaled image. Note that this is not vector based, so I am not sure of the quality. To increase scaling quality, you can play with the rendering hints.
Try this code:
Barcode b = BarcodeFactory.create2of7(jTextField1.getText());
b.setBarHeight(5);
b.setBarWidth(1);