Graphics Antics, Mostly Image manipulation


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 6 of 6

Thread: Graphics Antics, Mostly Image manipulation

  1. #1
    Join Date
    Jan 2004
    Posts
    7

    Graphics Antics, Mostly Image manipulation

    So, I've been tinkering around with java, not sure why, but I am nonetheless. I have figured out how to load an image, and load multiple images, but I haven't figured out how to load images more than once, like an animation. I've been gutting one of Sun's examples to examine it, and all I can figure out is that it stores all the images, then prints all the images. I want to know how I can call paint( aka. paint to the screen) more than once, preferably right after I declare the images. See below for a bit of the code. Thanks in advance.
    And I can't figure out how to put this in a quote box..... If someone would tell me I'd be happy to do it.

    public void init() {
    setBackground(Color.white);
    bi = new BufferedImage[4];
    String s[] = { "Intro-01.jpg", "Intro-02.jpg", "protobackground.jpg", "untitled.jpg"};
    for ( int i = 0; i < bi.length; i++ ) {
    Image img = getToolkit().getImage("images/" + s[i]);
    try {
    MediaTracker tracker = new MediaTracker(this);
    tracker.addImage(img, 0);
    tracker.waitForID(0);
    }
    catch ( Exception e ) {}
    int iw = img.getWidth(this);
    int ih = img.getHeight(this);
    bi[i] = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
    Graphics2D big = bi[i].createGraphics();
    big.drawImage(img,0,0,this);
    System.out.println("Check1");
    }
    }
    public void paint(Graphics g) {
    System.out.println("Check..");
    Graphics2D g2 = (Graphics2D) g;
    int w = getSize().width;
    int h = getSize().height;
    g2.setColor(Color.black);
    for ( int i = 0; i < bi.length; i++ ) { ;
    int x = 0, y = 0;
    switch ( i ) {
    case 0 :
    break;
    case 1 : x = w/2+3; y = 15;
    break;
    case 2 : x = 5; y = h/2+15;
    break;
    case 3 : x = w/2+3; y = h/2+15;
    }
    g2.drawImage(bi[i],null,x,y);
    }
    }
    </quote>
    Last edited by Runesoul; 05-04-2005 at 10:01 PM.

  2. #2
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Here is some advice..

    When you show an animation you dont load the images for each
    display, you just do a drawImage each time using the image object(s)
    you already have loaded.

    You should not attempt to invoke the paint(Graphics g) method directly.
    If you use the repaint() method instead, then the paint/update(Graphics g)
    methods wil be called with the proper grahics context.

    For an animation this means that you have a thread that loops forever
    and basically just does three things:
    checks the continueAnimation -flag on each loop, breaks when false
    invokes repaint()
    sleeps for a short while (calibrate this)

    If you are planning to do animations you should uverride both paint & update
    like this (memImg and memG are the memoryImage and graphics created
    during image load). The images load processing sets the graphicsReady
    to true after completion and calls repaint.

    Code:
    public void paint (Graphics g) {
      update (g)
    }
    public void update (Graphics g) {
      Color oldColor=g.getColor();
      g.setColor(myBackgroundColor);
      g.fillRect(0,0,getWidth(), getHeight());
      g.setColor(oldColor);
      if (!graphicsReady) { // flag set after successful  image load
        g.drawString("Graphics not ready yet", 20,20);
        return;
      }
      drawBufferedGraphics();
      g.drawImage(memImg,0,0,this);
    }
    private void drawBufferedGraphics () {
      memG.drawImage(whatevver, x,y,this);
    }
    I posted this code using the code tag:
    start: "["+"code"+"]", end: "["+"/code"+"]"

    Note: if you override the update(Graphics g) method then a statement like
    setBackground(Color c) will not have any effect. As I recall the default
    update processing is just to set the selected/default background color and
    filling a rectangle the size of the display with that color. In other words,
    your update method will have to do it by itself, like I've shown above.

    I've included the body of a little method I've been using, it clips a big image
    into smaller ones, enabling you to have animations that uses just a single
    image "sheet" where the "frames" are set up as an xy grid of images. I think
    its kinda neat

    Code:
    .
    .
    ImageProducer ip = baseImageIcon.getImage().getSource();
    .
    .
    clipImage(imgGrid, dim, ip);
    .
    .
    /**
       * Clip the base image into a set of smaller images.
       * @param base empty image matrix
       * @param dim the single image dimension
       * @param ip the image (producer) to be clipped
       */
      private void clipImage(Image [][] base,
                             Dimension dim, ImageProducer ip) {
        int x=0;
        int y=0;
        int wtCnt=0;
    
        MediaTracker mt=new MediaTracker(frame);
        imageQue.clear();
        for (int i=0;i<base.length;i++) {
          x=0;
          for (int j=0;j<base[0].length;j++) {
            CropImageFilter cropFilter= new CropImageFilter(x,y,dim.width,dim.height);
            Image img =  frame.createImage(new FilteredImageSource(ip,cropFilter));
            try {
              /**
               * add to que
               */
              imageQue.add(img);
            }
            catch (QueueException ex1) {
              MSSApp.deb.trLn(ex1.getMessage());
              continue;
            }
            mt.addImage(img,wtCnt++);
            base[i][j]=img;
            x+=dim.width;
          }
          y+=dim.height;
        }
        try {
          mt.waitForAll();
        }
        catch (InterruptedException ex) {
          ex.printStackTrace();
        }
    
      }
    eschew obfuscation

  3. #3
    Join Date
    Jan 2004
    Posts
    7
    Alright first, that's helps A LOT, but I still have a couple questions. The most important of which, is when exactly is the image drawn to the stream? From what I can gather from your first example, You first draw the image onto a buffer in the drawBufferedGraphics step. And then it outputs to the screen inside the update method at the drawImage call. Am I on the right track?

    Also, I was tinkering around with it, and I think that half of my problem was that once I invoked show(); It took up the focus, and thus never got to the second show(); to show the second picture, I realize this is probably an inefficient way to do it, but could this be solved by putting it in a thread? And if so, how exactly would I go about doing that, I've only glanced at threads before, and they seemed rather confusing.

    Thanks again.
    Runesoul

  4. #4
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560
    Right track ? yes
    I make a memory image and draw into its graphics, - when that is done I
    draw the memoryImage to the display graphics, that is the g delivered
    to the update/paint methods you have made.
    In other words, never deliver an unfinished image to the display, - no flickering ...

    To fully understand the workings of threads you have to see it like delivering a job
    to the machine, and that machine has a lot to do, so it starts your job but (rather
    randomly) gives other jobs (display update, other apps, other threads) a chance to do
    their stuff too, thus halting your job for a little while. If you use show (deprecated?)
    it only tells the GUI to appear on screen, - and thats all.

    You must use the repaint() method in cooperation with your animations thread:

    Your thread does the positional/imageselection job, - issues a repaint invocation,
    and your paint/update selects the graphics/positions from that info and
    draws the appropriate ...whatever.

    Yes, threads are confusing, I mean seriously, we are talking "simultaneous" processing
    here, and that is quite a logical mouthfull...
    eschew obfuscation

  5. #5
    Join Date
    Jan 2004
    Posts
    7
    Alright, so I have gotten the basics down, but I'm having a bit of problems implementing them into a form that I want to use. I'm basically making a game, and so far what I have works, but i can't do some stuff I want to. Right now, I have the graphics process on a seperate thread running through an infinite loop repainting an array that is adjusted from another class, but I've hit several problems. First, the background changes to the default background (some wierd gray color) every time another picture is loaded. THis is fine for the pictures that are the size of the screen, but as you can imagine, it causes quite a visible blip when something smaller is painted. I want to change it to where it is only repainted everytime something is added or subtracted or set (think arraylist). Also, I am not quite sure how I will be able to do animation within the array...

    Here's some of the code:

    From the Sprite class, just has the imagearry and locs of the imgs and the update method, which i think is the most important
    Code:
    public boolean update() {	
        if(currentImgIndex < images.length-1)
        {
          	currentImgIndex++;
          	if(currentImgIndex == images.length-1)
          		firstTime = true;
          	return true;
        }
        else
        	return false; 
        	
        
      }
    And this is the other game, GameGraphics, which paints the images and such.

    Code:
     public void run() {
      	repaint();
        while (true) {    	
        	while(sprite.update())
        	{
        		repaint();         	
        	}      
          try {
            Thread.sleep(50);
          } catch (InterruptedException e) {}
        }
      }
    
    //override update()
      public void update(Graphics g) {
        paint(g);
      }
    
      //on-screen image buffer
      public void paint(Graphics g) {
      	//g.setColor(g.getColor());
      	System.out.println(getSize().width);
        offImg = createImage(getSize().width, getSize().height);
        Graphics offg = offImg.getGraphics();
        paintOffScreen(offg);
        g.drawImage(offImg, 0, 0, null);
      }
    
      //off-screen image buffer
      public void paintOffScreen(Graphics g) {
        g.drawImage(sprite.getCurrentImage(), sprite.getCurrentLocation().x,
                    sprite.getCurrentLocation().y, this);
       }

    Thanks for any help

    Runesoul
    Last edited by Runesoul; 05-10-2005 at 01:44 PM.

  6. #6
    Join Date
    Nov 2004
    Location
    Norway
    Posts
    1,560

    Almost there.

    Instead of shifting your code around I have attached
    the basics as an application. You should study this little code snippet
    carefully, and you'll see how you can mold it into your game requirements.

    The paint/update methods of all visible java components have the following jobs:

    update : paint background
    paint : paint the rest of the graphics on the newly painted background.

    In other words, they work in cooperation, first update, then paint, on
    every screen refresh.
    The default behaviour of a plain JPanel is to call update, e.g. first fill the back with a default color and then call its dummy paint method that does
    nothing.... nada.

    But, when your JPanel extension overrides the paint method it works like:
    after the superclass has called its update method, it calls the paint method (your override), thus delivering you a freshly painted gray canvas.

    This happends on every call to the JPanels repaint method, so you don't
    call paint/update, ok ? Call repaint.

    The visible object, components or sprites as you call them all have one thing
    in common, they want to be drawn on the screen. So why not let them do it
    themselves ? - Instead of having a big paint job metod, you just code your paint
    job like a loop over an arraylist of SpriteObjects that, in turn, draw
    themselves on the graphical contex. Needless to say, the sequence in this list
    determines the layers of the image; the lower the index, the lower the
    layer.

    So define an abstract class that defines the draw method, make all your
    sprite classes as extensions of this class, store them in the diplayList,
    loop over this list in every paint job telling the spriteObjects to draw
    themselves.

    All events in the application that changes the "innards" of any object in the
    displayList of a gamePanel must result in/finish with an invokation of
    gamePanels repaint method. Typically for a game, that event is when the
    application (game) has finished one tick; the actions between each
    thread sleep period. I have included a very basic game where
    the user bursts bubbles and squares and gets one pont per object, challenging
    stuff in other words.


    Note the sequence of invokation: My GamePanel has overridden both paint and
    update, and the paint method only calls update. Nothing more required.


    And one more thing, never put code in paint/update that repeatedly loads/creates images, fonts or colors ! Its gonna overload.
    Attached Files Attached Files
    eschew obfuscation

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center