| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | # ##### BEGIN GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #  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 | 
					
						
							|  |  |  | #  of the License, 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; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  | #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # ##### END GPL LICENSE BLOCK ##### | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # <pep8 compliant> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | This script dices up PNG into small files to store in version control. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Example: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ./blender.bin \ | 
					
						
							|  |  |  |     --background -noaudio \ | 
					
						
							|  |  |  |     --python ./release/datafiles/icon_dice.py -- \ | 
					
						
							|  |  |  |     --image=./release/datafiles/blender_icons16.png \ | 
					
						
							|  |  |  |     --output=./release/datafiles/blender_icons16 | 
					
						
							|  |  |  |     --output_prefix=icon16_ | 
					
						
							|  |  |  |     --name_style=UI_ICONS | 
					
						
							|  |  |  |     --parts_x 26 --parts_y 32 \ | 
					
						
							|  |  |  |     --minx=10 --maxx 10 --miny 10 --maxy 10 | 
					
						
							|  |  |  |     --minx_icon 2 --maxx_icon 2 --miny_icon 2 --maxy_icon 2 \ | 
					
						
							|  |  |  |     --spacex_icon 1 --spacey_icon 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SOURCE_DIR = os.path.normpath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) | 
					
						
							|  |  |  | VERBOSE = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def image_from_file__bpy(filepath): | 
					
						
							|  |  |  |     import bpy | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     image = bpy.data.images.load(filepath) | 
					
						
							|  |  |  |     image.reload() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pixel_w, pixel_h = image.size | 
					
						
							|  |  |  |     pixels = image.pixels[:] | 
					
						
							|  |  |  |     return pixels, pixel_w, pixel_h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def image_from_file(filepath): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Return pixels, w, h from an image. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     note: bpy import is ONLY used here. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import bpy | 
					
						
							| 
									
										
										
										
											2015-01-29 15:35:06 +11:00
										 |  |  |     except ImportError: | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |         bpy = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if bpy is not None: | 
					
						
							|  |  |  |         pixels, pixel_w, pixel_h = image_from_file__bpy(filepath) | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     # else: | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |     #    pixels, pixel_w, pixel_h = image_from_file__py(filepath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return pixels, pixel_w, pixel_h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def write_subimage(sub_x, sub_y, sub_w, sub_h, | 
					
						
							|  |  |  |                    filepath, | 
					
						
							|  |  |  |                    pixels, pixel_w, pixel_h): | 
					
						
							|  |  |  |     import struct | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # first check if the icon is worth writing | 
					
						
							|  |  |  |     is_fill = False | 
					
						
							|  |  |  |     for y in range(sub_h): | 
					
						
							|  |  |  |         for x in range(sub_w): | 
					
						
							|  |  |  |             i = (sub_x + x) + ((sub_y + y) * pixel_w) | 
					
						
							|  |  |  |             a = pixels[(i * 4) + 3] | 
					
						
							|  |  |  |             if a != 0.0: | 
					
						
							|  |  |  |                 is_fill = True | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not is_fill: | 
					
						
							|  |  |  |         # print("skipping:", filepath) | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with open(filepath, 'wb') as f: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |         f.write( | 
					
						
							|  |  |  |             struct.pack( | 
					
						
							|  |  |  |                 '<6I', | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |                 sub_w, sub_h, | 
					
						
							|  |  |  |                 sub_x, sub_y, | 
					
						
							|  |  |  |                 # redundant but including to maintain consistency | 
					
						
							| 
									
										
										
										
											2018-07-07 08:48:35 +02:00
										 |  |  |                 pixel_w, pixel_h, | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |             )) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for y in range(sub_h): | 
					
						
							|  |  |  |             for x in range(sub_w): | 
					
						
							|  |  |  |                 i = (sub_x + x) + ((sub_y + y) * pixel_w) | 
					
						
							|  |  |  |                 rgba = pixels[(i * 4):(i * 4) + 4] | 
					
						
							|  |  |  |                 c = sum((int(p * 255) << (8 * i)) for i, p in enumerate(rgba)) | 
					
						
							|  |  |  |                 f.write(struct.pack("<I", c)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _dice_icon_name_cache = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  | def dice_icon_name( | 
					
						
							|  |  |  |         x, y, parts_x, parts_y, | 
					
						
							|  |  |  |         name_style=None, prefix=""): | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     How to name icons, this is mainly for what name we get in git, | 
					
						
							|  |  |  |     the actual names don't really matter, its just nice to have the | 
					
						
							|  |  |  |     name match up with something recognizable for commits. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if name_style == 'UI_ICONS': | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Init on demand | 
					
						
							|  |  |  |         if not _dice_icon_name_cache: | 
					
						
							|  |  |  |             import re | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |             count = 0 | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Search for eg: DEF_ICON(BRUSH_NUDGE) --> BRUSH_NUDGE | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |             re_icon = re.compile(r'^\s*DEF_ICON.*\(\s*([A-Za-z0-9_]+)\s*\).*$') | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |             ui_icons_h = os.path.join(SOURCE_DIR, "source", "blender", "editors", "include", "UI_icons.h") | 
					
						
							|  |  |  |             with open(ui_icons_h, 'r', encoding="utf-8") as f: | 
					
						
							|  |  |  |                 for l in f: | 
					
						
							|  |  |  |                     match = re_icon.search(l) | 
					
						
							|  |  |  |                     if match: | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |                         if l.find('DEF_ICON_BLANK') == -1: | 
					
						
							|  |  |  |                             icon_name = match.group(1).lower() | 
					
						
							| 
									
										
										
										
											2018-10-01 10:45:50 +02:00
										 |  |  |                             print(icon_name) | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |                             _dice_icon_name_cache[count] = icon_name | 
					
						
							|  |  |  |                         count += 1 | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |         # ---- Done with icon cache | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         index = (y * parts_x) + x | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |         if index not in _dice_icon_name_cache: | 
					
						
							|  |  |  |             return None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |         icon_name = _dice_icon_name_cache[index] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # for debugging its handy to sort by number | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |         # ~ id_str = "%03d_%s%s.dat" % (index, prefix, icon_name) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |         id_str = "%s%s.dat" % (prefix, icon_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     elif name_style == "": | 
					
						
							|  |  |  |         # flip so icons are numbered from top-left | 
					
						
							|  |  |  |         # because new icons will be added at the bottom | 
					
						
							|  |  |  |         y_flip = parts_y - (y + 1) | 
					
						
							|  |  |  |         id_str = "%s%02xx%02x.dat" % (prefix, x, y_flip) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         raise Exception("Invalid '--name_style' arg") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return id_str | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  | def dice( | 
					
						
							|  |  |  |         filepath, output, output_prefix, name_style, | 
					
						
							|  |  |  |         parts_x, parts_y, | 
					
						
							|  |  |  |         minx, miny, maxx, maxy, | 
					
						
							|  |  |  |         minx_icon, miny_icon, maxx_icon, maxy_icon, | 
					
						
							|  |  |  |         spacex_icon, spacey_icon, | 
					
						
							|  |  |  | ): | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     is_simple = (max( | 
					
						
							|  |  |  |         minx, miny, maxx, maxy, | 
					
						
							|  |  |  |         minx_icon, miny_icon, maxx_icon, maxy_icon, | 
					
						
							|  |  |  |         spacex_icon, spacey_icon) == 0) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     pixels, pixel_w, pixel_h = image_from_file(filepath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not (pixel_w and pixel_h): | 
					
						
							|  |  |  |         print("Image not found %r!" % filepath) | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.exists(output): | 
					
						
							|  |  |  |         os.mkdir(output) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if is_simple: | 
					
						
							|  |  |  |         pixels_w_clip = pixel_w | 
					
						
							|  |  |  |         pixels_h_clip = pixel_h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         icon_w = pixels_w_clip // parts_x | 
					
						
							|  |  |  |         icon_h = pixels_h_clip // parts_y | 
					
						
							|  |  |  |         icon_w_clip = icon_w | 
					
						
							|  |  |  |         icon_h_clip = icon_h | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         pixels_w_clip = pixel_w - (minx + maxx) | 
					
						
							|  |  |  |         pixels_h_clip = pixel_h - (miny + maxy) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         icon_w = (pixels_w_clip - ((parts_x - 1) * spacex_icon)) // parts_x | 
					
						
							|  |  |  |         icon_h = (pixels_h_clip - ((parts_y - 1) * spacey_icon)) // parts_y | 
					
						
							|  |  |  |         icon_w_clip = icon_w - (minx_icon + maxx_icon) | 
					
						
							|  |  |  |         icon_h_clip = icon_h - (miny_icon + maxy_icon) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print(pixel_w, pixel_h, icon_w, icon_h) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for x in range(parts_x): | 
					
						
							|  |  |  |         for y in range(parts_y): | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |             id_str = dice_icon_name( | 
					
						
							|  |  |  |                 x, y, | 
					
						
							|  |  |  |                 parts_x, parts_y, | 
					
						
							|  |  |  |                 name_style=name_style, prefix=output_prefix | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2018-09-27 18:38:36 +02:00
										 |  |  |             if not id_str: | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |             filepath = os.path.join(output, id_str) | 
					
						
							|  |  |  |             if VERBOSE: | 
					
						
							|  |  |  |                 print("  writing:", filepath) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # simple, no margins | 
					
						
							|  |  |  |             if is_simple: | 
					
						
							| 
									
										
										
										
											2014-04-25 05:31:20 +10:00
										 |  |  |                 sub_x = x * icon_w | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  |                 sub_y = y * icon_h | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 sub_x = minx + ((x * (icon_w + spacex_icon)) + minx_icon) | 
					
						
							|  |  |  |                 sub_y = miny + ((y * (icon_h + spacey_icon)) + miny_icon) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             write_subimage(sub_x, sub_y, icon_w_clip, icon_h_clip, | 
					
						
							|  |  |  |                            filepath, | 
					
						
							|  |  |  |                            pixels, pixel_w, pixel_h) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     import sys | 
					
						
							|  |  |  |     import argparse | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     epilog = "Run this after updating the SVG file" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     argv = sys.argv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if "--" not in argv: | 
					
						
							|  |  |  |         argv = [] | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         argv = argv[argv.index("--") + 1:] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser = argparse.ArgumentParser(description=__doc__, epilog=epilog) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # File path options | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--image", dest="image", metavar='FILE', | 
					
						
							|  |  |  |         help="Image file", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--output", dest="output", metavar='DIR', | 
					
						
							|  |  |  |         help="Output directory", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--output_prefix", dest="output_prefix", metavar='STRING', | 
					
						
							|  |  |  |         help="Output prefix", | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Icon naming option | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--name_style", dest="name_style", metavar='ENUM', type=str, | 
					
						
							|  |  |  |         choices=('', 'UI_ICONS'), | 
					
						
							| 
									
										
										
										
											2019-07-31 14:25:09 +02:00
										 |  |  |         help="The method used for naming output data", | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     ) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Options for dicing up the image | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--parts_x", dest="parts_x", metavar='INT', type=int, | 
					
						
							|  |  |  |         help="Grid X parts", | 
					
						
							|  |  |  |     ) | 
					
						
							|  |  |  |     parser.add_argument( | 
					
						
							|  |  |  |         "--parts_y", dest="parts_y", metavar='INT', type=int, | 
					
						
							|  |  |  |         help="Grid Y parts", | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |     _help = "Inset from the outer edge (in pixels)" | 
					
						
							|  |  |  |     parser.add_argument("--minx", dest="minx", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--miny", dest="miny", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--maxx", dest="maxx", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--maxy", dest="maxy", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _help = "Inset from each icons bounds (in pixels)" | 
					
						
							|  |  |  |     parser.add_argument("--minx_icon", dest="minx_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--miny_icon", dest="miny_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--maxx_icon", dest="maxx_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--maxy_icon", dest="maxy_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _help = "Empty space between icons" | 
					
						
							|  |  |  |     parser.add_argument("--spacex_icon", dest="spacex_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  |     parser.add_argument("--spacey_icon", dest="spacey_icon", metavar='INT', type=int, help=_help) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     del _help | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     args = parser.parse_args(argv) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not argv: | 
					
						
							|  |  |  |         print("No args given!") | 
					
						
							|  |  |  |         parser.print_help() | 
					
						
							|  |  |  |         return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     dice(args.image, args.output, args.output_prefix, args.name_style, | 
					
						
							|  |  |  |          args.parts_x, args.parts_y, | 
					
						
							|  |  |  |          args.minx, args.miny, args.maxx, args.maxy, | 
					
						
							|  |  |  |          args.minx_icon, args.miny_icon, args.maxx_icon, args.maxy_icon, | 
					
						
							|  |  |  |          args.spacex_icon, args.spacey_icon, | 
					
						
							|  |  |  |          ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-03 06:47:49 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-13 23:47:33 +11:00
										 |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     main() |