From 786ddf3de80a2e21b8eb64642d819252123883e1 Mon Sep 17 00:00:00 2001 From: Marcos Del Sol Vives Date: Sun, 7 Jan 2024 22:25:47 +0100 Subject: [PATCH 1/2] Add image cropping and scaling --- client/src/cmdhfwaveshare.c | 15 +++++---- client/src/imgutils.c | 63 ++++++++++++++++++++++++++++++++----- client/src/imgutils.h | 14 +++++++++ 3 files changed, 76 insertions(+), 16 deletions(-) diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c index c45f19f8a..d3d5fff78 100644 --- a/client/src/cmdhfwaveshare.c +++ b/client/src/cmdhfwaveshare.c @@ -631,14 +631,13 @@ static int CmdHF14AWSLoad(const char *Cmd) { return PM3_EFILE; } - if ( - gdImageSX(rgb_img) != models[model_nr].width || - gdImageSY(rgb_img) != models[model_nr].height - ) { - PrintAndLogEx(WARNING, "Image size does not match panel size"); + gdImagePtr scaled_img = img_crop_to_fit(rgb_img, models[model_nr].width, models[model_nr].height); + if (scaled_img == NULL) { + PrintAndLogEx(WARNING, "Failed to scale input image"); gdImageDestroy(rgb_img); return PM3_EFILE; } + gdImageDestroy(rgb_img); int pal_len = 2; int pal[3]; @@ -649,8 +648,8 @@ static int CmdHF14AWSLoad(const char *Cmd) { pal[2] = gdTrueColorAlpha(0xFF, 0x00, 0x00, 0); // Red } - gdImagePtr pal_img = img_palettize(rgb_img, pal, pal_len); - gdImageDestroy(rgb_img); + gdImagePtr pal_img = img_palettize(scaled_img, pal, pal_len); + gdImageDestroy(scaled_img); if (!pal_img) { PrintAndLogEx(WARNING, "Could not convert image"); @@ -662,7 +661,7 @@ static int CmdHF14AWSLoad(const char *Cmd) { PrintAndLogEx(INFO, "Save converted image to " _YELLOW_("%s"), outfile); gdImageDestroy(pal_img); return PM3_SUCCESS; - } else { + } else { PrintAndLogEx(WARNING, "Could not save converted image", outfile); gdImageDestroy(pal_img); return PM3_EFILE; diff --git a/client/src/imgutils.c b/client/src/imgutils.c index a58a5b29a..4b396c0ac 100644 --- a/client/src/imgutils.c +++ b/client/src/imgutils.c @@ -33,14 +33,6 @@ static inline void cap_comp(int * x) { } } -/* - * 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); @@ -157,3 +149,58 @@ gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size) { free(pal_ycbcr); return res; } + +gdImagePtr img_crop_to_fit(gdImagePtr orig, int width, int height) { + assert(orig != NULL); + assert(width >= 1); + assert(height >= 1); + + gdImagePtr res; + if (gdImageTrueColor(orig)) { + res = gdImageCreateTrueColor(width, height); + } else { + res = gdImageCreate(width, height); + } + + if (!res) { + return NULL; + } + + if (gdImageSY(orig) * width <= gdImageSX(orig) * height) { + // Image is wider than expected, so we will crop the left and right sides + + int crop_width = gdImageSY(orig) * width / height; + int crop_sx = gdImageSX(orig) / 2 - crop_width / 2; + gdImageCopyResampled( + res, // Dest img + orig, // Src image + 0, // Dest X + 0, // Dest Y + crop_sx, // Src X + 0, // Src Y + width, // Dest width + height, // Dest height + crop_width, // Src width + gdImageSY(orig) // Src height + ); + } else { + // Image is taller than expected, so we will crop the top and bottom sides + + int crop_height = gdImageSX(orig) * height / width; + int crop_sy = gdImageSY(orig) / 2 - crop_height / 2; + gdImageCopyResampled( + res, // Dest img + orig, // Src image + 0, // Dest X + 0, // Dest Y + 0, // Src X + crop_sy, // Src Y + width, // Dest width + height, // Dest height + gdImageSX(orig), // Src width + crop_height // Src height + ); + } + + return res; +} diff --git a/client/src/imgutils.h b/client/src/imgutils.h index 1ffa07833..ff619a5e1 100644 --- a/client/src/imgutils.h +++ b/client/src/imgutils.h @@ -20,6 +20,20 @@ #include +/* + * Converts a true color image to a palette image, using Floyd-Steinberg dithering. + * + * For color matching, this function uses the Euclidean distance between colors in the + * YCbCr color space, which yields to better results than using sRGB directly. + * + * A comparison can be found at https://twitter.com/Socram4x8/status/1733157380097995205/photo/1. + */ gdImagePtr img_palettize(gdImagePtr rgb, int * palette, int palette_size); +/* + * This function scales and crops the image to the given size. + * Think of "background-size: cover" in CSS. + */ +gdImagePtr img_crop_to_fit(gdImagePtr orig, int width, int height); + #endif From 442df4aaffc0cdd445f6ba45e4abab1823246bb3 Mon Sep 17 00:00:00 2001 From: Marcos Del Sol Vives Date: Sun, 7 Jan 2024 22:34:40 +0100 Subject: [PATCH 2/2] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e41c2e35c..df18b8f79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fixed `lf pyramid sim` - wrong parameter handling (@iceman1001) - 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) + - Changed `hf waveshare` - image is automatically scaled and cropped to match panel size (@socram8888) ## [Steamboat Willie.4.17768][2024-01-03] - Changed `mem spiffs dump -t` - now supports downloading direct into trace buffer (@hazardousvoltage)