Remove unused files and graphics app.
Factory loader : display InfiniTime logo & progress bar.
This commit is contained in:
parent
a7484e6daa
commit
9ae0550a84
13629
factory/image2.h
13629
factory/image2.h
File diff suppressed because it is too large
Load Diff
@ -425,24 +425,6 @@ list(APPEND FACTORY_SOURCE_FILES
|
||||
|
||||
)
|
||||
|
||||
list(APPEND GRAPHICS_SOURCE_FILES
|
||||
# FreeRTOS
|
||||
FreeRTOS/port.c
|
||||
FreeRTOS/port_cmsis_systick.c
|
||||
FreeRTOS/port_cmsis.c
|
||||
|
||||
drivers/SpiNorFlash.cpp
|
||||
drivers/SpiMaster.cpp
|
||||
drivers/Spi.cpp
|
||||
logging/NrfLogger.cpp
|
||||
|
||||
components/gfx/Gfx.cpp
|
||||
drivers/St7789.cpp
|
||||
components/brightness/BrightnessController.cpp
|
||||
|
||||
graphics.cpp
|
||||
)
|
||||
|
||||
list(APPEND FACTORYLOADER_SOURCE_FILES
|
||||
# FreeRTOS
|
||||
FreeRTOS/port.c
|
||||
@ -454,10 +436,13 @@ list(APPEND FACTORYLOADER_SOURCE_FILES
|
||||
drivers/Spi.cpp
|
||||
logging/NrfLogger.cpp
|
||||
|
||||
components/rle/RleDecoder.cpp
|
||||
|
||||
components/gfx/Gfx.cpp
|
||||
drivers/St7789.cpp
|
||||
components/brightness/BrightnessController.cpp
|
||||
|
||||
displayapp/icons/infinitime/infinitime-nb.c
|
||||
factory.cpp
|
||||
)
|
||||
|
||||
@ -736,35 +721,6 @@ add_custom_command(TARGET ${EXECUTABLE_MCUBOOT_NAME}
|
||||
COMMENT "post build steps for ${EXECUTABLE_MCUBOOT_FILE_NAME}"
|
||||
)
|
||||
|
||||
# Build binary that writes the graphic assets for the bootloader
|
||||
set(EXECUTABLE_GRAPHICS_NAME "pinetime-graphics")
|
||||
set(EXECUTABLE_GRAPHICS_FILE_NAME ${EXECUTABLE_GRAPHICS_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
add_executable(${EXECUTABLE_GRAPHICS_NAME} ${GRAPHICS_SOURCE_FILES})
|
||||
target_link_libraries(${EXECUTABLE_GRAPHICS_NAME} nrf-sdk)
|
||||
set_target_properties(${EXECUTABLE_GRAPHICS_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_GRAPHICS_FILE_NAME})
|
||||
target_compile_options(${EXECUTABLE_GRAPHICS_NAME} PUBLIC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3>
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3>
|
||||
$<$<COMPILE_LANGUAGE:ASM>: -MP -MD -std=c99 -x assembler-with-cpp>
|
||||
)
|
||||
|
||||
set_target_properties(${EXECUTABLE_GRAPHICS_NAME} PROPERTIES
|
||||
SUFFIX ".out"
|
||||
LINK_FLAGS "-mthumb -mabi=aapcs -std=gnu++98 -std=c99 -L ${NRF5_SDK_PATH}/modules/nrfx/mdk -T${NRF5_LINKER_SCRIPT} -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wl,--gc-sections --specs=nano.specs -lc -lnosys -lm -Wl,-Map=${EXECUTABLE_GRAPHICS_FILE_NAME}.map"
|
||||
CXX_STANDARD 11
|
||||
C_STANDARD 99
|
||||
)
|
||||
|
||||
add_custom_command(TARGET ${EXECUTABLE_GRAPHICS_NAME}
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_SIZE_UTIL} ${EXECUTABLE_GRAPHICS_FILE_NAME}.out
|
||||
COMMAND ${CMAKE_OBJCOPY} -O binary ${EXECUTABLE_GRAPHICS_FILE_NAME}.out "${EXECUTABLE_GRAPHICS_FILE_NAME}.bin"
|
||||
COMMAND ${CMAKE_OBJCOPY} -O ihex ${EXECUTABLE_GRAPHICS_FILE_NAME}.out "${EXECUTABLE_GRAPHICS_FILE_NAME}.hex"
|
||||
COMMENT "post build steps for ${EXECUTABLE_GRAPHICS_FILE_NAME}"
|
||||
)
|
||||
|
||||
# infinitime-light
|
||||
set(EXECUTABLE_FACTORY_NAME "pinetime-factory")
|
||||
set(EXECUTABLE_FACTORY_FILE_NAME ${EXECUTABLE_FACTORY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH})
|
||||
|
32
src/components/rle/RleDecoder.cpp
Normal file
32
src/components/rle/RleDecoder.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "RleDecoder.h"
|
||||
|
||||
using namespace Pinetime::Tools;
|
||||
|
||||
RleDecoder::RleDecoder(const uint8_t *buffer, size_t size) : buffer{buffer}, size{size} {
|
||||
|
||||
}
|
||||
|
||||
void RleDecoder::DecodeNext(uint8_t *output, size_t maxBytes) {
|
||||
for (;encodedBufferIndex<size; encodedBufferIndex++) {
|
||||
uint8_t rl = buffer[encodedBufferIndex] - processedCount;
|
||||
while (rl) {
|
||||
output[bp] = color >> 8;
|
||||
output[bp + 1] = color & 0xff;
|
||||
bp += 2;
|
||||
rl -= 1;
|
||||
processedCount++;
|
||||
|
||||
if (bp >= maxBytes) {
|
||||
bp = 0;
|
||||
y += 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
processedCount = 0;
|
||||
|
||||
if (color == backgroundColor)
|
||||
color = foregroundColor;
|
||||
else
|
||||
color = backgroundColor;
|
||||
}
|
||||
}
|
32
src/components/rle/RleDecoder.h
Normal file
32
src/components/rle/RleDecoder.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace Pinetime {
|
||||
namespace Tools {
|
||||
/* 1-bit RLE decoder. Provide the encoded buffer to the constructor and then call DecodeNext() by
|
||||
* specifying the output (decoded) buffer and the maximum number of bytes this buffer can handle.
|
||||
*
|
||||
* Code from https://github.com/daniel-thompson/wasp-bootloader by Daniel Thompson released under the MIT license.
|
||||
*/
|
||||
class RleDecoder {
|
||||
public:
|
||||
RleDecoder(const uint8_t* buffer, size_t size);
|
||||
|
||||
void DecodeNext(uint8_t* output, size_t maxBytes);
|
||||
|
||||
private:
|
||||
const uint8_t* buffer;
|
||||
size_t size;
|
||||
|
||||
int encodedBufferIndex = 0;
|
||||
int y = 0;
|
||||
uint16_t bp = 0;
|
||||
static constexpr uint16_t foregroundColor = 0xffff;
|
||||
static constexpr uint16_t backgroundColor = 0;
|
||||
uint16_t color = backgroundColor;
|
||||
int processedCount = 0;
|
||||
};
|
||||
}
|
||||
}
|
127
src/displayapp/icons/infinitime/infinitime-nb.c
Normal file
127
src/displayapp/icons/infinitime/infinitime-nb.c
Normal file
@ -0,0 +1,127 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
// 1-bit RLE, generated from ./infinitime-nb.png, 1445 bytes
|
||||
static const uint8_t infinitime_nb[] = {
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0x66, 0x2, 0xed, 0x4, 0xec, 0x5,
|
||||
0xea, 0x7, 0xe8, 0x9, 0xe6, 0xa, 0xe5, 0xc, 0xe3, 0xe, 0xe1, 0x10,
|
||||
0xdf, 0x12, 0xde, 0x12, 0xdd, 0x14, 0xdb, 0x16, 0xd9, 0x18, 0xd7, 0x1a,
|
||||
0xd5, 0x1b, 0xd4, 0x1d, 0xd3, 0xd, 0x3, 0xe, 0xd1, 0xd, 0x5, 0xe,
|
||||
0xcf, 0xe, 0x5, 0xf, 0xcd, 0xf, 0x5, 0xf, 0xcc, 0x10, 0x5, 0x10,
|
||||
0xca, 0x11, 0x5, 0x11, 0xc8, 0x12, 0x5, 0x12, 0xc6, 0x13, 0x5, 0x13,
|
||||
0xc5, 0x13, 0x5, 0x13, 0xc4, 0x14, 0x5, 0x14, 0xc2, 0x15, 0x5, 0x15,
|
||||
0xc0, 0x17, 0x3, 0x17, 0xbe, 0x33, 0xbc, 0x34, 0xbb, 0x36, 0xba, 0x37,
|
||||
0xb8, 0x39, 0xb6, 0x3b, 0xb4, 0x3c, 0xb3, 0x3e, 0xb1, 0x40, 0xaf, 0x9,
|
||||
0x2, 0x2e, 0x1, 0x8, 0xad, 0x9, 0x4, 0x2c, 0x3, 0x8, 0xac, 0x8,
|
||||
0x6, 0x2a, 0x5, 0x7, 0xab, 0x9, 0x6, 0x29, 0x6, 0x8, 0xa9, 0xb,
|
||||
0x5, 0x29, 0x5, 0xa, 0xa7, 0xd, 0x3, 0x2b, 0x3, 0xc, 0xa5, 0x4c,
|
||||
0xa3, 0x4d, 0xa2, 0x4f, 0xa0, 0x51, 0x9f, 0x52, 0x9d, 0x54, 0x9b, 0x55,
|
||||
0x9a, 0x57, 0x98, 0x59, 0x96, 0x5b, 0x94, 0x5d, 0x93, 0x5d, 0x92, 0x5f,
|
||||
0x90, 0x61, 0x8e, 0x63, 0x8c, 0x65, 0x8a, 0x66, 0x89, 0x68, 0x87, 0x8,
|
||||
0x2, 0x59, 0x2, 0x5, 0x86, 0x7, 0x4, 0x57, 0x4, 0x5, 0x84, 0x8,
|
||||
0x5, 0x55, 0x6, 0x5, 0x82, 0x9, 0x6, 0x54, 0x6, 0x5, 0x81, 0xa,
|
||||
0x5, 0x55, 0x5, 0x7, 0x7f, 0xc, 0x4, 0x56, 0x3, 0x9, 0x7d, 0x74,
|
||||
0x7b, 0x76, 0x79, 0x77, 0x79, 0x78, 0x77, 0x7a, 0x75, 0x7c, 0x73, 0x7e,
|
||||
0x71, 0x7f, 0x70, 0x81, 0x6e, 0x83, 0x6c, 0x85, 0x6b, 0x86, 0x69, 0x87,
|
||||
0x68, 0x89, 0x66, 0x8b, 0x64, 0x8d, 0x62, 0x8f, 0x60, 0x90, 0x60, 0x91,
|
||||
0x5e, 0x93, 0x5c, 0x95, 0x5a, 0xe, 0x7, 0x71, 0x7, 0xa, 0x58, 0xd,
|
||||
0xb, 0x6d, 0xb, 0x8, 0x57, 0xe, 0xc, 0x6c, 0xc, 0x8, 0x55, 0xf,
|
||||
0xc, 0x6c, 0xb, 0xa, 0x53, 0x11, 0xa, 0x6d, 0xb, 0xb, 0x52, 0x9f,
|
||||
0x50, 0xa0, 0x4f, 0xa2, 0x4d, 0xa4, 0x4b, 0xa6, 0x49, 0xa8, 0x48, 0xa8,
|
||||
0xff, 0x0, 0xe3, 0x44, 0xad, 0x43, 0xae, 0x41, 0xb0, 0x40, 0xb1, 0x3e,
|
||||
0xb2, 0x3e, 0xb3, 0x3c, 0xb5, 0x3a, 0xb7, 0x39, 0xb8, 0x37, 0xb9, 0x36,
|
||||
0xbb, 0x35, 0xe, 0x1, 0x66, 0x1, 0x3c, 0x1, 0x9, 0x33, 0xe, 0x3,
|
||||
0x15, 0x5, 0xe, 0x4, 0x16, 0x15, 0xd, 0x3, 0x11, 0x5, 0xe, 0x4,
|
||||
0x12, 0x3, 0x9, 0x31, 0xf, 0x4, 0x14, 0x6, 0xd, 0x4, 0x16, 0x15,
|
||||
0xd, 0x4, 0x10, 0x5, 0xe, 0x4, 0x12, 0x4, 0x9, 0x30, 0xf, 0x4,
|
||||
0x14, 0x6, 0xd, 0x4, 0x16, 0x15, 0xd, 0x4, 0x10, 0x6, 0xd, 0x4,
|
||||
0x12, 0x4, 0x9, 0x2f, 0x10, 0x4, 0x14, 0x7, 0xc, 0x4, 0x16, 0x15,
|
||||
0xd, 0x4, 0x10, 0x6, 0xd, 0x4, 0x12, 0x4, 0xa, 0x2d, 0x11, 0x4,
|
||||
0x14, 0x7, 0xc, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x7, 0xc, 0x4,
|
||||
0x12, 0x4, 0xb, 0x2c, 0x11, 0x4, 0x14, 0x8, 0xb, 0x4, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x7, 0xc, 0x4, 0x12, 0x4, 0xc, 0x2a, 0x12, 0x4,
|
||||
0x14, 0x8, 0xb, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x8, 0xb, 0x4,
|
||||
0x12, 0x4, 0xd, 0x28, 0x13, 0x4, 0x14, 0x4, 0x1, 0x4, 0xa, 0x4,
|
||||
0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x1, 0x3, 0xb, 0x4, 0x12, 0x4,
|
||||
0xd, 0x28, 0x13, 0x4, 0x14, 0x4, 0x1, 0x4, 0xa, 0x4, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0x1, 0x4, 0xa, 0x4, 0x12, 0x4, 0xe, 0x26,
|
||||
0x14, 0x4, 0x14, 0x4, 0x2, 0x4, 0x9, 0x4, 0x16, 0x4, 0x1e, 0x4,
|
||||
0x10, 0x4, 0x2, 0x3, 0xa, 0x4, 0x12, 0x4, 0xf, 0x24, 0x15, 0x4,
|
||||
0x14, 0x4, 0x2, 0x4, 0x9, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4,
|
||||
0x2, 0x4, 0x9, 0x4, 0x12, 0x4, 0x10, 0x23, 0x15, 0x4, 0x14, 0x4,
|
||||
0x3, 0x4, 0x8, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x2, 0x4,
|
||||
0x9, 0x4, 0x12, 0x4, 0x11, 0x21, 0x16, 0x4, 0x14, 0x4, 0x3, 0x4,
|
||||
0x8, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x3, 0x4, 0x8, 0x4,
|
||||
0x12, 0x4, 0x11, 0x20, 0x17, 0x4, 0x14, 0x4, 0x4, 0x3, 0x8, 0x4,
|
||||
0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x3, 0x4, 0x8, 0x4, 0x12, 0x4,
|
||||
0x12, 0x1f, 0x17, 0x4, 0x14, 0x4, 0x4, 0x4, 0x7, 0x4, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0x4, 0x3, 0x8, 0x4, 0x12, 0x4, 0x13, 0x1d,
|
||||
0x18, 0x4, 0x14, 0x4, 0x5, 0x3, 0x7, 0x4, 0x16, 0x13, 0xf, 0x4,
|
||||
0x10, 0x4, 0x4, 0x4, 0x7, 0x4, 0x12, 0x4, 0x14, 0x1b, 0x1a, 0x3,
|
||||
0x14, 0x4, 0x5, 0x4, 0x6, 0x4, 0x16, 0x13, 0x10, 0x3, 0x10, 0x4,
|
||||
0x5, 0x3, 0x7, 0x4, 0x13, 0x3, 0x15, 0x1a, 0x1b, 0x1, 0x15, 0x4,
|
||||
0x6, 0x3, 0x6, 0x4, 0x16, 0x13, 0x11, 0x1, 0x11, 0x4, 0x5, 0x4,
|
||||
0x6, 0x4, 0x14, 0x1, 0x16, 0x19, 0x32, 0x4, 0x6, 0x4, 0x5, 0x4,
|
||||
0x16, 0x13, 0x23, 0x4, 0x6, 0x3, 0x6, 0x4, 0x2c, 0x17, 0x33, 0x4,
|
||||
0x7, 0x3, 0x5, 0x4, 0x16, 0x4, 0x32, 0x4, 0x6, 0x4, 0x5, 0x4,
|
||||
0x2d, 0x16, 0x1d, 0x1, 0x15, 0x4, 0x7, 0x4, 0x4, 0x4, 0x16, 0x4,
|
||||
0x20, 0x1, 0x11, 0x4, 0x7, 0x3, 0x5, 0x4, 0x14, 0x1, 0x19, 0x14,
|
||||
0x1d, 0x3, 0x14, 0x4, 0x7, 0x4, 0x4, 0x4, 0x16, 0x4, 0x1f, 0x3,
|
||||
0x10, 0x4, 0x7, 0x4, 0x4, 0x4, 0x13, 0x3, 0x19, 0x12, 0x1d, 0x4,
|
||||
0x14, 0x4, 0x8, 0x4, 0x3, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4,
|
||||
0x8, 0x3, 0x4, 0x4, 0x12, 0x4, 0x19, 0x12, 0x1d, 0x4, 0x14, 0x4,
|
||||
0x8, 0x4, 0x3, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x8, 0x4,
|
||||
0x3, 0x4, 0x12, 0x4, 0x1a, 0x10, 0x1e, 0x4, 0x14, 0x4, 0x9, 0x3,
|
||||
0x3, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x8, 0x4, 0x3, 0x4,
|
||||
0x12, 0x4, 0x1b, 0xe, 0x1f, 0x4, 0x14, 0x4, 0x9, 0x4, 0x2, 0x4,
|
||||
0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0x9, 0x4, 0x2, 0x4, 0x12, 0x4,
|
||||
0x1c, 0xd, 0x1f, 0x4, 0x14, 0x4, 0xa, 0x3, 0x2, 0x4, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0x9, 0x4, 0x2, 0x4, 0x12, 0x4, 0x1d, 0xb,
|
||||
0x20, 0x4, 0x14, 0x4, 0xa, 0x4, 0x1, 0x4, 0x16, 0x4, 0x1e, 0x4,
|
||||
0x10, 0x4, 0xa, 0x3, 0x2, 0x4, 0x12, 0x4, 0x1d, 0xb, 0x20, 0x4,
|
||||
0x14, 0x4, 0xb, 0x3, 0x1, 0x4, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4,
|
||||
0xa, 0x4, 0x1, 0x4, 0x12, 0x4, 0x1e, 0x9, 0x21, 0x4, 0x14, 0x4,
|
||||
0xb, 0x8, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0xb, 0x3, 0x1, 0x4,
|
||||
0x12, 0x4, 0x1f, 0x7, 0x22, 0x4, 0x14, 0x4, 0xc, 0x7, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0xb, 0x8, 0x12, 0x4, 0x20, 0x6, 0x22, 0x4,
|
||||
0x14, 0x4, 0xc, 0x7, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0xc, 0x7,
|
||||
0x12, 0x4, 0x21, 0x4, 0x23, 0x4, 0x14, 0x4, 0xd, 0x6, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0xc, 0x7, 0x12, 0x4, 0x21, 0x3, 0x24, 0x4,
|
||||
0x14, 0x4, 0xd, 0x6, 0x16, 0x4, 0x1e, 0x4, 0x10, 0x4, 0xd, 0x6,
|
||||
0x12, 0x4, 0x22, 0x2, 0x24, 0x4, 0x14, 0x4, 0xd, 0x6, 0x16, 0x4,
|
||||
0x1e, 0x4, 0x10, 0x4, 0xd, 0x6, 0x12, 0x4, 0x48, 0x3, 0x15, 0x4,
|
||||
0xe, 0x5, 0x16, 0x4, 0x1e, 0x3, 0x11, 0x4, 0xd, 0x6, 0x12, 0x3,
|
||||
0x4a, 0x1, 0x66, 0x1, 0x3c, 0x1, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0x10, 0x11,
|
||||
0xf, 0x9, 0xf, 0x4, 0x9, 0x4, 0xd, 0xf, 0x8b, 0x11, 0xf, 0x9,
|
||||
0xf, 0x5, 0x7, 0x5, 0xd, 0xf, 0x8b, 0x11, 0xf, 0x9, 0xf, 0x5,
|
||||
0x7, 0x5, 0xd, 0xf, 0x92, 0x3, 0x19, 0x3, 0x12, 0x6, 0x5, 0x6,
|
||||
0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x6, 0x5, 0x6, 0xd, 0x3,
|
||||
0x9e, 0x3, 0x19, 0x3, 0x12, 0x6, 0x5, 0x6, 0xd, 0x3, 0x9e, 0x3,
|
||||
0x19, 0x3, 0x12, 0x3, 0x1, 0x3, 0x3, 0x3, 0x1, 0x3, 0xd, 0x3,
|
||||
0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0x2, 0x2, 0x3, 0x2, 0x2, 0x3,
|
||||
0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0x2, 0x3, 0x1, 0x3,
|
||||
0x2, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0x2, 0x3,
|
||||
0x1, 0x3, 0x2, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x3, 0x5, 0x3, 0x3, 0xd, 0xd, 0x94, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x3, 0x5, 0x3, 0x3, 0xd, 0xd, 0x94, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x4, 0x3, 0x4, 0x3, 0xd, 0xd, 0x94, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x4, 0x3, 0x4, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x5, 0x1, 0x5, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0x5, 0x1, 0x5, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3,
|
||||
0xb, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0xb, 0x3,
|
||||
0xd, 0x3, 0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0xb, 0x3, 0xd, 0x3,
|
||||
0x9e, 0x3, 0x19, 0x3, 0x12, 0x3, 0xb, 0x3, 0xd, 0x3, 0x9e, 0x3,
|
||||
0x19, 0x3, 0x12, 0x3, 0xb, 0x3, 0xd, 0x3, 0x9e, 0x3, 0x19, 0x3,
|
||||
0x12, 0x3, 0xb, 0x3, 0xd, 0xf, 0x92, 0x3, 0x16, 0x9, 0xf, 0x3,
|
||||
0xb, 0x3, 0xd, 0xf, 0x92, 0x3, 0x16, 0x9, 0xf, 0x3, 0xb, 0x3,
|
||||
0xd, 0xf, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0,
|
||||
0xff, 0x0, 0xff, 0x0, 0xec,
|
||||
};
|
BIN
src/displayapp/icons/infinitime/infinitime-nb.png
Normal file
BIN
src/displayapp/icons/infinitime/infinitime-nb.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -15,6 +15,9 @@
|
||||
#include <components/brightness/BrightnessController.h>
|
||||
#include "factoryImage.h"
|
||||
|
||||
#include "displayapp/icons/infinitime/infinitime-nb.c"
|
||||
#include "components/rle/RleDecoder.h"
|
||||
|
||||
|
||||
#if NRF_LOG_ENABLED
|
||||
#include "logging/NrfLogger.h"
|
||||
@ -31,6 +34,13 @@ static constexpr uint8_t pinSpiFlashCsn = 5;
|
||||
static constexpr uint8_t pinLcdCsn = 25;
|
||||
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||
|
||||
static constexpr uint8_t displayWidth = 240;
|
||||
static constexpr uint8_t displayHeight = 240;
|
||||
static constexpr uint8_t bytesPerPixel = 2;
|
||||
|
||||
static constexpr uint16_t colorWhite = 0xFFFF;
|
||||
static constexpr uint16_t colorGreen = 0xE007;
|
||||
|
||||
Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {
|
||||
Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||
@ -49,6 +59,10 @@ Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
|
||||
Pinetime::Components::Gfx gfx{lcd};
|
||||
Pinetime::Controllers::BrightnessController brightnessController;
|
||||
|
||||
void DisplayProgressBar(uint8_t percent, uint16_t color);
|
||||
|
||||
void DisplayLogo();
|
||||
|
||||
extern "C" {
|
||||
void vApplicationIdleHook(void) {
|
||||
|
||||
@ -71,10 +85,8 @@ void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t displayBuffer[displayWidth * bytesPerPixel];
|
||||
void Process(void* instance) {
|
||||
// Wait before erasing the memory to let the time to the SWD debugger to flash a new firmware before running this one.
|
||||
vTaskDelay(5000);
|
||||
|
||||
APP_GPIOTE_INIT(2);
|
||||
|
||||
NRF_LOG_INFO("Init...");
|
||||
@ -84,49 +96,52 @@ void Process(void* instance) {
|
||||
brightnessController.Init();
|
||||
lcd.Init();
|
||||
gfx.Init();
|
||||
NRF_LOG_INFO("Init Done!")
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
for(int j = 0; j < 100; j++) {
|
||||
gfx.pixel_draw(70+i, 70+j, 0x00AA);
|
||||
}
|
||||
}
|
||||
NRF_LOG_INFO("Display logo")
|
||||
DisplayLogo();
|
||||
|
||||
NRF_LOG_INFO("Erasing...");
|
||||
for (uint32_t erased = 0; erased < sizeof(factoryImage); erased += 0x1000) {
|
||||
spiNorFlash.SectorErase(erased);
|
||||
}
|
||||
NRF_LOG_INFO("Erase done!");
|
||||
|
||||
NRF_LOG_INFO("Writing graphic...");
|
||||
for(int i = 0; i < 100; i++) {
|
||||
for(int j = 0; j < 100; j++) {
|
||||
gfx.pixel_draw(70+i, 70+j, 0xaa00);
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("Writing factory image...");
|
||||
static constexpr uint32_t memoryChunkSize = 200;
|
||||
uint8_t writeBuffer[memoryChunkSize];
|
||||
for(size_t offset = 0; offset < sizeof(factoryImage); offset+=memoryChunkSize) {
|
||||
std::memcpy(writeBuffer, &factoryImage[offset], memoryChunkSize);
|
||||
spiNorFlash.Write(offset, writeBuffer, memoryChunkSize);
|
||||
DisplayProgressBar((static_cast<float>(offset) / static_cast<float>(sizeof(factoryImage))) * 100.0f, colorWhite);
|
||||
}
|
||||
NRF_LOG_INFO("Writing graphic done!");
|
||||
|
||||
for(int i = 0; i < 100; i++) {
|
||||
for(int j = 0; j < 100; j++) {
|
||||
gfx.pixel_draw(70+i, 70+j, 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NRF_LOG_INFO("Done!");
|
||||
NRF_LOG_INFO("Writing factory image done!");
|
||||
DisplayProgressBar(100.0f, colorGreen);
|
||||
|
||||
while(1) {
|
||||
asm("nop" );
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayLogo() {
|
||||
Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb));
|
||||
for(int i = 0; i < displayWidth; i++) {
|
||||
rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel);
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
lcd.BeginDrawBuffer(0, i, displayWidth, 1);
|
||||
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), displayWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayProgressBar(uint8_t percent, uint16_t color) {
|
||||
static constexpr uint8_t barHeight = 20;
|
||||
std::fill(displayBuffer, displayBuffer+(displayWidth * bytesPerPixel), color);
|
||||
for(int i = 0; i < barHeight; i++) {
|
||||
ulTaskNotifyTake(pdTRUE, 500);
|
||||
uint16_t barWidth = std::min(static_cast<float>(percent) * 2.4f, static_cast<float>(displayWidth));
|
||||
lcd.BeginDrawBuffer(0, displayWidth - barHeight + i, barWidth, 1);
|
||||
lcd.NextDrawBuffer(reinterpret_cast<const uint8_t *>(displayBuffer), barWidth * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
TaskHandle_t taskHandle;
|
||||
|
||||
|
136
src/graphics.cpp
136
src/graphics.cpp
@ -1,136 +0,0 @@
|
||||
#include <legacy/nrf_drv_clock.h>
|
||||
#include <softdevice/common/nrf_sdh.h>
|
||||
#include <drivers/SpiMaster.h>
|
||||
#include <drivers/Spi.h>
|
||||
#include <drivers/SpiNorFlash.h>
|
||||
#include <libraries/log/nrf_log.h>
|
||||
#include "bootloader/boot_graphics.h"
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <legacy/nrf_drv_gpiote.h>
|
||||
#include <libraries/gpiote/app_gpiote.h>
|
||||
#include <hal/nrf_wdt.h>
|
||||
#include <cstring>
|
||||
#include <components/gfx/Gfx.h>
|
||||
#include <drivers/St7789.h>
|
||||
#include <components/brightness/BrightnessController.h>
|
||||
|
||||
#if NRF_LOG_ENABLED
|
||||
#include "logging/NrfLogger.h"
|
||||
Pinetime::Logging::NrfLogger logger;
|
||||
#else
|
||||
#include "logging/DummyLogger.h"
|
||||
Pinetime::Logging::DummyLogger logger;
|
||||
#endif
|
||||
|
||||
static constexpr uint8_t pinSpiSck = 2;
|
||||
static constexpr uint8_t pinSpiMosi = 3;
|
||||
static constexpr uint8_t pinSpiMiso = 4;
|
||||
static constexpr uint8_t pinSpiFlashCsn = 5;
|
||||
static constexpr uint8_t pinLcdCsn = 25;
|
||||
static constexpr uint8_t pinLcdDataCommand = 18;
|
||||
|
||||
Pinetime::Drivers::SpiMaster spi{Pinetime::Drivers::SpiMaster::SpiModule::SPI0, {
|
||||
Pinetime::Drivers::SpiMaster::BitOrder::Msb_Lsb,
|
||||
Pinetime::Drivers::SpiMaster::Modes::Mode3,
|
||||
Pinetime::Drivers::SpiMaster::Frequencies::Freq8Mhz,
|
||||
pinSpiSck,
|
||||
pinSpiMosi,
|
||||
pinSpiMiso
|
||||
}
|
||||
};
|
||||
Pinetime::Drivers::Spi flashSpi{spi, pinSpiFlashCsn};
|
||||
Pinetime::Drivers::SpiNorFlash spiNorFlash{flashSpi};
|
||||
|
||||
Pinetime::Drivers::Spi lcdSpi {spi, pinLcdCsn};
|
||||
Pinetime::Drivers::St7789 lcd {lcdSpi, pinLcdDataCommand};
|
||||
|
||||
Pinetime::Components::Gfx gfx{lcd};
|
||||
Pinetime::Controllers::BrightnessController brightnessController;
|
||||
|
||||
extern "C" {
|
||||
void vApplicationIdleHook(void) {
|
||||
|
||||
}
|
||||
|
||||
void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) {
|
||||
if(((NRF_SPIM0->INTENSET & (1<<6)) != 0) && NRF_SPIM0->EVENTS_END == 1) {
|
||||
NRF_SPIM0->EVENTS_END = 0;
|
||||
spi.OnEndEvent();
|
||||
}
|
||||
|
||||
if(((NRF_SPIM0->INTENSET & (1<<19)) != 0) && NRF_SPIM0->EVENTS_STARTED == 1) {
|
||||
NRF_SPIM0->EVENTS_STARTED = 0;
|
||||
spi.OnStartedEvent();
|
||||
}
|
||||
|
||||
if(((NRF_SPIM0->INTENSET & (1<<1)) != 0) && NRF_SPIM0->EVENTS_STOPPED == 1) {
|
||||
NRF_SPIM0->EVENTS_STOPPED = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Process(void* instance) {
|
||||
// Wait before erasing the memory to let the time to the SWD debugger to flash a new firmware before running this one.
|
||||
vTaskDelay(5000);
|
||||
|
||||
APP_GPIOTE_INIT(2);
|
||||
|
||||
NRF_LOG_INFO("Init...");
|
||||
spi.Init();
|
||||
spiNorFlash.Init();
|
||||
spiNorFlash.Wakeup();
|
||||
brightnessController.Init();
|
||||
lcd.Init();
|
||||
gfx.Init();
|
||||
NRF_LOG_INFO("Init Done!")
|
||||
|
||||
NRF_LOG_INFO("Erasing...");
|
||||
for (uint32_t erased = 0; erased < graphicSize; erased += 0x1000) {
|
||||
spiNorFlash.SectorErase(erased);
|
||||
}
|
||||
NRF_LOG_INFO("Erase done!");
|
||||
|
||||
NRF_LOG_INFO("Writing graphic...");
|
||||
static constexpr uint32_t memoryChunkSize = 200;
|
||||
uint8_t writeBuffer[memoryChunkSize];
|
||||
for(int offset = 0; offset < 115200; offset+=memoryChunkSize) {
|
||||
std::memcpy(writeBuffer, &graphicBuffer[offset], memoryChunkSize);
|
||||
spiNorFlash.Write(offset, writeBuffer, memoryChunkSize);
|
||||
}
|
||||
NRF_LOG_INFO("Writing graphic done!");
|
||||
|
||||
NRF_LOG_INFO("Read memory and display the graphic...");
|
||||
static constexpr uint32_t screenWidth = 240;
|
||||
static constexpr uint32_t screenWidthInBytes = screenWidth*2; // LCD display 16bits color (1 pixel = 2 bytes)
|
||||
uint16_t displayLineBuffer[screenWidth];
|
||||
for(uint32_t line = 0; line < screenWidth; line++) {
|
||||
spiNorFlash.Read(line*screenWidthInBytes, reinterpret_cast<uint8_t *>(displayLineBuffer), screenWidth);
|
||||
spiNorFlash.Read((line*screenWidthInBytes)+screenWidth, reinterpret_cast<uint8_t *>(displayLineBuffer) + screenWidth, screenWidth);
|
||||
for(uint32_t col = 0; col < screenWidth; col++) {
|
||||
gfx.pixel_draw(col, line, displayLineBuffer[col]);
|
||||
}
|
||||
}
|
||||
|
||||
NRF_LOG_INFO("Done!");
|
||||
|
||||
while(1) {
|
||||
asm("nop" );
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
TaskHandle_t taskHandle;
|
||||
|
||||
logger.Init();
|
||||
nrf_drv_clock_init();
|
||||
|
||||
if (pdPASS != xTaskCreate(Process, "MAIN", 512, nullptr, 0, &taskHandle))
|
||||
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
|
||||
|
||||
vTaskStartScheduler();
|
||||
|
||||
for (;;) {
|
||||
APP_ERROR_HANDLER(NRF_ERROR_FORBIDDEN);
|
||||
}
|
||||
}
|
379
tools/rle_encode.py
Executable file
379
tools/rle_encode.py
Executable file
@ -0,0 +1,379 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
# Copyright (C) 2020 Daniel Thompson
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os.path
|
||||
from PIL import Image
|
||||
|
||||
def clut8_rgb888(i):
|
||||
"""Reference CLUT for wasp-os.
|
||||
|
||||
Technically speaking this is not a CLUT because the we lookup the colours
|
||||
algorithmically to avoid the cost of a genuine CLUT. The palette is
|
||||
designed to be fairly easy to generate algorithmically.
|
||||
|
||||
The palette includes all 216 web-safe colours together 4 grays and
|
||||
36 additional colours that target "gaps" at the brighter end of the web
|
||||
safe set. There are 11 greys (plus black and white) although two are
|
||||
fairly close together.
|
||||
|
||||
:param int i: Index (from 0..255 inclusive) into the CLUT
|
||||
:return: 24-bit colour in RGB888 format
|
||||
"""
|
||||
if i < 216:
|
||||
rgb888 = ( i % 6) * 0x33
|
||||
rg = i // 6
|
||||
rgb888 += (rg % 6) * 0x3300
|
||||
rgb888 += (rg // 6) * 0x330000
|
||||
elif i < 252:
|
||||
i -= 216
|
||||
rgb888 = 0x7f + (( i % 3) * 0x33)
|
||||
rg = i // 3
|
||||
rgb888 += 0x4c00 + ((rg % 4) * 0x3300)
|
||||
rgb888 += 0x7f0000 + ((rg // 4) * 0x330000)
|
||||
else:
|
||||
i -= 252
|
||||
rgb888 = 0x2c2c2c + (0x101010 * i)
|
||||
|
||||
return rgb888
|
||||
|
||||
def clut8_rgb565(i):
|
||||
"""RBG565 CLUT for wasp-os.
|
||||
|
||||
This CLUT implements the same palette as :py:meth:`clut8_888` but
|
||||
outputs RGB565 pixels.
|
||||
|
||||
.. note::
|
||||
|
||||
This function is unused within this file but needs to be
|
||||
maintained alongside the reference clut so it is reproduced
|
||||
here.
|
||||
|
||||
:param int i: Index (from 0..255 inclusive) into the CLUT
|
||||
:return: 16-bit colour in RGB565 format
|
||||
"""
|
||||
if i < 216:
|
||||
rgb565 = (( i % 6) * 0x33) >> 3
|
||||
rg = i // 6
|
||||
rgb565 += ((rg % 6) * (0x33 << 3)) & 0x07e0
|
||||
rgb565 += ((rg // 6) * (0x33 << 8)) & 0xf800
|
||||
elif i < 252:
|
||||
i -= 216
|
||||
rgb565 = (0x7f + (( i % 3) * 0x33)) >> 3
|
||||
rg = i // 3
|
||||
rgb565 += ((0x4c << 3) + ((rg % 4) * (0x33 << 3))) & 0x07e0
|
||||
rgb565 += ((0x7f << 8) + ((rg // 4) * (0x33 << 8))) & 0xf800
|
||||
else:
|
||||
i -= 252
|
||||
gr6 = (0x2c + (0x10 * i)) >> 2
|
||||
gr5 = gr6 >> 1
|
||||
rgb565 = (gr5 << 11) + (gr6 << 5) + gr5
|
||||
|
||||
return rgb565
|
||||
|
||||
class ReverseCLUT:
|
||||
def __init__(self, clut):
|
||||
l = []
|
||||
for i in range(256):
|
||||
l.append(clut(i))
|
||||
self.clut = tuple(l)
|
||||
self.lookup = {}
|
||||
|
||||
def __call__(self, rgb888):
|
||||
"""Compare rgb888 to every element of the CLUT and pick the
|
||||
closest match.
|
||||
"""
|
||||
if rgb888 in self.lookup:
|
||||
return self.lookup[rgb888]
|
||||
|
||||
best = 200000
|
||||
index = -1
|
||||
clut = self.clut
|
||||
r = rgb888 >> 16
|
||||
g = (rgb888 >> 8) & 0xff
|
||||
b = rgb888 & 0xff
|
||||
|
||||
for i in range(256):
|
||||
candidate = clut[i]
|
||||
rd = r - (candidate >> 16)
|
||||
gd = g - ((candidate >> 8) & 0xff)
|
||||
bd = b - (candidate & 0xff)
|
||||
# This is the Euclidian distance (squared)
|
||||
distance = rd * rd + gd * gd + bd * bd
|
||||
if distance < best:
|
||||
best = distance
|
||||
index = i
|
||||
|
||||
self.lookup[rgb888] = index
|
||||
#print(f'# #{rgb888:06x} -> #{clut8_rgb888(index):06x}')
|
||||
return index
|
||||
|
||||
def varname(p):
|
||||
return os.path.basename(os.path.splitext(p)[0])
|
||||
|
||||
def encode(im):
|
||||
pixels = im.load()
|
||||
|
||||
rle = []
|
||||
rl = 0
|
||||
px = pixels[0, 0]
|
||||
|
||||
def encode_pixel(px, rl):
|
||||
while rl > 255:
|
||||
rle.append(255)
|
||||
rle.append(0)
|
||||
rl -= 255
|
||||
rle.append(rl)
|
||||
|
||||
for y in range(im.height):
|
||||
for x in range(im.width):
|
||||
newpx = pixels[x, y]
|
||||
if newpx == px:
|
||||
rl += 1
|
||||
assert(rl < (1 << 21))
|
||||
continue
|
||||
|
||||
# Code the previous run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
# Start a new run
|
||||
rl = 1
|
||||
px = newpx
|
||||
|
||||
# Handle the final run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
return (im.width, im.height, bytes(rle))
|
||||
|
||||
def encode_2bit(im):
|
||||
"""2-bit palette based RLE encoder.
|
||||
|
||||
This encoder has a reprogrammable 2-bit palette. This allows it to encode
|
||||
arbitrary images with a full 8-bit depth but the 2-byte overhead each time
|
||||
a new colour is introduced means it is not efficient unless the image is
|
||||
carefully constructed to keep a good locality of reference for the three
|
||||
non-background colours.
|
||||
|
||||
The encoding competes well with the 1-bit encoder for small monochrome
|
||||
images but once run-lengths longer than 62 start to become frequent then
|
||||
this encoding is about 30% larger than a 1-bit encoding.
|
||||
"""
|
||||
pixels = im.load()
|
||||
assert(im.width <= 255)
|
||||
assert(im.height <= 255)
|
||||
|
||||
full_palette = ReverseCLUT(clut8_rgb888)
|
||||
|
||||
rle = []
|
||||
rl = 0
|
||||
px = pixels[0, 0]
|
||||
# black, grey25, grey50, white
|
||||
palette = [0, 254, 219, 215]
|
||||
next_color = 1
|
||||
|
||||
def encode_pixel(px, rl):
|
||||
nonlocal next_color
|
||||
px = full_palette((px[0] << 16) + (px[1] << 8) + px[2])
|
||||
if px not in palette:
|
||||
rle.append(next_color << 6)
|
||||
rle.append(px)
|
||||
palette[next_color] = px
|
||||
next_color += 1
|
||||
if next_color >= len(palette):
|
||||
next_color = 1
|
||||
px = palette.index(px)
|
||||
if rl >= 63:
|
||||
rle.append((px << 6) + 63)
|
||||
rl -= 63
|
||||
while rl >= 255:
|
||||
rle.append(255)
|
||||
rl -= 255
|
||||
rle.append(rl)
|
||||
else:
|
||||
rle.append((px << 6) + rl)
|
||||
|
||||
# Issue the descriptor
|
||||
rle.append(2)
|
||||
rle.append(im.width)
|
||||
rle.append(im.height)
|
||||
|
||||
for y in range(im.height):
|
||||
for x in range(im.width):
|
||||
newpx = pixels[x, y]
|
||||
if newpx == px:
|
||||
rl += 1
|
||||
assert(rl < (1 << 21))
|
||||
continue
|
||||
|
||||
# Code the previous run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
# Start a new run
|
||||
rl = 1
|
||||
px = newpx
|
||||
|
||||
# Handle the final run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
return bytes(rle)
|
||||
|
||||
def encode_8bit(im):
|
||||
"""Experimental 8-bit RLE encoder.
|
||||
|
||||
For monochrome images this is about 3x less efficient than the 1-bit
|
||||
encoder. This encoder is not currently used anywhere in wasp-os and
|
||||
currently there is no decoder either (so don't assume this code
|
||||
actually works).
|
||||
"""
|
||||
pixels = im.load()
|
||||
|
||||
rle = []
|
||||
rl = 0
|
||||
px = pixels[0, 0]
|
||||
|
||||
def encode_pixel(px, rl):
|
||||
px = (px[0] & 0xe0) | ((px[1] & 0xe0) >> 3) | ((px[2] & 0xc0) >> 6)
|
||||
|
||||
rle.append(px)
|
||||
if rl > 0:
|
||||
rle.append(px)
|
||||
rl -= 2
|
||||
if rl > (1 << 14):
|
||||
rle.append(0x80 | ((rl >> 14) & 0x7f))
|
||||
if rl > (1 << 7):
|
||||
rle.append(0x80 | ((rl >> 7) & 0x7f))
|
||||
if rl >= 0:
|
||||
rle.append( rl & 0x7f )
|
||||
|
||||
for y in range(im.height):
|
||||
for x in range(im.width):
|
||||
newpx = pixels[x, y]
|
||||
if newpx == px:
|
||||
rl += 1
|
||||
assert(rl < (1 << 21))
|
||||
continue
|
||||
|
||||
# Code the previous run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
# Start a new run
|
||||
rl = 1
|
||||
px = newpx
|
||||
|
||||
# Handle the final run
|
||||
encode_pixel(px, rl)
|
||||
|
||||
return (im.width, im.height, bytes(rle))
|
||||
|
||||
def render_c(image, fname, indent, depth):
|
||||
extra_indent = ' ' * indent
|
||||
if len(image) == 3:
|
||||
print(f'{extra_indent}// {depth}-bit RLE, generated from {fname}, '
|
||||
f'{len(image[2])} bytes')
|
||||
(x, y, pixels) = image
|
||||
else:
|
||||
print(f'{extra_indent}// {depth}-bit RLE, generated from {fname}, '
|
||||
f'{len(image)} bytes')
|
||||
pixels = image
|
||||
|
||||
print(f'{extra_indent}static const uint8_t {varname(fname)}[] = {{')
|
||||
print(f'{extra_indent} ', end='')
|
||||
i = 0
|
||||
for rl in pixels:
|
||||
print(f' {hex(rl)},', end='')
|
||||
|
||||
i += 1
|
||||
if i == 12:
|
||||
print(f'\n{extra_indent} ', end='')
|
||||
i = 0
|
||||
print('\n};')
|
||||
|
||||
def render_py(image, fname, indent, depth):
|
||||
extra_indent = ' ' * indent
|
||||
if len(image) == 3:
|
||||
print(f'{extra_indent}# {depth}-bit RLE, generated from {fname}, '
|
||||
f'{len(image[2])} bytes')
|
||||
(x, y, pixels) = image
|
||||
print(f'{extra_indent}{varname(fname)} = (')
|
||||
print(f'{extra_indent} {x}, {y},')
|
||||
else:
|
||||
print(f'{extra_indent}# {depth}-bit RLE, generated from {fname}, '
|
||||
f'{len(image)} bytes')
|
||||
pixels = image[3:]
|
||||
print(f'{extra_indent}{varname(fname)} = (')
|
||||
print(f'{extra_indent} {image[0:1]}')
|
||||
print(f'{extra_indent} {image[1:3]}')
|
||||
|
||||
# Split the bytestring to ensure each line is short enough to
|
||||
# be absorbed on the target if needed.
|
||||
for i in range(0, len(pixels), 16):
|
||||
print(f'{extra_indent} {pixels[i:i+16]}')
|
||||
print(f'{extra_indent})')
|
||||
|
||||
|
||||
def decode_to_ascii(image):
|
||||
(sx, sy, rle) = image
|
||||
data = bytearray(2*sx)
|
||||
dp = 0
|
||||
black = ord('#')
|
||||
white = ord(' ')
|
||||
color = black
|
||||
|
||||
for rl in rle:
|
||||
while rl:
|
||||
data[dp] = color
|
||||
data[dp+1] = color
|
||||
dp += 2
|
||||
rl -= 1
|
||||
|
||||
if dp >= (2*sx):
|
||||
print(data.decode('utf-8'))
|
||||
dp = 0
|
||||
|
||||
if color == black:
|
||||
color = white
|
||||
else:
|
||||
color = black
|
||||
|
||||
# Check the image is the correct length
|
||||
assert(dp == 0)
|
||||
|
||||
parser = argparse.ArgumentParser(description='RLE encoder tool.')
|
||||
parser.add_argument('files', nargs='+',
|
||||
help='files to be encoded')
|
||||
parser.add_argument('--ascii', action='store_true',
|
||||
help='Run the resulting image(s) through an ascii art decoder')
|
||||
parser.add_argument('--c', action='store_true',
|
||||
help='Render the output as C instead of python')
|
||||
parser.add_argument('--indent', default=0, type=int,
|
||||
help='Add extra indentation in the generated code')
|
||||
parser.add_argument('--2bit', action='store_true', dest='twobit',
|
||||
help='Generate 2-bit image')
|
||||
parser.add_argument('--8bit', action='store_true', dest='eightbit',
|
||||
help='Generate 8-bit image')
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.eightbit:
|
||||
encoder = encode_8bit
|
||||
depth = 8
|
||||
elif args.twobit:
|
||||
encoder = encode_2bit
|
||||
depth = 2
|
||||
else:
|
||||
encoder = encode
|
||||
depth =1
|
||||
|
||||
for fname in args.files:
|
||||
image = encoder(Image.open(fname))
|
||||
|
||||
if args.c:
|
||||
render_c(image, fname, args.indent, depth)
|
||||
else:
|
||||
render_py(image, fname, args.indent, depth)
|
||||
|
||||
if args.ascii:
|
||||
print()
|
||||
decode_to_ascii(image)
|
Loading…
Reference in New Issue
Block a user