Category: Tk

[ RSS Feed | Older > ]
Running Tkx on Perl

Kirsle
kirsle
Posted by Kirsle on Friday, Jun 22 2012 @ 1:10 PM
I took a fresh look at trying to wrangle Tkx into working on the standard Perl distribution.

Tkx is ActiveState's module that provides a modern, updated Tk framework for Perl. I previously wrote about how the old Tk module for Perl has been neglected for many years and is extremely outdated and has very little hope for being improved on. Tkx brings a more updated Tk interface to Perl.

The only problem is, it only really runs well on ActivePerl, and not the stock version of Perl. I've been testing Tkx over the years on various versions of Fedora Linux and Perl, and every time I'd get the same results: segmentation faults. It was impossible to run any code that uses the Tkx module, because attempting to do so much as use Tkx; would cause a segfault. I chalked it up to "it only works with ActivePerl" and left it alone. But now I decided to give it another go.

I was seeing the same symptoms this time as before. When trying to install it with cpan or cpanm, it would fail to install because its test suite was failing (giving errors like, can't find package tk). If I installed it while skipping the test suite, the tkx-ed example program would give segfaults when run. Just as before.

I found out through tinkering with it that I needed to yum install tk (it makes sense; Tkx is a wrapper around Tcl/Tk for Perl, so you need "the" Tk installed for it to work). With this, running make test would have it run through the test suite and I'd see all the graphical Tk windows pop up and disappear. But running tkx-ed would still give segfaults.

I believe I'd gotten to this point before. The test suite would work, but nothing else would. So I decided to try running the test suite "by hand", perl t/LabEntry.t. Segmentation fault. What? How can the test suite run all these scripts successfully but I can't run them myself? So, I dissected the Makefile that was used for the test suite.

Long story short, this doesn't work:

[kirsle@fireworks Tkx-1.09]$ perl tkx-ed 
Segmentation fault (core dumped)
But this does:
[kirsle@fireworks Tkx-1.09]$ PERL_DL_NONLAZY=1 perl tkx-ed
tkx-ed screenshot

Shazam. This is tkx-ed running on a stock version of Perl 5.14.2 on Fedora 17. It seems that the PERL_DL_NONLAZY environment variable is required for the Tkx module to work. This is weird.

I don't call this a victory though. Requiring this environment variable to be set for your Tkx app to run isn't very ideal. If you wrote and distributed a Tkx app for Linux users, you'd require the users to run a Bash shell script in order to launch your program instead of just running your Perl program directly like they'd expect. But, at least it works!

Note: I also needed to yum install bwidget because tkx-ed would give a "can't find package BWidget" error without it).

Update (6/24/12):

As for that environment variable issue, I found that this will work:

#!/usr/bin/perl

BEGIN {
    $ENV{PERL_DL_NONLAZY} = 1;
}

use 5.14.0;
use strict;
use warnings;
use Tkx;

...
Since your BEGIN block gets run before Perl attempts to load the modules, you can set the variable inside your script. And now a simple "perl yourscript.pl" will work without segfaults. :)

Categories: Perl , Tk , Tkx

[ 2 comments | Add comment | Permalink ]

Perl Module Neglect

Kirsle
kirsle
Posted by Kirsle on Sunday, Mar 20 2011 @ 2:54 AM
This is just a sort of review, or an organizing of thoughts, about the general state of the Perl modules available on CPAN.

I love Perl as a programming language. It's easy, fast enough for almost any application, and is often called the "swiss army chainsaw" of programming languages because it makes easy tasks easy and hard tasks possible. But, it doesn't excel very well in a couple of areas which I'll outline below, due to the state of neglect of some of its modules and ports.

Tk GUI Toolkit

The de facto module for the Tk framework for Perl is aptly named "Tk," as in:

use Tk;
This module is probably one of the most neglected modules on CPAN. It was a direct port from the Tcl/Tk that was current at the time that Perl/Tk was written. The result is that, when you run a Perl/Tk program on any platform other than Windows, it resembles an excruciatingly ugly Motif style application (see my screenshots of my Perl CyanChat Client for examples). Under Windows, though, a Perl/Tk app more or less fits in.

Because Perl/Tk was a direct port of a very old version of Tk, updating it to keep it modern has been a difficult task and so naturally nobody has done it. The only love Perl/Tk gets these days is maintenance work just to be sure it can still be compiled for modern versions of Perl.

So what can we do about this?

There are a couple other Tk implementations for Perl: Tkx by ActiveState and Tcl::Tk. These two modules are modern Tk implementations for Perl, and so they look very nice on every platform. But how usable are they?

Tkx is ActiveState's creation, and I've only been able to get it to work when using ActivePerl. This is fine for Windows, where ActivePerl is arguably the most popular Perl interpreter for Windows. But when I tried compiling Tkx for a stock Perl that ships with Fedora Linux, it gives segmentation faults and crashes. It's not usable under Linux with a stock version of Perl.

