mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Merge pull request #2237 from socram8888/waveshare-gd
[WIP] Use GDlib in Waveshare ePapers command
This commit is contained in:
commit
18fd68900d
20 changed files with 458 additions and 541 deletions
6
.github/workflows/macos.yml
vendored
6
.github/workflows/macos.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
||||||
run: brew tap RfidResearchGroup/proxmark3
|
run: brew tap RfidResearchGroup/proxmark3
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
|
@ -75,7 +75,7 @@ jobs:
|
||||||
run: brew tap RfidResearchGroup/proxmark3
|
run: brew tap RfidResearchGroup/proxmark3
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
|
@ -116,7 +116,7 @@ jobs:
|
||||||
run: brew tap RfidResearchGroup/proxmark3
|
run: brew tap RfidResearchGroup/proxmark3
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
|
|
6
.github/workflows/ubuntu.yml
vendored
6
.github/workflows/ubuntu.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
||||||
run: sudo apt-get update
|
run: sudo apt-get update
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
|
@ -56,7 +56,7 @@ jobs:
|
||||||
run: sudo apt-get update
|
run: sudo apt-get update
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
|
@ -87,7 +87,7 @@ jobs:
|
||||||
run: sudo apt-get update
|
run: sudo apt-get update
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|
1
.github/workflows/windows.yml
vendored
1
.github/workflows/windows.yml
vendored
|
@ -119,6 +119,7 @@ jobs:
|
||||||
python3-dev
|
python3-dev
|
||||||
libpython3-all-dev
|
libpython3-all-dev
|
||||||
libssl-dev
|
libssl-dev
|
||||||
|
libgd-dev
|
||||||
|
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -80,6 +80,7 @@ tools/jtag_openocd/openocd_configuration
|
||||||
tools/mfd_aes_brute/mfd_aes_brute
|
tools/mfd_aes_brute/mfd_aes_brute
|
||||||
tools/mfd_aes_brute/mfd_multi_brute
|
tools/mfd_aes_brute/mfd_multi_brute
|
||||||
tools/mfd_aes_brute/brute_key
|
tools/mfd_aes_brute/brute_key
|
||||||
|
!tools/lena.bmp
|
||||||
|
|
||||||
fpga/__build*
|
fpga/__build*
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added troubleshooting entry - ARM architecture error (@francis2054)
|
- Added troubleshooting entry - ARM architecture error (@francis2054)
|
||||||
- Fixed `lf pyramid sim` - wrong parameter handling (@iceman1001)
|
- Fixed `lf pyramid sim` - wrong parameter handling (@iceman1001)
|
||||||
- Fixed bootloader - Ignore jitters when pressing the button (@wh201906)
|
- Fixed bootloader - Ignore jitters when pressing the button (@wh201906)
|
||||||
|
- Changed `hf waveshare` - image loading and processing is now done using [GDlib](https://github.com/libgd/libgd) (@socram8888)
|
||||||
|
|
||||||
## [Steamboat Willie.4.17768][2024-01-03]
|
## [Steamboat Willie.4.17768][2024-01-03]
|
||||||
- Changed `mem spiffs dump -t` - now supports downloading direct into trace buffer (@hazardousvoltage)
|
- Changed `mem spiffs dump -t` - now supports downloading direct into trace buffer (@hazardousvoltage)
|
||||||
|
|
|
@ -97,11 +97,12 @@ if (CMAKE_TOOLCHAIN_FILE)
|
||||||
set(EMBED_READLINE ON)
|
set(EMBED_READLINE ON)
|
||||||
set(EMBED_BZIP2 ON)
|
set(EMBED_BZIP2 ON)
|
||||||
set(EMBED_LZ4 ON)
|
set(EMBED_LZ4 ON)
|
||||||
|
set(EMBED_GD ON)
|
||||||
endif (CMAKE_TOOLCHAIN_FILE)
|
endif (CMAKE_TOOLCHAIN_FILE)
|
||||||
|
|
||||||
if (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4)
|
if (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
endif (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4)
|
endif (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||||
|
|
||||||
if (NOT SKIPREADLINE EQUAL 1)
|
if (NOT SKIPREADLINE EQUAL 1)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -213,6 +214,27 @@ if (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||||
set(LZ4_FOUND ON)
|
set(LZ4_FOUND ON)
|
||||||
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||||
|
|
||||||
|
if (NOT SKIPGD EQUAL 1)
|
||||||
|
if (EMBED_GD)
|
||||||
|
cmake_policy(SET CMP0114 NEW)
|
||||||
|
set(GD_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/gd)
|
||||||
|
# Specify SOURCE_DIR will cause some errors
|
||||||
|
ExternalProject_Add(gd
|
||||||
|
URL https://github.com/libgd/libgd/releases/download/gd-2.3.3/libgd-2.3.3.tar.gz
|
||||||
|
URL_HASH SHA256=dd3f1f0bb016edcc0b2d082e8229c822ad1d02223511997c80461481759b1ed2
|
||||||
|
PREFIX deps/gd
|
||||||
|
CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DENABLE_CPP=0 -DCMAKE_INSTALL_PREFIX=.
|
||||||
|
PATCH_COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/deps/gd-static.patch | patch -p1
|
||||||
|
)
|
||||||
|
ExternalProject_Add_StepTargets(gd configure build install)
|
||||||
|
set(GD_INCLUDE_DIRS ${GD_BUILD_DIR}/src/gd-build/include)
|
||||||
|
set(GD_LIBRARIES ${GD_BUILD_DIR}/src/gd-build/lib/libgd.a)
|
||||||
|
set(GD_FOUND ON)
|
||||||
|
else (EMBED_GD)
|
||||||
|
pkg_search_module(GD QUIET gdlib)
|
||||||
|
endif (EMBED_GD)
|
||||||
|
endif (NOT SKIPGD EQUAL 1)
|
||||||
|
|
||||||
if (NOT SKIPWHEREAMISYSTEM EQUAL 1)
|
if (NOT SKIPWHEREAMISYSTEM EQUAL 1)
|
||||||
find_path(WHEREAMI_INCLUDE_DIRS whereami.h)
|
find_path(WHEREAMI_INCLUDE_DIRS whereami.h)
|
||||||
find_library(WHEREAMI_LIBRARIES whereami)
|
find_library(WHEREAMI_LIBRARIES whereami)
|
||||||
|
@ -332,7 +354,6 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||||
${PM3_ROOT}/client/src/cmdhfvas.c
|
${PM3_ROOT}/client/src/cmdhfvas.c
|
||||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
|
||||||
${PM3_ROOT}/client/src/cmdhfxerox.c
|
${PM3_ROOT}/client/src/cmdhfxerox.c
|
||||||
${PM3_ROOT}/client/src/cmdhw.c
|
${PM3_ROOT}/client/src/cmdhw.c
|
||||||
${PM3_ROOT}/client/src/cmdlf.c
|
${PM3_ROOT}/client/src/cmdlf.c
|
||||||
|
@ -495,6 +516,17 @@ if (LZ4_FOUND)
|
||||||
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
|
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
endif (LZ4_FOUND)
|
endif (LZ4_FOUND)
|
||||||
|
|
||||||
|
if (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||||
|
set(ADDITIONAL_DIRS ${GD_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||||
|
set(ADDITIONAL_LNK ${GD_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
|
set(ADDITIONAL_LNKDIRS ${GD_LIBRARY_DIRS} ${ADDITIONAL_LNKDIRS})
|
||||||
|
set(TARGET_SOURCES
|
||||||
|
${PM3_ROOT}/client/src/imgutils.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||||
|
${TARGET_SOURCES})
|
||||||
|
add_definitions("-DHAVE_GD")
|
||||||
|
endif (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||||
|
|
||||||
if (WHEREAMI_FOUND)
|
if (WHEREAMI_FOUND)
|
||||||
set(ADDITIONAL_DIRS ${WHEREAMI_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
set(ADDITIONAL_DIRS ${WHEREAMI_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||||
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
|
@ -547,6 +579,18 @@ else (LZ4_FOUND)
|
||||||
message(SEND_ERROR "LZ4 library: LZ4 not found")
|
message(SEND_ERROR "LZ4 library: LZ4 not found")
|
||||||
endif (LZ4_FOUND)
|
endif (LZ4_FOUND)
|
||||||
|
|
||||||
|
if (SKIPGD EQUAL 1)
|
||||||
|
message(STATUS "GD library: skipped")
|
||||||
|
elseif (GD_FOUND)
|
||||||
|
if (EMBED_GD)
|
||||||
|
message(STATUS "GD library: embedded")
|
||||||
|
else (EMBED_GD)
|
||||||
|
message(STATUS "GD library: system library found")
|
||||||
|
endif (EMBED_GD)
|
||||||
|
else (SKIPGD EQUAL 1)
|
||||||
|
message(STATUS "GD library: GD not found, disabled")
|
||||||
|
endif (SKIPGD EQUAL 1)
|
||||||
|
|
||||||
if (SKIPJANSSONSYSTEM EQUAL 1)
|
if (SKIPJANSSONSYSTEM EQUAL 1)
|
||||||
message(STATUS "Jansson library: local library forced")
|
message(STATUS "Jansson library: local library forced")
|
||||||
else (SKIPJANSSONSYSTEM EQUAL 1)
|
else (SKIPJANSSONSYSTEM EQUAL 1)
|
||||||
|
@ -721,14 +765,14 @@ endif (NOT SKIPPTHREAD EQUAL 1)
|
||||||
if (NOT SKIPPYTHON EQUAL 1)
|
if (NOT SKIPPYTHON EQUAL 1)
|
||||||
# OSX have a hard time compiling python3 dependency with older cmake.
|
# OSX have a hard time compiling python3 dependency with older cmake.
|
||||||
if (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
if (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||||
if (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
if (CMAKE_VERSION VERSION_LESS 3.13)
|
||||||
target_link_directories(proxmark3 PRIVATE ${ADDITIONAL_LNKDIRS})
|
message( SEND_ERROR "Your CMAKE version is too old for Apple platform, please update to a version >=3.13" )
|
||||||
elseif (APPLE)
|
endif (CMAKE_VERSION VERSION_LESS 3.13)
|
||||||
message( SEND_ERROR "Your CMAKE version is too old for Apple platform, please update to a version >=3.13" )
|
|
||||||
endif (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
|
||||||
endif (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
endif (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||||
endif (NOT SKIPPYTHON EQUAL 1)
|
endif (NOT SKIPPYTHON EQUAL 1)
|
||||||
|
|
||||||
|
target_link_directories(proxmark3 PRIVATE ${ADDITIONAL_LNKDIRS})
|
||||||
|
|
||||||
install(TARGETS proxmark3 DESTINATION "bin")
|
install(TARGETS proxmark3 DESTINATION "bin")
|
||||||
install(DIRECTORY cmdscripts lualibs luascripts pyscripts resources dictionaries DESTINATION "share/proxmark3")
|
install(DIRECTORY cmdscripts lualibs luascripts pyscripts resources dictionaries DESTINATION "share/proxmark3")
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,17 @@ endif
|
||||||
LDLIBS += $(QTLDLIBS)
|
LDLIBS += $(QTLDLIBS)
|
||||||
CXXINCLUDES += $(QTINCLUDES)
|
CXXINCLUDES += $(QTINCLUDES)
|
||||||
|
|
||||||
|
## GD (optional)
|
||||||
|
ifneq ($(SKIPGD),1)
|
||||||
|
GDINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags gdlib 2>/dev/null)
|
||||||
|
GDLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs gdlib 2>/dev/null)
|
||||||
|
ifneq ($(GDLDLIBS),)
|
||||||
|
LDLIBS += $(GDLDLIBS)
|
||||||
|
PM3INCLUDES += $(GDINCLUDES)
|
||||||
|
GD_FOUND = 1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
## Readline
|
## Readline
|
||||||
ifneq ($(SKIPREADLINE),1)
|
ifneq ($(SKIPREADLINE),1)
|
||||||
ifeq ($(USE_BREW),1)
|
ifeq ($(USE_BREW),1)
|
||||||
|
@ -410,6 +421,10 @@ ifeq ($(PYTHON_FOUND),1)
|
||||||
PM3CFLAGS += -DHAVE_PYTHON
|
PM3CFLAGS += -DHAVE_PYTHON
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(GD_FOUND),1)
|
||||||
|
PM3CFLAGS += -DHAVE_GD
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(SWIG_LUA_FOUND),1)
|
ifeq ($(SWIG_LUA_FOUND),1)
|
||||||
PM3CFLAGS += -DHAVE_LUA_SWIG
|
PM3CFLAGS += -DHAVE_LUA_SWIG
|
||||||
endif
|
endif
|
||||||
|
@ -510,6 +525,16 @@ else
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(SKIPGD),1)
|
||||||
|
$(info GD library: skipped)
|
||||||
|
else
|
||||||
|
ifeq ($(GD_FOUND),1)
|
||||||
|
$(info GD library: GD v$(shell $(PKG_CONFIG_ENV) pkg-config --modversion gdlib) found, enabled)
|
||||||
|
else
|
||||||
|
$(info GD library: GD not found, disabled)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(SKIPREADLINE),1)
|
ifeq ($(SKIPREADLINE),1)
|
||||||
$(info Readline library: skipped)
|
$(info Readline library: skipped)
|
||||||
else
|
else
|
||||||
|
@ -605,7 +630,6 @@ SRCS = mifare/aiddesfire.c \
|
||||||
cmdhftopaz.c \
|
cmdhftopaz.c \
|
||||||
cmdhftexkom.c \
|
cmdhftexkom.c \
|
||||||
cmdhfvas.c \
|
cmdhfvas.c \
|
||||||
cmdhfwaveshare.c \
|
|
||||||
cmdhfxerox.c \
|
cmdhfxerox.c \
|
||||||
cmdhw.c \
|
cmdhw.c \
|
||||||
cmdlf.c \
|
cmdlf.c \
|
||||||
|
@ -738,6 +762,12 @@ SRCS += bucketsort.c \
|
||||||
lfdemod.c \
|
lfdemod.c \
|
||||||
util_posix.c
|
util_posix.c
|
||||||
|
|
||||||
|
ifeq ($(GD_FOUND),1)
|
||||||
|
# electronic shelf labels
|
||||||
|
SRCS += imgutils.c \
|
||||||
|
cmdhfwaveshare.c
|
||||||
|
endif
|
||||||
|
|
||||||
# swig
|
# swig
|
||||||
|
|
||||||
SWIGSRCS =
|
SWIGSRCS =
|
||||||
|
|
11
client/deps/gd-static.patch
Normal file
11
client/deps/gd-static.patch
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
--- a/src/gd.h 2024-01-07 16:51:43.749223000 +0100
|
||||||
|
+++ b/src/gd.h 2024-01-07 16:52:34.162291600 +0100
|
||||||
|
@@ -45,7 +45,7 @@
|
||||||
|
the gd sources in a project. */
|
||||||
|
|
||||||
|
/* http://gcc.gnu.org/wiki/Visibility */
|
||||||
|
-#if defined(_WIN32) || defined(CYGWIN) || defined(_WIN32_WCE)
|
||||||
|
+#if 0 // Disable DLL annotations when building statically. Needed for embedding under MinGW.
|
||||||
|
# ifdef BGDWIN32
|
||||||
|
# ifdef NONDLL
|
||||||
|
# define BGD_EXPORT_DATA_PROT
|
|
@ -98,11 +98,12 @@ if (CMAKE_TOOLCHAIN_FILE)
|
||||||
set(EMBED_READLINE ON)
|
set(EMBED_READLINE ON)
|
||||||
set(EMBED_BZIP2 ON)
|
set(EMBED_BZIP2 ON)
|
||||||
set(EMBED_LZ4 ON)
|
set(EMBED_LZ4 ON)
|
||||||
|
set(EMBED_GD ON)
|
||||||
endif (CMAKE_TOOLCHAIN_FILE)
|
endif (CMAKE_TOOLCHAIN_FILE)
|
||||||
|
|
||||||
if (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4)
|
if (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
endif (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4)
|
endif (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||||
|
|
||||||
if (NOT SKIPREADLINE EQUAL 1)
|
if (NOT SKIPREADLINE EQUAL 1)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@ -214,6 +215,27 @@ if (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||||
set(LZ4_FOUND ON)
|
set(LZ4_FOUND ON)
|
||||||
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||||
|
|
||||||
|
if (NOT SKIPGD EQUAL 1)
|
||||||
|
if (EMBED_GD)
|
||||||
|
cmake_policy(SET CMP0114 NEW)
|
||||||
|
set(GD_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/gd)
|
||||||
|
# Specify SOURCE_DIR will cause some errors
|
||||||
|
ExternalProject_Add(gd
|
||||||
|
URL https://github.com/libgd/libgd/releases/download/gd-2.3.3/libgd-2.3.3.tar.gz
|
||||||
|
URL_HASH SHA256=dd3f1f0bb016edcc0b2d082e8229c822ad1d02223511997c80461481759b1ed2
|
||||||
|
PREFIX deps/gd
|
||||||
|
CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DENABLE_CPP=0 -DCMAKE_INSTALL_PREFIX=.
|
||||||
|
PATCH_COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/deps/gd-static.patch | patch -p1
|
||||||
|
)
|
||||||
|
ExternalProject_Add_StepTargets(gd configure build install)
|
||||||
|
set(GD_INCLUDE_DIRS ${GD_BUILD_DIR}/src/gd-build/include)
|
||||||
|
set(GD_LIBRARIES ${GD_BUILD_DIR}/src/gd-build/lib/libgd.a)
|
||||||
|
set(GD_FOUND ON)
|
||||||
|
else (EMBED_GD)
|
||||||
|
pkg_search_module(GD QUIET gdlib)
|
||||||
|
endif (EMBED_GD)
|
||||||
|
endif (NOT SKIPGD EQUAL 1)
|
||||||
|
|
||||||
if (NOT SKIPWHEREAMISYSTEM EQUAL 1)
|
if (NOT SKIPWHEREAMISYSTEM EQUAL 1)
|
||||||
find_path(WHEREAMI_INCLUDE_DIRS whereami.h)
|
find_path(WHEREAMI_INCLUDE_DIRS whereami.h)
|
||||||
find_library(WHEREAMI_LIBRARIES whereami)
|
find_library(WHEREAMI_LIBRARIES whereami)
|
||||||
|
@ -333,7 +355,6 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||||
${PM3_ROOT}/client/src/cmdhfvas.c
|
${PM3_ROOT}/client/src/cmdhfvas.c
|
||||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
|
||||||
${PM3_ROOT}/client/src/cmdhfxerox.c
|
${PM3_ROOT}/client/src/cmdhfxerox.c
|
||||||
${PM3_ROOT}/client/src/cmdhw.c
|
${PM3_ROOT}/client/src/cmdhw.c
|
||||||
${PM3_ROOT}/client/src/cmdlf.c
|
${PM3_ROOT}/client/src/cmdlf.c
|
||||||
|
@ -496,6 +517,17 @@ if (LZ4_FOUND)
|
||||||
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
|
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
endif (LZ4_FOUND)
|
endif (LZ4_FOUND)
|
||||||
|
|
||||||
|
if (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||||
|
set(ADDITIONAL_DIRS ${GD_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||||
|
set(ADDITIONAL_LNK ${GD_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
|
set(ADDITIONAL_LNKDIRS ${GD_LIBRARY_DIRS} ${ADDITIONAL_LNKDIRS})
|
||||||
|
set(TARGET_SOURCES
|
||||||
|
${PM3_ROOT}/client/src/imgutils.c
|
||||||
|
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||||
|
${TARGET_SOURCES})
|
||||||
|
add_definitions("-DHAVE_GD")
|
||||||
|
endif (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||||
|
|
||||||
if (WHEREAMI_FOUND)
|
if (WHEREAMI_FOUND)
|
||||||
set(ADDITIONAL_DIRS ${WHEREAMI_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
set(ADDITIONAL_DIRS ${WHEREAMI_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||||
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
||||||
|
@ -548,6 +580,18 @@ else (LZ4_FOUND)
|
||||||
message(SEND_ERROR "LZ4 library: LZ4 not found")
|
message(SEND_ERROR "LZ4 library: LZ4 not found")
|
||||||
endif (LZ4_FOUND)
|
endif (LZ4_FOUND)
|
||||||
|
|
||||||
|
if (SKIPGD EQUAL 1)
|
||||||
|
message(STATUS "GD library: skipped")
|
||||||
|
elseif (GD_FOUND)
|
||||||
|
if (EMBED_GD)
|
||||||
|
message(STATUS "GD library: embedded")
|
||||||
|
else (EMBED_GD)
|
||||||
|
message(STATUS "GD library: system library found")
|
||||||
|
endif (EMBED_GD)
|
||||||
|
else (SKIPGD EQUAL 1)
|
||||||
|
message(STATUS "GD library: GD not found, disabled")
|
||||||
|
endif (SKIPGD EQUAL 1)
|
||||||
|
|
||||||
if (SKIPJANSSONSYSTEM EQUAL 1)
|
if (SKIPJANSSONSYSTEM EQUAL 1)
|
||||||
message(STATUS "Jansson library: local library forced")
|
message(STATUS "Jansson library: local library forced")
|
||||||
else (SKIPJANSSONSYSTEM EQUAL 1)
|
else (SKIPJANSSONSYSTEM EQUAL 1)
|
||||||
|
@ -722,10 +766,10 @@ endif (NOT SKIPPTHREAD EQUAL 1)
|
||||||
if (NOT SKIPPYTHON EQUAL 1)
|
if (NOT SKIPPYTHON EQUAL 1)
|
||||||
# OSX have a hard time compiling python3 dependency with older cmake.
|
# OSX have a hard time compiling python3 dependency with older cmake.
|
||||||
if (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
if (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||||
if (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
if (CMAKE_VERSION VERSION_LESS 3.13)
|
||||||
target_link_directories(pm3rrg_rdv4 PRIVATE ${ADDITIONAL_LNKDIRS})
|
message( SEND_ERROR "Your CMAKE version is too old for Apple platform, please update to a version >=3.13" )
|
||||||
elseif (APPLE)
|
endif (CMAKE_VERSION VERSION_LESS 3.13)
|
||||||
message( SEND_ERROR "Your CMAKE version is too old for Apple platform, please update to a version >=3.13" )
|
|
||||||
endif (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
|
||||||
endif (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
endif (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||||
endif (NOT SKIPPYTHON EQUAL 1)
|
endif (NOT SKIPPYTHON EQUAL 1)
|
||||||
|
|
||||||
|
target_link_directories(pm3rrg_rdv4 PRIVATE ${ADDITIONAL_LNKDIRS})
|
||||||
|
|
|
@ -566,7 +566,9 @@ static command_t CommandTable[] = {
|
||||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||||
{"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service }"},
|
{"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service }"},
|
||||||
|
#ifdef HAVE_GD
|
||||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||||
|
#endif
|
||||||
{"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"},
|
{"xerox", CmdHFXerox, AlwaysAvailable, "{ Fuji/Xerox cartridge RFIDs... }"},
|
||||||
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
{"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"},
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
|
|
@ -28,31 +28,7 @@
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
#include "util_posix.h" // msleep
|
#include "util_posix.h" // msleep
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
|
#include "imgutils.h"
|
||||||
// Currently the largest pixel 880*528 only needs 58.08K bytes
|
|
||||||
#define WSMAPSIZE 60000
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t B;
|
|
||||||
uint8_t M;
|
|
||||||
uint32_t fsize;
|
|
||||||
uint16_t res1;
|
|
||||||
uint16_t res2;
|
|
||||||
uint32_t offset;
|
|
||||||
uint32_t Bit_Pixel;
|
|
||||||
uint32_t BMP_Width;
|
|
||||||
uint32_t BMP_Height;
|
|
||||||
uint16_t planes;
|
|
||||||
uint16_t bpp;
|
|
||||||
uint32_t ctype;
|
|
||||||
uint32_t dsize;
|
|
||||||
uint32_t hppm;
|
|
||||||
uint32_t vppm;
|
|
||||||
uint32_t colorsused;
|
|
||||||
uint32_t colorreq;
|
|
||||||
uint32_t Color_1; //Color palette
|
|
||||||
uint32_t Color_2;
|
|
||||||
} PACKED bmp_header_t;
|
|
||||||
|
|
||||||
#define EPD_1IN54B 0
|
#define EPD_1IN54B 0
|
||||||
#define EPD_1IN54C 1
|
#define EPD_1IN54C 1
|
||||||
|
@ -105,254 +81,24 @@ static model_t models[] = {
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static int picture_bit_depth(const uint8_t *bmp, const size_t bmpsize, const uint8_t model_nr) {
|
static uint8_t * map8to1(gdImagePtr img, int color) {
|
||||||
if (bmpsize < sizeof(bmp_header_t)) {
|
// Calculate width rounding up
|
||||||
return PM3_ESOFT;
|
uint16_t width8 = (gdImageSX(img) + 7) / 8;
|
||||||
|
|
||||||
|
uint8_t * colormap8 = malloc(width8 * gdImageSY(img));
|
||||||
|
if (!colormap8) {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bmp_header_t *pbmpheader = (bmp_header_t *)bmp;
|
|
||||||
PrintAndLogEx(DEBUG, "colorsused = %d", pbmpheader->colorsused);
|
|
||||||
PrintAndLogEx(DEBUG, "pbmpheader->bpp = %d", pbmpheader->bpp);
|
|
||||||
if ((pbmpheader->BMP_Width != models[model_nr].width) || (pbmpheader->BMP_Height != models[model_nr].height)) {
|
|
||||||
PrintAndLogEx(WARNING, "Invalid BMP size, expected %ix%i, got %ix%i", models[model_nr].width, models[model_nr].height, pbmpheader->BMP_Width, pbmpheader->BMP_Height);
|
|
||||||
}
|
|
||||||
return pbmpheader->bpp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, uint8_t **black, uint8_t **red) {
|
|
||||||
bmp_header_t *pbmpheader = (bmp_header_t *)bmp;
|
|
||||||
// check file is bitmap
|
|
||||||
if (pbmpheader->bpp != 1) {
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
if (pbmpheader->B == 'M' || pbmpheader->M == 'B') { //0x4d42
|
|
||||||
PrintAndLogEx(WARNING, "The file is not a BMP!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(DEBUG, "file size = %d", pbmpheader->fsize);
|
|
||||||
PrintAndLogEx(DEBUG, "file offset = %d", pbmpheader->offset);
|
|
||||||
if (pbmpheader->fsize > bmpsize) {
|
|
||||||
PrintAndLogEx(WARNING, "The file is truncated!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
uint8_t color_flag = pbmpheader->Color_1;
|
|
||||||
// Get BMP file data pointer
|
|
||||||
uint32_t offset = pbmpheader->offset;
|
|
||||||
uint16_t width = pbmpheader->BMP_Width;
|
|
||||||
uint16_t height = pbmpheader->BMP_Height;
|
|
||||||
if ((width + 8) * height > WSMAPSIZE * 8) {
|
|
||||||
PrintAndLogEx(WARNING, "The file is too large, aborting!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t X, Y;
|
|
||||||
uint16_t Image_Width_Byte = (width % 8 == 0) ? (width / 8) : (width / 8 + 1);
|
|
||||||
uint16_t Bmp_Width_Byte = (Image_Width_Byte % 4 == 0) ? Image_Width_Byte : ((Image_Width_Byte / 4 + 1) * 4);
|
|
||||||
|
|
||||||
*black = calloc(WSMAPSIZE, sizeof(uint8_t));
|
|
||||||
if (*black == NULL) {
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
// Write data into RAM
|
|
||||||
for (Y = 0; Y < height; Y++) { // columns
|
|
||||||
for (X = 0; X < Bmp_Width_Byte; X++) { // lines
|
|
||||||
if ((X < Image_Width_Byte) && ((X + (height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
|
|
||||||
(*black)[X + (height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
|
|
||||||
}
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((model_nr == M1in54B) || (model_nr == M2in13B)) {
|
|
||||||
// for BW+Red screens:
|
|
||||||
*red = calloc(WSMAPSIZE, sizeof(uint8_t));
|
|
||||||
if (*red == NULL) {
|
|
||||||
free(*black);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rgb_to_gray(const int16_t *chanR, const int16_t *chanG, const int16_t *chanB,
|
|
||||||
uint16_t width, uint16_t height, int16_t *chanGrey) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
// greyscale conversion
|
|
||||||
float Clinear = 0.2126 * chanR[X + Y * width] + 0.7152 * chanG[X + Y * width] + 0.0722 * chanB[X + Y * width];
|
|
||||||
// Csrgb = 12.92 Clinear when Clinear <= 0.0031308
|
|
||||||
// Csrgb = 1.055 Clinear1/2.4 - 0.055 when Clinear > 0.0031308
|
|
||||||
chanGrey[X + Y * width] = Clinear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Floyd-Steinberg dithering
|
|
||||||
static void dither_chan_inplace(int16_t *chan, uint16_t width, uint16_t height) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
int16_t oldp = chan[X + Y * width];
|
|
||||||
int16_t newp = oldp > 127 ? 255 : 0;
|
|
||||||
chan[X + Y * width] = newp;
|
|
||||||
int16_t err = oldp - newp;
|
|
||||||
const float m[] = {7, 3, 5, 1};
|
|
||||||
if (X < width - 1) {
|
|
||||||
chan[X + 1 + Y * width] = chan[X + 1 + Y * width] + m[0] / 16 * err;
|
|
||||||
}
|
|
||||||
if (Y < height - 1) {
|
|
||||||
chan[X - 1 + (Y + 1) * width] = chan[X - 1 + (Y + 1) * width] + m[1] / 16 * err;
|
|
||||||
chan[X + (Y + 1) * width] = chan[X + (Y + 1) * width] + m[2] / 16 * err;
|
|
||||||
}
|
|
||||||
if ((X < width - 1) && (Y < height - 1)) {
|
|
||||||
chan[X + 1 + (Y + 1) * width] = chan[X + 1 + (Y + 1) * width] + m[3] / 16 * err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t color_compare(int16_t r1, int16_t g1, int16_t b1, int16_t r2, int16_t g2, int16_t b2) {
|
|
||||||
// Compute (square of) distance from oldR/G/B to this color
|
|
||||||
int16_t inR = r1 - r2;
|
|
||||||
int16_t inG = g1 - g2;
|
|
||||||
int16_t inB = b1 - b2;
|
|
||||||
// use RGB-to-grey weighting
|
|
||||||
float dist = 0.2126 * inR * inR + 0.7152 * inG * inG + 0.0722 * inB * inB;
|
|
||||||
return dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void nearest_color(int16_t oldR, int16_t oldG, int16_t oldB, const uint8_t *palette,
|
|
||||||
uint16_t palettelen, uint8_t *newR, uint8_t *newG, uint8_t *newB) {
|
|
||||||
uint32_t bestdist = 0x7FFFFFFF;
|
|
||||||
for (uint16_t i = 0; i < palettelen; i++) {
|
|
||||||
uint8_t R = palette[i * 3 + 0];
|
|
||||||
uint8_t G = palette[i * 3 + 1];
|
|
||||||
uint8_t B = palette[i * 3 + 2];
|
|
||||||
uint32_t dist = color_compare(oldR, oldG, oldB, R, G, B);
|
|
||||||
if (dist < bestdist) {
|
|
||||||
bestdist = dist;
|
|
||||||
*newR = R;
|
|
||||||
*newG = G;
|
|
||||||
*newB = B;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, uint16_t width, uint16_t height, uint8_t *palette, uint16_t palettelen) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
// scan odd lines in the opposite direction
|
|
||||||
uint16_t XX = X;
|
|
||||||
if (Y % 2) {
|
|
||||||
XX = width - X - 1;
|
|
||||||
}
|
|
||||||
int16_t oldR = chanR[XX + Y * width];
|
|
||||||
int16_t oldG = chanG[XX + Y * width];
|
|
||||||
int16_t oldB = chanB[XX + Y * width];
|
|
||||||
uint8_t newR = 0, newG = 0, newB = 0;
|
|
||||||
nearest_color(oldR, oldG, oldB, palette, palettelen, &newR, &newG, &newB);
|
|
||||||
chanR[XX + Y * width] = newR;
|
|
||||||
chanG[XX + Y * width] = newG;
|
|
||||||
chanB[XX + Y * width] = newB;
|
|
||||||
int16_t errR = oldR - newR;
|
|
||||||
int16_t errG = oldG - newG;
|
|
||||||
int16_t errB = oldB - newB;
|
|
||||||
const float m[] = {7, 3, 5, 1};
|
|
||||||
if (Y % 2) {
|
|
||||||
if (XX > 0) {
|
|
||||||
chanR[XX - 1 + Y * width] = (chanR[XX - 1 + Y * width] + m[0] / 16 * errR);
|
|
||||||
chanG[XX - 1 + Y * width] = (chanG[XX - 1 + Y * width] + m[0] / 16 * errG);
|
|
||||||
chanB[XX - 1 + Y * width] = (chanB[XX - 1 + Y * width] + m[0] / 16 * errB);
|
|
||||||
}
|
|
||||||
if (Y < height - 1) {
|
|
||||||
chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[3] / 16 * errR);
|
|
||||||
chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[3] / 16 * errG);
|
|
||||||
chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[3] / 16 * errB);
|
|
||||||
chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2] / 16 * errR);
|
|
||||||
chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2] / 16 * errG);
|
|
||||||
chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2] / 16 * errB);
|
|
||||||
}
|
|
||||||
if ((XX < width - 1) && (Y < height - 1)) {
|
|
||||||
chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[1] / 16 * errR);
|
|
||||||
chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[1] / 16 * errG);
|
|
||||||
chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[1] / 16 * errB);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (XX < width - 1) {
|
|
||||||
chanR[XX + 1 + Y * width] = (chanR[XX + 1 + Y * width] + m[0] / 16 * errR);
|
|
||||||
chanG[XX + 1 + Y * width] = (chanG[XX + 1 + Y * width] + m[0] / 16 * errG);
|
|
||||||
chanB[XX + 1 + Y * width] = (chanB[XX + 1 + Y * width] + m[0] / 16 * errB);
|
|
||||||
}
|
|
||||||
if (Y < height - 1) {
|
|
||||||
chanR[XX - 1 + (Y + 1) * width] = (chanR[XX - 1 + (Y + 1) * width] + m[1] / 16 * errR);
|
|
||||||
chanG[XX - 1 + (Y + 1) * width] = (chanG[XX - 1 + (Y + 1) * width] + m[1] / 16 * errG);
|
|
||||||
chanB[XX - 1 + (Y + 1) * width] = (chanB[XX - 1 + (Y + 1) * width] + m[1] / 16 * errB);
|
|
||||||
chanR[XX + (Y + 1) * width] = (chanR[XX + (Y + 1) * width] + m[2] / 16 * errR);
|
|
||||||
chanG[XX + (Y + 1) * width] = (chanG[XX + (Y + 1) * width] + m[2] / 16 * errG);
|
|
||||||
chanB[XX + (Y + 1) * width] = (chanB[XX + (Y + 1) * width] + m[2] / 16 * errB);
|
|
||||||
}
|
|
||||||
if ((XX < width - 1) && (Y < height - 1)) {
|
|
||||||
chanR[XX + 1 + (Y + 1) * width] = (chanR[XX + 1 + (Y + 1) * width] + m[3] / 16 * errR);
|
|
||||||
chanG[XX + 1 + (Y + 1) * width] = (chanG[XX + 1 + (Y + 1) * width] + m[3] / 16 * errG);
|
|
||||||
chanB[XX + 1 + (Y + 1) * width] = (chanB[XX + 1 + (Y + 1) * width] + m[3] / 16 * errB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rgb_to_gray_red_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, uint16_t width, uint16_t height) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
float Clinear = 0.2126 * chanR[X + Y * width] + 0.7152 * chanG[X + Y * width] + 0.0722 * chanB[X + Y * width];
|
|
||||||
if ((chanR[X + Y * width] < chanG[X + Y * width] && chanR[X + Y * width] < chanB[X + Y * width])) {
|
|
||||||
chanR[X + Y * width] = Clinear;
|
|
||||||
chanG[X + Y * width] = Clinear;
|
|
||||||
chanB[X + Y * width] = Clinear;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void threshold_chan(const int16_t *colorchan, uint16_t width, uint16_t height, uint8_t threshold, uint8_t *colormap) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
colormap[X + Y * width] = colorchan[X + Y * width] < threshold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void threshold_rgb_black_red(const int16_t *chanR, const int16_t *chanG, const int16_t *chanB,
|
|
||||||
uint16_t width, uint16_t height, uint8_t threshold_black,
|
|
||||||
uint8_t threshold_red, uint8_t *blackmap, uint8_t *redmap) {
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
if ((chanR[X + Y * width] < threshold_black) && (chanG[X + Y * width] < threshold_black) && (chanB[X + Y * width] < threshold_black)) {
|
|
||||||
blackmap[X + Y * width] = 1;
|
|
||||||
redmap[X + Y * width] = 0;
|
|
||||||
} else if ((chanR[X + Y * width] > threshold_red) && (chanG[X + Y * width] < threshold_black) && (chanB[X + Y * width] < threshold_black)) {
|
|
||||||
blackmap[X + Y * width] = 0;
|
|
||||||
redmap[X + Y * width] = 1;
|
|
||||||
} else {
|
|
||||||
blackmap[X + Y * width] = 0;
|
|
||||||
redmap[X + Y * width] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void map8to1(const uint8_t *colormap, uint16_t width, uint16_t height, uint8_t *colormap8) {
|
|
||||||
uint16_t width8;
|
|
||||||
if (width % 8 == 0) {
|
|
||||||
width8 = width / 8;
|
|
||||||
} else {
|
|
||||||
width8 = width / 8 + 1;
|
|
||||||
}
|
|
||||||
uint8_t data = 0;
|
uint8_t data = 0;
|
||||||
uint8_t count = 0;
|
uint8_t count = 0;
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
for (uint16_t Y = 0; Y < gdImageSY(img); Y++) {
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
for (uint16_t X = 0; X < gdImageSX(img); X++) {
|
||||||
data = data | colormap[X + Y * width];
|
if (gdImageGetPixel(img, X, Y) == color) {
|
||||||
|
data |= 1;
|
||||||
|
}
|
||||||
count += 1;
|
count += 1;
|
||||||
if ((count >= 8) || (X == width - 1)) {
|
if ((count >= 8) || (X == gdImageSX(img) - 1)) {
|
||||||
colormap8[X / 8 + Y * width8] = (~data) & 0xFF;
|
colormap8[X / 8 + Y * width8] = (~data) & 0xFF;
|
||||||
count = 0;
|
count = 0;
|
||||||
data = 0;
|
data = 0;
|
||||||
|
@ -360,194 +106,8 @@ static void map8to1(const uint8_t *colormap, uint16_t width, uint16_t height, ui
|
||||||
data = (data << 1) & 0xFF;
|
data = (data << 1) & 0xFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, uint8_t **black, uint8_t **red, char *filename, bool save_conversions) {
|
return colormap8;
|
||||||
bmp_header_t *pbmpheader = (bmp_header_t *)bmp;
|
|
||||||
// check file is full color
|
|
||||||
if ((pbmpheader->bpp != 24) && (pbmpheader->bpp != 32)) {
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pbmpheader->B == 'M' || pbmpheader->M == 'B') { //0x4d42
|
|
||||||
PrintAndLogEx(WARNING, "The file is not a BMP!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
PrintAndLogEx(DEBUG, "file size = %d", pbmpheader->fsize);
|
|
||||||
PrintAndLogEx(DEBUG, "file offset = %d", pbmpheader->offset);
|
|
||||||
if (pbmpheader->fsize > bmpsize) {
|
|
||||||
PrintAndLogEx(WARNING, "The file is truncated!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get BMP file data pointer
|
|
||||||
uint32_t offset = pbmpheader->offset;
|
|
||||||
uint16_t width = pbmpheader->BMP_Width;
|
|
||||||
uint16_t height = pbmpheader->BMP_Height;
|
|
||||||
if ((width + 8) * height > WSMAPSIZE * 8) {
|
|
||||||
PrintAndLogEx(WARNING, "The file is too large, aborting!");
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t *chanR = calloc(((size_t)width) * height, sizeof(int16_t));
|
|
||||||
if (chanR == NULL) {
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t *chanG = calloc(((size_t)width) * height, sizeof(int16_t));
|
|
||||||
if (chanG == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
int16_t *chanB = calloc(((size_t)width) * height, sizeof(int16_t));
|
|
||||||
if (chanB == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extracting BMP chans
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
chanB[X + (height - Y - 1) * width] = bmp[offset++];
|
|
||||||
chanG[X + (height - Y - 1) * width] = bmp[offset++];
|
|
||||||
chanR[X + (height - Y - 1) * width] = bmp[offset++];
|
|
||||||
if (pbmpheader->bpp == 32) // Skip Alpha chan
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
// Skip line padding
|
|
||||||
offset += width % 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((model_nr == M1in54B) || (model_nr == M2in13B)) {
|
|
||||||
// for BW+Red screens:
|
|
||||||
uint8_t *mapBlack = calloc(((size_t)width) * height, sizeof(uint8_t));
|
|
||||||
if (mapBlack == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
uint8_t *mapRed = calloc(((size_t)width) * height, sizeof(uint8_t));
|
|
||||||
if (mapRed == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
free(mapBlack);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
rgb_to_gray_red_inplace(chanR, chanG, chanB, width, height);
|
|
||||||
|
|
||||||
uint8_t palette[] = {0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; // black, white, red
|
|
||||||
dither_rgb_inplace(chanR, chanG, chanB, width, height, palette, sizeof(palette) / 3);
|
|
||||||
|
|
||||||
threshold_rgb_black_red(chanR, chanG, chanB, width, height, 128, 128, mapBlack, mapRed);
|
|
||||||
if (save_conversions) {
|
|
||||||
// fill BMP chans
|
|
||||||
offset = pbmpheader->offset;
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
bmp[offset++] = chanB[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
bmp[offset++] = chanG[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
bmp[offset++] = chanR[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
if (pbmpheader->bpp == 32) // Fill Alpha chan
|
|
||||||
bmp[offset++] = 0xFF;
|
|
||||||
}
|
|
||||||
// Skip line padding
|
|
||||||
offset += width % 4;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(INFO, "Saving red+black dithered version...");
|
|
||||||
if (saveFile(filename, ".bmp", bmp, offset) != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(WARNING, "Could not save file " _YELLOW_("%s"), filename);
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
free(mapBlack);
|
|
||||||
free(mapRed);
|
|
||||||
return PM3_EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
*black = calloc(WSMAPSIZE, sizeof(uint8_t));
|
|
||||||
if (*black == NULL) {
|
|
||||||
free(mapBlack);
|
|
||||||
free(mapRed);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
map8to1(mapBlack, width, height, *black);
|
|
||||||
free(mapBlack);
|
|
||||||
*red = calloc(WSMAPSIZE, sizeof(uint8_t));
|
|
||||||
if (*red == NULL) {
|
|
||||||
free(mapRed);
|
|
||||||
free(*black);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
map8to1(mapRed, width, height, *red);
|
|
||||||
free(mapRed);
|
|
||||||
} else {
|
|
||||||
// for BW-only screens:
|
|
||||||
int16_t *chanGrey = calloc(((size_t)width) * height, sizeof(int16_t));
|
|
||||||
if (chanGrey == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
rgb_to_gray(chanR, chanG, chanB, width, height, chanGrey);
|
|
||||||
dither_chan_inplace(chanGrey, width, height);
|
|
||||||
|
|
||||||
uint8_t *mapBlack = calloc(((size_t)width) * height, sizeof(uint8_t));
|
|
||||||
if (mapBlack == NULL) {
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
free(chanGrey);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
threshold_chan(chanGrey, width, height, 128, mapBlack);
|
|
||||||
|
|
||||||
if (save_conversions) {
|
|
||||||
// fill BMP chans
|
|
||||||
offset = pbmpheader->offset;
|
|
||||||
for (uint16_t Y = 0; Y < height; Y++) {
|
|
||||||
for (uint16_t X = 0; X < width; X++) {
|
|
||||||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
|
|
||||||
if (pbmpheader->bpp == 32) // Fill Alpha chan
|
|
||||||
bmp[offset++] = 0xFF;
|
|
||||||
}
|
|
||||||
// Skip line padding
|
|
||||||
offset += width % 4;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(INFO, "Saving black dithered version...");
|
|
||||||
if (saveFile(filename, ".bmp", bmp, offset) != PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(WARNING, "Could not save file " _YELLOW_("%s"), filename);
|
|
||||||
free(chanGrey);
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
free(mapBlack);
|
|
||||||
return PM3_EIO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(chanGrey);
|
|
||||||
free(chanR);
|
|
||||||
free(chanG);
|
|
||||||
free(chanB);
|
|
||||||
*black = calloc(WSMAPSIZE, sizeof(uint8_t));
|
|
||||||
if (*black == NULL) {
|
|
||||||
free(mapBlack);
|
|
||||||
return PM3_EMALLOC;
|
|
||||||
}
|
|
||||||
map8to1(mapBlack, width, height, *black);
|
|
||||||
free(mapBlack);
|
|
||||||
}
|
|
||||||
return PM3_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_black(uint32_t i, uint8_t *l, uint8_t model_nr, const uint8_t *black) {
|
static void read_black(uint32_t i, uint8_t *l, uint8_t model_nr, const uint8_t *black) {
|
||||||
|
@ -1003,13 +563,13 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
static int CmdHF14AWSLoad(const char *Cmd) {
|
||||||
|
|
||||||
char desc[800] = {0};
|
char desc[800] = {0};
|
||||||
for (uint8_t i = 0; i < MEND; i++) {
|
for (uint8_t i = 0; i < MEND; i++) {
|
||||||
snprintf(desc + strlen(desc),
|
snprintf(desc + strlen(desc),
|
||||||
sizeof(desc) - strlen(desc),
|
sizeof(desc) - strlen(desc),
|
||||||
"hf waveshare loadbmp -f myfile -m %2u -> %s ( %u, %u )\n",
|
"hf waveshare load -f myfile -m %2u -> %s ( %u, %u )\n",
|
||||||
i,
|
i,
|
||||||
models[i].desc,
|
models[i].desc,
|
||||||
models[i].width,
|
models[i].width,
|
||||||
|
@ -1018,8 +578,8 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf waveshare loadbmp",
|
CLIParserInit(&ctx, "hf waveshare load",
|
||||||
"Load BMP file to Waveshare NFC ePaper.",
|
"Load image file to Waveshare NFC ePaper",
|
||||||
desc
|
desc
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1029,24 +589,25 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_int1("m", NULL, "<nr>", modeldesc),
|
arg_int1("m", NULL, "<nr>", modeldesc),
|
||||||
arg_lit0("s", "save", "save dithered version in filename-[n].bmp, only for RGB BMP"),
|
arg_str1("f", "file", "<fn>", "specify image to upload to tag"),
|
||||||
arg_str1("f", "file", "<fn>", "specify filename[.bmp] to upload to tag"),
|
arg_str0("s", "save", "<fn>", "save paletized version in file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
|
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int model_nr = arg_get_int_def(ctx, 1, -1);
|
int model_nr = arg_get_int_def(ctx, 1, -1);
|
||||||
bool save_conversions = arg_get_lit(ctx, 2);
|
|
||||||
|
|
||||||
int fnlen = 0;
|
int infilelen, outfilelen;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char infile[FILE_PATH_SIZE];
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
char outfile[FILE_PATH_SIZE];
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)infile, FILE_PATH_SIZE, &infilelen);
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)outfile, FILE_PATH_SIZE, &outfilelen);
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
//Validations
|
//Validations
|
||||||
if (fnlen < 1) {
|
if (infilelen < 1) {
|
||||||
PrintAndLogEx(WARNING, "Missing filename");
|
PrintAndLogEx(WARNING, "Missing input file");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (model_nr == -1) {
|
if (model_nr == -1) {
|
||||||
|
@ -1057,64 +618,85 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
||||||
PrintAndLogEx(WARNING, "Unknown model");
|
PrintAndLogEx(WARNING, "Unknown model");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
if (!g_session.pm3_present && !outfilelen) {
|
||||||
|
PrintAndLogEx(WARNING, "Offline - can only perform image conversion");
|
||||||
|
return PM3_ENOTTY;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *bmp = NULL;
|
bool model_has_red = model_nr == M1in54B || model_nr == M2in13B;
|
||||||
uint8_t *black = NULL;
|
|
||||||
uint8_t *red = NULL;
|
gdImagePtr rgb_img = gdImageCreateFromFile(infile);
|
||||||
size_t bytes_read = 0;
|
if (!rgb_img) {
|
||||||
if (loadFile_safe(filename, ".bmp", (void **)&bmp, &bytes_read) != PM3_SUCCESS) {
|
PrintAndLogEx(WARNING, "Could not load image from " _YELLOW_("%s"), infile);
|
||||||
PrintAndLogEx(WARNING, "Could not find file " _YELLOW_("%s"), filename);
|
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
}
|
}
|
||||||
if (bmp == NULL) {
|
|
||||||
|
if (
|
||||||
|
gdImageSX(rgb_img) != models[model_nr].width ||
|
||||||
|
gdImageSY(rgb_img) != models[model_nr].height
|
||||||
|
) {
|
||||||
|
PrintAndLogEx(WARNING, "Image size does not match panel size");
|
||||||
|
gdImageDestroy(rgb_img);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pal_len = 2;
|
||||||
|
int pal[3];
|
||||||
|
pal[0] = gdTrueColorAlpha(0xFF, 0xFF, 0xFF, 0); // White
|
||||||
|
pal[1] = gdTrueColorAlpha(0x00, 0x00, 0x00, 0); // Black
|
||||||
|
if (model_has_red) {
|
||||||
|
pal_len = 3;
|
||||||
|
pal[2] = gdTrueColorAlpha(0xFF, 0x00, 0x00, 0); // Red
|
||||||
|
}
|
||||||
|
|
||||||
|
gdImagePtr pal_img = img_palettize(rgb_img, pal, pal_len);
|
||||||
|
gdImageDestroy(rgb_img);
|
||||||
|
|
||||||
|
if (!pal_img) {
|
||||||
|
PrintAndLogEx(WARNING, "Could not convert image");
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
if (bytes_read < sizeof(bmp_header_t)) {
|
|
||||||
free(bmp);
|
if (outfilelen) {
|
||||||
return PM3_ESOFT;
|
if (gdImageFile(pal_img, outfile)) {
|
||||||
|
PrintAndLogEx(INFO, "Save converted image to " _YELLOW_("%s"), outfile);
|
||||||
|
gdImageDestroy(pal_img);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(WARNING, "Could not save converted image", outfile);
|
||||||
|
gdImageDestroy(pal_img);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int depth = picture_bit_depth(bmp, bytes_read, model_nr);
|
uint8_t * black_plane = map8to1(pal_img, 1);
|
||||||
if (depth == PM3_ESOFT) {
|
if (!black_plane) {
|
||||||
PrintAndLogEx(ERR, "Error, BMP file is too small");
|
PrintAndLogEx(WARNING, "Could not convert image to bit plane");
|
||||||
free(bmp);
|
gdImageDestroy(pal_img);
|
||||||
return PM3_ESOFT;
|
return PM3_EMALLOC;
|
||||||
} else if (depth == 1) {
|
|
||||||
PrintAndLogEx(DEBUG, "BMP file is a bitmap");
|
|
||||||
if (read_bmp_bitmap(bmp, bytes_read, model_nr, &black, &red) != PM3_SUCCESS) {
|
|
||||||
free(bmp);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
} else if (depth == 24) {
|
|
||||||
PrintAndLogEx(DEBUG, "BMP file is a RGB");
|
|
||||||
if (read_bmp_rgb(bmp, bytes_read, model_nr, &black, &red, filename, save_conversions) != PM3_SUCCESS) {
|
|
||||||
free(bmp);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
} else if (depth == 32) {
|
|
||||||
PrintAndLogEx(DEBUG, "BMP file is a RGBA, we will ignore the Alpha channel");
|
|
||||||
if (read_bmp_rgb(bmp, bytes_read, model_nr, &black, &red, filename, save_conversions) != PM3_SUCCESS) {
|
|
||||||
free(bmp);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Must be 1 (BW), 24 (RGB) or 32 (RGBA)", depth);
|
|
||||||
free(bmp);
|
|
||||||
return PM3_ESOFT;
|
|
||||||
}
|
}
|
||||||
free(bmp);
|
|
||||||
|
|
||||||
start_drawing(model_nr, black, red);
|
uint8_t * red_plane = NULL;
|
||||||
free(black);
|
if (model_has_red) {
|
||||||
if ((model_nr == M1in54B) || (model_nr == M2in13B)) {
|
red_plane = map8to1(pal_img, 2);
|
||||||
free(red);
|
if (!red_plane) {
|
||||||
|
PrintAndLogEx(WARNING, "Could not convert image to bit plane");
|
||||||
|
free(black_plane);
|
||||||
|
gdImageDestroy(pal_img);
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
gdImageDestroy(pal_img);
|
||||||
|
|
||||||
|
int res = start_drawing(model_nr, black_plane, red_plane);
|
||||||
|
free(black_plane);
|
||||||
|
free(red_plane);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
{"loadbmp", CmdHF14AWSLoadBmp, IfPm3Iso14443a, "Load BMP file to Waveshare NFC ePaper"},
|
{"load", CmdHF14AWSLoad, AlwaysAvailable, "Load image file to Waveshare NFC ePaper"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
159
client/src/imgutils.c
Normal file
159
client/src/imgutils.c
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include "imgutils.h"
|
||||||
|
|
||||||
|
struct ycbcr_t {
|
||||||
|
int y;
|
||||||
|
int cb;
|
||||||
|
int cr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rgb_to_ycbcr(int rgb, struct ycbcr_t * ycbcr) {
|
||||||
|
int r = gdTrueColorGetRed(rgb);
|
||||||
|
int g = gdTrueColorGetGreen(rgb);
|
||||||
|
int b = gdTrueColorGetBlue(rgb);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Below is a fixed-point version of the following code:
|
||||||
|
* ycbcr->y = r * 0.29900 + g * 0.58700 + b * 0.11400;
|
||||||
|
* ycbcr->cb = r * -0.16874 + g * -0.33126 + b * 0.50000 + 128;
|
||||||
|
* ycbcr->cr = r * 0.50000 + g * -0.41869 + b * -0.08131 + 128;
|
||||||
|
*/
|
||||||
|
|
||||||
|
ycbcr->y = (r * 19595 + g * 38470 + b * 7471) / 65536;
|
||||||
|
ycbcr->cb = (r * -11059 + g * -21709 + b * 32768) / 65536 + 128;
|
||||||
|
ycbcr->cr = (r * 32768 + g * -27439 + b * -5329) / 65536 + 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void cap_comp(int * x) {
|
||||||
|
if (*x < 0) {
|
||||||
|
*x = 0;
|
||||||
|
} else if (*x > 255) {
|
||||||
|
*x = 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following function implements a Floyd-Steinberg in YCbCr color space.
|
||||||
|
*
|
||||||
|
* Using this colorspace, the Euclidean distance between colors is closer to human perception than
|
||||||
|
* in sRGB, which results in a more accurate color rendering.
|
||||||
|
*
|
||||||
|
* A comparison can be found at https://twitter.com/Socram4x8/status/1733157380097995205/photo/1.
|
||||||
|
*/
|
||||||
|
gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) {
|
||||||
|
assert(rgb != NULL);
|
||||||
|
assert(palette != NULL);
|
||||||
|
assert(palette_size >= 2 && palette_size < 256);
|
||||||
|
|
||||||
|
// Create paletized image
|
||||||
|
gdImagePtr res = gdImageCreate(gdImageSX(rgb), gdImageSY(rgb));
|
||||||
|
if (!res) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate space for palette in YCbCr
|
||||||
|
struct ycbcr_t * pal_ycbcr = calloc(palette_size, sizeof(struct ycbcr_t));
|
||||||
|
if (!pal_ycbcr) {
|
||||||
|
gdImageDestroy(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the column's error array.
|
||||||
|
*
|
||||||
|
* Note that we are storing two extra values so we don't have to do boundary checking at
|
||||||
|
* the left and right edges of the image.
|
||||||
|
*
|
||||||
|
* To reduce shifts and increase accuracy, each entry is stored with 16x times the error,
|
||||||
|
* and gets divided by that amount when it is read.
|
||||||
|
*/
|
||||||
|
struct ycbcr_t * forward = calloc(gdImageSX(rgb) + 2, sizeof(struct ycbcr_t));
|
||||||
|
if (!forward) {
|
||||||
|
free(pal_ycbcr);
|
||||||
|
gdImageDestroy(res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert palette to YCbCr and allocate in image
|
||||||
|
for (int i = 0; i < palette_size; i++) {
|
||||||
|
int c = palette[i];
|
||||||
|
rgb_to_ycbcr(c, pal_ycbcr + i);
|
||||||
|
gdImageColorAllocate(res, gdTrueColorGetRed(c), gdTrueColorGetGreen(c), gdTrueColorGetBlue(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < gdImageSY(rgb); y++) {
|
||||||
|
// Load current row error and reset its storage
|
||||||
|
struct ycbcr_t row_err = forward[1];
|
||||||
|
forward[1].y = forward[1].cb = forward[1].cr = 0;
|
||||||
|
|
||||||
|
for (int x = 0; x < gdImageSX(rgb); x++) {
|
||||||
|
struct ycbcr_t pix;
|
||||||
|
rgb_to_ycbcr(gdImageGetTrueColorPixel(rgb, x, y), &pix);
|
||||||
|
|
||||||
|
// Add error for current pixel
|
||||||
|
pix.y += row_err.y / 16;
|
||||||
|
pix.cb += row_err.cb / 16;
|
||||||
|
pix.cr += row_err.cr / 16;
|
||||||
|
|
||||||
|
// Cap in case it went to imaginary color territory
|
||||||
|
cap_comp(&pix.y);
|
||||||
|
cap_comp(&pix.cb);
|
||||||
|
cap_comp(&pix.cr);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate through all candidate colors and find the nearest one using the
|
||||||
|
* squared Euclidean distance.
|
||||||
|
*/
|
||||||
|
int best_idx = 0;
|
||||||
|
struct ycbcr_t best_err = { 0 };
|
||||||
|
int best_score = 0x7FFFFFFF;
|
||||||
|
for (int can_idx = 0; can_idx < palette_size; can_idx++) {
|
||||||
|
struct ycbcr_t can_err = {
|
||||||
|
.y = pix.y - pal_ycbcr[can_idx].y,
|
||||||
|
.cb = pix.cb - pal_ycbcr[can_idx].cb,
|
||||||
|
.cr = pix.cr - pal_ycbcr[can_idx].cr,
|
||||||
|
};
|
||||||
|
|
||||||
|
int can_score = (
|
||||||
|
can_err.y * can_err.y +
|
||||||
|
can_err.cb * can_err.cb +
|
||||||
|
can_err.cr * can_err.cr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (can_score < best_score) {
|
||||||
|
best_idx = can_idx;
|
||||||
|
best_score = can_score;
|
||||||
|
best_err = can_err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set current pixel
|
||||||
|
gdImageSetPixel(res, x, y, best_idx);
|
||||||
|
|
||||||
|
// Propagate error within the current row, to the pixel to the right
|
||||||
|
row_err.y = best_err.y * 7 + forward[x + 2].y;
|
||||||
|
row_err.cb = best_err.cb * 7 + forward[x + 2].cb;
|
||||||
|
row_err.cr = best_err.cr * 7 + forward[x + 2].cr;
|
||||||
|
|
||||||
|
// Add error to bottom left
|
||||||
|
forward[x + 0].y += best_err.y * 3;
|
||||||
|
forward[x + 0].cb += best_err.cb * 3;
|
||||||
|
forward[x + 0].cr += best_err.cr * 3;
|
||||||
|
|
||||||
|
// Add error to bottom center
|
||||||
|
forward[x + 1].y += best_err.y * 5;
|
||||||
|
forward[x + 1].cb += best_err.cb * 5;
|
||||||
|
forward[x + 1].cr += best_err.cr * 5;
|
||||||
|
|
||||||
|
// Set error to bottom right
|
||||||
|
forward[x + 2].y = best_err.y * 1;
|
||||||
|
forward[x + 2].cb = best_err.cb * 1;
|
||||||
|
forward[x + 2].cr = best_err.cr * 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(forward);
|
||||||
|
free(pal_ycbcr);
|
||||||
|
return res;
|
||||||
|
}
|
25
client/src/imgutils.h
Normal file
25
client/src/imgutils.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// 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 3 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.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Image utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#ifndef IMGUTILS_H__
|
||||||
|
#define IMGUTILS_H__
|
||||||
|
|
||||||
|
#include <gd.h>
|
||||||
|
|
||||||
|
gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -72,6 +72,9 @@ you can skip the installation of `qtbase5-dev`.
|
||||||
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
||||||
you can skip the installation of `libpython3-dev`.
|
you can skip the installation of `libpython3-dev`.
|
||||||
|
|
||||||
|
👉 If you don't need support for NFC ePaper devices,
|
||||||
|
you can skip the installation of `libgd-dev`.
|
||||||
|
|
||||||
### Failed to load module...
|
### Failed to load module...
|
||||||
⚠️ If you get some (non blocking) error at runtime such as _Gtk-Message: Failed to load module "canberra-gtk-module"_
|
⚠️ If you get some (non blocking) error at runtime such as _Gtk-Message: Failed to load module "canberra-gtk-module"_
|
||||||
you may have to install `libcanberra-gtk-module`.
|
you may have to install `libcanberra-gtk-module`.
|
||||||
|
@ -82,7 +85,7 @@ you may have to install `libcanberra-gtk-module`.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo pacman -Syu git base-devel readline bzip2 lz4 arm-none-eabi-gcc \
|
sudo pacman -Syu git base-devel readline bzip2 lz4 arm-none-eabi-gcc \
|
||||||
arm-none-eabi-newlib qt5-base bluez python --needed
|
arm-none-eabi-newlib qt5-base bluez python gd --needed
|
||||||
```
|
```
|
||||||
|
|
||||||
### If you don't need...
|
### If you don't need...
|
||||||
|
@ -95,6 +98,9 @@ you can skip the installation of `qt5-base`.
|
||||||
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
||||||
you can skip the installation of `python`.
|
you can skip the installation of `python`.
|
||||||
|
|
||||||
|
👉 If you don't need support for NFC ePaper devices,
|
||||||
|
you can skip the installation of `gd`.
|
||||||
|
|
||||||
|
|
||||||
## On Fedora
|
## On Fedora
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
@ -102,7 +108,7 @@ you can skip the installation of `python`.
|
||||||
```sh
|
```sh
|
||||||
sudo dnf install git make gcc gcc-c++ arm-none-eabi-gcc-cs arm-none-eabi-newlib \
|
sudo dnf install git make gcc gcc-c++ arm-none-eabi-gcc-cs arm-none-eabi-newlib \
|
||||||
readline-devel bzip2-devel lz4-devel qt5-qtbase-devel bluez-libs-devel \
|
readline-devel bzip2-devel lz4-devel qt5-qtbase-devel bluez-libs-devel \
|
||||||
python3-devel libatomic openssl-devel
|
python3-devel libatomic openssl-devel gd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
### If you don't need...
|
### If you don't need...
|
||||||
|
@ -115,6 +121,9 @@ you can skip the installation of `qt5-qtbase-devel`.
|
||||||
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
||||||
you can skip the installation of `python3-devel`.
|
you can skip the installation of `python3-devel`.
|
||||||
|
|
||||||
|
👉 If you don't need support for NFC ePaper devices,
|
||||||
|
you can skip the installation of `gd-devel`.
|
||||||
|
|
||||||
|
|
||||||
## On openSUSE
|
## On openSUSE
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
@ -122,7 +131,8 @@ you can skip the installation of `python3-devel`.
|
||||||
```sh
|
```sh
|
||||||
sudo zypper install git patterns-devel-base-devel_basis gcc-c++ \
|
sudo zypper install git patterns-devel-base-devel_basis gcc-c++ \
|
||||||
readline-devel libbz2-devel liblz4-devel cross-arm-none-gcc9 \
|
readline-devel libbz2-devel liblz4-devel cross-arm-none-gcc9 \
|
||||||
cross-arm-none-newlib-devel python3-devel libqt5-qtbase-devel libopenssl-devel
|
cross-arm-none-newlib-devel python3-devel libqt5-qtbase-devel \
|
||||||
|
libopenssl-devel gd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that Bluez is not available on openSUSE so the native Bluetooth support won't be available in the client.
|
Note that Bluez is not available on openSUSE so the native Bluetooth support won't be available in the client.
|
||||||
|
@ -134,6 +144,9 @@ you can skip the installation of `libqt5-qtbase-devel`.
|
||||||
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
👉 If you don't need support for Python3 scripts in the Proxmark3 client,
|
||||||
you can skip the installation of `python3-devel`.
|
you can skip the installation of `python3-devel`.
|
||||||
|
|
||||||
|
👉 If you don't need support for NFC ePaper devices,
|
||||||
|
you can skip the installation of `gd-devel`.
|
||||||
|
|
||||||
|
|
||||||
# Clone the repository
|
# Clone the repository
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
|
@ -169,11 +169,12 @@ Install dependencies:
|
||||||
```sh
|
```sh
|
||||||
sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \
|
sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \
|
||||||
libreadline-dev gcc-arm-none-eabi libnewlib-dev \
|
libreadline-dev gcc-arm-none-eabi libnewlib-dev \
|
||||||
libbz2-dev liblz4-dev libpython3-dev qtbase5-dev libssl-dev
|
libbz2-dev liblz4-dev libpython3-dev qtbase5-dev libssl-dev libgd-dev
|
||||||
```
|
```
|
||||||
_note_
|
_note_
|
||||||
If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qtbase5-dev`.
|
If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qtbase5-dev`.
|
||||||
If you don't need support for Python3 scripts in the Proxmark3 client, you can skip the installation of `libpython3-dev`.
|
If you don't need support for Python3 scripts in the Proxmark3 client, you can skip the installation of `libpython3-dev`.
|
||||||
|
If you don't need support for NFC ePaper devices, you can skip the installation of `libgd-dev`.
|
||||||
|
|
||||||
## Clone the Iceman repository
|
## Clone the Iceman repository
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
|
@ -108,12 +108,14 @@ then, install proxmark dependencies:
|
||||||
sudo apt-get install --no-install-recommends \
|
sudo apt-get install --no-install-recommends \
|
||||||
git ca-certificates build-essential pkg-config \
|
git ca-certificates build-essential pkg-config \
|
||||||
libreadline-dev gcc-arm-none-eabi libnewlib-dev \
|
libreadline-dev gcc-arm-none-eabi libnewlib-dev \
|
||||||
libbz2-dev liblz4-dev libpython3-dev qtbase5-dev libssl-dev
|
libbz2-dev liblz4-dev libpython3-dev qtbase5-dev \
|
||||||
|
libssl-dev libgd-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
_note_
|
_note_
|
||||||
If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qtbase5-dev`.
|
If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qtbase5-dev`.
|
||||||
If you don't need support for Python3 scripts in the Proxmark3 client, you can skip the installation of `libpython3-dev`.
|
If you don't need support for Python3 scripts in the Proxmark3 client, you can skip the installation of `libpython3-dev`.
|
||||||
|
If you don't need support for NFC ePaper devices, you can skip the installation of `libgd-dev`.
|
||||||
|
|
||||||
## X Server Installation
|
## X Server Installation
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
|
@ -161,7 +161,7 @@ These instructions will show how to setup the environment on OSX to the point wh
|
||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
|
|
||||||
```
|
```
|
||||||
brew install readline qt5 pkgconfig coreutils
|
brew install readline qt5 gd pkgconfig coreutils
|
||||||
brew install RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
brew install RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
||||||
```
|
```
|
||||||
3. (optional) Install makefile dependencies:
|
3. (optional) Install makefile dependencies:
|
||||||
|
|
|
@ -61,7 +61,7 @@ These instructions will show how to setup the environment on OSX to the point wh
|
||||||
2. Install dependencies:
|
2. Install dependencies:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo port install readline jansson lua52 python311 bzip2 lz4 openssl11 arm-none-eabi-gcc arm-none-eabi-binutils coreutils qt5 qt5-qtbase pkgconfig
|
sudo port install readline jansson lua52 python311 bzip2 lz4 openssl11 arm-none-eabi-gcc arm-none-eabi-binutils coreutils qt5 qt5-qtbase gd2 pkgconfig
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Clamp Python version for pkg-config
|
3. Clamp Python version for pkg-config
|
||||||
|
|
BIN
tools/lena.bmp
Normal file
BIN
tools/lena.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 117 KiB |
|
@ -535,6 +535,7 @@ while true; do
|
||||||
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test\(s\) \[ ok"; then break; fi
|
if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Test\(s\) \[ ok"; then break; fi
|
||||||
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \[ ok"; then break; fi
|
if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \[ ok"; then break; fi
|
||||||
if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \[ ok"; then break; fi
|
if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \[ ok"; then break; fi
|
||||||
|
if ! CheckExecute "hf waveshare load" "$CLIENTBIN -c 'hf waveshare load -m 6 -f tools/lena.bmp -s dither.bmp' && echo '34ff55fe7257876acf30dae00eb0e439 dither.bmp' | md5sum -c" "dither.bmp: OK"; then break; fi
|
||||||
fi
|
fi
|
||||||
echo -e "\n------------------------------------------------------------"
|
echo -e "\n------------------------------------------------------------"
|
||||||
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
|
echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue