Java Forum / First Aid / February 2008
Has working with raster graphics always been this complicated?
jsalzman@gmail.com - 25 Feb 2008 16:21 GMT Hello,
I'm not new to programming, but I'm new to Java, at least as far as programming an entire applet. I'm familiar with looking through a language's API to learn more about developing an application using available methods. I've done it plenty of times.
When I learn a new programming language, I do it by having a goal in mind. Something that I want to program to achieve a task. in doing so, I develop an understanding of the language.
I just can't, for the life of me, figure out how to manipulate raster images the way I want. I find references to Image objects, Graphics objects, BufferedImage objects and such. You can do things with Image objects that you can't do with Graphics objects. There's plenty of online help for Java, but help through API docs and tutorials don't seem to spell out many details. There seems to be more useful tutorials, describing the theory behind an API call, for Visual Basic than Java out there.
I'm trying to figure out the true differences between an Image and Graphics object. From what I can find, You can draw primitives on Graphics, but not Image. If you can draw primitives on Images, I can't figure out the details.
Here's what I'm trying to do. This is the "demo" project I'm making to help me learn graphics handling concepts in Java. I wanted to make a mouse driven application that reveals a hidden picture. I have the picture graphics to be revealed, in the form of GIF files. I have a series of "covering" images that I want to use to cover the pictures in the form of GIF files (in the shape of doors, curtains, etc.).
Here's my concept. I have code working that can get the door image to draw over the picture image. I'm having trouble with the code that will do the "reveal". I want to animate a box that widens from the middle of the cover picture to the edges (simulating a barn door wipe). My first thought would be to paint 1px wide box in a transparent color and redraw the box to as wide as the graphic. Sounds easy enough in a drawing program like Photoshop. I can't figure out how to paint in a transparent color on a raster image object and then superimpose that image on the picture making the picture visible under those transparent pixels.
I'm not asking anyone to write the entire program for me. The way I'm trying to accomplish the task may be overkill, but I'm doing it this way to become familiar with certain concepts. I'm looking for working examples of code that'll show me how to draw transparent pixels on a raster image, overlay the raster on another image with the image showing through the transparent spot, and draw primitives on a raster image (if different from other drawing methods using rasters). Double buffering the drawing process would be a plus, is that what I would use a BufferedImage for?
Thanks, Jeff
Nigel Wade - 25 Feb 2008 16:44 GMT > Hello, > [quoted text clipped - 15 lines] > tutorials, describing the theory behind an API call, for Visual Basic > than Java out there. This isn't anything I'm really familiar with myself. I've done some basic programming with the Graphics2D object, images and transforms etc. but not a lot. I don't know if these links are of any use to you, they are some I filed away for myself, if you haven't looked through them yet they could provide some insight:
http://java.sun.com/docs/books/tutorial/2d/index.html http://www.apl.jhu.edu/~hall/java/Java2D-Tutorial.html
 Signature Nigel Wade, System Administrator, Space Plasma Physics Group, University of Leicester, Leicester, LE1 7RH, UK E-mail : nmw@ion.le.ac.uk Phone : +44 (0)116 2523548, Fax : +44 (0)116 2523555
Knute Johnson - 25 Feb 2008 17:20 GMT > Hello, > [quoted text clipped - 51 lines] > Thanks, > Jeff Graphics and Graphics2D should be thought of as the paint brush with which you draw on Images, BufferedImages, Printers, etc. If an object is something to draw on, you will be able to get a Graphics/2D object for it.
If you load an image that has transparent pixels, when you draw that image on top of another image, the first image will show through the transparent pixels. There are numerous other ways to make drawings or images transparent (see AlphaComposite). Color objects can be created with transparency too. Below I create a BufferedImage, draw translucent yellow pixels on the entire image. In the paintComponent(), where all drawing on the component must take place, I draw a red and blue X on the component and then draw the BufferedImage with its transparent pixels over the top. The is just one simple way to do this sort of drawing.
import java.awt.*; import java.awt.image.*; import java.awt.event.*; import javax.swing.*;
public class test extends JPanel { BufferedImage bi = new BufferedImage(400,300,BufferedImage.TYPE_INT_ARGB);
public test() { setPreferredSize(new Dimension(400,300));
// draw translucent yellow on the buffered image Graphics2D g = bi.createGraphics(); g.setColor(new Color(255,255,0,180)); g.fillRect(0,0,bi.getWidth(),bi.getHeight()); }
public void paintComponent(Graphics g2D) { Graphics2D g = (Graphics2D)g2D; // draw blue and red X first g.setColor(Color.BLUE); BasicStroke bs = new BasicStroke(20.0f); g.setStroke(bs); g.drawLine(0,0,getWidth(),getHeight()); g.setColor(Color.RED); g.drawLine(getWidth(),0,0,getHeight());
// draw translucent image g.drawImage(bi,0,0,null); }
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); test t = new test(); f.add(t); f.pack(); f.setVisible(true); } }); } }
 Signature Knute Johnson email s/nospam/knute/
