#!/usr/bin/env python3 # Convert png icons to bitmap.hpp inspired by # make_bitmap.py - Copyright (C) 2016 Furrtek # Convert bitmap.hpp to icons inspired 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", hpp_outpath) ### 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 .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 .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("From path", graphics_path, "to file", args.hpp) pp_write_bitmaphpp(graphics_path, args.hpp) sys.exit()