Include image data in your Perl script or module

@kobame asks "What is a recommended method of storing binary data in the __DATA__ section?"

Following that principle, @DavidO posted an answer recommending Base64 encoding the binary data, and using MIME::Base64 to decode it at run time.

That is, of course, a correct way to do this.

But, there is another way using just Perl builtins.

For this example, I am going to use a 249 byte PNG image (QR code for νu42). First, take a hex dump of the image file, and append it to your Perl source file. For this, I used xxd:

C:\...> xxd -ps qrcode.png >>

My Perl module files tend to end with:


'cause, you know, any true value will do and it's cute.

So, the hex dump goes right after the __END__ marker.

You can then decode this hex dump using Perl's pack function:

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

Of course, this being Perl, there is more than one way to do it. You could also use the oft-forgotten hex function:

sub load_data {
    my $hex = do { local $/; <DATA> };
    join '', map chr(hex), $hex =~ /([[:xdigit:]]{2})/g;

This is shorter, cuter, but I am assuming it has a much larger memory footprint. Of course, one could further shorten, or obfuscate this in a variety of ways, but that's not the point of this post.

A much better way to handle any whitespace that might sneak into the script or module file, however, is to just read the data, and then remove all whitespace as it should consist solely of hexadecimal digits:

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

And, of course, if your perl is version 5.14 or later, you can take advantage of the new s///r alternative which gives you a fresh string. That looks more elegant, but creates a copy of the string we just read in:

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

The particular method you choose probably wouldn't matter when you are decoding something less than 4Kb only once in your program, especially compared to loading MIME::Base64 (if your project didn't already need it) but the slurpers ought not to be used with large inputs.

And, for reference here's a script which you can use to save the aformentioned QR code on your computer. I am assuming you are not going tack the hex dump of a full length DVD onto your script, so slurping should be OK.

#!/usr/bin/env perl

use strict;
use warnings;

my $png = load_qr_from_data();
binmode STDOUT;
print $png;

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


PS: No comments for now, but if you wish, you can discuss this post on /r/perl.

PPS: When I was originally writing this post, I was confused, and assumed, without checking, that MIME::Base64 is not a core module. Module::Corelist tells me it's been in the core since 5.007003. Thanks to @ikegami on Stackoverflow for pointing this out.

PPPS: It turns out, I was even more confused than I realized at the time I was writing this. There was a much better way to handle the slurpy case as further discussion on Stackoverflow showed. Updated the post to use that rather than using hex.