From c6e3c0ee304c124142a81f8d97ca354973735b33 Mon Sep 17 00:00:00 2001 From: Wolfvak Date: Thu, 29 Mar 2018 23:45:58 -0300 Subject: [PATCH] Save screenshots as PNGs. --- arm9/source/common/screenshot.c | 61 ++++++++++++++++++++------------- arm9/source/system/png.c | 37 +++++++++++++++----- arm9/source/system/png.h | 1 + 3 files changed, 67 insertions(+), 32 deletions(-) diff --git a/arm9/source/common/screenshot.c b/arm9/source/common/screenshot.c index fedf948..6838639 100644 --- a/arm9/source/common/screenshot.c +++ b/arm9/source/common/screenshot.c @@ -2,42 +2,54 @@ #include "ui.h" #include "rtc.h" #include "vff.h" +#include "png.h" void CreateScreenshot() { - const u32 snap_size = 54 + (SCREEN_SIZE_TOP * 2); - const u8 bmp_header[54] = { - 0x42, 0x4D, 0x36, 0xCA, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xCA, 0x08, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - + const u32 snap_size = SCREEN_SIZE_TOP * 2, snap_width = SCREEN_WIDTH_TOP, snap_height = SCREEN_HEIGHT * 2; + u8 *png_data = NULL; + size_t png_size; + char filename[64]; DsTime dstime; fvx_rmkdir(OUTPUT_PATH); get_dstime(&dstime); - snprintf(filename, 64, OUTPUT_PATH "/snap_%02X%02X%02X%02X%02X%02X.bmp", + snprintf(filename, 64, OUTPUT_PATH "/snap_%02X%02X%02X%02X%02X%02X.png", dstime.bcd_Y, dstime.bcd_M, dstime.bcd_D, dstime.bcd_h, dstime.bcd_m, dstime.bcd_s); - + u8* buffer = (u8*) malloc(snap_size); if (!buffer) return; - - u8* buffer_b = buffer + 54; - u8* buffer_t = buffer_b + (400 * 240 * 3); - + + u8* buffer_t = buffer; + u8* buffer_b = buffer + SCREEN_SIZE_TOP; + memset(buffer, 0x1F, snap_size); // gray background - memcpy(buffer, bmp_header, 54); - for (u32 x = 0; x < 400; x++) - for (u32 y = 0; y < 240; y++) - memcpy(buffer_t + (y*400 + x) * 3, TOP_SCREEN + (x*240 + y) * 3, 3); - for (u32 x = 0; x < 320; x++) - for (u32 y = 0; y < 240; y++) - memcpy(buffer_b + (y*400 + x + 40) * 3, BOT_SCREEN + (x*240 + y) * 3, 3); - fvx_qwrite(filename, buffer, 0, snap_size, NULL); - + + for (u32 x = 0; x < 400; x++) { + for (u32 y = 0; y < 240; y++) { + buffer_t[(y * SCREEN_WIDTH_TOP + x) * 3 + 0] = *(TOP_SCREEN + (((x * 240) + (239 - y)) * 3) + 2); + buffer_t[(y * SCREEN_WIDTH_TOP + x) * 3 + 1] = *(TOP_SCREEN + (((x * 240) + (239 - y)) * 3) + 1); + buffer_t[(y * SCREEN_WIDTH_TOP + x) * 3 + 2] = *(TOP_SCREEN + (((x * 240) + (239 - y)) * 3) + 0); + } + } + + for (u32 x = 0; x < 320; x++) { + for (u32 y = 0; y < 240; y++) { + buffer_b[(y * SCREEN_WIDTH_TOP + x + 40) * 3 + 0] = *(BOT_SCREEN + (((x * 240) + (239 - y)) * 3) + 2); + buffer_b[(y * SCREEN_WIDTH_TOP + x + 40) * 3 + 1] = *(BOT_SCREEN + (((x * 240) + (239 - y)) * 3) + 1); + buffer_b[(y * SCREEN_WIDTH_TOP + x + 40) * 3 + 2] = *(BOT_SCREEN + (((x * 240) + (239 - y)) * 3) + 0); + } + } + + png_data = PNG_Compress(buffer, snap_width, snap_height, &png_size); + + if (png_data && png_size) + fvx_qwrite(filename, png_data, 0, png_size, NULL); + else + ShowPrompt(false, "Failed to write screenshot!"); + // "snap effect" memcpy(buffer_b, BOT_SCREEN, SCREEN_SIZE_BOT); memcpy(buffer_t, TOP_SCREEN, SCREEN_SIZE_TOP); @@ -45,6 +57,7 @@ void CreateScreenshot() { memset(TOP_SCREEN, 0, SCREEN_SIZE_TOP); memcpy(BOT_SCREEN, buffer_b, SCREEN_SIZE_BOT); memcpy(TOP_SCREEN, buffer_t, SCREEN_SIZE_TOP); - + free(buffer); + if (png_data) free(png_data); } diff --git a/arm9/source/system/png.c b/arm9/source/system/png.c index 4a424bc..8b4f847 100644 --- a/arm9/source/system/png.c +++ b/arm9/source/system/png.c @@ -6,6 +6,16 @@ #include "ui.h" +static inline void _rgb_swap(u8 *img, size_t sz) +{ + // maybe process in batches of 3 pixels / 12 bytes at a time? + for (size_t i = 0; i < sz; i+=3) { + u8 c = img[i]; + img[i] = img[i + 2]; + img[i + 2] = c; + } +} + u8 *PNG_Decompress(const u8 *png, size_t png_len, u32 *w, u32 *h) { u8 *img; @@ -13,18 +23,29 @@ u8 *PNG_Decompress(const u8 *png, size_t png_len, u32 *w, u32 *h) size_t w_, h_; res = lodepng_decode24(&img, &w_, &h_, png, png_len); - if (res) + if (res) { + if (img) free(img); return NULL; - - // maybe process in batches of 3 pixels / 12 bytes at a time? - for (size_t i = 0; i < (w_ * h_ * 3); i += 3) { - u8 c = img[i]; - img[i] = img[i + 2]; - img[i + 2] = c; } - + _rgb_swap(img, w_ * h_ * 3); if (w) *w = w_; if (h) *h = h_; return img; } + +u8 *PNG_Compress(u8 *fb, u32 w, u32 h, size_t *png_sz) +{ + u32 res; + size_t png_size; + u8 *img; + + res = lodepng_encode24(&img, &png_size, fb, w, h); + if (res) { + if (img) free(img); + return NULL; + } + if (png_sz) *png_sz = png_size; + + return img; +} diff --git a/arm9/source/system/png.h b/arm9/source/system/png.h index af2d619..819b047 100644 --- a/arm9/source/system/png.h +++ b/arm9/source/system/png.h @@ -7,3 +7,4 @@ #define PNG_MAGIC 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A u8 *PNG_Decompress(const u8 *png, size_t png_len, u32 *w, u32 *h); +u8 *PNG_Compress(u8 *fb, u32 w, u32 h, size_t *png_sz);