Re: getting color from gdk::pixbuf (probably a bug in Gdk::Pixbuf)



doome said:

Is it possible that the get_pixels function doesn't work?
The get_pixels function returns nothing, however the png image shows up
in the Gtk2::Image.
...
The $image shows up in the window, but the $pixels string is empty.

It works, but it's being fooled.  I bet the first pixel in your image has a
value of 0 for the red channel, doesn't it?  0 is the null terminator for
strings, so the output typemap for the get_pixels binding is just giving you
an empty string.

I tried it with a different image and got about a quarter of the image data
--- up until it hit a 0.

The solution is this patch, which will be applied to HEAD in just a few minutes:

Index: xs/GdkPixbuf.xs
===================================================================
RCS file: /cvsroot/gtk2-perl/gtk2-perl-xs/Gtk2/xs/GdkPixbuf.xs,v
retrieving revision 1.28
diff -u -r1.28 GdkPixbuf.xs
--- xs/GdkPixbuf.xs     23 Feb 2004 19:35:27 -0000      1.28
+++ xs/GdkPixbuf.xs     3 Mar 2004 15:58:33 -0000
@@ -212,9 +212,18 @@
        GdkPixbuf *pixbuf

 ##  guchar *gdk_pixbuf_get_pixels (const GdkPixbuf *pixbuf)
-guchar *
+SV *
 gdk_pixbuf_get_pixels (pixbuf)
        GdkPixbuf *pixbuf
+    PREINIT:
+       guchar * pixels;
+    CODE:
+       pixels = gdk_pixbuf_get_pixels (pixbuf);
+       RETVAL = newSVpv (pixels,
+                         gdk_pixbuf_get_height (pixbuf)
+                         * gdk_pixbuf_get_rowstride (pixbuf));
+    OUTPUT:
+       RETVAL

 ##  int gdk_pixbuf_get_width (const GdkPixbuf *pixbuf)
 int



With that patch, the following code works fine (and is pretty cool, too).

-=-=-

#!/usr/bin/perl

use strict;
use warnings;
use Glib qw(FALSE TRUE);
use Gtk2 -init;

die "Usage: $0 imagefile\n" unless @ARGV;
my $pixbuf = Gtk2::Gdk::Pixbuf->new_from_file ($ARGV[0]);
my $pixels = $pixbuf->get_pixels;
print "length: ".length($pixels)."\n";
foreach my $attr (qw/width height rowstride n_channels has_alpha/) {
        my $sym = "get_$attr";
        print "$attr: ".($pixbuf->$sym ())."\n";
}
my $l = $pixbuf->get_height * $pixbuf->get_rowstride;
print "calculated length: $l\n";

my $window = Gtk2::Window->new;
my $hbox = Gtk2::HBox->new;
my $ebox = Gtk2::EventBox->new;
my $vbox2 = Gtk2::VBox->new;
my $image = Gtk2::Image->new_from_pixbuf ($pixbuf);
my $frame = Gtk2::Frame->new ('Color');
my $vbox = Gtk2::VBox->new;
my $label = Gtk2::Label->new;
my $darea = Gtk2::DrawingArea->new;
$darea->set_size_request (64, 64);

$window->add ($hbox);
$ebox->add ($image);
$vbox2->pack_start ($ebox, TRUE, FALSE, 0);
$hbox->pack_start ($vbox2, TRUE, FALSE, 0);
$hbox->pack_start ($frame, FALSE, FALSE, 0);
$frame->add ($vbox);
$vbox->pack_start ($label, FALSE, FALSE, 0);
$vbox->pack_start ($darea, FALSE, FALSE, 0);

$window->set_title ("Color Snooper");
$window->show_all;
$window->signal_connect (delete_event => sub {Gtk2->main_quit;});
$ebox->window->set_cursor (create_cursor());

$ebox->add_events (['pointer-motion-mask', 'pointer-motion-hint-mask']);
$ebox->signal_connect (motion_notify_event => sub {
        my ($widget, $event) = @_;
        $widget->window->get_pointer;
        my ($x, $y) = $widget->translate_coordinates ($image,
                                                      $event->x, $event->y);
        my ($r, $g, $b, $a) =
                unpack "C*",
                        substr $pixels,
                               $pixbuf->get_rowstride * $y
                                + $pixbuf->get_n_channels * $x,
                               $pixbuf->get_n_channels;
        $label->set_text ("x,y: ".$event->x.", ".$event->y."\n"
                         ."R: $r\n"
                         ."G: $g\n"
                         ."B: $b"
                         .($pixbuf->get_has_alpha ? "\nA: $a" : ""));

        my $color = Gtk2::Gdk::Color->new ($r << 8, $g << 8, $b << 8);

        $darea->modify_bg ('normal', $color);
        $darea->queue_draw;
});

Gtk2->main;


sub create_cursor {
# these icons borrowed from the gimp.
use constant dropper_small_width => 32;
use constant dropper_small_height => 32;
use constant dropper_small_x_hot => 13;
use constant dropper_small_y_hot => 30;
my $dropper_small_bits = pack 'C*',
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x41,
   0x00, 0x00, 0xc0, 0xa1, 0x00, 0x00, 0x20, 0xbc, 0x00, 0x00, 0x40, 0xbb,
   0x00, 0x00, 0x80, 0x44, 0x00, 0x00, 0x40, 0x34, 0x00, 0x00, 0x20, 0x13,
   0x00, 0x00, 0x90, 0x15, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x64, 0x00,
   0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x80, 0x0c, 0x00,
   0x00, 0x40, 0x06, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0xe0, 0x01, 0x00,
   0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00;
my $dropper_small_mask_bits = pack 'C*',
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x7f,
   0x00, 0x00, 0xc0, 0xff, 0x00, 0x00, 0xe0, 0xff, 0x00, 0x00, 0xc0, 0xff,
   0x00, 0x00, 0xc0, 0x7f, 0x00, 0x00, 0xe0, 0x3f, 0x00, 0x00, 0xf0, 0x1f,
   0x00, 0x00, 0xf8, 0x1f, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfe, 0x00,
   0x00, 0x00, 0x7f, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0xc0, 0x1f, 0x00,
   0x00, 0xe0, 0x0f, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xf0, 0x03, 0x00,
   0x00, 0xe0, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00;

my $icon = Gtk2::Gdk::Bitmap->create_from_data (undef, $dropper_small_bits,
dropper_small_width, dropper_small_height);
my $mask = Gtk2::Gdk::Bitmap->create_from_data (undef,
$dropper_small_mask_bits, dropper_small_width, dropper_small_height);
return Gtk2::Gdk::Cursor->new_from_pixmap
                ($icon, $mask,
                 Gtk2::Gdk::Color->new (0, 0, 0),
                 Gtk2::Gdk::Color->new (65535, 65535, 65535),
                 dropper_small_x_hot, dropper_small_y_hot);
}

-=-=-=-

-- 
muppet <scott at asofyet dot org>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]