Re: Handling Gnome::Canvas data
- From: muppet <scott asofyet org>
- To: Chris Bartak <chrisbartak gmail com>
- Cc: gtk-perl-list gnome org
- Subject: Re: Handling Gnome::Canvas data
- Date: Sat, 24 Jun 2006 09:38:34 -0400
On Jun 23, 2006, at 12:14 PM, Chris Bartak wrote:
I've been trying to render a Gnome::Canvas to a pixbuf, without any
luck. I read that in Perl you must use the pack() function to pack
the pixel data from the Gdk::Window into a scalar. Unfortunately,
I'm not sure how to get the pixel data, or how to pack it
properly. Could anyone provide a quick demo of how this is done?
There are a few different issues with what you're asking, so forgive
me for answering the pieces and not the whole.
The pixel data of a Gtk2::Gdk::Pixbuf is, indeed, packed into a
scalar. It's either 24-bit RGB or 32-bit RGBA, depending on whether
the pixbuf has an alpha channel. The math to walk around in the
pixels is quite simple, provided you remember to use the rowstride.
I've included a simple bit expensive example of walking through pixel
data below; there's another example included with Gtk2 in examples/
color_snooper.pl[1], which uses substr() along with unpack() to use
less memory when attempting to deal with packed pixel data.
You can get a pixbuf from any drawable with
Gtk2::Gdk::Pixbuf::new_from_drawable(). This basically gets the
contents of the drawable as a GdkImage, then converts the GdkImage to
a GdkPixbuf for you -- that is, it's rather like a screenshot.
Beware that it will just get the contents of the window as they are,
so if the window is obscured or not completely drawn, you'll get what
you see. The example code below shows how to use new_from_drawable
(), as well as how to deal with no-window widgets.
So, as you might guess, about the only way i know of to "render" a
Gnome2::Canvas to a pixbuf is to use the screen grab method i just
described, with all the potential pitfalls. There may be some other
trick with canvas, but i don't know of it. Good luck!
[1] http://gtk2-perl.cvs.sourceforge.net/gtk2-perl/gtk2-perl-xs/Gtk2/
examples/color_snooper.pl?revision=1.1&view=markup
-=-=-=-=-=-
#!/usr/bin/perl -w
use strict;
use Gtk2 -init;
my $window = Gtk2::Window->new;
my $label = Gtk2::Label->new ("hi there");
my $button = Gtk2::Button->new ("grab it");
my $vbox = Gtk2::VBox->new;
$window->add ($vbox);
$vbox->add ($label);
$vbox->add ($button);
$window->show_all;
$window->signal_connect (destroy => sub { Gtk2->main_quit });
$button->signal_connect (clicked => sub {
my $w2 = Gtk2::Window->new;
$w2->add (Gtk2::Image->new_from_pixbuf (widget_to_pixbuf ($label)));
$w2->show_all;
my $w3 = Gtk2::Window->new;
$w3->add (Gtk2::Image->new_from_pixbuf (widget_to_pixbuf ($button)));
$w3->show_all;
my $w4 = Gtk2::Window->new;
$w4->add (Gtk2::Image->new_from_pixbuf (swizzle (widget_to_pixbuf
($window))));
$w4->show_all;
});
Gtk2->main;
sub widget_to_pixbuf {
my $widget = shift;
# The widget's allocation holds the coordinates of the widget's a
# rectangle in the gdk window on which it is drawn.
my $allocation = $widget->allocation;
# Of course, the widget itself may not have a gdk window. We'll
# walk backwards up the widget tree until we find a widget with a
# gdk window, and grab from that one.
$widget = $widget->get_parent while $widget->no_window;
# Now we get all the pixels of the widget as a pixbuf.
return Gtk2::Gdk::Pixbuf->get_from_drawable
($widget->window,
$widget->get_colormap,
$allocation->x,
$allocation->y,
0, 0,
$allocation->width,
$allocation->height);
}
sub swizzle {
my $pixbuf = shift;
# Get all the pixels of the image as a packed array of bytes.
my $pixels = $pixbuf->get_pixels;
# We'll be really wasteful and unpack the whole thing into a
# large array.
my @big = unpack 'C*', $pixels;
# The image data is either 24-bit RGB or 32-bit RGBA. We'll decide
# whether the column offset (a.k.a. number of bytes per pixel) is
# 3 for RGB or 4 for RGBA based on the pixbuf's has-alpha value.
my $coloff = $pixbuf->get_has_alpha ? 4 : 3;
# Now we'll do something silly -- zero out the green plane, and put
# a ramp pattern into the red plane, while leaving the blue (and
# alpha, if applicable) planes untouched.
for (my $row = 0 ; $row < $pixbuf->get_height ; $row++) {
# The length of a row and the number of bytes from one row
# to the next are not necessarily the same. The rowstride
# tells you exactly how many bytes to go forward to get from
# here to the same column in the next row. We'll use that
# instead of width * coloff to ensure that we don't have
# runout problems.
my $this_row_offset = $row * $pixbuf->get_rowstride;
for (my $col = 0 ; $col < $pixbuf->get_width ; $col++) {
my $this_pixel_index =
$this_row_offset + $col * $coloff;
$big[$this_pixel_index+0] =
($col / $pixbuf->get_width) * 255;
$big[$this_pixel_index+1] = 0;
}
}
# Now, pack those pixels back together...
$pixels = pack 'C*', @big;
# and wrap a new pixbuf around them.
return Gtk2::Gdk::Pixbuf->new_from_data ($pixels, 'rgb',
$pixbuf->get_has_alpha,
8,
$pixbuf->get_width,
$pixbuf->get_height,
$pixbuf->get_rowstride);
}
--
Walk softly, and carry a BFG-9000.
-- unknown
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]