There's an ActivePerl for Linux, though, but the problem is that this Perl installation would be independent from the stock Perl that comes with your operating system. So if I needed to install another third party module to use with a ActivePerl/Tkx application, I wouldn't be able to run a simple "yum install perl-{module}" command to get it. I'd have to use ActivePerl's ppm tool, if it even had the module I want. Otherwise I need to compile the module myself for ActivePerl. Yuck. This isn't "the Linux way" of doing things. The package manager should be aware of everything that you install on your system.

ActivePerl/Tkx is out of the question for Linux then. What about Tcl::Tk? I've attempted to compile and use Tcl::Tk on a few different versions of Fedora Linux and every time they give me segmentation faults just like Tkx did. No good.

So Tk is one thing that Perl can't do very well due to lots of neglect. In contrast, the Tk ports for Python, Ruby and Tcl (of course) are much better maintained.

I know there are ports to GTK+, Wx and Qt for Perl as well, if you want to create a GUI. In my experience: Wx has a completely broken HTML widget in Perl and parts of the demo crash, GTK+ is neglected too, and I never got Qt to compile.

SDL

The Simple DirectMedia Library for Perl. This module is horribly neglected as well. Ideally, it could be used to be able to create 2D videogames using pure Perl, just like you would be able to make games in Python using the pygame library (which is the SDL port for Python).

The Perl SDL module is very "feature incomplete." The only notable thing anybody has made with Perl SDL was Frozen Bubble, and the developers of that had to hack up their code a lot to get around the limitations of the SDL module.

Perl for games? Sure, if you want to blow the dust off the SDL module and are ready to do a ton more hacking than you wanted to just to get it to work.

Most other languages have modern SDL ports. Pygame comes to mind as I mentioned before, which has a fairly active community of users actually creating games in Python.

GD Graphics Library

Ah, GD, the popular graphics library used by many PHP script kiddies the world over, for doing all sorts of image generation and modification tasks. A user uploaded their picture to your site, how do you scale it down to make thumbnails? GD. How do you stamp your own branding on the corner of their image? GD. How do you generate dynamic statistic images for users to embed in forum signatures? GD.

Perl's GD module though is in a pretty bad state of neglect. All it's good for in Perl is scaling images down (and even then it doesn't do very well; look at my photo album on kirsle.net; it can't seem to save a jpeg image with any good amount of quality. Every time it saves an image it comes out extremely grainy and it completely ignores any settings to make it not do this).

Generating an image from scratch? Maybe you can get it to work with enough effort, but good luck getting text to show up in any color besides black. Using a "template image" to generate a dynamic image off of? Good luck coming up with new colors to use that aren't in the template image. It's just a giant mess.

Image::Magick or Imager are better alternatives, at least. I started using Image::Magick on all my new web development projects, and the next iteration of kirsle.net's code will be using that to handle images instead of GD.

What is Perl good for?

Perl does well as a shell scripting language for system administrators, and it does well for web development. GD sucks for it, but it does have Image::Magick and Imager for dealing with photo manipulation for a web application.

It's also good, of course, for regular expressions and number crunching, which is what it was targeted towards in the first place.

It's not particularly strong at anything else though. Creating a graphical application? Good luck. Creating a game? Don't think about it. Use Python instead.

There are a ton of other modules on CPAN collecting dust that don't work anymore, or don't work particularly well. Net::YMSG for interacting with Yahoo Messenger? Completely broken. Net::AIM for AOL Instant Messenger? Not working (but Net::OSCAR still works as far as I last checked). Audio::Audiere? I don't know anybody who's managed to compile it.

Part of me hopes Perl 6 will be usable soon and I can start learning that (contrary to popular belief, Perl 6 is not the successor to Perl 5 but is a completely separate language), and that any new modules for Perl 6 will be modern (using modern Tk and SDL for example) and will be maintained well in the future, as the ports for Python and other languages are. But part of me just thinks I should put a lot more effort into making Python my new favorite language and using Perl only for the few tasks that Perl does well (like for shell scripting).

Categories: Perl , Tk

[ 0 comments | Add comment | Permalink ]

Webcam Streaming in Perl/Tk (Linux)

Kirsle
kirsle
Posted by Kirsle on Wednesday, Sep 02 2009 @ 9:38 AM
Late last week I started thinking about how to access a webcam device from within Perl. I have no direct need of such capability at the time being but I wanted to know how to do it in case I wanted to do something in the future involving webcams.

A few years ago when I used mostly Windows I found EZTwain, a DLL library for accessing a webcam in Windows using the TWAIN protocol (which as I understand is obsolete by now). The DLL was a pain in the butt to use and I couldn't get it to work how I wanted it to (it insisted on displaying its own GUI windows instead of allowing my Perl script to directly pull a frame from it without a GUI).

