baklobsters has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

I have a Perl script that generates a display window
containing various informational text in varying
colors all on a black background. What I need to do
is to be able to "screen capture" this display and
save it as an image file (JPEG, BMP, whatever).

Various suggestions on the web talk about using
Tk::WinPhoto, but I'm not using X (I'm on Windows XP)
and WinPhoto doesn't exist in my Tk directory.

Attempts to even try it using the following snippet
(with Tk::Photo and Tk::JPEG)

$image = $mw->Photo(-format => 'Window', -data => oct($JTADisplay->id)); $filename = 'myimage.jpg'; $image->write($filename, -format => 'JPEG');

gives me the following error (understandably):

Tk::Error: image format "Window" is not supported at C:/Perl/site/lib/Tk/Image.pm line 21.

So, if anybody can shed some light to this, I would be
most thankful. The following is another snippet of my
code if it helps:

$mw = MainWindow->new(-background => 'black'); $mw->geometry('+0+0'); $mw->title("My Display"); $f = $mw->Frame(-background => 'black')->pack; $f->Label(-text => 'PROJECTION', -foreground => 'white', -background => 'black')-> grid(-row => 1, -column => 1, -columnspan => 3, -sticky => ' +w'); for ($i = 0; $i <= 5; $i++) { $f->Label(-text => $i, -foreground => 'white', -background => 'bla +ck')-> grid(-row => 1, -column => $i + 4, -sticky => 'nsew'); } $advisoryLabel = $f->Label(-textvariable => \$advisory, -foreground => $advisoryColor, -background => 'black')-> grid(-row => 2, -column => 1, -columnspan => 3 +, -sticky => 'w'); for ($i = 0; $i <= 5; $i++) { $JTALabel[$i] = $f->Label(-textvariable => \$JTA[$i + 1], -foreground => $JTAColor[$i + 1], -background => 'black')-> grid(-row => 2, -column => $i + 4, -sticky => 'nsew'); } $f->Label(-text => 'BREAKDOWN', -foreground => 'white', -background => 'black')->grid(-row => 3, -column => 1, -columnspan => 9, -sticky => 'nsew'); $f->Label(-text => 'ID', -foreground => 'white', -background => 'black')->grid(-row => 4, -column => 1, -sticky => 'w'); $f->Label(-text => 'TYPE', -foreground => 'white', -background => 'black')->grid(-row => 4, -column => 2, -sticky => 'w'); for ($i = 0; $i <= 5; $i++) { $f->Label(-text => $i, -foreground => 'white', -background => 'bla +ck')-> grid(-row => 4, -column => $i + 4, -sticky => 'nsew'); } foreach $name (keys %Domes) { $domeIndex = $Domes{$name}{dome}; $fRow = ($domeIndex * 2) + 6; $IDLabel[$domeIndex] = $f->Label(-text => $name, -foreground => 'green', -background => 'black')-> grid(-row => $fRow, -column => 1, -sticky => 'w'); $TypeLabel[$domeIndex] = $f->Label( -textvariable => \$Type[$domeIndex], -foreground => 'green', -background => 'black')-> grid(-row => $fRow, -column => 2, -sticky => 'w'); $f->Label(-text => 'PA:', -foreground => 'white', -background => 'black')-> grid(-row => $fRow, -column => 3, -sticky => 'w'); $f->Label(-text => 'RA:', -foreground => 'white', -background => 'black')-> grid(-row => $fRow + 1, -column => 3, -sticky => 'w'); for ($i = 0; $i <= 5; $i++) { $JABLabel[$domeIndex][0][$i] = $f->Label( -textvariable => \$JABText[$domeIndex][0][$i + 1], -foreground => 'green', -background => 'black')-> grid(-row => $fRow, -column => $i + 4, -sticky => 'nsew'); $JABLabel[$domeIndex][1][$i] = $f->Label( -textvariable => \$JABText[$domeIndex][1][$i + 1], -foreground => 'green', -background => 'black')-> grid(-row => $fRow + 1, -column => $i + 4, -sticky => 'nse +w'); } } # create the menus $menuBar = $mw->Menu; $mw->configure(-menu => $menuBar); $file = $menuBar->cascade(-label => 'File', -tearoff => 0); $file->command(-label => 'New', -command => \&newDemo); $file->command(-label => 'Save Display', -command => \&saveDisplay); $file->separator; $file->command(-label => 'Quit', -command => \&closeWindow); $action = $menuBar->cascade(-label => 'Scenario', -tearoff => 0); $action->command(-label => 'Start Demo', -command => \&JTAMain); $action->command(-label => 'Stop Demo', -command => sub {$stopDemo = 1 +}); MainLoop(); sub saveDisplay { $image = $mw->Photo(-format => 'Window', -data => oct($JTADisplay->id)); $filename = 'myimage.jpg'; $image->write($filename, -format => 'JPEG'); }
Thanks in advance.

