lomidien
asked on
RGBImageFilter
I'm using double-buffering in my applet to paint my image to an offscreen image before posting to the screen. After the offscreen image is assembled, I'm running it through an RGBImageFilter in order to change the pixel values to greyscale. I've attached the whole code below, but the RGBImageFilter code is at the bottom if that is all you need. It seems as though the image is not being filtered at all, however, my animated box disappears if I'm using that method on the offscreen image. If I remove the call to the filter, the image animates correctly.
I can change the method which alters the pixel value...for instance, to swap blue and red values and then the animatin works again and the screen changes, however the code to change the pixel values to greyscale do nothing except make the animation disappear.
Thanks,
David
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener ;
import java.awt.image.FilteredIma geSource;
import java.awt.image.ImageFilter ;
import java.awt.image.RGBImageFil ter;
public class GameApplet extends Applet implements Runnable, KeyListener {
public boolean paused = false;
private int maxWidth , maxHeight ; // animation boundary
private int currX , currY ; // left,top (x,y) of the animating rectangle
private int currXVelocity , currYVelocity ; // pixels per move
private int imageHeight , imageWidth ; // size of animating rectangle
// new stuff for dbl-buffering
Graphics offscreen ;
Image imageForOffscreen ;
// This method is called once by the browser when it starts the applet.
public void init() {
this.addKeyListener(this); //add keylistener to trap P key
Color c = Color.blue;
setBackground(c) ;
maxWidth = 500 ;
maxHeight = 500 ;
imageHeight = 25 ;
imageWidth = 40 ;
currXVelocity = 3 ;
currYVelocity = 3 ;
// set up random positions to start the images
currX = (int)( ( Math.random() * 80 ) + 1 );
currY = (int)( ( Math.random() * 80 ) + 10 );
// new stuff for dbl-buffering
imageForOffscreen = createImage( maxWidth , maxHeight );
offscreen = imageForOffscreen.getGraph ics();
Thread animator = new Thread( this );
animator.start();
}
// This method is called whenever the page containing this applet is made visible.
public void start() {
}
// This method is called whenever the page containing this applet is not visible.
public void stop() {
}
// This method is called once when the browser destroys this applet.
public void destroy() {
}
// Runnable contract
public void run() {
// Generic Game Loop
while ( !paused )
{
try
{
Thread.sleep( 50 );
}
catch ( InterruptedException e )
{
}
currX = currX + currXVelocity ;
currY = currY + currYVelocity ;
if ( ( currX + imageWidth ) >= maxWidth )
{
currXVelocity = -3 ;
}
else if ( currX <= 0 )
{
currXVelocity = 3 ;
}
if ( ( currY + imageHeight ) >= maxHeight )
{
currYVelocity = -3 ;
}
else if ( currY <= 0 )
{
currYVelocity = 3 ;
}
repaint();
}
}
// This method is called whenever this applet needs to repaint itself.
public void paint(Graphics g) {
// first do what the update would have done --
//erase the background of the offscreen Graphics surface
offscreen.setColor( getBackground() );
offscreen.fillRect( 0 ,0 ,maxWidth , maxHeight );
// paint the rectangle onto the offscreen surface
// If there were more images to be painted, it would
// all happen here. Paint ALL images at this step
offscreen.setColor( Color.black );
offscreen.drawRect( currX , currY , imageWidth , imageHeight );
// Create the filter
ImageFilter filter = new GetRedFilter();
FilteredImageSource filteredSrc = new FilteredImageSource(imageF orOffscree n.getSourc e(), filter);
// Create the filtered image
imageForOffscreen = Toolkit.getDefaultToolkit( ).createIm age(filter edSrc);
// then blast that final image to the screen
g.drawImage( imageForOffscreen , 0 , 0 , this );
}
// override update to prevent it from erasing the background
public void update( Graphics g ) {
paint( g );
}
// KeyListener contract
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//change paused status
if(key == KeyEvent.VK_P) {
if(paused){
paused = false;
//restart game loop
Thread animator = new Thread( this );
animator.start();
}
else if(!paused){
paused = true;
}
//force repaint
this.repaint();
}
}
// This filter removes all but the red values in an image
class GetRedFilter extends RGBImageFilter {
public GetRedFilter() {
// work with pixels whose indices are into a color table
canFilterIndexColorModel = true;
}
public int filterRGB(int x, int y, int rgb) {
int r = (rgb & 0x00ff0000) >> 16;
int g = (rgb & 0x0000ff00) >> 8;
int b = (rgb & 0x000000ff);
rgb = (int) (0.2989*r + 0.5870*g + 0.1140*b); // NTSC formula
if (x == -1) {
// The pixel value is from the image's color table rather than the image itself
}
// Return only the red component
return rgb;
}
}
}
I can change the method which alters the pixel value...for instance, to swap blue and red values and then the animatin works again and the screen changes, however the code to change the pixel values to greyscale do nothing except make the animation disappear.
Thanks,
David
import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener
import java.awt.image.FilteredIma
import java.awt.image.ImageFilter
import java.awt.image.RGBImageFil
public class GameApplet extends Applet implements Runnable, KeyListener {
public boolean paused = false;
private int maxWidth , maxHeight ; // animation boundary
private int currX , currY ; // left,top (x,y) of the animating rectangle
private int currXVelocity , currYVelocity ; // pixels per move
private int imageHeight , imageWidth ; // size of animating rectangle
// new stuff for dbl-buffering
Graphics offscreen ;
Image imageForOffscreen ;
// This method is called once by the browser when it starts the applet.
public void init() {
this.addKeyListener(this);
Color c = Color.blue;
setBackground(c) ;
maxWidth = 500 ;
maxHeight = 500 ;
imageHeight = 25 ;
imageWidth = 40 ;
currXVelocity = 3 ;
currYVelocity = 3 ;
// set up random positions to start the images
currX = (int)( ( Math.random() * 80 ) + 1 );
currY = (int)( ( Math.random() * 80 ) + 10 );
// new stuff for dbl-buffering
imageForOffscreen = createImage( maxWidth , maxHeight );
offscreen = imageForOffscreen.getGraph
Thread animator = new Thread( this );
animator.start();
}
// This method is called whenever the page containing this applet is made visible.
public void start() {
}
// This method is called whenever the page containing this applet is not visible.
public void stop() {
}
// This method is called once when the browser destroys this applet.
public void destroy() {
}
// Runnable contract
public void run() {
// Generic Game Loop
while ( !paused )
{
try
{
Thread.sleep( 50 );
}
catch ( InterruptedException e )
{
}
currX = currX + currXVelocity ;
currY = currY + currYVelocity ;
if ( ( currX + imageWidth ) >= maxWidth )
{
currXVelocity = -3 ;
}
else if ( currX <= 0 )
{
currXVelocity = 3 ;
}
if ( ( currY + imageHeight ) >= maxHeight )
{
currYVelocity = -3 ;
}
else if ( currY <= 0 )
{
currYVelocity = 3 ;
}
repaint();
}
}
// This method is called whenever this applet needs to repaint itself.
public void paint(Graphics g) {
// first do what the update would have done --
//erase the background of the offscreen Graphics surface
offscreen.setColor( getBackground() );
offscreen.fillRect( 0 ,0 ,maxWidth , maxHeight );
// paint the rectangle onto the offscreen surface
// If there were more images to be painted, it would
// all happen here. Paint ALL images at this step
offscreen.setColor( Color.black );
offscreen.drawRect( currX , currY , imageWidth , imageHeight );
// Create the filter
ImageFilter filter = new GetRedFilter();
FilteredImageSource filteredSrc = new FilteredImageSource(imageF
// Create the filtered image
imageForOffscreen = Toolkit.getDefaultToolkit(
// then blast that final image to the screen
g.drawImage( imageForOffscreen , 0 , 0 , this );
}
// override update to prevent it from erasing the background
public void update( Graphics g ) {
paint( g );
}
// KeyListener contract
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
//change paused status
if(key == KeyEvent.VK_P) {
if(paused){
paused = false;
//restart game loop
Thread animator = new Thread( this );
animator.start();
}
else if(!paused){
paused = true;
}
//force repaint
this.repaint();
}
}
// This filter removes all but the red values in an image
class GetRedFilter extends RGBImageFilter {
public GetRedFilter() {
// work with pixels whose indices are into a color table
canFilterIndexColorModel = true;
}
public int filterRGB(int x, int y, int rgb) {
int r = (rgb & 0x00ff0000) >> 16;
int g = (rgb & 0x0000ff00) >> 8;
int b = (rgb & 0x000000ff);
rgb = (int) (0.2989*r + 0.5870*g + 0.1140*b); // NTSC formula
if (x == -1) {
// The pixel value is from the image's color table rather than the image itself
}
// Return only the red component
return rgb;
}
}
}
ASKER
Ok, I made that change and it appears to be doing the same as before. I.E. no pixel color changes and the animation is still not visible. I'm really wondering why the call to the filter eliminates my animation, however does not do anything else. hmmm
No errors are reported and the code executes just fine....just with undesired results. :(
And thanks for your suggestion to try image filtering....it set me off in the hunt through the api and got me to this point.
Thanks,
David
No errors are reported and the code executes just fine....just with undesired results. :(
And thanks for your suggestion to try image filtering....it set me off in the hunt through the api and got me to this point.
Thanks,
David
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Objects, thanks for all your help in this matter...spanning a week or more!
I'm posting below the altered code which appears to work as I need. I'll test it with a more advanced picture, but it works for this example.
David
The following code works in place of the filterRGB method posted above:
// find out the red, green and blue color components
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb) & 0xff;
// calculate the grayscale value
int gray = (r*30 + g*59 + b*11)/100;
// return the color code of the new color
return (rgb & 0xff000000) | (gray<<16) | (gray<<8) | (gray);
I'm posting below the altered code which appears to work as I need. I'll test it with a more advanced picture, but it works for this example.
David
The following code works in place of the filterRGB method posted above:
// find out the red, green and blue color components
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb) & 0xff;
// calculate the grayscale value
int gray = (r*30 + g*59 + b*11)/100;
// return the color code of the new color
return (rgb & 0xff000000) | (gray<<16) | (gray<<8) | (gray);
ASKER
Same post time. I'll try your suggestion....and thanks again!
try:
rgb = (int) (0.2989*(double)r + 0.5870*(double)g + 0.1140*(double)b); // NTSC formula