Besides that there's pretty much no libraries Perl has been built to use yet that can access a webcam. So, I started looking into using third-party programs such as ffmpeg and mplayer/mencoder to provide the hardware layer for me so that Perl can get just the jpeg images out and do with them what it needs.

Of these programs I wanted to use ffmpeg the most, because I know for sure there's an ffmpeg.exe for Windows, which might mean that whatever code I come up with might be reasonably portable to Windows as well.

After some searching I found some command-line sorcery for using ffmpeg over SSH to activate the camera on a remote computer and stream the video from it over SSH to the local system, and display it in mplayer:

ssh user@remoteip ffmpeg -b 100K -an -f video4linux2 -s 320x240 -r 10 -i /dev/video0 -b 100K -f ogg - | mplayer - -idle -demuxer ogg

Using the basic ffmpeg command in there, along with some hours of research and poking around, I eventually came up with a command that would activate the webcam and output a ton of jpeg images with consecutive file names, of each frame of video that the camera recorded:

ffmpeg -b 100K -an -f video4linux2 -s 640x480 -r 10 -i /dev/video0 -b 100K -f image2 -vcodec mjpeg test%d.jpg

The mjpeg codec (or "motion jpeg"), in ffmpeg, really means it's a bunch of jpeg images all combined together one after the other (the start of each jpeg image can be seen in hex by looking for the magic number, 0xFFD8). The "image2" format here means that each frame from the mjpeg stream gets written to an individual image file, in the format "test%d.jpg" where %d is a number that goes up for each image written.

By changing the image2 to image2pipe instead, the output (all the jpeg images in the mjpeg stream) is sent through the program's standard output, so it can be piped into another program, or read from in Perl.

So in Perl I opened a pipe that executes this command and have the script read from it, reading all the jpeg images and then displaying them in a Perl/Tk window as they come in. In effect: a live webcam stream, where Perl is entirely in control of the jpegs as they come in from ffmpeg and can do with them whatever it wants!

Tk Stream

I added a button to my GUI for taking a snapshot and saving it to disk (in actuality, as each complete image is read and displayed, it's kept around in memory until the next image is read and displayed... so this button just saves the last full image to disk).

Here's my proof of concept Perl code:

#!/usr/bin/perl -w

# Perl/Tk Webcam Streamer and Snapshot Taker
# Proof of Concept
# Author: Casey Kirsle, http://www.cuvou.com/

use Tk;
use Tk::JPEG;
use MIME::Base64 "encode_base64";

# Some things that might need to be configured.
my $device = shift(@ARGV) || "/dev/video0";
if ($device =~ /^\// && !-e $device) {
    die "Can't see video device: $device";
}

# Tk MainWindow
my $mw = MainWindow->new (
    -title => 'Tk Stream',
);
$mw->protocol (WM_DELETE_WINDOW => \&onExit);

# A label to display the photos.
my $photo = $mw->Label ()->pack();

# A button to capture a photo
my $capture = $mw->Button (
    -text => "Take Picture",
    -command => \&snapshot,
)->pack();

$mw->update();

my $cmd = "ffmpeg -b 100K -an -f video4linux2 -s 320x240 -r 10 -i $device -b 100K -f image2pipe -vcodec mjpeg - "
    . "| perl -pi -e 's/\\xFF\\xD8/KIRSLESEP\\xFF\\xD8/ig'";
open (PIPE, "$cmd |");

my ($image,$lastimage);

my $i = 0;
my $jpgBuffer = ""; # last complete jpg image
my $buffer = ""; # bytes read
my $lastFrame = ""; # last complete jpg (kept until another full frame was read; for capturing to disk)
while (read(PIPE, $buffer, 2048)) {
    my (@images) = split(/KIRSLESEP/, $buffer);
    shift(@images) if length $images[0] == 0;
    if (scalar(@images) == 1) {
        # Still the old image.
        my $len = length $images[0];
        $jpgBuffer .= $images[0];
    }
    elsif (scalar(@images) == 2) {
        # We've completed the old image.
        $jpgBuffer .= shift(@images);
        my $len = length $images[0];
        next if length $jpgBuffer == 0;

        # Put this into the last frame received, in case the user
        # wants to save this snapshot to disk.
        $lastFrame = $jpgBuffer;

        # Create a new Photo object to hold the jpeg
        eval {
            $image = $mw->Photo (
                -data => encode_base64($jpgBuffer),
                -format => 'JPEG',
            );
        };
        # Update the label to display the snapshot
        eval {
            $photo->configure (-image => $image);
        };
        # Delete the last image to free up memory leaks,
        # then copy the new image to it.
        $lastimage->delete if ($lastimage);
        $lastimage = $image;

        # Refresh the GUI
        $mw->update();

        # Start reading the next image.
        $jpgBuffer = shift(@images);
    }
    else {
        print "Weird error: 3 items in array!\n";
        exit(1);
    }
}

sub snapshot {
    # Make up a capture filename.
    my $i = 0;
    my $fname = "capture" . (sprintf("%04d",$i)) . ".jpg";
    while (-f $fname) {
        $fname = "capture" . (sprintf("%04d",++$i)) . ".jpg";
    }

    # Save it.
    open (WRITE, ">$fname");
    binmode WRITE;
    print WRITE $lastFrame;
    close (WRITE);
    print "Frame capture saved as $fname\n";
}

sub onExit {
    # Close ffmpeg.
    print "Exiting!\n";
    close (PIPE);
}
You can download it here. It should run on any Linux distribution and it depends on having Perl/Tk and ffmpeg installed, and the video4linux2 system (any modern distro will have that).

In the ffmpeg command here you'll see I also piped the output into a quick Perl script that substitutes all the jpeg headers so that they begin with "KIRSLESEP" -- this was to make it easier to split the jpegs up while reading from the stream.

Since this uses ffmpeg and there's an ffmpeg.exe for Windows, this might work on Windows (you'll definitely need to modify the arguments sent to the ffmpeg command, though). I don't currently have access to a Windows machine with a webcam, though, so I can't work on that just yet.

