In Perl/Tk there is the postscript method for saving an entire unseen canvas. In Gtk2's Gnome2::Canvas, you can only grab a snapshot of the visible portion of the canvas. This is a way to slide thru a scrolled window( which contains a canvas), and stitch together a full snapshot.
It may seem clumsy the way I cycle thru the scrolled window, (and someone may be able to refine the loop), but this way makes it obvious what is happeneing.
Any comments, bugs found, improvements are welcome. ( I'm probably overlooking something :-) )
#!/usr/bin/perl
use warnings;
use strict;
use Glib qw/TRUE FALSE/;
use Gtk2 -init;
use Gnome2::Canvas;
my $debug = 0; # set to 1 to get small pixbuf files
# Create the window
my $window = new Gtk2::Window ( "toplevel" );
$window->signal_connect ("delete_event", sub { Gtk2->main_quit; });
$window->set_border_width (10);
#$window->set_size_request(640,480);
$window->set_position('center');
my $vbox = Gtk2::VBox->new( 0, 0 );
$window->add($vbox);
$vbox->set_border_width(2);
my $hbox = Gtk2::HBox->new( 0, 0 );
$vbox->pack_start($hbox,1,1,0);
$hbox->set_size_request(320,240);
$hbox->set_border_width(0);
my $hbox1 = Gtk2::HBox->new( 0, 0 );
$vbox->pack_start($hbox1,0,0,0);
$hbox1->set_border_width(0);
my $scwin = Gtk2::ScrolledWindow->new();
my $ha1 = $scwin->get_hadjustment;
my $va1 = $scwin->get_vadjustment;
$scwin->set_policy('automatic','automatic');
$hbox->add($scwin);
my $white = Gtk2::Gdk::Color->new (0xFFFF,0xFFFF,0xFFFF);
my $canvas = Gnome2::Canvas->new();
$canvas->set_scroll_region(0,0,1000,1000);
$canvas->modify_bg('normal',$white);
$canvas->set_center_scroll_region (0);
my $root = $canvas->root();
my $item = Gnome2::Canvas::Item->new($root,
"Gnome2::Canvas::Ellipse",
x1 => 0,
y1 => 0,
x2 => 1000,
y2 => 400,
fill_color=>"red",
outline_color=>"black"
);
$item = Gnome2::Canvas::Item->new($root,
"Gnome2::Canvas::Ellipse",
x1 => 0,
y1 => 400,
x2 => 1000,
y2 => 800,
fill_color=>"blue",
outline_color=>"black"
);
$item = Gnome2::Canvas::Item->new($root,
"Gnome2::Canvas::Ellipse",
x1 => 0,
y1 => 800,
x2 => 1000,
y2 => 1000,
fill_color=>"green",
outline_color=>"black"
);
$scwin->add($canvas);
my $button2 = Gtk2::Button->new('Quit');
$hbox1->pack_start( $button2, FALSE, FALSE, 2);
$button2->signal_connect( clicked => sub{ exit; });
my $button3 = Gtk2::Button->new('Save');
$hbox1->pack_start( $button3, FALSE, FALSE, 2);
$button3->signal_connect( clicked => \&save_it,$canvas);
$window->show_all;
Gtk2->main;
#######################################################
sub save_it{
my (undef, $widget) = @_;
my ($width, $height) = $widget->get_size;
my ($x,$y,$width1, $height1,$depth) = $widget->window->get_geometry;
print "$width $height\n" if $debug;
print "$width1 $height1\n" if $debug;
# a hack to slide the viewport and grab each viewable area
my $cols = int($width/$width1);
my $cmod = $width % $width1;
my $rows = int($height/$height1);
my $rmod = $height % $height1;
print "rows - rmod-> $rows - $rmod\n" if $debug;
print "cols - cmod-> $cols - $cmod\n" if $debug;
# create large blank pixbuf to hold the stitched image
my $gdkpixbuf_l = Gtk2::Gdk::Pixbuf->new ('rgb',
0, 8, $width, $height);
# get full rows and cols ##################################
for my $c (0 .. $cols - 1 ){
#slide viewport along
$ha1->set_value( $c * $width1 );
for my $r (0..$rows - 1 ){
$va1->set_value( $r * $height1 );
# create blank pixbuf to hold the small image
my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
0, 8,$width1, $height1);
$gdkpixbuf->get_from_drawable ($canvas->window,
undef, 0, 0, 0, 0, $width1, $height1);
# $src_pixbuf->copy_area ($src_x, $src_y, $width, $height,
# $dest_pixbuf, $dest_x, $dest_y)
$gdkpixbuf->copy_area (0, 0, $width1, $height1,
$gdkpixbuf_l, $c*$width1, $r*$height1);
$gdkpixbuf->save ("$0-$c-$r.jpg", 'jpeg',
quality => 100) if $debug;
} #end rows
} #end cols
######################################################################
+##
# get bottom odd row except lower right corner#######################
for my $c (0 .. $cols - 1 ){
$ha1->set_value( $c * $width1 );
$va1->set_value( $rows * $height1 );
my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
0,8,$width1,$rmod);
$gdkpixbuf->get_from_drawable ($canvas->window,
undef, 0, 0, 0, 0, $width1, $rmod);
$gdkpixbuf->copy_area (0, 0, $width1, $rmod,
$gdkpixbuf_l, $c*$width1, $rows*$height1);
$gdkpixbuf->save ("$0-$c-rmod.jpg", 'jpeg',
quality => 100) if $debug;
} #end odd row
######################################################################
+##
# get right odd col except lower right corner ########################
+##
for my $r (0 .. $rows - 1 ){
$ha1->set_value( $cols * $width1 );
$va1->set_value( $r * $height1 );
# create blank pixbuf to hold the image
my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
0,8,$cmod, $height1);
$gdkpixbuf->get_from_drawable ($canvas->window,
undef, 0, 0, 0, 0, $cmod, $height1);
$gdkpixbuf->copy_area (0, 0, $cmod, $height1,
$gdkpixbuf_l, $cols*$width1, $r*$height1);
$gdkpixbuf->save ("$0-$r-cmod.jpg", 'jpeg',
quality => 100) if $debug;
} #end odd col
######################################################################
+##
# get lower right corner ##########################
$ha1->set_value( $cols * $width1 );
$va1->set_value( $rows * $height1 );
# create blank pixbuf to hold the image
my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
0,8,$cmod,$rmod);
$gdkpixbuf->get_from_drawable ($canvas->window,
undef, 0, 0, 0, 0, $cmod, $rmod);
$gdkpixbuf->copy_area (0, 0, $cmod, $rmod,
$gdkpixbuf_l, $width - $cmod, $height - $rmod);
$gdkpixbuf->save ("$0-rmod-cmod.jpg", 'jpeg',
quality => 100) if $debug;
######################################################################
+##
$gdkpixbuf_l->save ("$0-large.jpg", 'jpeg', quality => 100);
$ha1->set_value( 0 );
$va1->set_value( 0 );
return FALSE;
}