jsalzman@gmail.com - 25 Feb 2008 17:59 GMT Thanks for the help Knute (and Nigel) for some of the direction.
I see by your sample code Knute that Java is highly "granular" when it comes to manipulating objects, mostly the requirement of getting a new instance of something you want to use to manipulate another object. Just something I need to keep in mind to better understand Java.
Mark Space - 25 Feb 2008 18:19 GMT > Thanks for the help Knute (and Nigel) for some of the direction. > > I see by your sample code Knute that Java is highly "granular" when it > comes to manipulating objects, mostly the requirement of getting a new > instance of something you want to use to manipulate another object. > Just something I need to keep in mind to better understand Java. You might also consider getting some introductory reading material on Java graphics. I don't have a lot of experience with it either, but _Learning Java_ by O'Reilly does have an introduction to Graphics2D. I remember specifically a demo program that loaded an image, then allowed you to grab it with the mouse and drag it around the window. It was pretty cool and with a little bit of study revealed some good hints how to think about the Graphics2D operations.
_Learning Java_ is also a very complete introduction to the language, and many important APIs. If you are feeling new and overwhelmed, I'd recommend it as a good start. With _Learning Java_ and Sun's on-line tutorial, you have 90% of what you need to get started. Make sure to get the latest edition (third I think).
There are also books specifically on 2D graphics in Java. I don't know how much they really add to _Learning Java_.
jsalzman@gmail.com - 26 Feb 2008 13:12 GMT OK, I'm getting close, but I seem to be missing something. I've included my code so far. I know it's a bit messy, but I'm still learning to tighten up java code. This is a proof of concept for me. It achieves something similar to what I wanted to do originally. I currently have the program draw an oval (circle) where the mouse clicks. That's enough to let me see what happens real-time. Eventually, I'll have the reveal "expand" from the point where the user clicks.
Anyway, drawing an expanding oval or box isn't the problem. This example takes one image file (revealArea) and is supposed to overlay it on another image file (baseImage). I expected to be able to click in the window and wherever my mouse is, an oval will "paint a hole" into the revealArea image, exposing part of the baseImage below.
I currently have the code of the revealArea image commented out. In lieu of that image, I simply draw a white filled rectangle to substitute. The rectangle overlays the base image fine (as witnessed from the flicker). Drawing the oval does something unexpected. I set the paint color to blue with an alpha of 30. I tried an alpha of zero, expecting the hole to appear. When I click in the window, I get a translucent blue circle blended with the white rectangle and not the "hole" I expected to be formed. Is there a way to "paint" the hole? Also, what techniques can I use to avoid the flicker of the images drawing over one another?
Thanks!
----------------------- import java.applet.*; import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.lang.Math; import javax.swing.*; import javax.imageio.*; import java.io.*;
public class Reveal extends Applet implements MouseMotionListener {
int width, height; int mx, my; // the mouse coordinates Image baseImage; Image revealArea; Image backbuffer; BufferedImage revealBuffer; Graphics revealOverlay;
public void init() { width = getSize().width; height = getSize().height; setBackground( Color.black );
mx = width/2; my = height/2;
baseImage = getImage( getDocumentBase(), "baseimage.gif" ); revealArea = getImage( getDocumentBase(),"overlay.gif");
revealBuffer = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); revealOverlay = revealBuffer.getGraphics(); revealOverlay.fillRect(10, 10, 80, 80); //revealOverlay.drawImage(scratchArea, 0, 0, 100, 100, null);
repaint();
addMouseMotionListener( this ); }
public void mouseMoved( MouseEvent e ) { repaint(); e.consume(); }
public void mouseDragged( MouseEvent e ) { int x = e.getX(); int y = e.getY();
revealOverlay.setColor(new Color(0, 0, 255, 30)); revealOverlay.fillOval(x-5, y-5, 20, 20);
repaint(); e.consume(); }
public void paint( Graphics g ) {
g.drawImage(baseImage, 0, 0, null); g.drawImage(revealBuffer, 0, 0, null); } }
Knute Johnson - 26 Feb 2008 22:37 GMT > OK, I'm getting close, but I seem to be missing something. I've > included my code so far. I know it's a bit messy, but I'm still [quoted text clipped - 89 lines] > } > } This can get really tricky. The problem usually turns out for me anyway is that you can't draw on an image and reduce its alpha. You have to use an AlphaComposite to set the pixel values to something less than opaque. Then you can draw that image over another image and the image behind will be visible through the alpha hole. If you draw translucent pixels over opaque pixels the image is still opaque. See the example below.
import java.awt.*; import java.awt.image.*; import java.awt.event.*; import javax.swing.*;
public class test extends JPanel { BufferedImage bi = new BufferedImage(400,300,Transparency.TRANSLUCENT); Graphics2D imageG;
public test() { setPreferredSize(new Dimension(400,300));
imageG = bi.createGraphics();
// the green overlay image will not be green until the first // time you press the mouse button addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent me) { // paint the whole image green imageG.setColor(Color.GREEN); imageG.fillRect(0,0,bi.getWidth(),bi.getHeight()); // save the composite Composite c = imageG.getComposite(); // clear a hole in the green image // adjust the alpha to keep a percentage of green // you could use AlphaComposite.CLEAR will be the same as using // an alpha of 0f imageG.setComposite(AlphaComposite.getInstance( AlphaComposite.DST_ATOP,0.4f)); imageG.fillOval(me.getX()-20,me.getY()-20,40,40); // restore the composite imageG.setComposite(c); repaint(); } }); }
public void paintComponent(Graphics g2D) { Graphics2D g = (Graphics2D)g2D;
// erase everything with white g.setColor(Color.WHITE); g.fillRect(0,0,getWidth(),getHeight()); // draw blue and red X g.setColor(Color.BLUE); BasicStroke bs = new BasicStroke(20.0f); g.setStroke(bs); g.drawLine(0,0,getWidth(),getHeight()); g.setColor(Color.RED); g.drawLine(getWidth(),0,0,getHeight());
// draw image with translucent hole g.drawImage(bi,0,0,null); }
public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); test t = new test(); f.add(t); f.pack(); f.setVisible(true); } }); } }
 Signature Knute Johnson email s/nospam/knute/
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|