Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Perl 将GooCanvas2保存到PNG文件_Perl_Gtk3 - Fatal编程技术网

Perl 将GooCanvas2保存到PNG文件

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

在使用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-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感谢您的所有努力:)