3 questions about Images
I'm pretty inexperienced when it comes to graphics programming, so these may have really simple answers I'm not getting.
(1) Say I have an image, and I want to draw just a portion of it to the screen. How do I do this?
(2) Also, I load my image this way:Image img = Toolkit.getDefaultToolkit().getImage("some.png");
This returns before the image is loaded. So I do this:Image img = Toolkit.getDefaultToolkit().getImage("some.png");
JLabel jl =new JLabel(new ImageIcon(img));
to wait for the image to finish loading. I'm sure this is not a good way to do it. What is the proper way?
(3) Finally, I want to rotate my image. I'm doing it like this:public Image getRotatedImage(double angle){
AffineTransform trans =new AffineTransform();
trans.rotate(Math.toRadians(angle), bimg.getWidth()/2d, bimg.getHeight()/2d);
AffineTransformOp op =new AffineTransformOp(trans, AffineTransformOp.TYPE_BILINEAR);
return op.filter(bimg, rotated);
}
where bimg and rotated are BufferedImages. The problem I'm running across is that if my original image isn't square, when I create rotated, the new image is cut off. What's the best way to avoid this? Should I do some calculations to figure out what the new bounds are going to be beforehand, or is there a shortcut I can use?
Thanks in advance,
m
[1719 byte] By [
wywiwyg] at [2007-9-27 19:04:24]

For 1), check out BufferedImage.getSubimage()... Then you can do ((BufferedImage)img).getSubimage(). There may also be a better way, but this is what I've used.
For 3), I use the Graphics2D method drawImage(BufferedImage, AffineTransform, ImageObserver). Although I'm not quite sure what you mean by "cut-off"...
Thanks for the responses.
(1) I'll try that
(3) By cutoff I mean, if the original image is 20x40, and I want to rotate it by, say 45 degrees, do I have to figure out what the new dimensions of the rotated image are before I write to the BufferedImage containing it? Or is there a shortcut that does this? Currently, I create my rotated BufferedImage with the same dimensions (20x40), so when it rotates the original image, it tries to fit it into 20x40, which won't work.
m
Sorry, brain ****.... I'll try what you suggested for (3) as well. ImageObserver confuses me a bit. I've just been using null for that. Probably not the best....Thanks again,m
i've never used ImageObserver either (apart from tracking the loading of images)all draw operations occur synchronously, unless they rely on an ImageProducer that hasn't got a fully buffered image, so for the vast majority of applications, its an absolutly useless parameter.
Abuse at 2007-7-6 21:16:16 >

How do you use ImageObserver to track the loading of images? That sounds like it would help me with question 2.Thanks,m
here you go, knocked this up for ya :P
import java.awt.*;
import java.awt.image.*;
public class ImageLoader implements ImageObserver
{
private static ImageLoader imgLoader = new ImageLoader();
private ImageLoader(){}
public static Image [] loadImages(Image [] imagesToLoad)
{
for(int ii = 0;ii < imagesToLoad.length;ii++)
{
synchronized(imgLoader)
{
System.out.print("Loading " + imagesToLoad[ii]);
if(imagesToLoad[ii].getWidth(imgLoader)==-1 || imagesToLoad[ii].getHeight(imgLoader)==-1)
{
try
{
imgLoader.wait();
}
catch(Exception e){}
}
}
}
System.out.println("All images fully loaded");
return imagesToLoad;
}
public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h)
{
if((flags & ImageObserver.ALLBITS)!=0)
{
System.out.println(" Load complete");
synchronized(imgLoader)
{
try
{
imgLoader.notify();
}
catch(Exception e){}
}
return false;
}
System.out.print(".");
return true;
}
public static void main(String [] args)
{
Toolkit t = Toolkit.getDefaultToolkit();
Image [] test = new Image[]
{
t.createImage("test.png"),
t.createImage("test.png"),
t.createImage("test.png"),
t.createImage("test.png"),
t.createImage("test.png")
};
ImageLoader.loadImages(test);
}
}
Abuse at 2007-7-6 21:16:16 >

Thanks a lot! That really helps. I'll look at it carefully later.m
I've always just used null for ImageObserver too, as it usually tends to be a useless parameter as far as I can tell...
This is the code I use to paint a rotated image in the middle of my screen...
void paintShip(Graphics2D g2){
int degs=(myShip.getDirection()-Byte.MIN_VALUE)*360/256;
AffineTransform totalTransform=AffineTransform.getRotateInstance(Math.toRadians(degs),
d.width/2-shipimage.getWidth(null)/2, d.height/2-shipimage.getHeight(null)/2);
//d is the screen's Dimension
totalTransform.translate(d.width/2-shipimage.getWidth(null),
d.height/2-shipimage.getHeight(null));
g2.drawImage(shipimage, totalTransform, null);
}
if you wnat to draw only a part of an image callGrahics.setClipBounds(x,y,w,h); // or similarthis will draw the image clipped to your desired size.
for loading images there is an MediaTracker class.Image img = getImage("xxx.jpg");MediaTracker mt = new MediaTacker();mt.add(img, 0);mt.waitForAll(); // wait until all images with id=0 are loaded
media tracker is abit **** though :|
Abuse at 2007-7-6 21:16:16 >

