![]() |
|
Al_save_bitmap only saves a blank png |
TheNextGuy
Member #15,702
August 2014
|
Hey guys, I'm trying to make a function that saves a screenshot to a folder. I have it creating the .png's correcting but all of them are blank. I am able to draw to the screen and I have tried to flipping the screen before and after screenshotting but neither does anything. Here is what my screen looks like and what the screenshots look like. Here is the code that produces my screenshots. The actual al_save_bitmap call is near the bottom but I thought it good measure to include it all. 1int AllegroEngine::FlushScreenshot(const char *destination_path, std::string myWorldName,int myCurrentYear,int myCurrentMonth, int myCurrentDay)
2{
3 ALLEGRO_PATH *path;
4 char *filename;
5 const char *path_cstr;
6 int char_index = 0;
7
8 //Testing the destination given
9 if(!destination_path)
10 path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH);
11 else
12 path = al_create_path_for_directory(destination_path);
13
14 if(!path)
15 return -1;//Where we want it is bad
16
17
18 //Length of gamename : YYYY- MM - DD NULL terminator
19 int bytes = myWorldName.size() + 1 + 4 + 1 + 2 + 1 + 2 + 1;
20 if (!(filename = (char *)malloc(bytes)))
21 {
22 al_destroy_path(path);
23 return -4;//We don't have enough space?
24 }
25
26 //Creating the file name
27 std::string name = myWorldName + "-"+ std::to_string(myCurrentYear)+"-"+std::to_string(myCurrentMonth)+"-" + std::to_string(myCurrentDay);
28
29 for (int c = 0; c < name.length(); c++)
30 {
31 filename[char_index] = name[c];
32 char_index++;
33 }
34 filename[char_index] = '\0';
35
36 //Setting up file specificiations
37 al_set_path_filename(path, filename);//Where are we writing this
38 al_set_path_extension(path, ".png");//We are creating a png
39 path_cstr = al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP);
40
41
42 if (!al_filename_exists(path_cstr))
43 {
44 //Saving the bitmap
45 std::cout<<"Screenshot saved at "<<path_cstr<<" named "<<filename<<"."<<endl;
46 al_save_bitmap(path_cstr,al_get_backbuffer(main_display));
47 return 1;
48 }
49 else
50 {
51 //We've already printed out this file
52 delete(filename);
53 al_destroy_path(path);
54 }
55 return -6;//We never placed a file
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Don't save from the backbuffer. It's contents are usually lost when you flip the display. And you won't be referring to the same bitmap as the one being displayed anyway. Try using a buffer bitmap or just redraw to a buffer when you want to save it. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Neil Roy
Member #2,229
April 2002
![]() |
This is a function I came up with to do just that and it works beautifully. Saves the screenshot with a date and time extension so if you save multiple screenshots they will all be named differently, just need to pass it the name of the game "My_Game" and that will be used with the date and time appended... a5_screenshot.c 1// Note: if you use physfs, than you need to call al_set_standard_file_interface();
2// before this function and al_set_physfs_file_interface(); afterwards.
3
4#include "a5_screenshot.h"
5
6bool a5_screenshot(const char *gamename)
7{
8 time_t rawtime;
9 struct tm *timeinfo;
10 char filename[80], timestr[80];
11 bool saved;
12 ALLEGRO_STATE state;
13
14 al_store_state(&state, ALLEGRO_STATE_NEW_FILE_INTERFACE);
15
16 al_set_standard_file_interface();
17
18 time(&rawtime);
19 timeinfo = localtime(&rawtime);
20
21 strftime(timestr, 80, "%Y%m%d_%H%M%S", timeinfo);
22 snprintf(filename, 80, "%s_%s.png", gamename, timestr);
23
24 saved = al_save_bitmap(filename, al_get_target_bitmap());
25
26 al_restore_state(&state);
27
28 if(!saved) return false;
29
30 return true;
31}
a5_screenshot.h #ifndef _a5_screenshot_h_ #define _a5_screenshot_h_ #include "allegro5/allegro.h" #include <stdio.h> bool a5_screenshot(const char *gamename); #endif //_a5_screenshot_h_
--- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
With that code, just make sure to call it before an al_flip_display if you're trying to save from the backbuffer. If not, then it doesn't really matter. -- |
TheNextGuy
Member #15,702
August 2014
|
Even when I say al_get_target_buffer it comes up blank. With both target and back buffer and whether or not the screen flipping comes before, after, or not all makes no difference. |
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
Dumb question : Have you init'ed the image addon? al_init_image_addon My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
TheNextGuy
Member #15,702
August 2014
|
Yes I have. The solution NickHackr presented is deprecated but even when updated it does not work. It creates blank png's all the same. I have tried setting it to al_get_target_bitmap() and moving and deleting the flipping to no avail. I suspect it has to do with drawing improperly or something. I only ever draw primitives. For instance: 1void Game::DrawBlade(int x, int y, unsigned char r,unsigned char g,unsigned char b)
2{
3 al_draw_line(x,y+1,x,y-4,al_map_rgb(0,0,0),1);//Shadow
4 al_draw_line(x,y-1,x,y-5,al_map_rgb(r,g,b),3);//Actual
5};
I'd like to note that my "engine" class has only static members. Static screen and static functions. However the thing that draws to it- the game class -is not static. 1void AllegroEngine::InitializeAllegro()
2{
3 if (!al_init())
4 {
5 std::cout<<"Al init failed."<<endl;
6 }
7 //allegro-5.0.10-monolith-md-debug.lib
8
9 //Anti Aliasing
10 al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);
11 al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);
12
13 //Initializing Addons
14 al_init_image_addon();
15 al_init_font_addon();
16 al_init_ttf_addon();
17 al_install_keyboard();
18 al_install_audio();
19 al_init_acodec_addon();
20 al_init_primitives_addon();
21
22 al_reserve_samples(10);
23
24 std::cout<<endl<<"Allegro initialized.";
25
26 InitializeFonts();
27};
28
29void AllegroEngine::InitializeScreen(int myScreenWidth, int myScreenHeight)
30{
31 screen_width = myScreenWidth;
32 screen_height = myScreenHeight;
33
34 //Creating screen
35 ALLEGRO_DISPLAY* display = al_create_display(myScreenWidth, myScreenHeight);
36 al_set_window_position(display,0,0);
37 al_set_window_title(display,"World Simulation");
38 main_display = display;
39};
|
Edgar Reynaldo
Major Reynaldo
May 2007
![]() |
I can load and save a png just fine here. Even off the backbuffer. Try this test code with the attached test.png and see what results it gives you on your computer. 1
2
3
4#include "allegro5/allegro.h"
5#include "allegro5/allegro_image.h"
6
7
8int main(int argc , char** argv) {
9
10 if (!al_init()) {return 1;}
11 al_init_image_addon();
12
13 al_set_new_display_flags(ALLEGRO_WINDOWED | ALLEGRO_OPENGL);
14 ALLEGRO_DISPLAY* display = al_create_display(200,200);
15
16 ALLEGRO_BITMAP* testbmp = al_load_bitmap("test.png");
17
18 al_save_bitmap("testsave.png" , testbmp);
19
20 al_set_target_backbuffer(display);
21 al_clear_to_color(al_map_rgb(0,255,0));
22 al_draw_bitmap(testbmp , 0 , 0 , 0);
23
24 al_save_bitmap("testbackbuffersave.png" , al_get_backbuffer(display));
25
26 al_flip_display();
27
28 al_rest(3.0);
29
30 return 0;
31}
It works for me on Windows Vista with MinGW 4.8.1 using either DirectX or OpenGL driver. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
TheNextGuy
Member #15,702
August 2014
|
Edgar my man it works. I fiddled with it so much I don't quite know what the exact solution is. Thanks a gorillian. I've attached a working screenshot x) |
Neil Roy
Member #2,229
April 2002
![]() |
Thomas Fjellstrom said: With that code, just make sure to call it before an al_flip_display if you're trying to save from the backbuffer. If not, then it doesn't really matter. I used it all through my game. I added calls to it from my title screen, my menu screen, my main game screen etc... never had a problem. But I will keep what you said in mind. --- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
NiteHackr said: I used it all through my game. I added calls to it from my title screen, my menu screen, my main game screen etc... never had a problem. The main issue is that there is no guarantee that the backbuffer after a flip has anything in it that makes sense. It could be what you drew to it the frame before last, 5 frames ago, or garbage. (this is why they say it's undefined or implementation defined). Often I think the "implementation" is just to keep N frames around for page flipping, and hand you back a previous frame on a flip. so for the most part it looks fine, but may not give you back the exact frame you expected if you called it after a flip, but before drawing. (not that it often matters, but it might if you're trying to use the screenshots for debugging) -- |
Neil Roy
Member #2,229
April 2002
![]() |
I may go over my code and make sure my screenshot code is after a draw, just to be safe. Perhaps detect the screenshot key, flag the next draw for a save, then add code in after the draw, but before the flip to respond on that. Hmmm... --- |
|