BufferedImage Sometimes Doesn't render
I had to modify most of the code to get something to work. I'm assuming that this is what you want.
Here are the changes I made.
I added a main method that called SwingUtilities invokeLater to put the Swing components on the Event Dispatch thread.
I split the code into 3 classes, DrawImage, DrawingPanel, and Snippet. DrawImage creates the four images. DrawingPanel draws the four images onto a JPanel. Snippet creates the JFrame and adds the drawing panel to the JFrame.
I defined the size of the drawing panel to hold 4 slots. I packed the JFrame so that
the JFrame would be the correct size to hold the drawing panel.I overrode the paintComponent method to draw the four images from the image list. These images were already created in the DrawImage class. I called super.paintComponent to make sure all of the Swing children components were drawn correctly.
I created the images before I created the Swing GUI.
I used a method I created, centerString, to center the text in the images. I left the scale method alone.
Here's the modified code. Unlike yours, it's runnable.
package snippet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Snippet implements Runnable {
private JFrame frame;
private List<BufferedImage> imageList;
public Snippet() {
imageList = new ArrayList<BufferedImage>();
new DrawImage().createImages();
}
@Override
public void run() {
frame = new JFrame();
frame.setTitle("ALevelUp 0.0.1 Alpha");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawingPanel p = new DrawingPanel();
frame.add(p);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
System.out.println(frame.getHeight() + "," + frame.getWidth());
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Snippet());
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID =
2535522354552193273L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(550, 350));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = 50;
int y = 50;
for (int i = 0; i < 2; i++) {
BufferedImage image = null;
for (int j = 0; j < 2; j++) {
image = imageList.get(i * 2 + j);
g.drawImage(image, x, y, this);
x += image.getWidth() + 50;
}
x = 50;
y += image.getHeight() + 50;
}
}
}
public class DrawImage {
public void createImages() {
imageList.add(createImage("Slot 1"));
imageList.add(createImage("Slot 2"));
imageList.add(createImage("Slot 3"));
imageList.add(createImage("Slot 4"));
}
private BufferedImage createImage(String text) {
Rectangle r = new Rectangle(0, 0, 200, 100);
BufferedImage image = new BufferedImage(r.width, r.height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) image.getGraphics();
Font font = g.getFont();
g.setFont(scale(font, g, text, image));
g.setColor(Color.BLACK);
g.fillRect(0, 0, image.getWidth(), image.getHeight());
g.setColor(Color.YELLOW);
centerString(g, r, text, font);
g.dispose();
return image;
}
private Font scale(Font f, Graphics g, String text,
BufferedImage img) {
float ntry = 20.0f;
Font font = null;
while (2 < 3) {
font = f.deriveFont(ntry);
FontMetrics fm = g.getFontMetrics(font);
int width = fm.stringWidth(text);
if (width < img.getWidth()) {
return font;
}
}
}
/**
* This method centers a <code>String</code> in
* a bounding <code>Rectangle</code>.
* @param g - The <code>Graphics</code> instance.
* @param r - The bounding <code>Rectangle</code>.
* @param s - The <code>String</code> to center in the
* bounding rectangle.
* @param font - The display font of the <code>String</code>
*
* @see java.awt.Graphics
* @see java.awt.Rectangle
* @see java.lang.String
*/
private void centerString(Graphics g, Rectangle r, String s,
Font font) {
FontRenderContext frc =
new FontRenderContext(null, true, true);
Rectangle2D r2D = font.getStringBounds(s, frc);
int rWidth = (int) Math.round(r2D.getWidth());
int rHeight = (int) Math.round(r2D.getHeight());
int rX = (int) Math.round(r2D.getX());
int rY = (int) Math.round(r2D.getY());
int a = (r.width / 2) - (rWidth / 2) - rX;
int b = (r.height / 2) - (rHeight / 2) - rY;
g.setFont(font);
g.drawString(s, r.x + a, r.y + b);
}
}
}
Image Quality Loss When Drawing One BufferedImage to Another Using Graphics2D
The problem is this line from the clearLayers()
method:
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), frames[0].getType());
As the GIF uses a palette, the BufferedImage
type will be TYPE_BYTE_INDEXED
. However, if you pass this parameter to the BufferedImage
constructor, it will use a default IndexColorModel
(a built-in, fixed 256 color palette), not the palette from your GIF. Thus, the frames from the GIF will have to be dithered into the destination, as the colors doesn't match.
Instead, use TYPE_INT_RGB/TYPE_INT_ARGB
for type, or use the constructor that also takes an IndexColorModel
parameter and pass the IndexColorModel
from the frames of the GIF.
In code:
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), BufferedImage.TYPE_INT_ARGB);
Alternatively, the following should also work if all frames of the GIF uses the same palette (not necessarily the case):
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), frames[0].getType(), (IndexColorModel) frames[0].getColorModel());
However, as the OP reports back the latter option doesn't work for him, the first option is probably safer. :-)
Drawing a Component to BufferedImage causes display corruption
Summary: The original JScrollNavigator
uses the Swing opacity
property to render a convenient green NavBox
over a scaled thumbnail of the component in an adjacent JScrollPane
. Because it extends JPanel
, the (shared) UI delegate's use of opacity
conflicts with that of the scrollable component. The images seen in edit 5 above typify the associated rendering artifact, also shown here. The solution is to let NavBox
, JScrollNavigator
and the scrollable component extend JComponent
, as suggested in the second addendum below. Each component can then manage it's own properties individually.
I see no unusual rendering artifact with your code as posted on my platform, Mac OS X, Java 1.6. Sorry, I don't see any glaring portability violations.
A few probably irrelevant, but perhaps useful, observations.
Even if you use
setSize()
, appropriately in this case, you should stillpack()
the enclosingWindow
.f.pack();
f.setSize(300, 200);For convenience,
add()
forwards the component to the content pane.f.add(nav, BorderLayout.WEST);
Prefer
StringBuilder
toStringBuffer
.Consider
ComponentAdapter
in place ofComponentListener
.
Addendum: As suggested here, I got somewhat more flexible results using RenderingHints
instead of getScaledInstance()
as shown below. Adding a few icons makes it easier to see the disparate effect on images and text.
editPane.insertIcon(UIManager.getIcon("OptionPane.errorIcon"));
editPane.insertIcon(UIManager.getIcon("OptionPane.warningIcon"));
...
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Component view = jScrollPane.getViewport().getView();
BufferedImage img = new BufferedImage(view.getWidth(),
view.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D off = img.createGraphics();
off.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
off.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
view.paint(off);
Graphics2D on = (Graphics2D)g;
on.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
on.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);
on.drawImage(img, 0, 0, getWidth(), getHeight(), null);
}
Addendum secundum: It looks like the JPanel
UI delegate is not cooperating. One workaround is to extend JComponent
so that you can control opacity. It's only slightly more work to manage the backgroundColor
. NavBox
and JScrollNavigator
are also candidates for a similar treatment.
jsp.setViewportView(new JComponent() {
{
setBackground(Color.red);
setBorder(BorderFactory.createLineBorder(Color.BLACK, 16));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
});
How do I fade a BufferedImage when manipulating it's pixel data?
Your game engine is drawing the image on top of itself in a loop. After drawing it enough many times the effect is the same as not having used transparency at all. The lower the alpha, the longer it takes though: with 50% alpha you need 7 frames to get 99% opacity, with 5% alpha you need about 90 frames.
For example, suppose you are drawing a pixel value of 100 on a screen that's intially 0 (black) with 50% opacity. After the first frame, the output pixel value is .5*100 + .5*0 = 50. The second frame is drawn on top of the first frame, so the output pixel value is .5*100 + .5*50 = 75. The third frame, drawn on top of the second frame, will show .5*100 + .5*75 = 87.5.
To avoid this, you need to fill a solid background color under the image in every frame.
Related Topics
Using Scala Traits with Implemented Methods in Java
Getting Class Type from String
Sorting Strings That Contains Number in Java
Arrayindexoutofboundsexception When Iterating Through All the Elements of an Array
Uses for the Java Void Reference Type
How to Configure JPA for Testing in Maven
Using Jaxb to Cross Reference Xmlids from Two Xml Files
In Java, How to Efficiently and Elegantly Stream a Tree Node's Descendants
Java Interfaces Methodology: Should Every Class Implement an Interface
Missing Return Statement in a Non-Void Method Compiles
Java's Date(...) Constructor Is Deprecated; What Does That Mean
Java Sax Parser Split Calls to Characters()
Java Regular Expressions and Dollar Sign
Increasing Heap Space in Eclipse: (Java.Lang.Outofmemoryerror)