Replies are listed 'Best First'.
Re: Saving Contents of Perl/Tk Display to a File
by liverpole (Monsignor) on Feb 02, 2006 at 02:03 UTC
    Hi, baklobsters, I tried running your code, (on Windows 2000) but it crashes with an Application Error, which isn't a good sign.

    I tried adding the pragmas:

    use strict; use warnings;
    at the top of the second code snippet (as well as the necessary library use Tk); not surprisingly, it fails to run.

    You may want to consider supplying a complete code example, which will help us separate the problem you're having from the other problems currently in the code, such as textvariable references which don't exist (eg. advisory and $JTA), and other data which hasn't been included.

    So, if you can post a program which runs as is, I'll be happy to try to give you an answer to your question.


    @ARGV=split//,"/:L"; map{print substr crypt($_,ord pop),2,3}qw"PerlyouC READPIPE provides"
Re: Saving Contents of Perl/Tk Display to a File
by zentara (Cardinal) on Feb 02, 2006 at 12:01 UTC
    Well maybe you could use import (from ImageMagick). It takes the window_id on the commandline, to capture a specific window. I don't know if it works on windows or not? Maybe you could find a function in the win32 set of modules, or find a 3rd party print-screen utility? For instance mwsnap

    I'm not really a human, but I play one on earth. flash japh
Re: Saving Contents of Perl/Tk Display to a File
by baklobsters (Initiate) on Feb 02, 2006 at 18:47 UTC
    Thanks guys for your quick replies.

    liverpole, the following is an executable code that
    will generate an example display of what I want to
    save as an image file:

    use Tk; use Tk::Photo; use Tk::JPEG; $advisory = 'CAUTION'; $advisoryColor = 'yellow'; @JTA = ('Y','Y','Y','N','N','Y'); @JTAColor = ('green','green','green','yellow','yellow','green'); @IDColor = ('green','green','green','yellow','yellow','yellow','green' +, 'yellow','yellow','green'); @type = ('PAI','PAO','PAS','RAO','RAS','RAI','PAI','RAI','PAS','PAO'); for ($i = 0; $i < 10; $i++) { if ((($i >= 0) && ($i <= 2)) || ($i == 6) || ($i == 9)) { @{$JABText[$i][0]} = ('Y','Y','Y','Y','Y','Y'); @{$JABColor[$i][0]} = ('green','green','green','green','green' +, 'green'); } else { @{$JABText[$i][0]} = ('Y','Y','Y','N','N','Y'); @{$JABColor[$i][0]} = ('green','green','green','yellow','yello +w', 'green'); } @{$JABText[$i][1]} = ('Y','Y','Y','Y','Y','Y'); @{$JABColor[$i][1]} = ('green','green','green','green','green','gr +een'); } # create the GUI display $mw = MainWindow->new(-background => 'black'); $mw->geometry('+0+0'); $mw->title("Info Display"); $f = $mw->Frame(-background => 'black')->pack; $f->Label(-text => 'Advisory', -foreground => 'white', -background => 'black')-> grid(-row => 1, -column => 1, -columnspan => 3, -sticky => ' +w'); for ($i = 0; $i <= 5; $i++) { $f->Label(-text => $i, -foreground => 'white', -background => 'bla +ck')-> grid(-row => 1, -column => $i + 4, -sticky => 'nsew'); } $advisoryLabel = $f->Label(-textvariable => \$advisory, -foreground => $advisoryColor, -background => 'black')-> grid(-row => 2, -column => 1, -columnspan => + 3, -sticky => 'w'); for ($i = 0; $i <= 5; $i++) { $JTALabel[$i] = $f->Label(-textvariable => \$JTA[$i], -foreground => $JTAColor[$i], -background => 'black')-> grid(-row => 2, -column => $i + 4, -sticky => 'nsew'); } $f->Label(-text => 'BREAKDOWN', -foreground => 'white', -background => 'black')->grid(-row => 3, -column => 1, -columnspan => 9, -sticky => 'nsew'); $f->Label(-text => 'ID', -foreground => 'white', -background => 'black +')-> grid(-row => 4, -column => 1, -sticky => 'w'); $f->Label(-text => 'TYPE', -foreground => 'white', -background => 'bla +ck')-> grid(-row => 4, -column => 2, -sticky => 'w'); for ($i = 0; $i <= 5; $i++) { $f->Label(-text => $i, -foreground => 'white', -background => 'bla +ck')-> grid(-row => 4, -column => $i + 4, -sticky => 'nsew'); } for ($i = 0; $i < 10; $i++) { $name = 'station'.$i; $fRow = ($i * 2) + 6; $IDLabel[$i] = $f->Label(-text => $name, -foreground => $IDColor[$i], -background => 'black')-> grid(-row => $fRow, -column => 1, -sticky => 'w'); $typeLabel[$domeIndex] = $f->Label(-textvariable => \$type[$i], -foreground => $IDColor[$i], -background => 'black')-> grid(-row => $fRow, -column => 2, -sticky => 'w'); $f->Label(-text => 'PA:', -foreground => 'white', -background => 'black')-> grid(-row => $fRow, -column => 3, -sticky => 'w'); $f->Label(-text => 'RA:', -foreground => 'white', -background => 'black')-> grid(-row => $fRow + 1, -column => 3, -sticky => 'w'); for ($j = 0; $j <= 5; $j++) { $JABLabel[$i][0][$j] = $f->Label( -textvariable => \$JABText[$i][0][$j], -foreground => $JABColor[$i][0][$j], -background => 'black +')-> grid(-row => $fRow, -column => $j + 4, -sticky => 'nsew'); $JABLabel[$i][1][$i] = $f->Label( -textvariable => \$JABText[$i][1][$j], -foreground => $JABColor[$i][1][$j], -background => 'black +')-> grid(-row => $fRow + 1, -column => $j + 4, -sticky => 'nse +w'); } } # create the menus $menuBar = $mw->Menu; $mw->configure(-menu => $menuBar); $file = $menuBar->cascade(-label => 'File', -tearoff => 0); $file->command(-label => 'Save Display', -command => \&saveDisplay); $file->separator; $file->command(-label => 'Quit', -command => \&closeWindow); MainLoop(); sub saveDisplay { $image = $mw->Photo(-format => 'Window', -data => oct($mw->id)); $filename = 'myimage.jpg'; $image->write($filename, -format => 'JPEG'); } sub closeWindow { $mw->destroy; }

    Thanks again for trying to help me out

    Zentara, I've seen many references to the Image Magick
    that you've mentioned while surfing the net for this
    solution. Maybe I should check this out. Thanks!

      Did you get a solution already? If not, take a look at Win32::Screenshot. It has Image::Magick as a dependancy, but it seems to cover most possibilities.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
      Much better, baklobsters ... your code example now runs (although I would still recommend understanding how to use strict and use warnings).

      I've only used the Photo object before to create images in the GUI itself, so I went to Active State's website to find out what they support.  According to their documentation for the Photo object:

          The standard Tk distribution comes with handlers for XBM, XPM, BMP, JPEG, PNG and PPM/PGM formats, which are automatically registered on initialization.

      I didn't see anything there about the Window format, or any kind of reference to doing a screen capture.  Are you sure it's supposed to be a valid operation?

      If it's a screen capture you need, would you consider doing it with a separate program?  If so, you might want to try The Gimp, which is a very powerful freeware image editor that supports screenshots (single windows and desktop both), and runs great on Windows.


      @ARGV=split//,"/:L"; map{print substr crypt($_,ord pop),2,3}qw"PerlyouC READPIPE provides"
Re: Saving Contents of Perl/Tk Display to a File
by Anonymous Monk on May 09, 2006 at 15:19 UTC
    Ik heb een veel betere code. Maar die geef ik lekker niet. Dank je voor de opzet!