Perl 将GooCanvas2保存到PNG文件
在使用GooCanvas2绘图之后,我尝试拍摄画布的“屏幕截图”,并将其保存到.PNG文件中 提供了一个使用Gtk2/GooCanvas的非常好的示例,但在将该脚本转换为Gtk3/GooCanvas2后,出现了一个我不理解的错误:Perl 将GooCanvas2保存到PNG文件,perl,gtk3,Perl,Gtk3,在使用GooCanvas2绘图之后,我尝试拍摄画布的“屏幕截图”,并将其保存到.PNG文件中 提供了一个使用Gtk2/GooCanvas的非常好的示例,但在将该脚本转换为Gtk3/GooCanvas2后,出现了一个我不理解的错误: Write PNG... *** unhandled exception in callback: *** `need' is not a valid cairo_status_t value; valid values are: success, no-memo
Write PNG...
*** unhandled exception in callback:
*** `need' is not a valid cairo_status_t value; valid values are: success, no-memory, invalid-restore, invalid-pop-group, no-current-point, invalid-matrix, invalid-status, null-pointer, invalid-string, invalid-path-data, read-error, write-error, surface-finished, surface-type-mismatch, pattern-type-mismatch, invalid-content, invalid-format, invalid-visual, file-not-found, invalid-dash, invalid-dsc-comment, invalid-index, clip-not-representable, temp-file-error, invalid-stride, font-type-mismatch, user-font-immutable, user-font-error, negative-count, invalid-clusters, invalid-slant, invalid-weight at goopng2.pl line 90.
*** ignoring at /usr/share/perl5/Gtk3.pm line 546.
错误是由Gtk3::Gdk::PixbufLoader->write()生成的。我根本没有修改该函数:
$surface->write_to_png_stream (sub {
my ($closure, $data) = @_;
$loader->write($data);
});
这是转换后的脚本:
#!/usr/bin/perl -w
use strict;
use warnings;
use GooCanvas2;
use Gtk3 '-init';
use Glib qw(TRUE FALSE);
my $window = Gtk3::Window->new('toplevel');
$window->signal_connect('delete_event' => sub { Gtk3->main_quit; });
$window->set_default_size(640, 600);
my $vbox = Gtk3::VBox->new;
$vbox->set_border_width(4);
$vbox->show;
$window->add($vbox);
my $swin = Gtk3::ScrolledWindow->new;
$swin->set_shadow_type('in');
$vbox->pack_start($swin, 1, 1, 0);
my $canvas = GooCanvas2::Canvas->new();
$canvas->set_size_request(600, 450);
$canvas->set_bounds(0, 0, 1000, 1000);
$swin->add($canvas);
my $root = $canvas->get_root_item();
my $rect = GooCanvas2::CanvasRect->new(
parent => $root,
'x' => 100,
'y' => 100,
'width' => 400,
'height' => 400,
'line-width' => 10,
'radius-x' => 20,
'radius-y' => 10,
'stroke-color' => 'yellow',
'fill-color' => 'red'
);
my $text = GooCanvas2::CanvasText->new(
'parent' => $root,
'text' => "Hello World",
'x' => 300,
'y' => 300,
'width' => -1,
'anchor' => 'center',
'font' => 'Sans 24',
);
$text->rotate(45, 300, 300);
# Create PNG
my $sb = Gtk3::Button->new_with_label('Write PNG and JPG');
$vbox->pack_start($sb, FALSE, FALSE, 0);
$sb->show;
$sb->signal_connect("clicked", \&write_png_clicked, $canvas);
$window->show_all();
Gtk3->main;
sub write_png_clicked {
my ($but, $canvas) = @_;
print "Write PNG...\n";
my $surface = Cairo::ImageSurface->create ('rgb24', 1000, 1000);
# also argb32 is available
# my $surface = Cairo::ImageSurface->create ('argb32', 1000, 1000);
my $cr = Cairo::Context->create($surface);
# make a background rectangle filled white so saved file looks same as screen
# otherwise a black background may appear, it's like pdf, if it isn't
# drawn , it will be a black background, It won't automagically pick up
# a white background on a canvas
$cr->rectangle( 0, 0, 1000, 1000 );
$cr->set_source_rgb( 1, 1, 1 );
$cr->fill;
$canvas->render($cr, undef, 1);
# this works, but see below for way to use pixbuf and jpg
# my $status = $surface->write_to_png ("$0.png");
# print "$status\n";
my $loader = Gtk3::Gdk::PixbufLoader->new;
$surface->write_to_png_stream (sub {
my ($closure, $data) = @_;
$loader->write($data);
});
$loader->close;
my $pixbuf = $loader->get_pixbuf;
print $pixbuf->get_bits_per_sample(),"\n";
print $pixbuf->get_colorspace(),"\n";
$pixbuf->save ("$0.png", 'png');
print "done png\n";
$pixbuf->save ("$0.jpg", 'jpeg', quality => 100);
print "done jpg\n";
return TRUE;
}
*回调中未处理的异常:
*“需要”不是有效的CAROU状态值;有效值为:success,no memory,[…]位于goopng2.pl第90行。
***忽视
at/usr/share/perl5/Gtk3.pm第546行
通过在代码上运行调试器,我可以看到$loader->write($data)
引发了一个异常:
need an array ref to convert to GArray
而write_to_png_stream()
不希望出现这种类型的异常,并将消息截断为第一个单词“need”
,正如您从顶部的Glib错误消息中看到的:'need'不是有效的cairo_状态值…
通过一些尝试和错误,我发现我可以将$buffer
参数作为字符数组而不是perl字符串传递:
sub write_png_clicked {
my ($but, $canvas) = @_;
print "Write PNG...\n";
my $surface = Cairo::ImageSurface->create ('rgb24', 1000, 1000);
my $cr = Cairo::Context->create($surface);
$cr->rectangle( 0, 0, 1000, 1000 );
$cr->set_source_rgb( 1, 1, 1 );
$cr->fill;
$canvas->render($cr, undef, 1);
my $loader = Gtk3::Gdk::PixbufLoader->new;
$surface->write_to_png_stream (
sub {
my ($loader, $buffer) = @_;
$loader->write([map ord, split //, $buffer]);
return TRUE;
}, $loader
);
$loader->close;
my $pixbuf = $loader->get_pixbuf;
print $pixbuf->get_bits_per_sample(),"\n";
print $pixbuf->get_colorspace(),"\n";
$pixbuf->save ("test.png", 'png');
print "done png\n";
$pixbuf->save ("test.jpg", 'jpeg', quality => 100);
print "done jpg\n";
return TRUE;
}
编辑:
要仅保存画布的一部分,可以将参数传递给render()
方法:
my $bounds = GooCanvas2::CanvasBounds->new();
$bounds->x1(50);
$bounds->x2(250);
$bounds->y1(50);
$bounds->y2(250);
$canvas->render($cr, $bounds, 1);
编辑2:
要在特定位置以及特定宽度和高度捕获区域,请执行以下操作:
my $img_width = 200;
my $img_height = 200;
my $img_x0 = 100;
my $img_y0 = 100;
my $surface = Cairo::ImageSurface->create ('rgb24', $img_width, $img_height);
$cr->translate(-$img_x0,-$img_y0);
$canvas->render($cr, undef, 1);
我不确定Gtk3中的参数是否正确:
my($closure,$data)=@
用于回调。我会检查一下。根据下面的说明,回调应该是Cairo::WriteFunc类型,并接受参数my($callback\u data,$data)=@\u
,所以看起来你得到了正确的$data
参数,也许问题是$loader->write($data)
的调用语法,然后呢?是的,它确实有效!顺便问一下,你能猜出如何捕捉画布的一部分吗?我试过:my$bounds=GooCanvas2::CanvasBounds->new(200200100100)$画布->渲染($cr,$bounds,1)代码>但这似乎是错误的格式。我认为第3和第4个参数是右边缘和下边缘的坐标,请参见,而不是宽度和高度。即使我将其更改为$bounds=GooCanvas2::CanvasBounds->new(50,50,250,250)
它仍然给了我一个空白的png文件,所以我认为在某个地方有bug。我还测试了用纯C编写的相同代码,效果很好,因此问题似乎出在perl包装函数中。@lesrol请参阅我更新的答案以了解正确的语法!因此,如果我们在坐标x=50,y=50处捕捉一个正方形,它也会在x=50,y=50处添加到Cairo::ImageSurface。如果我们想要一个与捕获的方块大小相同的PNG文件,我们会很失望。我试过“$cr->翻译(-50,-50)$画布->渲染($cr,$bounds,1);',但显然这不是正确的方法。再次感谢!游戏::Axmud感谢您的所有努力:)