Cleanup: remove unused icon utilities and make convenience target
Remove utilities to assist in creation of the now removed `*.dat` icons. Pull Request: https://projects.blender.org/blender/blender/pulls/123837
This commit is contained in:
parent
9584f8fb55
commit
a8fae77f10
14
GNUmakefile
14
GNUmakefile
@ -96,15 +96,6 @@ Spell Checkers
|
|||||||
Utilities
|
Utilities
|
||||||
Not associated with building Blender.
|
Not associated with building Blender.
|
||||||
|
|
||||||
* icons:
|
|
||||||
Updates PNG icons from SVG files.
|
|
||||||
|
|
||||||
Optionally pass in variables: 'BLENDER_BIN', 'INKSCAPE_BIN'
|
|
||||||
otherwise default paths are used.
|
|
||||||
|
|
||||||
Example
|
|
||||||
make icons INKSCAPE_BIN=/path/to/inkscape
|
|
||||||
|
|
||||||
* icons_geom:
|
* icons_geom:
|
||||||
Updates Geometry icons from BLEND file.
|
Updates Geometry icons from BLEND file.
|
||||||
|
|
||||||
@ -565,11 +556,6 @@ source_archive_complete: .FORCE
|
|||||||
# This assumes CMake is still using a default `PACKAGE_DIR` variable:
|
# This assumes CMake is still using a default `PACKAGE_DIR` variable:
|
||||||
@$(PYTHON) ./build_files/utils/make_source_archive.py --include-packages "$(BUILD_DIR)/source_archive/packages"
|
@$(PYTHON) ./build_files/utils/make_source_archive.py --include-packages "$(BUILD_DIR)/source_archive/packages"
|
||||||
|
|
||||||
icons: .FORCE
|
|
||||||
@BLENDER_BIN=$(BLENDER_BIN) "$(BLENDER_DIR)/release/datafiles/blender_icons_update.py"
|
|
||||||
"$(BLENDER_DIR)/release/datafiles/prvicons_update.py"
|
|
||||||
"$(BLENDER_DIR)/release/datafiles/alert_icons_update.py"
|
|
||||||
|
|
||||||
icons_geom: .FORCE
|
icons_geom: .FORCE
|
||||||
@BLENDER_BIN=$(BLENDER_BIN) \
|
@BLENDER_BIN=$(BLENDER_BIN) \
|
||||||
"$(BLENDER_DIR)/release/datafiles/blender_icons_geom_update.py"
|
"$(BLENDER_DIR)/release/datafiles/blender_icons_geom_update.py"
|
||||||
|
@ -1040,91 +1040,6 @@ function(data_to_c_simple
|
|||||||
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
set_source_files_properties(${_file_to} PROPERTIES GENERATED TRUE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Function for converting pixmap directory to a '.png' and then a '.c' file.
|
|
||||||
function(data_to_c_simple_icons
|
|
||||||
path_from icon_prefix icon_names
|
|
||||||
list_to_add
|
|
||||||
)
|
|
||||||
|
|
||||||
# Conversion steps
|
|
||||||
# path_from -> _file_from -> _file_to
|
|
||||||
# foo/*.dat -> foo.png -> foo.png.c
|
|
||||||
|
|
||||||
get_filename_component(_path_from_abs ${path_from} ABSOLUTE)
|
|
||||||
# remove ../'s
|
|
||||||
get_filename_component(_file_from ${CMAKE_CURRENT_BINARY_DIR}/${path_from}.png REALPATH)
|
|
||||||
get_filename_component(_file_to ${CMAKE_CURRENT_BINARY_DIR}/${path_from}.png.c REALPATH)
|
|
||||||
|
|
||||||
list(APPEND ${list_to_add} ${_file_to})
|
|
||||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
||||||
|
|
||||||
get_filename_component(_file_to_path ${_file_to} PATH)
|
|
||||||
|
|
||||||
# Construct a list of absolute paths from input
|
|
||||||
set(_icon_files)
|
|
||||||
foreach(_var ${icon_names})
|
|
||||||
list(APPEND _icon_files "${_path_from_abs}/${icon_prefix}${_var}.dat")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${_file_from} ${_file_to}
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_to_path}
|
|
||||||
# COMMAND python3 ${CMAKE_SOURCE_DIR}/source/blender/datatoc/datatoc_icon.py
|
|
||||||
# ${_path_from_abs} ${_file_from}
|
|
||||||
COMMAND "$<TARGET_FILE:datatoc_icon>" ${_path_from_abs} ${_file_from}
|
|
||||||
COMMAND "$<TARGET_FILE:datatoc>" ${_file_from} ${_file_to}
|
|
||||||
DEPENDS
|
|
||||||
${_icon_files}
|
|
||||||
datatoc_icon
|
|
||||||
datatoc
|
|
||||||
# could be an arg but for now we only create icons depending on UI_icons.hh
|
|
||||||
${CMAKE_SOURCE_DIR}/source/blender/editors/include/UI_icons.hh
|
|
||||||
)
|
|
||||||
|
|
||||||
set_source_files_properties(${_file_from} ${_file_to} PROPERTIES GENERATED TRUE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
# XXX Not used for now...
|
|
||||||
function(svg_to_png
|
|
||||||
file_from
|
|
||||||
file_to
|
|
||||||
dpi
|
|
||||||
list_to_add
|
|
||||||
)
|
|
||||||
|
|
||||||
# remove ../'s
|
|
||||||
get_filename_component(_file_from ${CMAKE_CURRENT_SOURCE_DIR}/${file_from} REALPATH)
|
|
||||||
get_filename_component(_file_to ${CMAKE_CURRENT_SOURCE_DIR}/${file_to} REALPATH)
|
|
||||||
|
|
||||||
list(APPEND ${list_to_add} ${_file_to})
|
|
||||||
set(${list_to_add} ${${list_to_add}} PARENT_SCOPE)
|
|
||||||
|
|
||||||
find_program(INKSCAPE_EXE inkscape)
|
|
||||||
mark_as_advanced(INKSCAPE_EXE)
|
|
||||||
|
|
||||||
if(INKSCAPE_EXE)
|
|
||||||
if(APPLE)
|
|
||||||
# in OS X app bundle, the binary is a shim that doesn't take any
|
|
||||||
# command line arguments, replace it with the actual binary
|
|
||||||
string(REPLACE "MacOS/Inkscape" "Resources/bin/inkscape" INKSCAPE_REAL_EXE ${INKSCAPE_EXE})
|
|
||||||
if(EXISTS "${INKSCAPE_REAL_EXE}")
|
|
||||||
set(INKSCAPE_EXE ${INKSCAPE_REAL_EXE})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${_file_to}
|
|
||||||
|
|
||||||
COMMAND ${INKSCAPE_EXE}
|
|
||||||
${_file_from} --export-dpi=${dpi} --without-gui --export-png=${_file_to}
|
|
||||||
|
|
||||||
DEPENDS ${_file_from} ${INKSCAPE_EXE}
|
|
||||||
)
|
|
||||||
else()
|
|
||||||
message(WARNING "Inkscape not found, could not re-generate ${_file_to} from ${_file_from}!")
|
|
||||||
endif()
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(msgfmt_simple
|
function(msgfmt_simple
|
||||||
file_from
|
file_from
|
||||||
list_to_add
|
list_to_add
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
if NOT EXIST %PYTHON% (
|
|
||||||
echo python not found, required for this operation
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
call "%~dp0\find_inkscape.cmd"
|
|
||||||
|
|
||||||
if EXIST "%INKSCAPE_BIN%" (
|
|
||||||
goto detect_inkscape_done
|
|
||||||
)
|
|
||||||
|
|
||||||
echo unable to locate inkscape, run "set inkscape_BIN=full_path_to_inkscape.exe"
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:detect_inkscape_done
|
|
||||||
|
|
||||||
call "%~dp0\find_blender.cmd"
|
|
||||||
|
|
||||||
if EXIST "%BLENDER_BIN%" (
|
|
||||||
goto detect_blender_done
|
|
||||||
)
|
|
||||||
|
|
||||||
echo unable to locate blender, run "set BLENDER_BIN=full_path_to_blender.exe"
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:detect_blender_done
|
|
||||||
|
|
||||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\blender_icons_update.py
|
|
||||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\prvicons_update.py
|
|
||||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\alert_icons_update.py
|
|
||||||
|
|
||||||
:EOF
|
|
@ -103,9 +103,6 @@ if NOT "%1" == "" (
|
|||||||
set FORMAT=1
|
set FORMAT=1
|
||||||
set FORMAT_ARGS=%2 %3 %4 %5 %6 %7 %8 %9
|
set FORMAT_ARGS=%2 %3 %4 %5 %6 %7 %8 %9
|
||||||
goto EOF
|
goto EOF
|
||||||
) else if "%1" == "icons" (
|
|
||||||
set ICONS=1
|
|
||||||
goto EOF
|
|
||||||
) else if "%1" == "icons_geom" (
|
) else if "%1" == "icons_geom" (
|
||||||
set ICONS_GEOM=1
|
set ICONS_GEOM=1
|
||||||
goto EOF
|
goto EOF
|
||||||
|
5
make.bat
5
make.bat
@ -78,11 +78,6 @@ call "%BLENDER_DIR%\build_files\windows\set_build_dir.cmd"
|
|||||||
|
|
||||||
:convenience_targets
|
:convenience_targets
|
||||||
|
|
||||||
if "%ICONS%" == "1" (
|
|
||||||
call "%BLENDER_DIR%\build_files\windows\icons.cmd"
|
|
||||||
goto EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%ICONS_GEOM%" == "1" (
|
if "%ICONS_GEOM%" == "1" (
|
||||||
call "%BLENDER_DIR%\build_files\windows\icons_geom.cmd"
|
call "%BLENDER_DIR%\build_files\windows\icons_geom.cmd"
|
||||||
goto EOF
|
goto EOF
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# SPDX-FileCopyrightText: 2014-2022 Blender Authors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
# This script updates icons from the SVG file
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from typing import (
|
|
||||||
Dict,
|
|
||||||
List,
|
|
||||||
Optional,
|
|
||||||
Sequence,
|
|
||||||
Tuple,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run(cmd: Sequence[str], *, env: Optional[Dict[str, str]] = None) -> None:
|
|
||||||
print(" ", " ".join(cmd))
|
|
||||||
subprocess.check_call(cmd, env=env)
|
|
||||||
|
|
||||||
|
|
||||||
BASEDIR = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
|
|
||||||
env = {}
|
|
||||||
# Developers may have ASAN enabled, avoid non-zero exit codes.
|
|
||||||
env["ASAN_OPTIONS"] = "exitcode=0:" + os.environ.get("ASAN_OPTIONS", "")
|
|
||||||
|
|
||||||
# These NEED to be set on windows for python to initialize properly.
|
|
||||||
if sys.platform[:3] == "win":
|
|
||||||
env["PATHEXT"] = os.environ.get("PATHEXT", "")
|
|
||||||
env["SystemDrive"] = os.environ.get("SystemDrive", "")
|
|
||||||
env["SystemRoot"] = os.environ.get("SystemRoot", "")
|
|
||||||
|
|
||||||
if not (inkscape_bin := os.environ.get("INKSCAPE_BIN")):
|
|
||||||
if sys.platform == 'darwin':
|
|
||||||
inkscape_bin = '/Applications/Inkscape.app/Contents/MacOS/inkscape'
|
|
||||||
else:
|
|
||||||
inkscape_bin = "inkscape"
|
|
||||||
|
|
||||||
blender_bin = os.environ.get("BLENDER_BIN", "blender")
|
|
||||||
|
|
||||||
cmd: Tuple[str, ...] = (
|
|
||||||
inkscape_bin,
|
|
||||||
os.path.join(BASEDIR, "blender_icons.svg"),
|
|
||||||
"--export-width=602",
|
|
||||||
"--export-height=640",
|
|
||||||
"--export-type=png",
|
|
||||||
"--export-filename=" + os.path.join(BASEDIR, "blender_icons16.png"),
|
|
||||||
)
|
|
||||||
run(cmd, env=env)
|
|
||||||
|
|
||||||
cmd = (
|
|
||||||
inkscape_bin,
|
|
||||||
os.path.join(BASEDIR, "blender_icons.svg"),
|
|
||||||
"--export-width=1204",
|
|
||||||
"--export-height=1280",
|
|
||||||
"--export-type=png",
|
|
||||||
"--export-filename=" + os.path.join(BASEDIR, "blender_icons32.png"),
|
|
||||||
)
|
|
||||||
run(cmd, env=env)
|
|
||||||
|
|
||||||
|
|
||||||
# For testing it can be good to clear all old
|
|
||||||
# rm ./blender_icons16/*.dat
|
|
||||||
# rm ./blender_icons32/*.dat
|
|
||||||
|
|
||||||
datatoc_icon_split_py = os.path.join(BASEDIR, "..", "..", "source", "blender", "datatoc", "datatoc_icon_split.py")
|
|
||||||
|
|
||||||
# create .dat pixmaps (which are stored in git)
|
|
||||||
cmd = (
|
|
||||||
blender_bin, "--background", "--factory-startup",
|
|
||||||
"--python", datatoc_icon_split_py, "--",
|
|
||||||
"--image=" + os.path.join(BASEDIR, "blender_icons16.png"),
|
|
||||||
"--output=" + os.path.join(BASEDIR, "blender_icons16"),
|
|
||||||
"--output_prefix=icon16_",
|
|
||||||
"--name_style=UI_ICONS",
|
|
||||||
"--parts_x", "26", "--parts_y", "30",
|
|
||||||
"--minx", "3", "--maxx", "53", "--miny", "3", "--maxy", "8",
|
|
||||||
"--minx_icon", "2", "--maxx_icon", "2", "--miny_icon", "2", "--maxy_icon", "2",
|
|
||||||
"--spacex_icon", "1", "--spacey_icon", "1",
|
|
||||||
)
|
|
||||||
run(cmd, env=env)
|
|
||||||
|
|
||||||
cmd = (
|
|
||||||
blender_bin, "--background", "--factory-startup",
|
|
||||||
"--python", datatoc_icon_split_py, "--",
|
|
||||||
"--image=" + os.path.join(BASEDIR, "blender_icons32.png"),
|
|
||||||
"--output=" + os.path.join(BASEDIR, "blender_icons32"),
|
|
||||||
"--output_prefix=icon32_",
|
|
||||||
"--name_style=UI_ICONS",
|
|
||||||
"--parts_x", "26", "--parts_y", "30",
|
|
||||||
"--minx", "6", "--maxx", "106", "--miny", "6", "--maxy", "16",
|
|
||||||
"--minx_icon", "4", "--maxx_icon", "4", "--miny_icon", "4", "--maxy_icon", "4",
|
|
||||||
"--spacex_icon", "2", "--spacey_icon", "2",
|
|
||||||
)
|
|
||||||
run(cmd, env=env)
|
|
||||||
|
|
||||||
os.remove(os.path.join(BASEDIR, "blender_icons16.png"))
|
|
||||||
os.remove(os.path.join(BASEDIR, "blender_icons32.png"))
|
|
||||||
|
|
||||||
# For testing, if we want the PNG of each image
|
|
||||||
# ./datatoc_icon_split_to_png.py ./blender_icons16/*.dat
|
|
||||||
# ./datatoc_icon_split_to_png.py ./blender_icons32/*.dat
|
|
@ -11,42 +11,3 @@ set(SRC
|
|||||||
|
|
||||||
# SRC_DNA_INC is defined in the parent dir
|
# SRC_DNA_INC is defined in the parent dir
|
||||||
add_executable(datatoc ${SRC})
|
add_executable(datatoc ${SRC})
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
|
||||||
# Build datatoc_icon executable
|
|
||||||
|
|
||||||
if(NOT WITH_HEADLESS)
|
|
||||||
|
|
||||||
set(SRC
|
|
||||||
datatoc_icon.cc
|
|
||||||
)
|
|
||||||
setup_platform_linker_flags(datatoc)
|
|
||||||
if(WIN32)
|
|
||||||
include_directories(
|
|
||||||
../blenlib
|
|
||||||
../../../intern/utfconv
|
|
||||||
)
|
|
||||||
|
|
||||||
# for winstuff_dir.cc
|
|
||||||
add_definitions(-DUSE_STANDALONE)
|
|
||||||
|
|
||||||
list(APPEND SRC
|
|
||||||
../blenlib/intern/winstuff_dir.cc
|
|
||||||
../../../intern/utfconv/utfconv.cc
|
|
||||||
)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include_directories(${PNG_INCLUDE_DIRS})
|
|
||||||
|
|
||||||
add_executable(datatoc_icon ${SRC})
|
|
||||||
setup_platform_linker_flags(datatoc_icon)
|
|
||||||
|
|
||||||
target_link_libraries(datatoc_icon ${PNG_LIBRARIES} ${ZLIB_LIBRARIES})
|
|
||||||
# PNG library uses pow() and floow(), so seems -lm is required for proper
|
|
||||||
# working binary.
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
target_link_libraries(datatoc_icon m)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
@ -1,496 +0,0 @@
|
|||||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
/** \file
|
|
||||||
* \ingroup datatoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
/* for bool */
|
|
||||||
#include "../blenlib/BLI_sys_types.h"
|
|
||||||
|
|
||||||
/* for DIR */
|
|
||||||
#if !defined(WIN32) || defined(FREEWINDOWS)
|
|
||||||
# include <dirent.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <png.h>
|
|
||||||
|
|
||||||
/* for Win32 DIR functions */
|
|
||||||
#ifdef WIN32
|
|
||||||
# include "../blenlib/BLI_winstuff.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
# define SEP '\\'
|
|
||||||
#else
|
|
||||||
# define SEP '/'
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Endian Defines
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
#define L_ENDIAN 1
|
|
||||||
#define B_ENDIAN 0
|
|
||||||
#ifdef __BIG_ENDIAN__
|
|
||||||
# define ENDIAN_ORDER B_ENDIAN
|
|
||||||
#else
|
|
||||||
# define ENDIAN_ORDER L_ENDIAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Utility Functions
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
static bool path_test_extension(const char *filepath, const char *ext)
|
|
||||||
{
|
|
||||||
const size_t a = strlen(filepath);
|
|
||||||
const size_t b = strlen(ext);
|
|
||||||
return !(a == 0 || b == 0 || b >= a) && (strcmp(ext, filepath + a - b) == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void endian_switch_uint32(uint *val)
|
|
||||||
{
|
|
||||||
uint tval = *val;
|
|
||||||
*val = (tval >> 24) | ((tval << 8) & 0x00ff0000) | ((tval >> 8) & 0x0000ff00) | (tval << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *path_slash_rfind(const char *path)
|
|
||||||
{
|
|
||||||
const char *const lfslash = strrchr(path, '/');
|
|
||||||
const char *const lbslash = strrchr(path, '\\');
|
|
||||||
|
|
||||||
if (!lfslash) {
|
|
||||||
return lbslash;
|
|
||||||
}
|
|
||||||
if (!lbslash) {
|
|
||||||
return lfslash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (lfslash > lbslash) ? lfslash : lbslash;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *path_basename(const char *path)
|
|
||||||
{
|
|
||||||
const char *const filename = path_slash_rfind(path);
|
|
||||||
return filename ? filename + 1 : path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool path_join(char *filepath,
|
|
||||||
size_t filepath_maxncpy,
|
|
||||||
const char *dirpath,
|
|
||||||
const char *filename)
|
|
||||||
{
|
|
||||||
int dirpath_len = strlen(dirpath);
|
|
||||||
if (dirpath_len && dirpath[dirpath_len - 1] == SEP) {
|
|
||||||
dirpath_len--;
|
|
||||||
}
|
|
||||||
const int filename_len = strlen(filename);
|
|
||||||
if (dirpath_len + 1 + filename_len + 1 > filepath_maxncpy) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
memcpy(filepath, dirpath, dirpath_len);
|
|
||||||
filepath[dirpath_len] = SEP;
|
|
||||||
memcpy(filepath + dirpath_len + 1, filename, filename_len + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Write a PNG from RGBA Pixels
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
static bool write_png(const char *filepath, const uint *pixels, const int width, const int height)
|
|
||||||
{
|
|
||||||
png_structp png_ptr;
|
|
||||||
png_infop info_ptr;
|
|
||||||
png_bytepp row_pointers = nullptr;
|
|
||||||
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
const int bytesperpixel = 4;
|
|
||||||
const int compression = 9;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fp = fopen(filepath, "wb");
|
|
||||||
if (fp == nullptr) {
|
|
||||||
printf("%s: Cannot open file for writing '%s'\n", __func__, filepath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
|
||||||
if (png_ptr == nullptr) {
|
|
||||||
printf("%s: Cannot png_create_write_struct for file: '%s'\n", __func__, filepath);
|
|
||||||
fclose(fp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
info_ptr = png_create_info_struct(png_ptr);
|
|
||||||
if (info_ptr == nullptr) {
|
|
||||||
png_destroy_write_struct(&png_ptr, (png_infopp) nullptr);
|
|
||||||
printf("%s: Cannot png_create_info_struct for file: '%s'\n", __func__, filepath);
|
|
||||||
fclose(fp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
||||||
printf("%s: Cannot setjmp for file: '%s'\n", __func__, filepath);
|
|
||||||
fclose(fp);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write the file */
|
|
||||||
png_init_io(png_ptr, fp);
|
|
||||||
|
|
||||||
png_set_compression_level(png_ptr, compression);
|
|
||||||
|
|
||||||
/* png image settings */
|
|
||||||
png_set_IHDR(png_ptr,
|
|
||||||
info_ptr,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
8,
|
|
||||||
PNG_COLOR_TYPE_RGBA,
|
|
||||||
PNG_INTERLACE_NONE,
|
|
||||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
|
||||||
PNG_FILTER_TYPE_DEFAULT);
|
|
||||||
|
|
||||||
/* write the file header information */
|
|
||||||
png_write_info(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
if (ENDIAN_ORDER == L_ENDIAN) {
|
|
||||||
png_set_swap(png_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate memory for an array of row-pointers */
|
|
||||||
row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));
|
|
||||||
if (row_pointers == nullptr) {
|
|
||||||
printf("%s: Cannot allocate row-pointers array for file '%s'\n", __func__, filepath);
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
||||||
if (fp) {
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the individual row-pointers to point at the correct offsets */
|
|
||||||
for (i = 0; i < height; i++) {
|
|
||||||
row_pointers[height - 1 - i] = (png_bytep)(((const uchar *)pixels) +
|
|
||||||
(i * width) * bytesperpixel * sizeof(uchar));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write out the entire image data in one call */
|
|
||||||
png_write_image(png_ptr, row_pointers);
|
|
||||||
|
|
||||||
/* write the additional chunks to the PNG file (not really needed) */
|
|
||||||
png_write_end(png_ptr, info_ptr);
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
free(row_pointers);
|
|
||||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
||||||
|
|
||||||
fflush(fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Merge Icon-Data from Files
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
struct IconHead {
|
|
||||||
uint icon_w, icon_h;
|
|
||||||
uint orig_x, orig_y;
|
|
||||||
uint canvas_w, canvas_h;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IconInfo {
|
|
||||||
IconHead head;
|
|
||||||
char *file_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct IconMergeContext {
|
|
||||||
/* Information about all icons read from disk.
|
|
||||||
* Is used for sanity checks like prevention of two files defining icon for
|
|
||||||
* the same position on canvas. */
|
|
||||||
int num_read_icons;
|
|
||||||
IconInfo *read_icons;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void icon_merge_context_init(IconMergeContext *context)
|
|
||||||
{
|
|
||||||
context->num_read_icons = 0;
|
|
||||||
context->read_icons = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get icon information from the context which matches given icon head.
|
|
||||||
* Is used to check whether icon is re-defined, and to provide useful information about which
|
|
||||||
* files are conflicting. */
|
|
||||||
static IconInfo *icon_merge_context_info_for_icon_head(IconMergeContext *context,
|
|
||||||
const IconHead *icon_head)
|
|
||||||
{
|
|
||||||
if (context->read_icons == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < context->num_read_icons; i++) {
|
|
||||||
IconInfo *read_icon_info = &context->read_icons[i];
|
|
||||||
const IconHead *read_icon_head = &read_icon_info->head;
|
|
||||||
if (read_icon_head->orig_x == icon_head->orig_x && read_icon_head->orig_y == icon_head->orig_y)
|
|
||||||
{
|
|
||||||
return read_icon_info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void icon_merge_context_register_icon(IconMergeContext *context,
|
|
||||||
const char *file_name,
|
|
||||||
const IconHead *icon_head)
|
|
||||||
{
|
|
||||||
context->read_icons = static_cast<IconInfo *>(
|
|
||||||
realloc(context->read_icons, sizeof(IconInfo) * (context->num_read_icons + 1)));
|
|
||||||
|
|
||||||
IconInfo *icon_info = &context->read_icons[context->num_read_icons];
|
|
||||||
icon_info->head = *icon_head;
|
|
||||||
icon_info->file_name = strdup(path_basename(file_name));
|
|
||||||
|
|
||||||
context->num_read_icons++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void icon_merge_context_free(IconMergeContext *context)
|
|
||||||
{
|
|
||||||
if (context->read_icons != nullptr) {
|
|
||||||
for (int i = 0; i < context->num_read_icons; i++) {
|
|
||||||
free(context->read_icons[i].file_name);
|
|
||||||
}
|
|
||||||
free(context->read_icons);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool icon_decode_head(FILE *f_src, IconHead *r_head)
|
|
||||||
{
|
|
||||||
if (fread(r_head, 1, sizeof(*r_head), f_src) == sizeof(*r_head)) {
|
|
||||||
if (ENDIAN_ORDER == B_ENDIAN) {
|
|
||||||
endian_switch_uint32(&r_head->icon_w);
|
|
||||||
endian_switch_uint32(&r_head->icon_h);
|
|
||||||
endian_switch_uint32(&r_head->orig_x);
|
|
||||||
endian_switch_uint32(&r_head->orig_y);
|
|
||||||
endian_switch_uint32(&r_head->canvas_w);
|
|
||||||
endian_switch_uint32(&r_head->canvas_h);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool icon_decode(FILE *f_src, IconHead *r_head, uint **r_pixels)
|
|
||||||
{
|
|
||||||
uint *pixels;
|
|
||||||
uint pixels_size;
|
|
||||||
|
|
||||||
if (!icon_decode_head(f_src, r_head)) {
|
|
||||||
printf("%s: failed to read header\n", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixels_size = sizeof(char[4]) * r_head->icon_w * r_head->icon_h;
|
|
||||||
pixels = static_cast<uint *>(malloc(pixels_size));
|
|
||||||
if (pixels == nullptr) {
|
|
||||||
printf("%s: failed to allocate pixels\n", __func__);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fread(pixels, 1, pixels_size, f_src) != pixels_size) {
|
|
||||||
printf("%s: failed to read pixels\n", __func__);
|
|
||||||
free(pixels);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*r_pixels = pixels;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool icon_read(const char *file_src, IconHead *r_head, uint **r_pixels)
|
|
||||||
{
|
|
||||||
FILE *f_src;
|
|
||||||
bool success;
|
|
||||||
|
|
||||||
f_src = fopen(file_src, "rb");
|
|
||||||
if (f_src == nullptr) {
|
|
||||||
printf("%s: failed to open '%s'\n", __func__, file_src);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
success = icon_decode(f_src, r_head, r_pixels);
|
|
||||||
|
|
||||||
fclose(f_src);
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool icon_merge(IconMergeContext *context,
|
|
||||||
const char *file_src,
|
|
||||||
uint32_t **r_pixels_canvas,
|
|
||||||
uint *r_canvas_w,
|
|
||||||
uint *r_canvas_h)
|
|
||||||
{
|
|
||||||
IconHead head;
|
|
||||||
uint *pixels;
|
|
||||||
|
|
||||||
uint x, y;
|
|
||||||
|
|
||||||
/* canvas */
|
|
||||||
uint32_t *pixels_canvas;
|
|
||||||
uint canvas_w, canvas_h;
|
|
||||||
|
|
||||||
if (!icon_read(file_src, &head, &pixels)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IconInfo *read_icon_info = icon_merge_context_info_for_icon_head(context, &head);
|
|
||||||
if (read_icon_info != nullptr) {
|
|
||||||
printf(
|
|
||||||
"Conflicting icon files %s and %s\n", path_basename(file_src), read_icon_info->file_name);
|
|
||||||
free(pixels);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
icon_merge_context_register_icon(context, file_src, &head);
|
|
||||||
|
|
||||||
if (*r_canvas_w == 0) {
|
|
||||||
/* init once */
|
|
||||||
*r_canvas_w = head.canvas_w;
|
|
||||||
*r_canvas_h = head.canvas_h;
|
|
||||||
*r_pixels_canvas = static_cast<uint32_t *>(
|
|
||||||
calloc(1, (head.canvas_w * head.canvas_h) * sizeof(uint32_t)));
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_w = *r_canvas_w;
|
|
||||||
canvas_h = *r_canvas_h;
|
|
||||||
pixels_canvas = *r_pixels_canvas;
|
|
||||||
|
|
||||||
assert(head.canvas_w == canvas_w);
|
|
||||||
assert(head.canvas_h == canvas_h);
|
|
||||||
|
|
||||||
for (x = 0; x < head.icon_w; x++) {
|
|
||||||
for (y = 0; y < head.icon_h; y++) {
|
|
||||||
uint pixel;
|
|
||||||
uint dst_x, dst_y;
|
|
||||||
uint pixel_xy_dst;
|
|
||||||
|
|
||||||
/* get pixel */
|
|
||||||
pixel = pixels[(y * head.icon_w) + x];
|
|
||||||
|
|
||||||
/* set pixel */
|
|
||||||
dst_x = head.orig_x + x;
|
|
||||||
dst_y = head.orig_y + y;
|
|
||||||
pixel_xy_dst = (dst_y * canvas_w) + dst_x;
|
|
||||||
assert(pixel_xy_dst < (canvas_w * canvas_h));
|
|
||||||
pixels_canvas[pixel_xy_dst] = pixel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(pixels);
|
|
||||||
|
|
||||||
/* only for bounds check */
|
|
||||||
(void)canvas_h;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool icondir_to_png(const char *path_src, const char *file_dst)
|
|
||||||
{
|
|
||||||
/* Takes a path full of 'dat' files and writes out */
|
|
||||||
DIR *dir;
|
|
||||||
const dirent *fname;
|
|
||||||
char filepath[1024];
|
|
||||||
int found = 0, fail = 0;
|
|
||||||
|
|
||||||
IconMergeContext context;
|
|
||||||
|
|
||||||
uint32_t *pixels_canvas = nullptr;
|
|
||||||
uint canvas_w = 0, canvas_h = 0;
|
|
||||||
|
|
||||||
icon_merge_context_init(&context);
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
dir = opendir(path_src);
|
|
||||||
if (dir == nullptr) {
|
|
||||||
printf(
|
|
||||||
"%s: failed to dir '%s', (%s)\n", __func__, path_src, errno ? strerror(errno) : "unknown");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((fname = readdir(dir)) != nullptr) {
|
|
||||||
if (path_test_extension(fname->d_name, ".dat")) {
|
|
||||||
if (!path_join(filepath, sizeof(filepath), path_src, fname->d_name)) {
|
|
||||||
printf("%s: path is too long (%s, %s)\n", __func__, path_src, fname->d_name);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (icon_merge(&context, filepath, &pixels_canvas, &canvas_w, &canvas_h)) {
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fail++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
icon_merge_context_free(&context);
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
if (found == 0) {
|
|
||||||
printf("%s: dir '%s' has no icons\n", __func__, path_src);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fail != 0) {
|
|
||||||
printf("%s: dir '%s' failed %d icons\n", __func__, path_src, fail);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write pixels. */
|
|
||||||
write_png(file_dst, pixels_canvas, canvas_w, canvas_h);
|
|
||||||
|
|
||||||
free(pixels_canvas);
|
|
||||||
|
|
||||||
return (fail == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
|
||||||
/** \name Main & Parse Arguments
|
|
||||||
* \{ */
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
const char *path_src;
|
|
||||||
const char *file_dst;
|
|
||||||
|
|
||||||
if (argc < 3) {
|
|
||||||
printf("Usage: datatoc_icon <dir_icons> <data_icon_to.png>\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
path_src = argv[1];
|
|
||||||
file_dst = argv[2];
|
|
||||||
|
|
||||||
return (icondir_to_png(path_src, file_dst) == true) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
|
@ -1,146 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# SPDX-FileCopyrightText: 2014-2022 Blender Authors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
|
|
||||||
|
|
||||||
|
|
||||||
def write_png(buf, width, height):
|
|
||||||
import zlib
|
|
||||||
import struct
|
|
||||||
# reverse the vertical line order and add null bytes at the start
|
|
||||||
width_byte_4 = width * 4
|
|
||||||
raw_data = b"".join(
|
|
||||||
b'\x00' + buf[span:span + width_byte_4]
|
|
||||||
for span in range((height - 1) * width * 4, -1, - width_byte_4)
|
|
||||||
)
|
|
||||||
|
|
||||||
def png_pack(png_tag, data):
|
|
||||||
chunk_head = png_tag + data
|
|
||||||
return struct.pack("!I", len(data)) + chunk_head + struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head))
|
|
||||||
|
|
||||||
return b"".join([
|
|
||||||
b'\x89PNG\r\n\x1a\n',
|
|
||||||
png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
|
|
||||||
png_pack(b'IDAT', zlib.compress(raw_data, 9)),
|
|
||||||
png_pack(b'IEND', b'')])
|
|
||||||
|
|
||||||
|
|
||||||
def icon_decode_head(f_src):
|
|
||||||
import struct
|
|
||||||
|
|
||||||
# 2 ints
|
|
||||||
temp_data = f_src.read(4 * 2)
|
|
||||||
icon_w, icon_h = struct.unpack('<2I', temp_data)
|
|
||||||
|
|
||||||
temp_data = f_src.read(4 * 2)
|
|
||||||
orig_x, orig_y = struct.unpack('<2I', temp_data)
|
|
||||||
|
|
||||||
temp_data = f_src.read(4 * 2)
|
|
||||||
canvas_w, canvas_h = struct.unpack('<2I', temp_data)
|
|
||||||
|
|
||||||
return (icon_w, icon_h,
|
|
||||||
orig_x, orig_y,
|
|
||||||
canvas_w, canvas_h)
|
|
||||||
|
|
||||||
|
|
||||||
def icon_decode(f_src):
|
|
||||||
head = icon_decode_head(f_src)
|
|
||||||
|
|
||||||
(icon_w, icon_h,
|
|
||||||
orig_x, orig_y,
|
|
||||||
canvas_w, canvas_h) = head
|
|
||||||
|
|
||||||
# pixels
|
|
||||||
import array
|
|
||||||
|
|
||||||
pixels = f_src.read(icon_w * icon_h * 4)
|
|
||||||
pixels = array.array('I', pixels)
|
|
||||||
if _IS_BIG_ENDIAN:
|
|
||||||
pixels.byteswap()
|
|
||||||
|
|
||||||
return head, pixels
|
|
||||||
|
|
||||||
|
|
||||||
def icon_read(file_src):
|
|
||||||
with open(file_src, 'rb') as f_src:
|
|
||||||
head, pixels = icon_decode(f_src)
|
|
||||||
return head, pixels
|
|
||||||
|
|
||||||
|
|
||||||
def icon_merge(file_src, pixels_canvas, canvas_w, canvas_h):
|
|
||||||
""" Takes an icon filepath and merges into a pixel array
|
|
||||||
"""
|
|
||||||
head, pixels = icon_read(file_src)
|
|
||||||
|
|
||||||
(icon_w, icon_h,
|
|
||||||
orig_x, orig_y,
|
|
||||||
w_canvas_test, h_canvas_test) = head
|
|
||||||
|
|
||||||
assert w_canvas_test == canvas_w
|
|
||||||
assert h_canvas_test == canvas_h
|
|
||||||
|
|
||||||
for x in range(icon_w):
|
|
||||||
for y in range(icon_h):
|
|
||||||
# get pixel
|
|
||||||
pixel = pixels[(y * icon_w) + x]
|
|
||||||
|
|
||||||
# set pixel
|
|
||||||
dst_x = orig_x + x
|
|
||||||
dst_y = orig_y + y
|
|
||||||
pixels_canvas[(dst_y * canvas_w) + dst_x] = pixel
|
|
||||||
|
|
||||||
|
|
||||||
def icondir_to_png(path_src, file_dst):
|
|
||||||
""" Takes a path full of 'dat' files and writes out
|
|
||||||
"""
|
|
||||||
import os
|
|
||||||
import array
|
|
||||||
|
|
||||||
files = [os.path.join(path_src, f) for f in os.listdir(path_src) if f.endswith(".dat")]
|
|
||||||
|
|
||||||
# First check if we need to bother.
|
|
||||||
if os.path.exists(file_dst):
|
|
||||||
dst_time = os.path.getmtime(file_dst)
|
|
||||||
has_newer = False
|
|
||||||
for f in files:
|
|
||||||
if os.path.getmtime(f) > dst_time:
|
|
||||||
has_newer = True
|
|
||||||
break
|
|
||||||
if not has_newer:
|
|
||||||
return
|
|
||||||
|
|
||||||
with open(files[0], 'rb') as f_src:
|
|
||||||
(icon_w, icon_h,
|
|
||||||
orig_x, orig_y,
|
|
||||||
canvas_w, canvas_h) = icon_decode_head(f_src)
|
|
||||||
|
|
||||||
# load in pixel data
|
|
||||||
pixels_canvas = array.array('I', [0]) * (canvas_w * canvas_h)
|
|
||||||
for f in files:
|
|
||||||
icon_merge(f, pixels_canvas, canvas_w, canvas_h)
|
|
||||||
|
|
||||||
# write pixels
|
|
||||||
with open(file_dst, 'wb') as f_dst:
|
|
||||||
pixels_data = pixels_canvas.tobytes()
|
|
||||||
image_data = write_png(pixels_data, canvas_w, canvas_h)
|
|
||||||
f_dst.write(image_data)
|
|
||||||
|
|
||||||
|
|
||||||
def main_ex(argv):
|
|
||||||
import os
|
|
||||||
|
|
||||||
path_src = argv[-2].rstrip(os.sep)
|
|
||||||
file_dst = argv[-1]
|
|
||||||
|
|
||||||
icondir_to_png(path_src, file_dst)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
main_ex(sys.argv)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,302 +0,0 @@
|
|||||||
# SPDX-FileCopyrightText: 2014-2022 Blender Authors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
"""
|
|
||||||
This script dices up PNG into small files to store in version control.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
./blender.bin \
|
|
||||||
--background \
|
|
||||||
--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
|
|
||||||
except ImportError:
|
|
||||||
bpy = None
|
|
||||||
|
|
||||||
if bpy is not None:
|
|
||||||
pixels, pixel_w, pixel_h = image_from_file__bpy(filepath)
|
|
||||||
# else:
|
|
||||||
# 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:
|
|
||||||
|
|
||||||
f.write(
|
|
||||||
struct.pack(
|
|
||||||
'<6I',
|
|
||||||
sub_w, sub_h,
|
|
||||||
sub_x, sub_y,
|
|
||||||
# redundant but including to maintain consistency
|
|
||||||
pixel_w, pixel_h,
|
|
||||||
))
|
|
||||||
|
|
||||||
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 = {}
|
|
||||||
|
|
||||||
|
|
||||||
def dice_icon_name(
|
|
||||||
x, y, parts_x, parts_y,
|
|
||||||
name_style=None, prefix=""):
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
count = 0
|
|
||||||
|
|
||||||
# Search for eg: DEF_ICON(BRUSH_NUDGE) --> BRUSH_NUDGE
|
|
||||||
re_icon = re.compile(r'^\s*DEF_ICON.*\(\s*([A-Za-z0-9_]+)\s*\).*$')
|
|
||||||
|
|
||||||
ui_icons_h = os.path.join(SOURCE_DIR, "source", "blender", "editors", "include", "UI_icons.hh")
|
|
||||||
with open(ui_icons_h, 'r', encoding="utf-8") as f:
|
|
||||||
for l in f:
|
|
||||||
match = re_icon.search(l)
|
|
||||||
if match:
|
|
||||||
if l.find('DEF_ICON_BLANK') == -1:
|
|
||||||
icon_name = match.group(1).lower()
|
|
||||||
print(icon_name)
|
|
||||||
_dice_icon_name_cache[count] = icon_name
|
|
||||||
count += 1
|
|
||||||
# ---- Done with icon cache
|
|
||||||
|
|
||||||
index = (y * parts_x) + x
|
|
||||||
if index not in _dice_icon_name_cache:
|
|
||||||
return None
|
|
||||||
|
|
||||||
icon_name = _dice_icon_name_cache[index]
|
|
||||||
|
|
||||||
# for debugging its handy to sort by number
|
|
||||||
# ~ id_str = "%03d_%s%s.dat" % (index, prefix, icon_name)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
):
|
|
||||||
|
|
||||||
is_simple = (max(
|
|
||||||
minx, miny, maxx, maxy,
|
|
||||||
minx_icon, miny_icon, maxx_icon, maxy_icon,
|
|
||||||
spacex_icon, spacey_icon) == 0)
|
|
||||||
|
|
||||||
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):
|
|
||||||
id_str = dice_icon_name(
|
|
||||||
x, y,
|
|
||||||
parts_x, parts_y,
|
|
||||||
name_style=name_style, prefix=output_prefix,
|
|
||||||
)
|
|
||||||
if not id_str:
|
|
||||||
continue
|
|
||||||
|
|
||||||
filepath = os.path.join(output, id_str)
|
|
||||||
if VERBOSE:
|
|
||||||
print(" writing:", filepath)
|
|
||||||
|
|
||||||
# simple, no margins
|
|
||||||
if is_simple:
|
|
||||||
sub_x = x * icon_w
|
|
||||||
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
|
|
||||||
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",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Icon naming option
|
|
||||||
parser.add_argument(
|
|
||||||
"--name_style", dest="name_style", metavar='ENUM', type=str,
|
|
||||||
choices=('', 'UI_ICONS'),
|
|
||||||
help="The method used for naming output data",
|
|
||||||
)
|
|
||||||
|
|
||||||
# Options for dicing up the image
|
|
||||||
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",
|
|
||||||
)
|
|
||||||
|
|
||||||
_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,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
@ -1,60 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# SPDX-FileCopyrightText: 2014-2022 Blender Authors
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
# This script is just to view the icons
|
|
||||||
|
|
||||||
|
|
||||||
def write_png(buf, width, height):
|
|
||||||
import zlib
|
|
||||||
import struct
|
|
||||||
# reverse the vertical line order and add null bytes at the start
|
|
||||||
width_byte_4 = width * 4
|
|
||||||
raw_data = b"".join(
|
|
||||||
b'\x00' + buf[span:span + width_byte_4]
|
|
||||||
for span in range((height - 1) * width * 4, -1, - width_byte_4)
|
|
||||||
)
|
|
||||||
|
|
||||||
def png_pack(png_tag, data):
|
|
||||||
chunk_head = png_tag + data
|
|
||||||
return struct.pack("!I", len(data)) + chunk_head + struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head))
|
|
||||||
|
|
||||||
return b"".join([
|
|
||||||
b'\x89PNG\r\n\x1a\n',
|
|
||||||
png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
|
|
||||||
png_pack(b'IDAT', zlib.compress(raw_data, 9)),
|
|
||||||
png_pack(b'IEND', b'')])
|
|
||||||
|
|
||||||
|
|
||||||
def icondata_to_png(file_src, file_dst):
|
|
||||||
import struct
|
|
||||||
|
|
||||||
with open(file_src, 'rb') as f_src:
|
|
||||||
# 2 ints
|
|
||||||
temp_data = f_src.read(4 * 2)
|
|
||||||
w, h = struct.unpack('<2I', temp_data)
|
|
||||||
temp_data = f_src.read(4 * 2) # (x, y) - ignored
|
|
||||||
temp_data = f_src.read(4 * 2) # (xfrom, yfrom) - ignored
|
|
||||||
# pixels
|
|
||||||
temp_data = f_src.read(w * h * 4)
|
|
||||||
|
|
||||||
buf = write_png(temp_data, w, h)
|
|
||||||
|
|
||||||
with open(file_dst, 'wb') as f_dst:
|
|
||||||
f_dst.write(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
for arg in sys.argv[1:]:
|
|
||||||
file_src = arg
|
|
||||||
file_dst = os.path.splitext(arg)[0] + ".png"
|
|
||||||
|
|
||||||
icondata_to_png(file_src, file_dst)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
Loading…
Reference in New Issue
Block a user