在__DATA__句柄中存储二进制数据

4

在一个模块中,我需要一些图像数据(BMP)用于一些Imager::Search操作。下面的代码可以实现:

my $pattern = Imager::Search::Pattern->new(
     driver => 'Imager::Search::Driver::BMP24',
     file   => 'test.bmp', #load the image from a file
);

对我来说,图像test.bmp)是固定的,因此希望直接将其存储在源代码中。

my $image = ... the image data ... ;

或者在 __DATA__ 部分中。

__DATA__ 中存储二进制数据(如 test.bmp)的推荐方法是什么?(2.3kb)


为什么?如果您实际上将二进制数据存储而不是只是放置十六进制表示,我可以想到各种有趣的方式来导致失败。请参见unpack - Sinan Ünür
使用Base64编码和核心模块Mime::Base64进行解码。这样可以避免尝试直接将原始二进制数据放入源代码文件的陷阱。 - DavidO
我认为将图像保留为单独的位图文件会更好,但您可能想查看MIME::Base64,它允许您将二进制数据编码为可打印的ASCII字符。 - Borodin
2个回答

10

你可能不想处理将原始二进制数据存储在源文件中的麻烦,但这并不意味着你不能仍然使用一种将图像存储在__DATA__段中的解决方案。你只需要先将它编码为纯文本格式,例如Base64。

Mojolicious就是这样一个例子。使用Mojolicious::Lite,可以在__DATA__部分中嵌入模板和其他静态内容。而Base64编码数据是其中一种可能性,如Mojolicious::Guides::Tutorial#Static Files所述。

这说明有时会使用这种方法。如果你想实现一个使用这种方法的解决方案,你可以使用核心Perl模块MIME::Base64。以下是一个示例,在其中将一些任意的普通文本以Base64格式存储,并检索以供使用。但是,由于Base64编码可用于二进制数据,因此该示例可以调整为存储图像。

use MIME::Base64;

my $foo = do {
    local $/ = undef;
    decode_base64(<DATA>);
};

print "<<$foo>>\n";

__DATA__
SnVzdCBhbm90aGVyClBlcmwgaGFja2VyLA==

2
非常好的答案(与“不要这样做”之类的无用评论相反)。正是我所寻找的。非常感谢。 - kobame
2
正确的做法是,用户将二进制数据编码为base64格式,然后将该字符串放入__DATA__部分。这很容易解码,且MIME::Base64模块已随Perl一同提供。 - DavidO
1
@SinanÜnür 谢谢您的澄清 :) - DavidO

3

显然,@DavidO的答案是正确的答案。你也可以使用十六进制代替base64。

为此,首先将图像的十六进制转储附加到模块源文件中。例如,您可以使用xxd实现:

$ xxd -ps /path/to/image >> lib/My/Module.pm

假设您的模块文件以__DATA____END__结尾。

然后,您可以将十六进制转储转换回二进制。作为Perl,当然有各种方法来完成这个任务...不是所有的方法都是同样好的,包括以下方法:

sub load_data {
    my $bin;
    while (my $line = <DATA>) {
        $line =~ s/\s+\z//;
        $bin .= pack 'H*', $line;
    }
    $bin;
}

或者,如果您想要使用 slurp:
my $png = pack 'H*',
          map { s{\s+}{}g; $_ }
          do { local $/; scalar <DATA> }
;
binmode STDOUT;
print $png;

当然,如果你的perl版本是5.14或更高,则可以利用s///r

my $png = pack 'H*', map s{\s+}{}gr, do { local $/; scalar <DATA> };

请参阅我的博客文章“在Perl脚本或模块中包含图像数据”以获取更多详细信息。

另请参阅perldoc packperldoc hex


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接