So, this is a problem I'm trying to figure out. I'm programming a game where you have a little guy in the center of your screen, who rotates towards where you click and moves around a map (altough the map moves around him). When I rotate the guy, he simply draws over top of what was there previously, so I'm currently redrawing the background in the center before I redraw the rotated guy. This is causing flickering (I'm repainting ~30 times a second). So a couple questions. What's the best way to do this, or at least some hints towards more efficient ways? Can anyone recommend any books or websites to learn more about this? Specifically, _not_ 3D games. That's all I can find, and that's really not what I want. Anyways, don't know how clear the above is.... my mind's a little cloudy today.....
m
> media tracker is abit **** though :|why is it ****?
> around him). When I rotate the guy, he simply draws
> over top of what was there previously, so I'm
> currently redrawing the background in the center
> before I redraw the rotated guy. This is causing
> flickering (I'm repainting ~30 times a second). So a
1) If you aren't already doing so, double buffer.
2) How are you "drawing" the guy? Is it a preloaded image or what? Anything you can do to cut down the number of different draws, the better... For instance, in the code snippet I listed above, I have my ship image already loaded and ready to go... The image is just drawn onto my buffer, and the whole buffer is drawn to the screen.
My canvas is double buffered, and I load my .png into a BufferedImage which I then draw to the panel in a way very similar to yours. My original image has transparent sections and is longer than it is wide, so it doesn't paint over its old self when rotated. m
> > media tracker is abit **** though :|
>
> why is it ****?
your joking right?
have a look at the source code, its incredibly bloaty, inefficient and inflexible.
The 3 biggest problems i've got with it...
1) No callback mechanism - for updating a loading bar etc... if you want periodic updates, you have to poll the class
2) Each Image that you add to a MediaTracker is wrapped inside an ImageMediaEntry object (which itself is a subclass of MediaEntry). This is totally unnecessary, and just bloats the code.
3) all the checkXXX methods execute in O(n) time, when they SHOULD execute in O(1) time. (it does a linear search of a linklist that contains all the added images) This is incredibly wasteful.
Abusea at 2007-7-18 15:26:04 >

ok you're right abuse :-)i believe you. and iam wondering why can't i use mediatracker for loading sounds? it is a mediatracker, not an imagetracker!
:) im glad you agreeperhaps Sun will take not, and write a 1/2 decent ImageTracker (1 that supports a listener architecture, so you can ezily intergrate it into an AWT/Swing Component)
Abusea at 2007-7-18 15:26:04 >

yes you should a RFC to sun for that!
> When I rotate the guy, he simply draws
> over top of what was there previously, so I'm
> currently redrawing the background in the center
> before I redraw the rotated guy. This is causing
> flickering (I'm repainting ~30 times a second). So a
> couple questions. What's the best way to do this, or
> at least some hints towards more efficient ways?
It is important you repaint only updated regions, so the rest is left alone. You should also prepare all images in the constructor, not in the paint methods !
You could use a LayeredPane of JPanel 's within a JFrame, it goes a bit like this:
/** here you put the drawing stuff of the background */
public class BackgroundMap extends JPanel {
public BackgroundMap() {
setDoubleBuffered(true);
setOpaque(false);
}
public void paint(Graphics g) {
...
}
}
/** here you draw your guys, make sure both the normal and rotated guy
* are made ready in the constructor (not in the drawing method)
*/
public class GuysMap extends JPanel {
public GuysMap() {
setDoubleBuffered(true);
setOpaque(false);
}
public void paint(Graphics g) {
...
}
}
public class MyGame extends JFrame() {
/** bottom panel*/
private BackgroundMap map;
/** top panel */
private GuysMap guys;
MyGame() {
/** create the map */
BackgroundMap map = new BackgroundMap(...);
/** add the map to the bottom layer */
getLayeredPane().add(map, 1000);
/** create the game */
GuysMap guys = new GuysMap(...);
/** add it to the top layer */
getLayeredPane().add(guys, 0);
}
public void paint(Graphics g) {
map.paint(g);
guys.paint(g);
}
/** maybe a couple of runnables (multithreaded, one for each player, for instance)*/
Runnable r = new Runnable() {
public void run() {
try {
sleep(30)
} catch (...) {}
//other stuff
if (myMapHasChanged)
map.repaint(
/*give bounds if only a small region needs to be updated*/
);
}
if (myGuysHasMoved) {
//avoid paintImmediately !!
guys.repaint(/* bound !! */);
}
}
};
}
Hope this is helpfull,
jpw
jpw35a at 2007-7-18 15:26:04 >

