embedding opengl in perl tk - perl

I have an application written with perl Tk, showing some data on a canvas. Now I would like to be able to generate a 3d view of the data with opengl. Is there any way to embed an OpenGL widget or window inside an Tk window?
I've seen some posts in perlmonks that use Tk and glpCreateWindow to create a new separated OpenGL window but I want the OpenGL "canvas" to be inside the main Tk window.

Here's an adaption of the tk_demo script which comes with the OpenGL perl module
https://metacpan.org/source/CHM/OpenGL-0.66/examples/tk_demo.pl
The script was changed so that the opengl drawing appears in a Frame widget, and not in a Toplevel/MainWindow widget, so other Tk widgets may be contained within the same Toplevel. It's even possible to resize the Tk window, the opengl drawing will adapt accordingly.
There's one flaw though: it seems that it's not possible to start the opengl drawing using afterIdle(); at this point the container frame does not seem to exist yet and a X11 error happens. It's also not possible to use waitVisibility() here. Hence the workaround using after(1000,...).
#!/usr/local/bin/perl
#
# This is an example of combining the tk module and opengl
# You have to have TK installed for this to work.
# this program opens a window and when you hit a key in
# the window a callback that does some opengl stuff is
# executed.
# Yes, this is a totally lame program, but its a proof
# of concept sort of thing.
# We'll get something better next time :-)
#
use lib ('blib');
use strict;
use Tk;
use OpenGL;
my $top = MainWindow->new();
$top->Label(-text => "Hello, OpenGL!")->pack;
my $f = $top->Frame(-bg => "green", -width => 200, -height => 200)->pack(-expand => 1, -fill => "both");
$top->Button(-text => "Exit", -command => sub { $top->destroy })->pack;
my $kid;
sub CreateKid {
my $par = shift;
my $id = hex($par->id);
print " window id: $id -> ", (sprintf '%#x', $id),"\n";
my ($w, $h) = ($par->Width, $par->Height);
my ($xbord, $ybord) = (int($w/8), int($h/8));
$kid = glpOpenWindow( x => $xbord, y => $ybord, width=> ($w-2*$xbord),
height=> ($h-2*$ybord),parent=>$id);
}
sub ResetKid {
return unless $kid;
my $par = shift;
my $w = $par->Width;
my $h = $par->Height;
my ($xbord, $ybord) = (int($w/8), int($h/8));
$w = $w-2*$xbord;
$h = $h-2*$ybord;
glpMoveResizeWindow($xbord,$ybord,$w,$h);
glViewport(0,0,$w,$h);
print "viewport $w x $h, origin $xbord, $ybord\n";
DrawKid();
}
my $pending = 0;
sub DrawKid {
return unless $kid;
return if $pending++;
$top->DoWhenIdle(\&DrawKid_do);
}
sub DrawKid_do {
return unless $kid;
$pending = 0;
print "Drawing...\n";
glClearColor(0,0,1,1);
glClear(GL_COLOR_BUFFER_BIT);
glOrtho(-1,1,-1,1,-1,1);
glColor3f(1,0,0);
glBegin(GL_POLYGON);
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5, 0.5);
glVertex2f( 0.5, 0.5);
glVertex2f( 0.5,-0.5);
glEnd();
glFlush();
}
sub DrawKid1 {
return unless $kid;
print "Visibility change\n";
DrawKid;
}
sub DrawKid2 {
return unless $kid;
print "Expose change\n";
DrawKid;
}
sub DoKey
{
my $w = shift;
return if $kid;
CreateKid $w;
DrawKid;
}
sub DoMouse
{
shift;
my ($b,$p) = (shift,shift);
print "mouse-$b $p\n";
}
$f->after(1000, sub { DoKey($f) });
$f->bind("<Any-ButtonPress>",[\&DoMouse, Ev('b'), Ev('#')]);
$f->bind("<KeyPress-q>",[$top, 'destroy']);
$f->bind("<KeyPress-Escape>",[$top, 'destroy']);
$f->bind("<Configure>",\&ResetKid);
$f->bind("<Visibility>",\&DrawKid1);
$f->bind("<Expose>",\&DrawKid2);
Tk::MainLoop();

Related

How to get a user-configurable buffer for printing?

I'd like to have a print function supporting a user-configurable buffer, so to print what I have in the buffer only when the buffer is > a threshold).
I need to write multiple files, so I have multiple filehandles to write to, and for this an object oriented module might be handier.
I imagine something like this:
my $printer1 = Print::Buffer->new({ size => 1000, filehandle => \$OUT1 });
for (my $i=1; $i<1000; $i++) {
$printer1->print("This string will be eventually printed ($i/1000)");
}
# and at the end print the remaining buffer
$printer1->flush();
Any recommendation? I probably don't use the right keywords as with print/buffer I didn't find clear matches in CPAN.
UPDATE:
Thanks everyone for the very useful comments. As some of you pointed out, the problem is more complex than I initially thought, and probably a bad idea. (This question arose as I was printing very large files [>100Gb] in with a print statement at each loop iteration, and noted that if I was printing every hunderth iteration I had a speedup, but it could be dependent on how the loop was changed...)
UPDATE 2:
I need/want to accept an answer. To me both have been instructive and they are both useful. I tested both and they both need further work before being able to benchmark the improvement (if any, see update above). The tie handle is a less known feature that I loved, that's why I accepted that. They were both equally close to the desired answer in my opinion. Thank you all very much for the discussion and the insights.
I'd like to have a print function supporting a user-configurable buffer, [...]
I imagine something like this: [...]
It's not hard to write something like it. Here's a basic sketch
File PrintBuffer.pm
package PrintBuffer;
use warnings;
use strict;
sub new {
my ($class, %args) = #_;
my $self = {
_size => $args{size} // 64*1024, #//
_fh => $args{filehandle} // *STDOUT,
_buf => ''
};
$self->{_fh}->autoflush; # want it out once it's printed
bless $self, $class;
}
sub print {
my ($self, $string) = #_;
$self->{_buf} .= $string;
if ( length($self->{_buf}) > $self->{_size} ) {
print { $self->{_fh} } $self->{_buf};
$self->{_buf} = '';
}
return $self;
}
sub DESTROY {
my $self = shift;
print { $self->{_fh} } $self->{_buf} if $self->{_buf} ne '';
$self->{_buf} = '';
}
1;
There's a bit more to do here, and a whole lot that can be added, and since it relies only on basic tools one can add/change as desired.† For one, I can imagine a size method to manipulate the buffer size of an existing object (print if there's already more data than the new size), and flush.
Note that DESTROY method provides for the buffer to be printed as the object drops out of any scope, and is getting destroyed, what seems reasonable to do.
A driver
use warnings;
use strict;
use feature 'say';
use PrintBuffer;
my $fout = shift // die "Usage: $0 out-file\n";
open my $fh, '>', $fout or die "Can't open $fout: $!";
my $obj_file = PrintBuffer->new(size => 100, filehandle => $fh);
my $obj_stdout = PrintBuffer->new(size => 100);
$obj_file->print('a little bit');
$obj_stdout->print('a little bit');
say "printed 'a little bit' ..."; sleep 10;
$obj_file->print('out'x30); # push it over a 100 chars
$obj_stdout->print('out'x30);
say "printed 'out'x30 ... "; sleep 10;
$obj_file->print('again...'); # check DESTROY
$obj_stdout->print('again');
say "printed 'again' (and we're done)";
Check the size of output file in another terminal after each informational print.
I tried PerlIO::buffersize brought up by Grinnz in a comment and it seems to work "as advertised" as they say. It doesn't allow you to do all you may wish but it may be a ready solution for basic needs. Note that this doesn't work with :encoding layer in use.
Thanks to ikegami for comments and tests (linked in comments).
† The print works with an autoflush-ed handle. Still, the first change could be to use syswrite instead, which is unbuffered and attempts to directly write all that's asked of it, via one write(2) call. But since there's no guarantee that all got written we also need to check
use Carp; # for croak
WRITE: {
my $bytes_written = 0;
while ( $bytes_written < length $self->{_buf} ) {
my $rv = syswrite(
$self->{_fh},
$self->{_buf},
length($self->{_buf}) - $bytes_written,
$bytes_written
);
croak "Error writing: $!" if not defined $rv;
$bytes_written += $rv;
}
$self->{_buf} = '';
};
I've put this in a block only to limit the scope of $bytes_written and any other variables that one may wish to introduce so to reduce the number of dereferences of $self (but note that $self->{_buf} may be quite large and copying it "to optimize" dereferencing may end up slower).
Naively we'd only need syswrite(FH, SCALAR) but if it happens that not all of SCALAR gets written then we need to continue writing from past what was written, thus the need to use the form with length-to-write and offset as well.
Since this is unbuffered it mustn't be mixed with buffered IO (or that need be done very carefully); see the docs. Also, :encoding layers can't be used with it. Consider these restrictions against other capabilities that may be wanted in this class.
I don't see a general solution on CPAN, either. But this is straightforward enough with tied filehandles. Something like
use Symbol;
sub Print::Buffer::new {
my ($class,$mode,$file,#opts) = #_;
my $x = Symbol::gensym;
open ($x, $mode, $file) or die "failed to open '$file': $!";
tie *$x, "Print::Buffer", fh => $fh, #opts;
$x;
}
sub Print::Buffer::TIEHANDLE {
my $pkg = shift;
my $self = { #_ };
$self->{bufsize} //= 16 * 1024 * 1024;
$self->{_buffer} = "";
bless $self, $pkg;
}
sub Print::Buffer::PRINT {
my ($self,#msg) = #_;
$self->{buffer} .= join($,,#msg);
$self->_FLUSH if length($self->{buffer}) > $self->{bufsize};
}
sub Print::Buffer::_FLUSH {
my $self = shift;
print {$self->{fh}} $self->{buffer};
$self->{buffer} = "";
}
sub Print::Buffer::CLOSE {
my $self = shift;
$self->_FLUSH;
close( $self->{fh} );
}
sub Print::Buffer::DESTROY {
my $self = shift;
$self->_FLUSH;
}
# ----------------------------------------
my $fh1 = Print::Buffer->new(">", "/tmp/file1",
bufsize => 16*1024*1024);
for (my $i=1; $i<1000; $i++) {
print $fh1 "This string will be eventually printed ($i/1000)\n";
}

Hiding a tie call from the user in Perl

How can I hide a "tie" call from the user so calling an accessor will implicitly do it for them?
I want to do this, because I have a data structure that can be accessed by the user, but values stored in this structure can be modified without the user's knowledge.
If an attribute in the data structure changes, I want any variables referencing that attribute modified as well so the user will always be using fresh data. Since the user will always want fresh data, it's simpler and more intuitive if the user doesn't even need to know it's happening.
This is what I have so far... it doesn't seem to work though, the output is:
hello
hello
What I want is:
hello
goodbye
Code:
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
{
package File;
use Moose;
has '_text' => (is => 'rw', isa => 'Str', required => 1);
sub text {
my ($self) = #_;
tie my $text, 'FileText', $self;
return $text;
}
}
{
package FileText;
use Tie::Scalar;
sub TIESCALAR {
my ($class, $obj) = #_;
return bless \$obj, $class;
}
sub FETCH {
my ($self) = #_;
return $$self->_text();
}
sub STORE {
die "READ ONLY";
}
}
my $file = 'File'->new('_text' => 'hello');
my $text = $file->text();
say $text;
$file->_text('goodbye');
say $text;
I would not recommend doing this. You're introducing "action at a distance" which leads to some very difficult to catch bugs. The user thinks they're getting a string. A lexical string can only be altered by changing it directly and obviously. It has to be altered in place or obviously passed into a function or a reference attached to something.
my $text = $file->text;
say $text; # let's say it's 'foo'
...do some stuff...
$file->text('bar');
...do some more stuff...
# I should be able to safely assume it will still be 'foo'
say $text;
That block of code is easy to understand because all the things which could affect $text are immediately visible. This is what lexical context is all about, isolating what can change a variable.
By returning a thing which can change at any time, you've quietly broken this assumption. There's no indication to the user that assumption has been broken. When they go to print $text and get bar it is non-obvious what changed $text. Anything in the whole program could change $text. That small block of code is now infinitely more complicated.
Another way to look at it is this: scalar variables in Perl have a defined interface. Part of that interface says how they can be changed. You are breaking this interface and lying to the user. This is how overloaded/tied variables are typically abused.
Whatever problem you're trying to solve, you're solving it by adding more problems, by making the code more complex and difficult to understand. I would step back and ask what problem you're trying to solve with tying.
What I would do instead is to just return a scalar reference. This alerts the user that it can be changed out from under them at any time. No magic to cover up a very important piece of information.
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
{
package File;
use Moose;
has 'text_ref' => (
is => 'rw',
isa => 'Ref',
default => sub {
return \("");
}
);
sub BUILDARGS {
my $class = shift;
my %args = #_;
# "Cast" a scalar to a scalar ref.
if( defined $args{text} ) {
$args{text_ref} = \(delete $args{text});
}
return \%args;
}
sub text {
my $self = shift;
if( #_ ) {
# Change the existing text object.
${$self->text_ref} = shift;
return;
}
else {
return $self->text_ref;
}
}
}
my $file = 'File'->new('text' => 'hello');
my $text = $file->text();
say $$text;
$file->text('goodbye');
say $$text;
That said, here's how you do what you want.
I would recommend against using tie. It is very slow, considerably slower than a method call, buggy and quirky. One of its quirks is that the tied nature is attached to the variable itself, not the referenced data. That means you can't return a tied variable.
Instead, I would recommend using an overloaded object to store your changing text.
{
package ChangingText;
# Moose wants class types to be in a .pm file. We have to explciitly
# tell it this is a class type.
use Moose::Util::TypeConstraints qw(class_type);
class_type('ChangingText');
use overload
'""' => sub {
my $self = shift;
return $$self;
},
fallback => 1;
sub new {
my $class = shift;
my $text = shift;
return bless \$text, $class;
}
sub set_text {
my $self = shift;
my $new_text = shift;
$$self = $new_text;
return;
}
}
Overloaded objects have their own caveats, mostly due to code which expects strings writing things like if !ref $arg, but they are easier to deal with than the deep tie bugs.
To make this transparent, store the ChangingText object in the File object and then put a hand made text accessor around it to handle plain strings. The accessor makes sure to reuse the same ChangingText object.
To complete the illusion, BUILDARGS is used to change plain text initialization arguments into a ChangingText object.
{
package File;
use Moose;
has 'text_obj' => (
is => 'rw',
isa => 'ChangingText',
default => sub {
return ChangingText->new;
}
);
sub BUILDARGS {
my $class = shift;
my %args = #_;
# "Cast" plain text into a text object
if( defined $args{text} ) {
$args{text_obj} = ChangingText->new(delete $args{text});
}
return \%args;
}
sub text {
my $self = shift;
if( #_ ) {
# Change the existing text object.
$self->text_obj->set_text(shift);
return;
}
else {
return $self->text_obj;
}
}
}
Then it works transparently.
my $file = File->new('text' => 'hello');
my $text = $file->text();
say $text; # hello
$file->text('goodbye');
say $text; # goodbye
return $text just returns the value of the variable, not the variable itself. You can return a reference to it, though:
sub text {
my ($self) = #_;
tie my $text, 'FileText', $self;
return \$text;
}
You then have to use $$text to dereference it:
my $file = 'File'->new('_text' => 'hello');
my $text = $file->text();
say $$text;
$file->_text('goodbye');
say $$text;

thumbnail screenshot of webpages with Perl :: Mechanize

i use WWW::Mechanize::Firefox to control a firefox instance and dump the rendered page with $mech->content_as_png.
New update: see at the end of the initial posting:
thanks to user1126070 we have a new solution - which i want to try out later the day [right now i am in office and not at home - in front of the machine with the programme ]
$mech->repl->repl->setup_client( { extra_client_args => { timeout => 5*60 } } );
i try out the version that put links to #list and use eval and do the following:
while (scalar(#list)) {
my $link = pop(#list);
print "trying $link\n";
eval{
$mech->get($link);
sleep (5);
my $png = $mech->content_as_png();
my $name = "$_";
$name =~s/^www\.//;
$name .= ".png";
open(OUTPUT, ">$name");
print OUTPUT $png;
close(OUTPUT);
}
if ($#){
print "link: $link failed\n";
push(#list,$link);#put the end of the list
next;
}
print "$link is done!\n";
}
BTW: user1126070 what with the trimming down the images to thumbnail-size. Should i use imager here. Can you suggest some solution thing here...!? That would be great.
end of Update
Here the problem-outline continues - as written at the very beginning of this Q & A
problem-outline: I have a list of 2500 websites and need to grab a thumbnail screenshot of them. How do I do that? I could try to parse the sites either with Perl.- Mechanize would be a good thing. Note: i only need the results as a thumbnails that are a maximum 240 pixels in the long dimension. At the moment i have a solution which is slow and does not give back thumbnails: How to make the script running faster with less overhead - spiting out the thumbnails
But i have to be aware that setting it up can pose quite a challenge, though.
If all works as expected, you can simply use a script like this to dump images of the desired websites, but you should start Firefox and resize it to the desired width manually (height doesn't matter, WWW::Mechanize::Firefox always dumps the whole page).
What i have done so far is alot - i work with mozrepl. At the moment i struggle with timeouts: Is there a way to specify Net::Telnet timeout with WWW::Mechanize::Firefox?
At the moment my internet connection is very slow and sometimes I get error
with $mech->get():
command timed-out at /usr/local/share/perl/5.12.3/MozRepl/Client.pm line 186
SEE THIS ONE:
> $mech->repl->repl->timeout(100000);
Unfortunatly it does not work: Can't locate object method "timeout" via package "MozRepl"
Documentation says this should:
$mech->repl->repl->setup_client( { extra_client_args => { timeout => 1 +80 } } );
What i have tried allready; here it is:
#!/usr/bin/perl
use strict;
use warnings;
use WWW::Mechanize::Firefox;
my $mech = new WWW::Mechanize::Firefox();
open(INPUT, "<urls.txt") or die $!;
while (<INPUT>) {
chomp;
print "$_\n";
$mech->get($_);
my $png = $mech->content_as_png();
my $name = "$_";
$name =~s/^www\.//;
$name .= ".png";
open(OUTPUT, ">$name");
print OUTPUT $png;
sleep (5);
}
Well this does not care about the size: See the output commandline:
linux-vi17:/home/martin/perl # perl mecha_test_1.pl
www.google.com
www.cnn.com
www.msnbc.com
command timed-out at /usr/lib/perl5/site_perl/5.12.3/MozRepl/Client.pm line 186
linux-vi17:/home/martin/perl #
And here - this is my source: see a snippet-example of the sites i have in the url-list.
urls.txt - the list of sources
www.google.com
www.cnn.com
www.msnbc.com
news.bbc.co.uk
www.bing.com
www.yahoo.com and so on...
BTW: With that many url's we have to expect that some will fail and handle that. For example, we put the failed ones in an array or hash and retry them X times.
UTSL
well how is this one here...
sub content_as_png {
my ($self, $tab, $rect) = #_;
$tab ||= $self->tab;
$rect ||= {};
# Mostly taken from
# http://wiki.github.com/bard/mozrepl/interactor-screenshot-server
my $screenshot = $self->repl->declare(<<'JS');
function (tab,rect) {
var browser = tab.linkedBrowser;
var browserWindow = Components.classes['#mozilla.org/appshell/window-mediator;1']
.getService(Components.interfaces.nsIWindowMediator)
.getMostRecentWindow('navigator:browser');
var win = browser.contentWindow;
var body = win.document.body;
if(!body) {
return;
};
var canvas = browserWindow
.document
.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
var left = rect.left || 0;
var top = rect.top || 0;
var width = rect.width || body.clientWidth;
var height = rect.height || body.clientHeight;
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
ctx.save();
ctx.scale(1.0, 1.0);
ctx.drawWindow(win, left, top, width, height, 'rgb(255,255,255)');
ctx.restore();
//return atob(
return canvas
.toDataURL('image/png', '')
.split(',')[1]
// );
}
JS
my $scr = $screenshot->($tab, $rect);
return $scr ? decode_base64($scr) : undef
};
Love to hear from you!
greetings zero
Are you tried this out? It is working?
$mech->repl->repl->setup_client( { extra_client_args => { timeout => 5*60 } } );
put links to #list and use eval
while (scalar(#list)) {
my $link = pop(#list);
print "trying $link\n";
eval{
$mech->get($link);
sleep (5);
my $png = $mech->content_as_png();
my $name = "$_";
$name =~s/^www\.//;
$name .= ".png";
open(OUTPUT, ">$name");
print OUTPUT $png;
close(OUTPUT);
}
if ($#){
print "link: $link failed\n";
push(#list,$link);#put the end of the list
next;
}
print "$link is done!\n";
}

In Perl, how can a subroutine get a coderef that points to itself?

For learning purposes, I am toying around with the idea of building
event-driven programs in Perl and noticed that it might be nice if a
subroutine that was registered as an event handler could, on failure,
just schedule another call to itself for a later time. So far, I have
come up with something like this:
my $cb;
my $try = 3;
$cb = sub {
my $rc = do_stuff();
if (!$rc && --$try) {
schedule_event($cb, 10); # schedule $cb to be called in 10 seconds
} else {
do_other_stuff;
}
};
schedule_event($cb, 0); # schedule initial call to $cb to be performed ASAP
Is there a way that code inside the sub can access the coderef to that
sub so I could do without using an extra variable? I'd like to
schedule the initial call like this.
schedule_event( sub { ... }, 0);
I first thought of using caller(0)[3], but this only gives me a
function name, (__ANON__ if there's no name), not a code reference
that has a pad attached to it.
__SUB__ has been added in 5.16, providing this usability.
I think Sub::Current will fix your problem.
To get a reference to the current subroutine without using an extra variable, you can use a tool from functional programming, the Y-combinator, which basically abstracts away the process of creating the closure. Here is a perlish version:
use Scalar::Util qw/weaken/;
sub Y (&) {
my ($code, $self, $return) = shift;
$return = $self = sub {$code->($self, #_)};
weaken $self; # prevent a circular reference that will leak memory
$return;
}
schedule_event( Y { my $self = shift; ... }, 0);
If you don't change $cb's value again, you can use that. If not, define a scalar to hold that and don't change it ever again. For example:
my $cb = do {
my $sub;
$sub = sub { contents using $sub here }
}
Using a fixed-point combinator, you can write your $cb function as if the first argument was the function itself:
sub U {
my $f = shift;
sub { $f->($f, #_) }
}
my $cb = sub {
my $cb = shift;
...
schedule_event(U($cb), 10);
...
}
schedule_event(U($cb), 0);

How can I get the width and height of a text string with CAM::PDF?

I use the following to read a PDF file and get text strings of a page:
my $pdf = CAM::PDF->new($pdf_file);
my $pagetree = $pdf->getPageContentTree($page_no);
# Get all text strings of the page
# MyRenderer is a separate package which implements getTextBlocks and
# renderText methods
my #text = $pagetree->traverse('MyRenderer')->getTextBlocks;
Now, #text has all the text strings and start x,y of each text string.
How can I get the width (and possibly the height) of each string?
MyRenderer package is as follows:
package MyRenderer;
use base 'CAM::PDF::GS';
sub new {
my ($pkg, #args) = #_;
my $self = $pkg->SUPER::new(#args);
$self->{refs}->{text} = [];
return $self;
}
sub getTextBlocks {
my ($self) = #_;
return #{$self->{refs}->{text}};
}
sub renderText {
my ($self, $string, $width) = #_;
my ($x, $y) = $self->textToDevice(0,0);
push #{$self->{refs}->{text}}, {
str => $string,
left => $x,
bottom => $y,
right =>$x + $width,
};
return;
}
Update 1:
There's a function getStringWidth($fontmetrics, $string)
in CAM::PDF. Altough there's a parameter $fontmetrics in that function, irespective of what I pass to that parameter, the function returns the same value for a given string.
Also, I am not sure of the unit of measure the returned value uses.
Update 2:
I changed the renderText function to following:
sub renderText {
my ($self, $string, $width) = #_;
my ($x, $y) = $self->textToDevice(0,0);
push #{$self->{refs}->{text}}, {
str => $string,
left => $x,
bottom => $y,
right =>$x + ($width * $self->{Tfs}),
font => $self->{Tf},
font_size => $self->{Tfs},
};
return;
}
Note that in addition to getting font and font_size, I multiplied $width with font size to get the real width of the string.
Now, only thing missing is the height.
getStringWidth() depends heavily on the font metrics you provide. If it can't find the character widths in that data structure, then it falls back to the following code:
if ($width == 0)
{
# HACK!!!
#warn "Using klugy width!\n";
$width = 0.2 * length $string;
}
which may be what you're seeing. When I wrote that, I thought it was better than returning 0. If your font metrics seem good and you think there's a bug in CAM::PDF, feel free to post more details and I'll take a look.