Anyway, here it is: webcam access in Perl!

Categories: Perl , Tk , Linux

[ 6 comments | Add comment | Permalink ]

Tk::StyleDialog

Kirsle
kirsle
Posted by Kirsle on Thursday, Sep 18 2008 @ 11:27 AM
Since there was enough interest in my two-year-old program, ErrorGen, I've created a Perl/Tk module that does basically what ErrorGen does.

Here's a screenshot:
Synopsis

It's only a module so far that can be included in other Perl/Tk applications. But it's one very large step closer to me creating a simplified tool to spawn error boxes which could be provoked from batch files or scripts. It will probably have a syntax similar to the GNOME program, Zenity.

CPAN takes a few hours to index module updates but the new module will be available at Tk::StyleDialog on CPAN.org.

UPDATE: I've thrown together a quick program called ZenMsg (a name derived from GNOME's Zenity, but since my program only does dialog boxes, it's called ZenMsg).

I've added it as a new tab to the ErrorGen page. Let me know if it can be improved. I had to use ActiveState PerlApp to compile it because PAR::Packer (which I usually prefer to use) was giving me trouble and I didn't have the time or motivation to setup a clean new compiling environment for it. PerlApp may be a bit too limiting.

Categories: Perl , Tk , Software

[ 0 comments | Add comment | Permalink ]

Tk::HyperText Uploaded

Kirsle
kirsle
Posted by Kirsle on Monday, Jul 14 2008 @ 3:45 PM
Finally, I've shipped Tk::HyperText version 0.06 on its way to CPAN's network. It won't be up immediately but in the next few hours the following link will go to the page for version 0.06:

Tk::HyperText.

Here's a screenshot of the demo program that comes with it:

Tk-HyperText

Categories: Perl , Tk

[ 0 comments | Add comment | Permalink ]

[ Older > ]

Kirsle
» Homepage (RSS)
» About Me
» Photo Albums
» Guestbook
» Contact Me
Channels
» Linux (47)
» General (43)
» Perl (34)
» Rant (20)
» Software (15)
» RiveScript (9)
» Gnome 3 (8)
» HowTo (8)
» Windows (8)
» HTML (7)
» Android (6)
» Design (6)
» Siikir (6)
» Tk (6)
» Curiosity (5)
» Blackhat (4)
» Gay (4)
» Java (4)
» Reviews (4)
» VirtualBox (4)
» DOS (3)
» KAGE (3)
» Licensing (3)
» Photos (3)
» Xfce (3)
» ttf2eot (3)
Creativity
» 3D Renderings
» Flash Animation
» JavaScript
» Fonts
» Metacity
» Tutorials
Software
» RiveScript
» Error Generator
» Tk Calculator
» Terminal Apps
» CyanChat Client
Web Tools
» TTF to EOT
» Text Fader
» Favicons
» Distance Calc
» Azulian Encoder
» XBM Masks
Subdomains
» Shell Scripts
» Linux RPMs
» Kirsle::Nano
» Minecraft Server
Miscellany
¤ Pokemon Fuchsia City
¤ DOS and Windows
¤ Raspberry Pi
Links
¤ Google+
¤ Facebook
¤ New MySpace
¤ Twitter
¤ Github
¤ CPAN
Fan Club
» Log In
» Sign Up

Stats
-= Today =-
> Total hits: 2766
> Unique: 1316
-= All Time =-
> Total hits: 1341059
> Unique: 124717
» Traffic History
» Referrers