Fanning Software Consulting

Capturing IDL Application Windows

QUESTION: I know how to print or save an IDL graphics window to a file (I use TVRead), but how can I capture my entire widget application window as a JPEG or TIFF file, or even send it to the printer? I run IDL on a Windows computer.

ANSWER: I've always used Hypersnap, from Hyperionics, for this. It is inexpensive shareware, and I have always been happy with it. But Hypersnap doesn't have a command line interface and sometimes you would like to give the user of a widget program the opportunity to save a screen capture of an entire application as a file, or send a copy of the application directly to a printer. This obviously can't be done from within an IDL program, except by spawning a command line call to the screen capture utility.

Dnyanesh Kadam has brought a new program to my attention that has several advantages over Hypersnap. First of all, the program is free. But best of all, it offers a command line interface. The program is called PrintScreen, and is distributed by Gadwin System, Inc.. It is only available for Windows computers. There are probably similar programs available for UNIX computers, but I don't know what they are. If you have a suggestion, I would like to hear it.(1)

I installed the program, named printscreen.exe, in the C:\Program Files\PrintScreen directory. I was interested in creating a JPEG file of a complete widget application. So, first, I configured the PrintScreen program to capture the window in the way I wanted it done. I chose to have it capture the currently active window as a JPEG file with a 75% quality factor. Then I wrote a short event handler, named CaptureWindow, and put it in my IDL path. The idea is that I can attach this event handler to any button in any widget application, and have the button initiate a screen capture of the IDL application window containing that button. I assume that the button user value will be set to the default name of the image file I wish to create. In my case, I wish to create a JPEG image of the widget application and store it in a file named selectimage.jpg.

Here is the code I wrote for the CaptureWindow event handler.

   PRO CaptureWindow, event

      ; Get the default name of the file from the user value of the button.
      Widget_Control, event.id, Get_UValue=defaultFilename
      IF N_Elements(defaultFilename) EQ 0 THEN defaultFilename='capture.jpg'

      ; Ask for confirmation of the name of the output file.
      filename = Dialog_Pickfile(Title='Save Application Window As...', $
         Get_Path=theDir, Filter='*.jpg', /Write, File=defaultFilename)
      IF filename EQ "" THEN RETURN
   
      ; Make sure the window containing the button is the active window 
      ; so it can be captured.
      Widget_Control, event.id, Input_Focus=1
      
      ; Capture the window.
      theFilename = StrMid(filename, StrLen(theDir))      
      SPAWN, /NoShell, "C:\Program Files\PrintScreen\printscreen.exe " + $
                       "/dir='" + theDir + "' /file='" + theFilename + "' " + $
                       "/nosplash /exit /justnow /askfname='no' " + $
                       "/notaskbar /preview='no' /image='1' /cptarea='0' " + $
                       "/autoname='no'"
          
   END

To test the program, I attached a Capture Window button to my SelectImage program. I defined the button like this.

   button = Widget_Button(buttonBase, Value='Capture Window', $
	Event_Pro='CaptureWindow', UValue='selectimage.jpg')

Clicking on the button produced a file, named selectimage.jpg, of the application. You see the result below.

The result of clinking the Capture Window button.
 

1 Several readers have suggested ImageMagick as a UNIX possibility. And I have heard from a reader who spawns the program ksnapshot from the KDE windows environment to accomplish the same thing. The Mac OS X has a built-in utility named Grab that can be used for this purpose.

Unix Solution

Allan Whiteford offers the following as a possible UNIX solution. He writes:

There are numerous UNIX solutions, but none of them are particularly satisfactory IMHO. I offer here what I consider the best I have come up with as a drop-in UNIX replacement for your CaptureWindow procedure.

The solution relies on xdpyinfo and import (import is part of ImageMagick). These are probably going to be on most Linux systems. Relying on ksnapshot is a bit more problematic and also harder to automate.

The main problem with the solution is that there isn't an easy way (that I know of) to take a screenshot of the current window. Hence the parsing of xdpyinfo to get the current window ID. I don't know of a command line utility which gives an input to the underlying X routine I want which is "XGetInputFocus". I could write a Call_External module to do this but this seems like overkill!

Of particular note, I don't know how portable:

    windowid = StrMid(text, 15, 10)

is across all UNIX platforms, hence the checking for the start of the string being '0x'. This also traps against the root window being the current window even after setting the input focus with Widget_Control.

Here is the code.

   PRO CaptureWindow, event

      ; Get the default name of the file from the user value of the button.
      Widget_Control, event.id, Get_UValue=defaultFilename
      IF N_Elements(defaultFilename) EQ 0 THEN defaultFilename='capture.jpg'

      ; Ask for confirmation of the name of the output file.
      filename = Dialog_Pickfile(Title='Save Application Window As...', $
         Get_Path=theDir, Filter='*.jpg', /Write, File=defaultFilename)
      IF filename EQ "" THEN RETURN
   
      ; Make sure the window containing the button is the active window 
      ; so it can be captured.
      Widget_Control, event.id, Input_Focus=1
      
      ; Capture the window.

      spawn,'xdpyinfo | grep focus',text
      windowid=strmid(text,15,10)
      if strmid(windowid,0,2) ne '0x' then return
      spawn,'import -frame -window '+windowid+' '+filename
          
   END

And a test program.

   pro screenshot
   a=widget_base(title='hello')
   b=widget_button(a,value='123456789')
   widget_control,a,/realize
   xmanager,'hello',a,event_handler='CaptureWindow'
   end

[Return to IDL Programming Tips]