0

I am creating a lightweight client for the game Runescape that has various user features such as custom keybinds/hotkeys. I'm pretty good with java and swing, but AWT and applets I am mediocre at best. I was able to get the applet downloaded and displayed on a JPanel and then in a JFrame and the game runs perfectly so far. However, when adding features I ran into a problem when I tried to implement a screenshot function to the client.

It's hard to post a concise working example so I'll post the methods I was trying based off of some other SO answers I was reading. I tried creating BufferedImage from the Applet, applet Canvas, the JPanel it is handled by, and the JFrame.

Here are some things I tried to create a screenshot from the Applet canvas:

public BufferedImage getScreenShot() {
    //getting the applet canvas
    Canvas canvas = (Canvas) this.getApplet().getComponent(0);
    //bufferedImage to draw to
    BufferedImage image = new BufferedImage(canvas.getWidth(), canvas.getHeight(), BufferedImage.TYPE_INT_ARGB);

    //Graphics2D g2=(Graphics2D)image.getGraphics();
    //test.print(g2);

    //g2.dispose();

    Graphics g = image.getGraphics();
    Image image2 = canvas.createImage(canvas.getWidth(), canvas.getHeight());
    canvas.print(g);

    System.out.println("Canvas Size: " + canvas.getSize().width + " x " + canvas.getSize().height);
    return image;
}

This one I tried in the JPanel class which holds only the Applet:

public BufferedImage getScreenShotFINAL(){
    BufferedImage bi = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
    applet.paint(bi.createGraphics());
    return bi;
}

I understand that the idea here is to create an off-screen BufferedImage, then to create a Graphics2d object and to then call the applet's paint() method to paint to the off-screen image. I tried this solution from here:

public BufferedImage getScreenShotFINAL2() {
    Dimension size = applet.getSize();
    BufferedImage offScreenImage = (BufferedImage) applet.createImage(size.width, size.height);
    Graphics2D g2 = offScreenImage.createGraphics();
    g2.setBackground(applet.getBackground());

    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g2.clearRect(0, 0, size.width, size.height);

    applet.paint(g2);

    return offScreenImage;
}

When saving the BufferedImages these and other methods I tried to a file the images just show up as black, just the default background color. Is there a good way to just get a BufferedImage from the JPanel which would include the Applet so I never have to deal with the Applet directly? Another thing, I had to override the java Canvas class in order to get the game to display (because it is double buffered I believe). I tried following a bunch of solutions from here but had no success. Any suggestions would be greatly appreciated. I also can provide a link to the full project or the custom Canvas project if you would like. Thanks!

EDIT

Here is the Canvas class which overrides the java AWT one. Didn't write it, followed a tutorial for this one and I think this is where the problem is, because the paint() method only calls clearRect():

package java.awt;

import Client.Client;
import java.awt.image.BufferStrategy;
import java.awt.peer.CanvasPeer;
import javax.accessibility.*;
import loaders.ClientPool;

public class Canvas extends Component implements Accessible {

private Client client = null;
private static final String base = "canvas";
private static int nameCounter = 0;
 private static final long serialVersionUID = -2284879212465893870L;

public Canvas() {
    super();
}

public Canvas(GraphicsConfiguration config) {
    this();
    setGraphicsConfiguration(config);
}
@Override
void setGraphicsConfiguration(GraphicsConfiguration gc) {
    synchronized(getTreeLock()) {
        CanvasPeer peer = (CanvasPeer)getPeer();
        if (peer != null) {
            gc = peer.getAppropriateGraphicsConfiguration(gc);
        }
        super.setGraphicsConfiguration(gc);
    }
}

@Override
public Graphics getGraphics(){
    if (this.client == null) {
        this.client = ClientPool.getClient(this);
    }

    if (client != null) {
        //call custom draw functions for specific client.  for drawing/double buffering
        return client.drawGraphics((Graphics2D) super.getGraphics());
    }
    return super.getGraphics();
}

@Override
String constructComponentName() {
    synchronized (Canvas.class) {
        return base + nameCounter++;
    }
}

@Override
public void addNotify() {
    synchronized (getTreeLock()) {
        if (peer == null)
            peer = getToolkit().createCanvas(this);
        super.addNotify();
    }
}

@Override
public void paint(Graphics g) {
    g.clearRect(0, 0, width, height);
}

@Override
public void update(Graphics g) {
    g.clearRect(0, 0, width, height);
    super.paint(g);
}

@Override
boolean postsOldMouseEvents() {
    return true;
}

@Override
public void createBufferStrategy(int numBuffers) {
    super.createBufferStrategy(numBuffers);
}

@Override
public void createBufferStrategy(int numBuffers,
    BufferCapabilities caps) throws AWTException {
    super.createBufferStrategy(numBuffers, caps);
}

@Override
public BufferStrategy getBufferStrategy() {
    return super.getBufferStrategy();
}

@Override
public AccessibleContext getAccessibleContext() {
    if (accessibleContext == null) {
        accessibleContext = new AccessibleAWTCanvas();
    }
    return accessibleContext;
}

protected class AccessibleAWTCanvas extends AccessibleAWTComponent
{
    private static final long serialVersionUID = -6325592262103146699L;

    public AccessibleRole getAccessibleRole() {
        return AccessibleRole.CANVAS;
    }
}

}

Community
  • 1
  • 1
Preston Garno
  • 1,175
  • 10
  • 33
  • 1
    Possible duplicate of [Swing: Obtain Image of JFrame](http://stackoverflow.com/questions/5853879/swing-obtain-image-of-jframe) – scsere Jan 03 '16 at 18:34
  • @scsere That question specifically asks for an image of a JFrame and Swing components which is pretty straightforward and I was able to do easily. I'm dealing with an applet. [http://stackoverflow.com/a/408828/4012979](http://stackoverflow.com/a/408828/4012979) – Preston Garno Jan 03 '16 at 18:38
  • *"It's hard to post a concise working example.."* If you're not prepared to do a bit of hard work, why would you expect lots of us to expend any trying to help? For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). *"I'm dealing with an applet."* And ..how do you think that is different? – Andrew Thompson Jan 03 '16 at 20:39
  • @AndrewThompson I've read through many of your answers to other users' questions about the same topic; thanks for that it really helped me understand even Swing&AWT alot better. The applet is for the game Runescape and the code to locate the URL for the applet, download it, and display it is quite extensive for a SO question (1000+ lines). [http://stackoverflow.com/a/16002857/4012979](This) is the method I've found in many, many SO answers. I got it to work in my own test applet, but doesn't work for the downloaded applet. What should I look at to see where this applet is different? – Preston Garno Jan 03 '16 at 21:05
  • Check the Robot#createScreenCapture method, it returns a BufferedImage from a screen capture. To use it in an applet though you need to grant the createRobot permission to it – A_Di-Matteo Jan 03 '16 at 21:11
  • @A.DiMatteo Robot thanks, but don't think that'll work, the game loader has tabbed panes for multiple accounts and the screenshot function will be called whenever an account levels up, and the pane won't necessarily be in the foreground then. – Preston Garno Jan 03 '16 at 21:13
  • Prefer `printAll` over `print` and don't forget to call `dispose` on the `Graphics` context. It's possible, because of the way that the applet is been rendered, it's not painting through the "paint" methods, but instead is using a `BufferedStrategy`, in which case using `print/All` won't work – MadProgrammer Jan 03 '16 at 23:52
  • @MadProgrammer if it is, how would I go about figuring that out? – Preston Garno Jan 04 '16 at 02:06
  • Without the source, it's pretty hard. My only recommendation if the doesn't work is to try Robot and capture the area of the applet. There are ways to figure out the screen coordinates of the component – MadProgrammer Jan 04 '16 at 02:15
  • @MadProgrammer Added the Canvas class which the applet uses. I think the problem is here, because most methods readily available on SO work on any applet I make. – Preston Garno Jan 04 '16 at 02:54
  • Adding the `java.awt.Canvas` class is, frankly, pretty pointless, as most of use already know it's basic operation – MadProgrammer Jan 04 '16 at 02:56
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/99642/discussion-between-preston-garno-and-madprogrammer). – Preston Garno Jan 04 '16 at 02:58

0 Answers0