Created
July 7, 2012 20:38
-
-
Save mattfoster/3068015 to your computer and use it in GitHub Desktop.
A simple script to convert (16x16) PNGs for display on small LCDs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #! /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