GFA BASIC 32‎ > ‎How To‎ > ‎

03 Saving Screen Shots

posted Jul 8, 2015, 1:00 PM by Troy Cheek   [ updated Jul 8, 2015, 1:00 PM ]
The other day, I created what I thought was a pretty nifty image with a GB32 program.  I wanted to save that image.  I didn't know how.

Sure, you can (almost) always grab a screen shot by hitting the Print Screen key on your keyboard, assuming your keyboard has that key, but that key hasn't actually printed the screen in so long that I forgot what version of MS-DOS it last worked in.  I never did find a use for Sys Req.  Regardless, hitting Print Screen nowadays copies the screen to the clipboard.  You can then load up Paint or your graphics manipulation program of choice and select the Paste command or shortcut.  You can then edit and save the image as usual.  That's the official way to do it.

However, that doesn't help you if you want to save multiple screenshots or save screenshots under program control.  Or if, as in my case, you want to save a screenshot 25 times a second while a program is running so you can later stitch the images together into a video.  For that, you need something special.

SavePicture Win_1.Image, "filename.bmp" will save an image of window # 1 in uncompressed bitmap format.  You can do the same for any other window or form.  These files are pretty large, but hard disk drives are cheap and you probably won't run out of room unless you do like I did and try to save a few thousand of them to a RAM disk.  Most graphics programs still know how to load and save bitmap files.

If you want to save only part of the screen, it's a little more complicated.  Check this out:

Local h As Handle, pic As Picture
Get 50, 50, 150, 150, h
Set pic = CreatePicture(h, False)
SavePicture pic, "filename.bmp"

The first line defines a couple of variables as special types.  A handle is a special type of variable that points GB32 to a certain section of memory.  In reality, it's just a 32-bit integer.  A picture is similar, but GB32 recognizes that it's image data.

The Get command should be called Grab, because that's what it does.  In the above example, it grabs a section of screen with the upper left corner at coordinates 50,50 and lower right corner at 150,150 saving the results to the handle h.  You can also use Get to save the image to a string variable, but that's for another article.

Set pic establishes that our picture variable pic is now associated with a picture created from the data pointed to by the handle.  In other words, it makes pic a certain type of picture.

SavePicture saves that picture in bitmap format as previously discussed.  The whole process is a little more convoluted than necessary because Get doesn't use the same picture format as SavePicture, but it gets the job done.

What if you want to save a bunch of images as the program is running?  I've got you covered!

Rem Save Screen
Mode StrSpace 0 : Mode Date "/"
OpenW # 1
Win_1.AutoRedraw = True
fn% = 0 : ntimer% = 0
Do
  Rem Stuff that outputs graphics to window # 1, like these random lines
  Line Rand(_X), Rand(_Y), Rand(_X), Rand(_Y), Rand(_C)
  SaveScreen(25)
  DoEvents
Loop Until Win_1 Is Nothing
CloseW # 1

Proc SaveScreen(frames%)
  Global fn%, ntimer%  ' set these to 0 before calling first time
  Local t$
If oTimer < ntimer% Then Return
  Inc fn%
  t$ = Str$(fn%)
  t$ = String$(4 - Len(t$), "0") + t$
  t$ = "z:\temp" + t$ + ".bmp"
  SavePicture Win_1.Image, t$
  ntimer% = oTimer + 1000 / frames% - 1
EndProc

This procedure should be called fairly regularly, so put it in your main program loop, or at least the loop that's creating the graphics you want to save.  The first thing it does is check to see if a certain amount of time has passed and return back to the main loop if that time hasn't.  The amount of time depends on how many frames per second you're aiming for.  If you want 25 frames per second, this procedure will run every 40 ms.  It will take around 10 ms.  At the end of the procedure, it sets a new timer goal.  oTimer is one of many timers in GB32.  This one counts in milliseconds, of which there are 1000 in every second.  1000 divided by frames per second equals the number of milliseconds before the next event, so we set that as the next target.

Note that we set this timer at the end of the procedure.  That way the main loop runs for 40 ms, we take 10 ms or however long we need to save the picture, then the main loop runs for another 40 ms.  This slows down execution of the main loop a little, but it keeps the timing the same as if the save procedure isn't there.  If we set the timer at the start of the procedure, it would run every 40 ms regardless of how much time the procedure took for itself, which would leave less time for the main loop, which might lead to unexpected results.

The t$ and the string manipulation just let us build a valid file name, in this case the path "z:\" plus file stub "temp" plus a 4-digit file number plus the extension ".bmp" to create a series of file names like "z:\temp0001.bmp", "z:\temp0002.bmp", "z:\temp0003.bmp", and so on.  Drive Z: is my RAM disk, so you'll need to change that before you run this program.

We use global variables for the file number and timer so that the procedure can remember their values between calls.  The official way to do this is to keep track of the values in the main loop and pass them to the procedure through the parameters like we did frames per second.  This clutters up the main loop, though

There are a few important things about the main program that need to be pointed out.  StrSpace affects the conversion of numbers to strings.  GB32 defaults to putting a space before and after the number.  I prefer no spaces, so I set this to 0.  This allows the file name we generate to not have any extra spaces in it.

The second important thing is setting Win_1.AutoRedraw = True.  You may think that's not really necessary if you're not planning on minimizing the window or whatever, but it's actually vital to the whole SavePicture command because the Win_1.Image that we're saving is actually the backup that AutoRedraw uses to restore the window.

Uncompressed bitmaps are very large, and not every graphics program can use them, so you may want to save them in a different format.  Unfortunately, SavePicture only works with bitmaps.  There are ways to convert the bitmap files after you save them, but that's the subject of another article.
Comments