-
-
Notifications
You must be signed in to change notification settings - Fork 627
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add generator and parser for bitmap.hpp (#2313)
* Combined the converter from <ico>.png to bitmap.hpp and reverse in one script: pp_png2hpp.py * Minor change ficed variables from testing. * Cleanup output for parser. Add description to readme.md * Update pp_png2hpp.py Added the suggested and much cleaner argparse code from zxkmm. Added a icon-name handling, to convert one or a comma seperated subset of icons by name. * Update pp_bitmap_parser.py Updated the handler with dynamic in/outputs, in parallel to the pp_png2hpp.py script ... But I think I'll delete this one, after I decide how to handle the alpha (transparent) code.
- Loading branch information
Showing
3 changed files
with
339 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,25 @@ | ||
bitmap is for icons, it's colorless and headless; splash and modal isn't using bitmap | ||
bitmap is for icons, it's colorless and headless; splash and modal isn't | ||
using bitmap | ||
|
||
## Bitmap helper folder | ||
The folder `bitmap_tools` contains scripts to convert icons in png format to | ||
the PortaPack readable format in `bitmap.hpp`. | ||
|
||
### Convert a folder contains one or more icon.png to one bitmap.hpp | ||
The `make_bitmap.py` is the traditional helper, well tested. The folder with | ||
the icons is given as argument and generates the `./bitmap.hpp`. This file | ||
needs to be copied to `mayhem-firmware/firmware/application/`. | ||
The icon size needs to be a multiple of 8. The generated icon is black/white. | ||
|
||
### Convert bitmap array to icon.png | ||
The `bitmap_arr_reverse_decode.py` takes an array from the bitmap.hpp and | ||
convert it back to a png. | ||
|
||
### Convert both ways | ||
The `pp_png2hpp.py` is based on the privious scripts, as all in one solution. | ||
With the `--hpp bitmap.hpp` file and the `--graphics /folder_to/png_icons/` | ||
arguments, theis script will generate a `bitmap.hpp`. | ||
Add the `--reverse` argument to generate png icons from the given `bitmap.hpp`. | ||
|
||
Especially the reverse function got a parser, to automatic get the filename | ||
and size of the image. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#!/usr/bin/env python3 | ||
|
||
## Note: This helper was just a POC for pp_png3hpp.py to test the regex. | ||
|
||
import argparse | ||
import numpy as np | ||
import re | ||
from PIL import Image | ||
|
||
|
||
def parse_bitmaphpp(bitmaphpp_file, icon_name): | ||
ico_pattern = re.compile(r"static constexpr uint8_t bitmap_(.*)_data\[\] = {\n((?:\s+(?:.*)\n)+)};\nstatic constexpr Bitmap bitmap_.*\{\n\s+\{(.*)\},", re.MULTILINE) | ||
ico_data = [] | ||
|
||
# read file to buffer, to find multiline regex | ||
readfile = open(bitmaphpp_file,'r') | ||
buff = readfile.read() | ||
readfile.close() | ||
|
||
if icon_name == 'all': | ||
for match in ico_pattern.finditer(buff): | ||
ico_data.append([match.group(1), match.group(2), match.group(3)]) | ||
else: | ||
for match in ico_pattern.finditer(buff): | ||
if match.group(1) in icon_name: | ||
ico_data.append([match.group(1), match.group(2), match.group(3)]) | ||
|
||
return (ico_data) | ||
|
||
def convert_hpp(icon_name,bitmap_array,iconsize_str): | ||
iconsize = iconsize_str.split(", ") | ||
bitmap_size = (int(iconsize[0]),int(iconsize[1])) | ||
bitmap_data=[] | ||
|
||
image_data = np.zeros((bitmap_size[1], bitmap_size[0]), dtype=np.uint8) | ||
|
||
#print(bitmap_array) | ||
for value in bitmap_array.split(",\n"): | ||
if (value): | ||
#print(int(value, 0)) | ||
bitmap_data.append(int(value, 0)) | ||
|
||
print(f"Count {len(bitmap_data)} Size: {bitmap_size[0]}x{bitmap_size[1]} ({bitmap_size[0]*bitmap_size[1]})") | ||
|
||
for y in range(bitmap_size[1]): | ||
for x in range(bitmap_size[0]): | ||
byte_index = (y * bitmap_size[0] + x) // 8 | ||
bit_index = x % 8 | ||
# bit_index = 7 - (x % 8) | ||
pixel_value = (bitmap_data[byte_index] >> bit_index) & 1 | ||
image_data[y, x] = pixel_value * 255 | ||
|
||
image = Image.fromarray(image_data, 'L') | ||
imagea = image.copy() | ||
imagea.putalpha(image) | ||
imagea.save(icon_name+".png") | ||
|
||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("hpp", help="Path for bitmap.hpp") | ||
parser.add_argument("--icon", help="Name of the icon from bitmap.hpp, Use 'All' for all icons in file", default = 'titlebar_image') | ||
|
||
args = parser.parse_args() | ||
|
||
if args.icon: | ||
icon_name = args.icon | ||
else: | ||
icon_name = 'titlebar_image' | ||
|
||
print("parse", icon_name) | ||
icons = parse_bitmaphpp(args.hpp, icon_name) | ||
|
||
for icon in icons: | ||
convert_hpp(icon[0],icon[1],icon[2]) | ||
|
||
|
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Convert png icons to bitmap.hpp inspired by | ||
# make_bitmap.py - Copyright (C) 2016 Furrtek | ||
# Convert bitmap.hpp to icons inspyred by | ||
# bitmap_arr_reverse_decode.py - Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. | ||
# bitmap_arr_reverse_decode.py - Copyleft (ɔ) 2024 zxkmm with the GPL license | ||
# Copysomething (c) 2024 LupusE with the license, needed by the PortaPack project | ||
# | ||
# This program is free software; you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation; either version 2, or (at your option) | ||
# any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program; see the file COPYING. If not, write to | ||
# the Free Software Foundation, Inc., 51 Franklin Street, | ||
# Boston, MA 02110-1301, USA. | ||
# | ||
|
||
import argparse | ||
import numpy as np | ||
import re | ||
import sys | ||
import os | ||
from PIL import Image | ||
|
||
### Convert a directory of icons in png format to one bitmap.hpp file. | ||
###################################################################### | ||
|
||
def pp_bitmaphpp_header(): | ||
return ("""/* | ||
* Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. | ||
* Copyright (C) 2016 Furrtek | ||
* | ||
* This file is part of PortaPack. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2, or (at your option) | ||
* any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program; see the file COPYING. If not, write to | ||
* the Free Software Foundation, Inc., 51 Franklin Street, | ||
* Boston, MA 02110-1301, USA. | ||
*/ | ||
// This file was generated by make_bitmap.py | ||
#ifndef __BITMAP_HPP__ | ||
#define __BITMAP_HPP__ | ||
#include \"ui.hpp\" | ||
namespace ui { | ||
""") | ||
|
||
|
||
def convert_png(file): | ||
bmp_data = [] | ||
data = 0 | ||
|
||
rgb_im = Image.open(file).convert('RGBA') | ||
|
||
if rgb_im.size[0] % 8 or rgb_im.size[1] % 8: | ||
print((file + ": Size is not a multiple of 8. Image is not included in bitmap.hpp.")) | ||
sys.exit(-1) | ||
|
||
name = os.path.basename(file).split(".")[0].lower() | ||
|
||
bmp_data.append(f"\nstatic constexpr uint8_t bitmap_{name}_data[] = {{\n") | ||
|
||
for i in range(rgb_im.size[1]): | ||
for j in range(rgb_im.size[0]): | ||
r, g, b, a = rgb_im.getpixel((j, i)) | ||
|
||
data >>= 1 | ||
|
||
if r > 127 and g > 127 and b > 127 and a > 127: | ||
data += 128 | ||
|
||
if j % 8 == 7: | ||
bmp_data.append(" 0x%0.2X,\n" % data) | ||
data = 0 | ||
|
||
bmp_data.append(f"""}}; | ||
static constexpr Bitmap bitmap_{name}{{ | ||
{{{str(rgb_im.size[0])}, {str(rgb_im.size[1])}}}, | ||
bitmap_{name}_data}}; | ||
""") | ||
|
||
out_bmpdata = ''.join(map(str, bmp_data)) | ||
|
||
return (out_bmpdata) | ||
|
||
def pp_bitmaphpp_data(pngicons_path): | ||
count = 0 | ||
bitmaphpp_data = [] | ||
for file in os.listdir(pngicons_path): | ||
if os.path.isfile(pngicons_path + file) and file.endswith(".png"): | ||
bitmaphpp_data.append(convert_png(pngicons_path + file)) | ||
count += 1 | ||
|
||
return bitmaphpp_data | ||
|
||
|
||
def pp_bitmaphpp_footer(): | ||
return(""" | ||
} /* namespace ui */ | ||
#endif /*__BITMAP_HPP__*/ | ||
""") | ||
|
||
|
||
def pp_write_bitmaphpp(pngicons_path, hpp_outpath): | ||
bitmaphpp_file = [] | ||
|
||
bitmaphpp_file.append(pp_bitmaphpp_header()) | ||
bitmaphpp_file.append("".join(str(x) for x in pp_bitmaphpp_data(pngicons_path))) | ||
bitmaphpp_file.append(pp_bitmaphpp_footer()) | ||
|
||
out_file = "".join(str(x) for x in bitmaphpp_file) | ||
|
||
with open(hpp_outpath, "w", encoding="utf-8") as fd: | ||
fd.writelines(out_file) | ||
|
||
print("Find your bitmap.hpp at", out_file) | ||
|
||
|
||
### Convert from a bitmap.hpp file one or all icons in png. | ||
########################################################### | ||
|
||
def parse_bitmaphpp(bitmaphpp_file,icon_name): | ||
ico_pattern = re.compile(r"static constexpr uint8_t bitmap_(.*)_data\[\] = {\n((?:\s+(?:.*)\n)+)};\nstatic constexpr Bitmap bitmap_.*\{\n\s+\{(.*)\},", re.MULTILINE) | ||
ico_data = [] | ||
|
||
# read file to buffer, to find multiline regex | ||
readfile = open(bitmaphpp_file,'r') | ||
buff = readfile.read() | ||
readfile.close() | ||
|
||
if icon_name == 'all': | ||
for match in ico_pattern.finditer(buff): | ||
ico_data.append([match.group(1), match.group(2), match.group(3)]) | ||
else: | ||
for match in ico_pattern.finditer(buff): | ||
if match.group(1) in icon_name: | ||
ico_data.append([match.group(1), match.group(2), match.group(3)]) | ||
|
||
return (ico_data) | ||
|
||
|
||
def convert_hpp(icon_name,bitmap_array,iconsize_str,png_outdir): | ||
iconsize = iconsize_str.split(", ") | ||
bitmap_size = (int(iconsize[0]),int(iconsize[1])) | ||
bitmap_data=[] | ||
|
||
image_data = np.zeros((bitmap_size[1], bitmap_size[0]), dtype=np.uint8) | ||
|
||
for value in bitmap_array.split(",\n"): | ||
if (value): | ||
bitmap_data.append(int(value, 0)) | ||
|
||
for y in range(bitmap_size[1]): | ||
for x in range(bitmap_size[0]): | ||
byte_index = (y * bitmap_size[0] + x) // 8 | ||
bit_index = x % 8 | ||
# bit_index = 7 - (x % 8) | ||
pixel_value = (bitmap_data[byte_index] >> bit_index) & 1 | ||
image_data[y, x] = pixel_value * 255 | ||
|
||
image = Image.fromarray(image_data, 'L') | ||
icon_out = os.path.join(png_outdir,icon_name+".png") | ||
image.save(icon_out) | ||
|
||
|
||
### Processing | ||
############## | ||
|
||
if __name__ == '__main__': | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("hpp", help="Path of the bitmap.hpp") | ||
parser.add_argument("graphics", help="Path of <icon>.png files to convert", default=os.path.join(os.getcwd(),"graphics")) | ||
parser.add_argument("--icon","-i", help="Name of the icon to convert in reverse. Use 'all' to convert all. More names can be comma seperated.") | ||
parser.add_argument("--reverse","-r", help="Convert icon from bitmap.hpp to <name>.png", action="store_true") | ||
|
||
args = parser.parse_args() | ||
|
||
if args.reverse: | ||
print("Reverse: Converting from hpp to png") | ||
|
||
# filter hpp arg is a file | ||
hpp_file_path = args.hpp | ||
if not os.path.isfile(hpp_file_path): | ||
print(f"Error: {hpp_file_path} is not a valid file.") | ||
sys.exit(1) | ||
|
||
# filter graph arg is a path | ||
if args.graphics: | ||
graphics_path = os.path.join(args.graphics, '') | ||
else: | ||
graphics_path = os.path.join(os.getcwd(),"graphics", '') | ||
if not os.path.exists(graphics_path): | ||
os.makedirs(graphics_path) # create if not exist | ||
|
||
# define icons to convert | ||
if args.icon: | ||
icon_name = args.icon | ||
else: | ||
icon_name = 'titlebar_image' | ||
|
||
icons = parse_bitmaphpp(hpp_file_path, icon_name) | ||
|
||
for icon in icons: | ||
print("Converting icon", icon[0]) | ||
convert_hpp(icon[0], icon[1], icon[2], graphics_path) | ||
sys.exit() | ||
else: | ||
print("Converting from png to hpp") | ||
if args.graphics: | ||
graphics_path = os.path.join(args.graphics, '') | ||
else: | ||
graphics_path = os.path.join(os.getcwd(),"graphics", '') | ||
print("Path", graphics_path, "hpp", args.hpp) | ||
pp_write_bitmaphpp(graphics_path, args.hpp) | ||
sys.exit() |