Skip to content

Instantly share code, notes, and snippets.

@jaggzh
Created January 14, 2024 14:03
Show Gist options
  • Select an option

  • Save jaggzh/70c77cf1959c2cc41f2eeee2c7e0541f to your computer and use it in GitHub Desktop.

Select an option

Save jaggzh/70c77cf1959c2cc41f2eeee2c7e0541f to your computer and use it in GitHub Desktop.
#!/usr/bin/perl
# Copyright (C) 2016, jaggz.h {who is at} gmail.com
# If you look or use this code, any further than this and the following line,
# you agree to all the terms and conditions outlined below in code.
# Otherwise, it's free to use, but if you make money off it, you must submit
# to me your first-born child.. nevermind. I don't want it. Go ahead
# and use it (the code) however you wish; I wish you well in life.
# gist-paste -u https://gist.github.com/jaggzh/70c77cf1959c2cc41f2eeee2c7e0541f
use strict;
use warnings;
my $fn;
my $f;
my ($r, $b, $g);
my $str;
my ($w,$h);
my $depth;
my @pixels;
use Getopt::Long;
my $opt_varname="img";
my $opt_help;
my $verbose=0;
GetOptions(
"v|verbose+" => \$verbose,
"n|var=s" => \$opt_varname,
"h|help" => \$opt_help,
) or die("Error in command line arguments\n");
if ($opt_help) {
print <<EOT;
Usage: ppmto565 [options] [input]
Generates a .C source file of RGB 16-bit data, suitable for use with many LCD
displays. Modification might be necessary if your MCU or API/libraries can't
make use of the unsigned int[] output. It also is customized for my ESP8266
use, with the Arduino IDE, where the INFLASH define, which you'll see in its
output, places the image data in flash memory so as not to consume program
space. Improvements are welcome <jaggz.h\@gmail.com>
As its name states, it requires PPM input (magic P6 in the file); this means,
if you're converting a greyscale or bw image with, say, pngtopnm, the output
will likely be rejected by this program (because it'll probably be in pbm
or pgm format). See the 'netpbm' package of utilities.
Options:
-n name, --var=name Output variable name for image data
Also defines name_w and name_h for width/height
Default: img
Results in an array img[] and img_w img_h defined
(They are not capitalized, but they are #defines)
-f, --useflash Export defines and variable for alignment and use
in PROGMEM (Arduino/ESP8266 use).
-h, --help This help
Examples:
ppmto565 -n myimg someimage.ppm > someimage.cpp
Outputs unsigned int myimg[] data, as well as defines
myimg_w and myimg_h
pngtopnm file.png | ppmto565 -f -n myimg someimage.ppm > someimage.cpp
Same as above, but includes #defines, and modifies the declaration,
for storage in the flash memory of the ESP8266.
Example steps:
1. Run: ppmto565 -n myimg someimage.ppm > someimage.cpp
2. Copy the top lines, from the #include to the //extern variable
declaration for myimg[], into your project's .c/.cpp file.
3. Remove // from the extern line (within your .c/.cpp file)
EOT
exit;
}
if ($#ARGV > -1) {
my $fn = shift @ARGV;
print STDERR "Using $fn\n";
open($f, "<", "$fn") || die "Can't open $fn: $!";
} else {
$f = *STDIN;
}
$str = <$f>;
die "Not ppm format" if $str !~ /^P6\s*$/;
$str = <$f>;
($w,$h) = ($str =~ /^(\d+)\s+(\d+)\s*$/);
die "Not ppm format (line 2)" if !defined $h;
$str = <$f>;
($depth) = ($str =~ /^(\d+)\s*$/);
die "Not ppm format (line 3)" if !defined $depth;
#die "Color depth too deep for current board (depth = ($depth) is > 15)"
# if $depth > 15;
while (read($f, $r, 1) && read($f, $g, 1) && read($f, $b, 1)) {
printf STDERR ("%d-%d-%d\n", ord $r, ord $g, ord $b) if $verbose>0;
push(@pixels, [ord $r,ord $g,ord $b]);
}
die "Invalid pixel count. Num pixels (".scalar(@pixels).") != ${w}x{$h} (" . $w*$h . ")"
if @pixels != $w*$h;
print <<EOT;
#include <pgmspace.h>
//#define ALIGN __attribute__ (( aligned (__BIGGEST_ALIGNMENT__) ))
#define ALIGN __attribute__ (( aligned ( sizeof(char*) ) ))
#define INFLASH PROGMEM ALIGN
EOT
print "#define ${opt_varname}_w $w\n";
print "#define ${opt_varname}_h $h\n";
printf("//extern unsigned int ${opt_varname}[%d] INFLASH;\n", $w*$h);
printf("unsigned int ${opt_varname}[%d] INFLASH = {\n", $w*$h);
for my $y (0 .. $h-1) {
print " ";
for my $x (0 .. $w-1) {
my $p = $pixels[$y*$w + $x];
$r = $p->[0];
$g = $p->[1];
$b = $p->[2];
#$r = 0;
#$g = 0;
#$b = 0;
printf STDERR ("Converting %d %d %d at depth $depth ==> ", $r, $g, $b)
if $verbose>0;
my $int = int(($r/$depth)*31)<<11 | int(($g/$depth)*63)<<5 | int(($b/$depth)*31)<<0;
printf STDERR ("$int -> 0x%x\n", $int) if $verbose>0;
printf("0x%x", $int);
#printf("0x%x%x%xF", ord($p->[0]), ord($p->[1]), ord($p->[2]));
#printf("0x%x%x%x%x", 0, 0xF, 0, 0);
if ($x != $w-1 || $y<$h-1) { print ", "; }
}
print "\n";
}
print "};";
close $f;
#!/usr/bin/perl
# Copyright (C) 2016, jaggz.h {who is at} gmail.com
# If you look or use this code, any further than this and the following line,
# you agree to all the terms and conditions outlined below in code.
# Otherwise, it's free to use, but if you make money off it, you must submit
# to me your first-born child.. nevermind. I don't want it. Go ahead
# and use it (the code) however you wish; I wish you well in life.
use strict;
use warnings;
my $fn;
my $f;
my ($r, $b, $g);
my $str;
my ($w,$h);
my $depth;
my @pixels;
use Getopt::Long;
my $opt_varname="img";
my $opt_help;
my $verbose=0;
GetOptions(
"v|verbose+" => \$verbose,
"n|var=s" => \$opt_varname,
"h|help" => \$opt_help,
) or die("Error in command line arguments\n");
if ($opt_help) {
print <<EOT;
Usage: ppmto565 [options] [input]
Generates a .C source file of RGB 16-bit data, suitable for use with many LCD
displays. Modification might be necessary if your MCU or API/libraries can't
make use of the unsigned int[] output. It also is customized for my ESP8266
use, with the Arduino IDE, where the INFLASH define, which you'll see in its
output, places the image data in flash memory so as not to consume program
space. Improvements are welcome <jaggz.h\@gmail.com>
As its name states, it requires PPM input (magic P6 in the file); this means,
if you're converting a greyscale or bw image with, say, pngtopnm, the output
will likely be rejected by this program (because it'll probably be in pbm
or pgm format). See the 'netpbm' package of utilities.
Options:
-n name, --var=name Output variable name for image data
Also defines name_w and name_h for width/height
Default: img
Results in an array img[] and img_w img_h defined
(They are not capitalized, but they are #defines)
-f, --useflash Export defines and variable for alignment and use
in PROGMEM (Arduino/ESP8266 use).
-h, --help This help
Examples:
ppmto565 -n myimg someimage.ppm > someimage.cpp
Outputs unsigned int myimg[] data, as well as defines
myimg_w and myimg_h
pngtopnm file.png | ppmto565 -f -n myimg someimage.ppm > someimage.cpp
Same as above, but includes #defines, and modifies the declaration,
for storage in the flash memory of the ESP8266.
Example steps:
1. Run: ppmto565 -n myimg someimage.ppm > someimage.cpp
2. Copy the top lines, from the #include to the //extern variable
declaration for myimg[], into your project's .c/.cpp file.
3. Remove // from the extern line (within your .c/.cpp file)
EOT
exit;
}
if ($#ARGV > -1) {
my $fn = shift @ARGV;
print STDERR "Using $fn\n";
open($f, "<", "$fn") || die "Can't open $fn: $!";
} else {
$f = *STDIN;
}
$str = <$f>;
die "Not ppm format" if $str !~ /^P6\s*$/;
$str = <$f>;
($w,$h) = ($str =~ /^(\d+)\s+(\d+)\s*$/);
die "Not ppm format (line 2)" if !defined $h;
$str = <$f>;
($depth) = ($str =~ /^(\d+)\s*$/);
die "Not ppm format (line 3)" if !defined $depth;
#die "Color depth too deep for current board (depth = ($depth) is > 15)"
# if $depth > 15;
while (read($f, $r, 1) && read($f, $g, 1) && read($f, $b, 1)) {
printf STDERR ("%d-%d-%d\n", ord $r, ord $g, ord $b) if $verbose>0;
push(@pixels, [ord $r,ord $g,ord $b]);
}
die "Invalid pixel count. Num pixels (".scalar(@pixels).") != ${w}x{$h} (" . $w*$h . ")"
if @pixels != $w*$h;
print <<EOT;
#include <pgmspace.h>
//#define ALIGN __attribute__ (( aligned (__BIGGEST_ALIGNMENT__) ))
#define ALIGN __attribute__ (( aligned ( sizeof(char*) ) ))
#define INFLASH PROGMEM ALIGN
EOT
print "#define ${opt_varname}_w $w\n";
print "#define ${opt_varname}_h $h\n";
printf("//extern unsigned int ${opt_varname}[%d] INFLASH;\n", $w*$h);
printf("unsigned int ${opt_varname}[%d] INFLASH = {\n", $w*$h);
for my $y (0 .. $h-1) {
print " ";
for my $x (0 .. $w-1) {
my $p = $pixels[$y*$w + $x];
$r = $p->[0];
$g = $p->[1];
$b = $p->[2];
#$r = 0;
#$g = 0;
#$b = 0;
printf STDERR ("Converting %d %d %d at depth $depth ==> ", $r, $g, $b)
if $verbose>0;
my $int = int(($r/$depth)*31)<<11 | int(($g/$depth)*63)<<5 | int(($b/$depth)*31)<<0;
printf STDERR ("$int -> 0x%x\n", $int) if $verbose>0;
printf("0x%x", $int);
#printf("0x%x%x%xF", ord($p->[0]), ord($p->[1]), ord($p->[2]));
#printf("0x%x%x%x%x", 0, 0xF, 0, 0);
if ($x != $w-1 || $y<$h-1) { print ", "; }
}
print "\n";
}
print "};";
close $f;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment