In-game screenshot via BitmapData.draw(FlxG.stage) differs from reality

  • It's interesting, it's not limited to interesting things like overlays. I just took one and one of two sprites I had set .color on had the wrong colour, whereas the other was fine. And the stage had a black right-margin (plus an even bigger right and bottom white margin?) vs native:


  • @DleanJeans said in In-game screenshot via BitmapData.draw(FlxG.stage) differs from reality:

    Have you seen this: FlxScreenGrab? It's an add-on so it may be outdated but I guess you can learn how it works.

    OK, attempt 1. Commented out my code, and instead put this just before switching to the minigame state that I want to take a shot of:

    		FlxScreenGrab.defineHotKeys(["F12"], true, false);

    Once in the game, pressing F12 did nothing.

    Attempt 2, ignore the note in their docs about using a string:

    		FlxScreenGrab.defineHotKeys([FlxKey.F12], true, false);

    Still, pressing F12 does nothing.

    Attempt 3, put this into my minigame state after create(). Still nothing.
    Attempt 4, same spot, back to "F12" as a string. Still nothing.


  • OK, this makes sense so far. Even though there are static methods for setting the hotkeys, they're only used by a non-static method, so I need to actually make a FlxScreenGrab object:

    		add(new FlxScreenGrab());

    With that, at least I know that grab() is being called, from a trace I added there. But no dialog comes up or anything like that, as one would expect from the docs.

  • Seems that the save() function requires flash for its dialog, or (!lime_legacy || lime < "2.9.0"), which I think returns false in my case because HaxeFlixel still uses lime legacy by default IIRC, and now I'm on lime 2.9.1. So the function just finishes without saving anything at all, because there's no other #elseafter those two options.

  • administrators

    The screengrab addon dialogs were changed from using systools to lime.ui.FileDialog a while ago to avoid additional dependencies. However, a bit later, a change in Lime made the dialog class only available for Next, see

  • @Gama11 right...

    Even without the save dialog, and just putting the save code in an #else block, I'm getting a null object error on


    Running trace() on png.length just before that line, interestingly, doesn't output anything before the crash. Maybe I need to build clean or something...

  • Oh, of course, because now it's crashing on my trace() line. That means png is null. Why is that? Because of this:

    	#if flash
    		png = PNGEncoder.encode(screenshot.bitmapData);
    	#elseif openfl_legacy
    		png = screenshot.bitmapData.encode(screenshot.bitmapData.rect, "png");
    		png = screenshot.bitmapData.encode(screenshot.bitmapData.rect, new PNGEncoderOptions());

    In my stripped-down code, I picked the third block there, which works (on openfl_legacy) at least in that it outputs something--but the second block is what's being executed in FlxScreenGrab.

  • Indeed, I think you can trace FlxScreenGrab's encode() call to this line in legacy:

    ...because of "png" being passed instead of a PNGEncoderOptions. So it just returns null on legacy.

    Legacy's the default, and openfl next currently breaks a bunch of random things in my project. Fixing either of these is beyond my scope at the moment. I guess someone in my position won't be getting normal-looking screenshots, then. :) Next project I guess I'll start with Next :)

    Unless something like this would work:

    			if ( (compressorOrQuality, PNGEncoderOptions)) {
    				return byteArray = lime_bitmap_data_encode (__handle, "png", 0);
    			} else if ( (compressorOrQuality, JPEGEncoderOptions)) {
    				return byteArray = lime_bitmap_data_encode (__handle, "jpg", cast (compressorOrQuality, JPEGEncoderOptions).quality / 100);
    			} else if ( (compressorOrQuality, String)) {
    				return byteArray = lime_bitmap_data_encode (__handle, compressorOrQuality, 0);

    Nope, the blendmode thing is still borked. Maybe the other context is an improvement though?

  • Yes, it still has blending issues (and colours incorrect when you simply set FlxSprite.color, as seen above), but at least the dimensions are OK and don't have strange margins (unlike as seen above.)

  • OK, if anyone's interested in this, you'll need these two pieces:

    And then you'll also need to supply a path, since, as Gama11 said, there's no file picker dialog right now on legacy.

    If you're using the excellent crashdumper anyway, you can use my code, which depends on it (Util and a crashdumper instance):

    		var path = Main.crashDumper.path + "screenshots/";
    		if (!FileSystem.exists(Util.pathFix(path)))
    		FlxScreenGrab.presetPath = path;
    		FlxScreenGrab.defineHotKeys(["F12"], true, false);

    Then just put this in any state's create() that you want to screenshot from:

    add(new FlxScreenGrab());

Log in to reply

Looks like your connection to HaxeFlixel was lost, please wait while we try to reconnect.