Skip to content

Instantly share code, notes, and snippets.

@mattfoster
Created July 7, 2012 20:38
Show Gist options
  • Save mattfoster/3068015 to your computer and use it in GitHub Desktop.
Save mattfoster/3068015 to your computer and use it in GitHub Desktop.
A simple script to convert (16x16) PNGs for display on small LCDs
#! /usr/bin/env perl
# Convert PNG file to hex array, for use in the Adafruit Arduino LCD library
use warnings;
use strict;
use Getopt::Long;
use Imager;
use List::MoreUtils qw(natatime);
use Pod::Usage;
use Readonly;
Readonly my $DEFAULT_THRESHOLD => 10;
my $verbose = 0;
my $threshold = $DEFAULT_THRESHOLD;
# Convert Imager image to binary by thresholding
sub image_to_binary {
my $image = shift;
my $threshold = shift;
my $width = $image->getwidth();
my $height = $image->getheight();
if ($width % 8 != 0 || $height % 8 != 0) {
warn "Image size ($width x $height) is not a multiple of 8. This will cause problems!\n";
}
# Loop over the entire image converting to binary
my @binary;
foreach my $x (0 .. $width-1 ) {
foreach my $y (0 .. $height-1 ) {
my $color = $image->getpixel( x=>$x, y=>$y, type=>'8bit' );
my ( $r, $g, $b, $a ) = $color->rgba();
# g seems like a decent channel to use here
unshift @binary, $g > 10 || 0;
if ($verbose) {
print $g > 10 || 0;
}
}
print "\n" if $verbose;
}
return @binary;
}
# Convert an array of binary strings to hex strings
sub bin_to_hex {
my @binary = @_;
my @hex;
my $it = natatime 8, @binary;
while (my @vals = $it->()) {
my $v = unpack('H2', pack("B8", join('', @vals)));
push @hex, "0x$v";
}
return @hex;
}
# print array elements if the passed coderef returns a true value
sub print_if {
my $cond = pop;
my @hex = @_;
my $i = 0;
foreach my $h (@hex) {
print "$h,", if (&{$cond}($i));
$i++;
}
}
main: {
my $filename;
my ( $help, $man );
GetOptions(
'filename=s' => \$filename,
'threshold=i' => \$threshold,
'verbose!' => \$verbose,
'help|?' => \$help,
'man' => \$man
) or pod2usage(2);
pod2usage(1) if ! $filename;
pod2usage(1) if $help;
pod2usage(-exitstatus => 0, -verbose => 2) if $man;
my $image = Imager->new;
$image->read(file=>$filename, type=>'png') or die "Problem loading image";
my @binary = image_to_binary($image, $threshold);
my @hex = bin_to_hex(@binary);
# We seem to need to split the image into two:
# TODO: what about images with weird sizes?
# Print odd elements:
print_if( @hex, sub { $_[0] % 2 != 0 });
print "\n";
# Print even elements:
print_if( @hex, sub { $_[0] % 2 == 0 });
print "\n";
}
__END__
=head1 NAME
lcd_icon - convert PNGs to hexadecimal bitmaps for display on single colour LCDs
=head1 SYNOPSIS
lcd_icon --filename <file.png>
Options:
--filename the PNG image to convert
--thresold threshold to use when converting to binary (default: 10)
--verbose print binary image
--help brief help message
--man full documentation
=head1 OPTIONS
=over 8
=item B<--filename>
Specify the filename of a PNG image to process.
=item B<--help>
Prints a brief help message and exits.
=item B<---man>
Prints the manual page and exits.
=back
=head1 DESCRIPTION
B<lcd_image> converts small PNG images into hex arrays for use within Arduio
sketches (etc.) making use of Adafruits OLED display libraries.
If you've seen the OLED library's demo code, you may have noticed the Adafruit
logo, which looks like this:
const unsigned char __attribute__ ((progmem)) logo16_glcd_bmp[]={
0x30, 0xf0, 0xf0, 0xf0, 0xf0, 0x30, 0xf8, 0xbe, 0x9f, 0xff, 0xf8, 0xc0, 0xc0, 0xc0, 0x80, 0x00,
0x20, 0x3c, 0x3f, 0x3f, 0x1f, 0x19, 0x1f, 0x7b, 0xfb, 0xfe, 0xfe, 0x07, 0x07, 0x07, 0x03, 0x00, };
These two rows correspond to the right and left halves of the logo. The first
row looks like this:
00110000
11110000
11110000
11110000
11110000
00110000
11111000
10111110
10011111
11111111
11111000
11000000
11000000
11000000
10000000
00000000
And the second like this:
00100000
00111100
00111111
00111111
00011111
00011001
00011111
01111011
11111011
11111110
11111110
00000111
00000111
00000111
00000011
00000000
This script emulates this and converts PNG images to this type of array. It has
not been tested with images larger than 16x16.
=head1 AUTHOR
Matt Foster <[email protected]>
=cut
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment