Slick Forums

Discuss the Slick 2D Library
It is currently Fri Apr 18, 2014 8:05 am

All times are UTC

Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Sun Feb 12, 2012 9:39 pm 

Joined: Sun Feb 12, 2012 9:31 pm
Posts: 2
I'm trying to copy the screen and store it as a grayscale image that I can render later.
(or at least an RGB image with the color data altered to appear grayscale)

I make a copy with this line:
gc.getGraphics().copyArea(img, 0, 0);

But I haven't a clue how to manipulate the image afterward.
Any help would be appreciated.

PostPosted: Mon Feb 13, 2012 4:17 am 
Slick Zombie

Joined: Sat Jan 27, 2007 7:10 pm
Posts: 1482
A very simple solution would be to implement your own copyArea function that accepts a format parameter.

   public void copyArea(GameContainer c, Image target, int x, int y, int format) {
      GL11.glCopyTexImage2D(SGL.GL_TEXTURE_2D, 0, format, x, c.getHeight()
            - (y + target.getHeight()), target.getTexture().getTextureWidth(),
            target.getTexture().getTextureHeight(), 0);
   public void init(GameContainer container) throws SlickException {
      // we will use this for our "screen shot"
      screenCapture = new Image(container.getWidth(), container.getHeight());
   public void render(GameContainer container, Graphics g) throws SlickException {
      // render your scene as per usual
      // if we should take a screen shot on this frame, then copy the area:
      if (grabScreen) {
         //we don't want to do this every frame if we can help it
         grabScreen = false;
         copyArea(container, screenCapture, 0, 0, GL11.GL_LUMINANCE8);
      // and then we can draw the grayscale screen shot like an image
      screenCapture.draw(0, 0, 0.25f); // 25% scale

Using this, each colour is scaled by 1, so red, blue and green would all show up as white. Converting to a more convincing grayscale image requires scaling the values first; this GIMP article suggests scaling 30% red, 59% green, and 11% blue; whereas this article suggests other values. You can include this in your code to scale the colours:
         GL11.glPixelTransferf(GL11.GL_RED_SCALE, 0.30f);
         GL11.glPixelTransferf(GL11.GL_GREEN_SCALE, 0.59f);
         GL11.glPixelTransferf(GL11.GL_BLUE_SCALE, 0.11f);

         copyArea(container, screenCapture, 0, 0, GL11.GL_LUMINANCE8);

         GL11.glPixelTransferf(GL11.GL_RED_SCALE, 1f);
         GL11.glPixelTransferf(GL11.GL_GREEN_SCALE, 1f);
         GL11.glPixelTransferf(GL11.GL_BLUE_SCALE, 1f);

Because we are scaling the colours, the image will be darker and we will want to brighten it. The best solution would be proper gamma correction, but some easier solutions would be to (a) use BIAS and glPixelTransfer to add a certain amount to the resulting color before copying to grayscale, or (b) render the screen capture in multiple passes using Slick's MODE_ADD.

Things to note:
  • The results may vary from system to system; I've only tested this on my own computer.
  • This method requires GL 2.1. If you are targeting older systems, check for compatibility like so:
    boolean gl21Supported = GLContext.getCapabilities().OpenGL21;
  • If performance isn't your top priority, you can loop through the "screen grabbed" image and alter the RGB pixels manually. This will be slower but it will produce a more accurate grayscale image, won't require GL2.1, won't require any brightness hacks, etc.
  • For maximum compatibility, you should be storing the grayscale screen capture as a GL_LUMINANCE8 texture instead of Slick's default GL_RGBA format -- it uses much less memory (three components vs one) and some drivers might not support the above code without appropriate internal formats. Until Nitram's patch is added to the codebase, you can write your own grayscale texture loader using code from InternalTextureLoader.

Last edited by davedes on Mon Feb 13, 2012 7:00 am, edited 2 times in total.

PostPosted: Mon Feb 13, 2012 5:53 am 

Joined: Sun Feb 12, 2012 9:31 pm
Posts: 2
Thanks for the detailed reply. I'm new to graphics programming, and I find Slick's library exceptionally easy to work with.
Your solution works perfectly for me. Performance isn't of utmost importance since this is only executed occasionally.

More information on my problem:
When the player opens the main menu, the game state changes. I wanted the previous frame from the game to remain frozen in the background in grayscale. Ideally, the screen would quickly fade to the grayscale image during the state transition, but I think I can figure that out on my own. Thanks again!

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC

Who is online

Users browsing this forum: No registered users and 1 guest

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group