Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "lv_drivers"]
path = lv_drivers
url = ../../lvgl/lv_drivers.git
[submodule "libpng"]
path = libpng
url = git@github.com:glennrp/libpng.git
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,10 @@ set(VERSION_EDIT_WARNING "// Do not edit this file, it is automatically generate
configure_file("${InfiniTime_DIR}/src/Version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/Version.h")

target_include_directories(infinisim PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")

option(WITH_PNG "Compile with libpng support to dump current screen as png" ON)
if(WITH_PNG)
target_compile_definitions(infinisim PRIVATE WITH_PNG)
add_subdirectory(libpng EXCLUDE_FROM_ALL)
target_link_libraries(infinisim PRIVATE png_static)
endif()
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ Using the keyboard the following events can be triggered:
- `S` ... decrease step count by 500 steps
- `h` ... set heartrate running, and on further presses increase by 10 bpm
- `H` ... stop heartrate
- `i` ... take screenshot

## Licenses

Expand Down
1 change: 1 addition & 0 deletions libpng
Submodule libpng added at a37d48
103 changes: 103 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,112 @@
#include <algorithm>
#include <cmath> // std::pow

// additional includes for 'saveScreenshot()' function
#include <date/date.h>
#include <chrono>
#if defined(WITH_PNG)
#include <libpng16/png.h>
#endif

/*********************
* DEFINES
*********************/

/**********************
* TYPEDEFS
**********************/
// copied from lv_drivers/display/monitor.c to get the SDL_Window for the InfiniTime screen
extern "C"
{
typedef struct {
SDL_Window * window;
SDL_Renderer * renderer;
SDL_Texture * texture;
volatile bool sdl_refr_qry;
#if MONITOR_DOUBLE_BUFFERED
uint32_t * tft_fb_act;
#else
uint32_t tft_fb[LV_HOR_RES_MAX * LV_VER_RES_MAX];
#endif
}monitor_t;
extern monitor_t monitor;
}

void saveScreenshot()
{
auto now = std::chrono::system_clock::now();
// TODO: timestamped png filename
std::string screenshot_filename_base = date::format("InfiniSim_%F_%H%M%S", date::floor<std::chrono::seconds>(now));
//std::string screenshot_filename_base = "InfiniSim";

const int width = 240;
const int height = 240;
auto renderer = monitor.renderer;


#if defined(WITH_PNG)
std::string screenshot_filename = screenshot_filename_base + ".png";

FILE * fp2 = fopen(screenshot_filename.c_str(), "wb");
if (!fp2) {
// dealing with error
return;
}
// 1. Create png struct pointer
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr){
// dealing with error
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
// dealing with error
}
int bit_depth = 8;
png_init_io(png_ptr, fp2);
png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, \
PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, \
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);

// 3. Convert 1d array to 2d array to be suitable for png struct
// I assumed the original array is 1d
std::array<png_bytep, 240> row_pointers;
//png_bytepp row_pointers = (png_bytepp)png_malloc(png_ptr, sizeof(png_bytep) * height);
for (int i = 0; i < height; i++) {
row_pointers[i] = (png_bytep)png_malloc(png_ptr, width*4);
}
const Uint32 format = SDL_PIXELFORMAT_RGBA8888;
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, format);
SDL_RenderReadPixels(renderer, NULL, format, surface->pixels, surface->pitch);
png_bytep pixels = (png_bytep)surface->pixels;
for (int hi = 0; hi < height; hi++) {
for (int wi = 0; wi < width; wi++) {
int c = wi * 4;
row_pointers.at(hi)[wi*4+0] = pixels[hi*surface->pitch + wi*4 + 3]; // red
row_pointers.at(hi)[wi*4+1] = pixels[hi*surface->pitch + wi*4 + 2]; // greeen
row_pointers.at(hi)[wi*4+2] = pixels[hi*surface->pitch + wi*4 + 1]; // blue
row_pointers.at(hi)[wi*4+3] = 255; // alpha
}
}

// 4. Write png file
png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, row_pointers.data());
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp2);

SDL_FreeSurface(surface);
#else
std::string screenshot_filename = screenshot_filename_base + ".bmp";
const Uint32 format = SDL_PIXELFORMAT_RGB888;
SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 24, format);
SDL_RenderReadPixels(renderer, NULL, format, surface->pixels, surface->pitch);
SDL_SaveBMP(surface, screenshot_filename.c_str());
SDL_FreeSurface(surface);
#endif
std::cout << "InfiniSim: Screenshot created: " << screenshot_filename << std::endl;
}

/**********************
* STATIC PROTOTYPES
Expand Down Expand Up @@ -450,6 +549,7 @@ class Framework {
debounce('p', 'P', state[SDL_SCANCODE_P], key_handled_p);
debounce('s', 'S', state[SDL_SCANCODE_S], key_handled_s);
debounce('h', 'H', state[SDL_SCANCODE_H], key_handled_h);
debounce('i', 'I', state[SDL_SCANCODE_I], key_handled_i);
// screen switcher buttons
debounce('1', '!'+1, state[SDL_SCANCODE_1], key_handled_1);
debounce('2', '!'+2, state[SDL_SCANCODE_2], key_handled_2);
Expand Down Expand Up @@ -525,6 +625,8 @@ class Framework {
}
} else if (key == 'H') {
heartRateController.Stop();
} else if (key == 'i') {
saveScreenshot();
} else if (key >= '0' && key <= '9') {
this->switch_to_screen(key-'0');
} else if (key >= '!'+0 && key <= '!'+9) {
Expand Down Expand Up @@ -679,6 +781,7 @@ class Framework {
bool key_handled_p = false; // p ... enable print memory usage, P ... disable print memory usage
bool key_handled_s = false; // s ... increase step count, S ... decrease step count
bool key_handled_h = false; // h ... set heartrate running, H ... stop heartrate
bool key_handled_i = false; // i ... take screenshot, I ... not assigned
// numbers from 0 to 9 to switch between screens
bool key_handled_1 = false;
bool key_handled_2 = false;
Expand Down