Java JLabel icons are displaying with distorted pixels in JFrame. This is happening consistently with different png images (all 32x32). I am not scaling the images, they are displayed in the program 32x32, which I verified using getWidth and getHeight on the JLabel. The distortions appear in the same place each time the program is run, not randomly.
Screenshot using the example code provided below.
In this screenshot you can see an array of JLabel icons, each affected one differently.
When resizing the window from sideways, as the icon moves with the window, the distortions move across the icon like a vertical line.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
public class FrameApp extends JFrame
{
public static void main(String[] args) throws IOException
{
FrameApp frameApp = new FrameApp();
}
private FrameApp() throws IOException
{
BufferedImage image;
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
image = ImageIO.read(url);
JLabel label = new JLabel(new ImageIcon(image));
add(label);
pack();
setVisible(true);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Edit:
I am using JDK 11.0.3, Java SE Runtime Environment build 1.8.0_202, on Windows 8.1 64-bit.
You may think you're displaying the images at 32x32 size, but your example of the tiled images says that's not so. You have a 9x2 grid of icons, which should be 288x64 pixels, but in your sample image the grid is 302x66.
If you carefully examine your tiled image, you can see that the individual tiles are being displayed 34px wide - see the magenta border that extends from 32px to 66px. (Note, some of the tiles are displayed 33px wide; it appears to be 33, 34, 34, 33, 34...)
In order to stretch the tiles to the wider width, certain columns are being doubled (red borders) and this creates the visual glitches you are seeing.
Have you tried fixing the size of the JLabel instead of allowing it to size based on its contents?
First option:
Instead of using ImageIcon, you can try to create your own icon class drawing the Image using graphics.drawImage(x,y,width,height,null) controlling rendering quality (https://docs.oracle.com/javase/tutorial/2d/advanced/quality.html)
an example would be something like this:
public class Icon32 extends ImageIcon {
public Icon32(String f) {
super(f);
BufferedImage i= new BufferedImage(32, 32,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) i.getGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(getImage(), 0, 0, 32, 32, null);
setImage(i);
}
public int getIconHeight() {
return 32;
}
public int getIconWidth() {
return 32;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.drawImage(getImage(), x, y, c);
}
}
where the method:
getImage()
is loading your image/icon...
Second option: if you are not happy with the result you can try to use this library:
https://github.com/mortennobel/java-image-scaling
it claims to provides better image scaling options than the Java runtime provides.
Answer is from this link to generate high quality image : https://componenthouse.com/2008/02/08/high-quality-image-resize-with-java/
The appropriate class from the link :
public class ImageResize {
public static void main(String[] args) {
try {
URL url = new URL("http://i.stack.imgur.com/L5DGx.png");
BufferedImage image = ImageIO.read(url);
ImageIO.write(resizeImage(image, 32, 32), "png", new File("D:/picture3.png"));
} catch (IOException e) {
e.printStackTrace();
}
}
private static BufferedImage resize(BufferedImage image, int width, int height) {
int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.setComposite(AlphaComposite.Src);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(image, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
private static BufferedImage resizeImage(BufferedImage image, int width, int height) {
image = createCompatibleImage(image);
image = resize(image, 100, 100);
image = blurImage(image);
return resize(image, width, height);
}
public static BufferedImage blurImage(BufferedImage image) {
float ninth = 1.0f/9.0f;
float[] blurKernel = {
ninth, ninth, ninth,
ninth, ninth, ninth,
ninth, ninth, ninth
};
Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
map.put(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
map.put(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
map.put(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
RenderingHints hints = new RenderingHints(map);
BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE_NO_OP, hints);
return op.filter(image, null);
}
private static BufferedImage createCompatibleImage(BufferedImage image) {
GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
int w = image.getWidth();
int h = image.getHeight();
BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
Graphics2D g2 = result.createGraphics();
g2.drawRenderedImage(image, null);
g2.dispose();
return result;
}
}
Related
I created the following code example to demonstrate my problem. I want to draw into a BufferedImage by a Graphics2D object, but the edges are not sharp. I tried using different renderinghints, but it didn't help. I also tried a BufferedImageOp as you can see in the code, but I don't understand its meaning in drawImage and don't know its possibilites. Can you help me please?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
public class SmoothGraphics extends JComponent{
private BufferedImage image;
private static JFrame frame;
private int x = 100;
private int y = 100;
private int size = 200;
public static void main(String[] args){
frame = new JFrame();
SmoothGraphics component = new SmoothGraphics();
frame.add(component);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
public SmoothGraphics(){
super();
setPreferredSize(new Dimension(400,400));
setBounds(100,100,400,400);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
int width = getWidth();
int height = getHeight();
GraphicsConfiguration gc = frame.getGraphicsConfiguration();
image = gc.createCompatibleImage(width, height);
Graphics2D imageGraphics = (Graphics2D) image.createGraphics();
imageGraphics.setColor(Color.RED);
/*imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);*/
drawExample(imageGraphics);
imageGraphics.dispose();
/*the following kernel helps with the smoothness of the rectangle, but not of the circle
int kernelWidth = 3;
int kernelHeight = 3;
float[] data = new float[kernelWidth*kernelHeight];
data[4]=1;
Kernel kernel = new Kernel(kernelWidth, kernelHeight, data);
BufferedImageOp op = new ConvolveOp(kernel);
*/
//draw image
BufferedImageOp op = null;
g2d.drawImage(image,op,0,0);
//I don't know if this line is necessary
image.flush();
}
private void drawExample(Graphics2D g2d){
//Square as path
Path2D.Double path = new Path2D.Double();
path.moveTo(x,y);
path.lineTo(x+size,y);
path.lineTo(x+size,y+size);
path.lineTo(x,y+size);
path.closePath();
g2d.draw(path);
//Circle
g2d.fillOval(x+size/4,y+size/4,size/2,size/2);
}
}
The output of my code. Notice that the edges are not very clean/sharp!
My result with antialiasing and kernel usage:
My wished result:
Okay... I believe the real problem you are facing is initial scaling of the component graphics (g), which makes your image stretched during drawImage(...). I don't get the same problem here.
To get proper smooth (or "sharp" as you call it) rendering, you do want to enable antialiasing. But you also need to paint without pixel scaling (it's possible with image too, by creating a larger image, however, I don't see why you need the extra image in this case).
Here's your sample program rewritten:
import javax.swing.*;
import java.awt.*;
public class SmoothGraphics extends JComponent {
private final int x = 100;
private final int y = 100;
private final int size = 200;
public static void main(String[] args) {
JFrame frame = new JFrame("Smooth");
SmoothGraphics component = new SmoothGraphics();
frame.getContentPane().add(component, BorderLayout.CENTER); // Add to content pane
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack(); // Pack *before* setVisible(true)!
frame.setLocationRelativeTo(null); // Center the frame after pack()
frame.setVisible(true);
}
public SmoothGraphics() {
setOpaque(true); // Minor optimization
setPreferredSize(new Dimension(400, 400)); // No need to use setBounds, pack() will fix that for you
}
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
// Clear background to black
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Paint in read, with antialiasing
g2d.setColor(Color.RED);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
drawExample(g2d);
}
private void drawExample(Graphics2D g2d) {
// Square (this way avoids the odd skewed lines)
g2d.drawRect(x, y, size, size);
// Circle
g2d.fillOval(x + size / 4, y + size / 4, size / 2, size / 2);
}
}
Result:
If you really want/need the BufferedImage, I found a way that works for me (MacOS). It might need some minor tweaks to work perfectly on other platforms.
#Override
public void paintComponent(Graphics g) {
// No need to call super, as we repaint everything
Graphics2D g2d = (Graphics2D) g;
GraphicsConfiguration gc = g2d.getDeviceConfiguration();
AffineTransform transform = gc.getNormalizingTransform();
BufferedImage image = gc.createCompatibleImage((int) ceil(getWidth() * transform.getScaleX()), (int) ceil(getHeight() * transform.getScaleY()));
Graphics2D graphics = image.createGraphics();
try {
graphics.setTransform(transform);
graphics.setColor(Color.RED);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Need antialiasing on
drawExample(graphics);
}
finally {
graphics.dispose();
}
try {
AffineTransform originalTransform = g2d.getTransform();
originalTransform.concatenate(transform.createInverse());
g2d.setTransform(originalTransform);
}
catch (NoninvertibleTransformException e) {
throw new RuntimeException(e); // API oddity, this should have been a RuntimeException
}
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); // Need render QUALITY here, to avoid the stretching/tearing
// g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // Don't need this on MacOS, but may be needed on other platforms
g2d.drawImage(image, null, 0, 0);
}
Result:
I am currently working with PNG images and I'm little bit blocked because a task that not sure how to fix...
This is the scenario. I have a PNG file of 655x265 pixels with a barcode inside of it. What I need to do is 'extend' the width of the image just to include a blank zone on the left of the image, just like this:
The problem is that nothing happens with the image dimensions when I execute my code:
public static void main(String[] args)
{
try
{
String path = "C:\\Users\\xxx\\Desktop\\a.png";
BufferedImage image = ImageIO.read(new File(path));
resizeImage(path, image.getWidth() + 100, image.getHeight());
Graphics graphics = image.getGraphics();
graphics.setColor(Color.BLACK);
graphics.setFont(new Font("Verdana", Font.PLAIN, 40));
graphics.drawString("TTT", 5, 250);
graphics.dispose();
ImageIO.write(image, "png", new File(path));
System.out.println("Image created");
} catch (Exception e)
{
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("Fin");
}
public static void resizeImage(String path, int newHeight, int newWidth) throws IOException
{
File inputFile = new File(path);
BufferedImage inputImage = ImageIO.read(inputFile);
BufferedImage outputImage = new BufferedImage(newWidth, newHeight, inputImage.getType());
Graphics2D graphics = outputImage.createGraphics();
graphics.drawImage(inputImage, 0, 0, newWidth, newHeight, null);
graphics.dispose();
ImageIO.write(outputImage, "png", new File(path));
inputImage.flush();
outputImage.flush();
}
Do you know what I am doing wrong? Is one of my first times working with image files and probably I misunderstood something important...
Edit: Solution provides in the comments. Link
What you could do is let the method take a BufferedImage, resize it and return it:
public static BufferedImage resizeImage(BufferedImage inputImage, int newHeight, int newWidth){
BufferedImage outputImage = new BufferedImage(newWidth, newHeight, inputImage.getType());
Graphics2D graphics = outputImage.createGraphics();
graphics.drawImage(inputImage, 0, 0, newWidth, newHeight, null);
graphics.dispose();
outputImage.flush();
return outputImage;
}
Then continue working on the resized image in your surrounding method:
String path = "C:\\Users\\xxx\\Desktop\\a.png";
BufferedImage image = ImageIO.read(new File(path));
image = resizeImage(image, image.getWidth() + 100, image.getHeight()); // here you replace the image with the new, resized image from your method
Graphics graphics = image.getGraphics();
graphics.setColor(Color.BLACK);
....
Need to make screenshot of some games. Found this JNA code, but when I try to do screen`s I just get black screen. When I try to do screen of some program, like WordPad ot smth it works well. As well I am bad in JNA, I want ask you about help. Is it possible to accomplish this task ?
public class Paint extends JFrame {
public BufferedImage capture(HWND hWnd) throws IOException {
String gettime = Gettime.screentime();
HDC hdcWindow = User32.INSTANCE.GetDC(hWnd);
HDC hdcMemDC = GDI32.INSTANCE.CreateCompatibleDC(hdcWindow);
RECT bounds = new RECT();
User32Extra.INSTANCE.GetClientRect(hWnd, bounds);
int width = bounds.right - bounds.left;
int height = bounds.bottom - bounds.top;
HBITMAP hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcWindow, width, height);
HANDLE hOld = GDI32.INSTANCE.SelectObject(hdcMemDC, hBitmap);
GDI32Extra.INSTANCE.BitBlt(hdcMemDC, 0, 0, width, height, hdcWindow, 0, 0, WinGDIExtra.SRCCOPY);
GDI32.INSTANCE.SelectObject(hdcMemDC, hOld);
GDI32.INSTANCE.DeleteDC(hdcMemDC);
BITMAPINFO bmi = new BITMAPINFO();
bmi.bmiHeader.biWidth = width;
bmi.bmiHeader.biHeight = -height;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = WinGDI.BI_RGB;
Memory buffer = new Memory(width * height * 4);
GDI32.INSTANCE.GetDIBits(hdcWindow, hBitmap, 0, height, buffer, bmi, WinGDI.DIB_RGB_COLORS);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
image.setRGB(0, 0, width, height, buffer.getIntArray(0, width * height), 0, width);
GDI32.INSTANCE.DeleteObject(hBitmap);
User32.INSTANCE.ReleaseDC(hWnd, hdcWindow);
File outputfile = new File("C:\\image" +gettime+ ".jpg");
ImageIO.write(image, "jpg", outputfile);
return image;
}
public static void main(String[] args) throws IOException {
new Paint();
}
BufferedImage image;
public Paint() throws IOException {
HWND hWnd = User32.INSTANCE.FindWindow(null, "some game");
this.image = capture(hWnd);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setExtendedState(MAXIMIZED_BOTH);
setVisible(true);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawImage(image, 20, 40, null);
}
}
GDI32Util.getScreenshot(HWND hwnd)
Method is already provided in jna.
but my case is as the same as you.... the game screen is black... nothing...
Using JNA to take a screenshot sounds utterly complicated, besides not being platform-agnostic. Java has built-in functionality to take screenshots using the Robot class:
import java.awt.Robot;
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage capture = new Robot().createScreenCapture(screenRect);
ImageIO.write(capture, "png", new File("./screenshot.png"));
By adjusting the screenRect you could also just take a screenshot of a portion of the screen.
I am rotating and scaling the image using AffineTransform. When I display the image using Graphics2D.drawImage() the whole image does not get displayed so I am calling the AffineTransform.translate method.
Here is the code I have currently written:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
Dimension dim = getPreferredSize();
int x = (getWidth() - image.getWidth(null)) / 2;
int y = (getHeight() - image.getHeight(null)) / 2;
double angle = Math.toRadians(rotateAngle);
AffineTransform identity = new AffineTransform();
identity.scale(scale, scale);
identity.translate(x,y);
AffineTransform at = new AffineTransform();
setPreferredSize(new Dimension((int)(identity.getTranslateX()+(image.getWidth(null)*scale)),(int)(identity.getTranslateY()+(image.getHeight(null)*scale))));
at.setTransform(identity);
at.rotate(angle);
g2d.transform(at);
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
}
The translate method sometimes displays the whole image and sometimes does not depending on the image size and rotating angle. Is there anyway to make sure the whole image gets displayed after a rotate.
I had a look at this previous asked question:
Java2D Image Rotation Issue
but the solution posted there gave the same problem for me.
I finally figured out a way to do this for 90 degrees, it will not work for other degrees.
void rotate90(){
if(image!=null){
int w = image.getWidth(null); //the Width of the original image
int h = image.getHeight(null);//the Height of the original image
if(w>h){
BufferedImage dimg = new BufferedImage(w, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
else{
BufferedImage dimg = new BufferedImage(h, h, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g = dimg.createGraphics();
g.translate(-(w-h), 0);
g.rotate(Math.toRadians(90), w/2, w/2);
g.drawImage(image, 0, 0,null);
BufferedImage bimg = new BufferedImage(h, w, BufferedImage.TYPE_3BYTE_BGR );
Graphics2D g2 = (Graphics2D)bimg.getGraphics();
g2.drawImage(dimg,0,0,h,w,0,0,h,w,null);
dimg.flush();
dimg=null;
image = createImage(bimg.getSource());
bimg.flush();
bimg= null;
}
}
}
void rotateClockWise(){
if(image!=null){
rotate90();
setPanelsize();
revalidate();
repaint();
}
}
sometimes displays the whole image and sometimes does not depending on the image size and rotating angle
You need to recalculate the size of the rotated image. Here is an example of how to do that:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
public class Rotation
{
BufferedImage image;
JLabel label;
public Rotation(BufferedImage image)
{
this.image = image;
}
private BufferedImage getImage(double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = image.getWidth();
double height = image.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Rotate and paint the original image onto a BufferedImage
BufferedImage out = new BufferedImage(w, h, image.getType());
Graphics2D g2 = out.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0,0,w,h);
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(image, at);
g2.dispose();
return out;
}
private JLabel getLabel()
{
ImageIcon icon = new ImageIcon(image);
label = new JLabel(icon);
label.setHorizontalAlignment(JLabel.CENTER);
return label;
}
private JSlider getSlider()
{
final JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage bi = getImage(Math.toRadians(value));
label.setIcon(new ImageIcon(bi));
}
});
return slider;
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
BufferedImage bi = ImageIO.read(cl.getResourceAsStream(path));
Rotation r = new Rotation(bi);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new JScrollPane(r.getLabel()));
f.getContentPane().add(r.getSlider(), "South");
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
catch(IOException e)
{
System.out.println(e);
}
}
});
}
}
Not sure how the scaling will affect this. Maybe you can just multiply the width/height by the scaling factor?
Alright so I'm making a game, and I'm trying to modify the original hit marker image by adding text on it, and I'm using the following code:
import javax.swing.ImageIcon;
import javax.swing.Timer;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
public class HitMarker {
public static final Image rangeHitMarker = new ImageIcon(HitMarker.class.getResource("rangeHitMarker.png")).getImage();
public static final Image magicHitMarker = new ImageIcon(HitMarker.class.getResource("magicHitMarker.png")).getImage();
public static final Image monsterHitMarker = new ImageIcon(HitMarker.class.getResource("monsterHitMarker.png")).getImage();
public static final Font font = new Font("Tahoma", Font.PLAIN, 10);
public static final Color t = new Color(0,0,0,0);
public Image hitMarker;
public BufferedImage image;
public String hit;
public int attackStyle;
public boolean rangeAttack;
public int x;
public int y;
public Timer timer;
public boolean remove;
public HitMarker(int x, int y, int hit, int attackStyle){
this.hit = String.format("%d", hit);
this.remove = false;
this.x = x;
this.y = y;
this.attackStyle = attackStyle;
this.hitMarker = getImage();
BufferedImage bi = new BufferedImage(35, 20, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.drawImage(hitMarker, 0, 0, null);
g.setFont(font);
g.setColor(Color.WHITE);
g.drawString(this.hit, 18, 13);
g.dispose();
image = bi;
timer = new Timer(800,
new ActionListener(){
public void actionPerformed(ActionEvent e){
remove = true;
timer.stop();
}
}
);
timer.setInitialDelay(800);
timer.start();
}
public HitMarker(int x, int y, int hit){
this.hit = String.format("%d", hit);
this.remove = false;
this.x = x;
this.y = y;
this.hitMarker = monsterHitMarker;
BufferedImage bi = new BufferedImage(35, 20, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();
g.drawImage(hitMarker, 0, 0, null);
g.setFont(font);
g.setColor(Color.WHITE);
g.drawString(this.hit, 18, 13);
g.dispose();
image = bi;
timer = new Timer(800,
new ActionListener(){
public void actionPerformed(ActionEvent e){
remove = true;
timer.stop();
}
}
);
timer.setInitialDelay(800);
timer.start();
}
public boolean isRangeAttack(){
return attackStyle == AttackStyleConstants.RANGE || attackStyle == AttackStyleConstants.RANGE_DEFENCE ? true : false;
}
public Image getImage(){
return isRangeAttack() ? rangeHitMarker : magicHitMarker;
}
}
Focusing particularly on either constructor:
And the error that I'm having is that when I create the BufferedImage and draw the image on the buffered image, it's creating a black background automatically and I don't know why. I've tried researching on this topic and some say to change something about the AlphaComposite and the g.clearRect() method, but neither of those seem to work. By the way, the image that I'm painting on the buffered image is 35x20 (which is the dimensions of the buffered image) and it has a transparent background. If anyone can tell me how to remove this black background, it would be very much appreciated, thank you.
Try BufferedImage.TYPE_INT_ARGB. This will make the regions transparent instead of black.
You might want to try and store the alpha channel as well,
BufferedImage bi = new BufferedImage(35, 20, BufferedImage.TYPE_INT_ARGB);
If you need a JPG with white background, you need to draw the image like this:
g.drawImage(hitMarker, 0, 0, Color.WHITE, null);
This way you avoid the black background when going from PNG to JPG.
Use png instead of jpeg. Png is much suitable for transparency operations.
Here is simple png export code snippet;
BufferedImage bImage = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) bImage.getGraphics();
DrawingContext context = new DrawingContext(g2d);
plot.draw(context);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DrawableWriter wr = DrawableWriterFactory.getInstance().get("image/png");
wr.write(plot, baos, 640, 480);
baos.flush();
baos.close();
InputStream inputStream = new ByteArrayInputStream(baos.toByteArray());
BufferedImage bufferedImage = ImageIO.read(inputStream);
ImageIO.write(bufferedImage,"png",new File(outputFolder.getPath()+"/result.png"));