From ee79247110d5da022f24bef469c3f8fdabea7b55 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 1 Jul 2021 16:00:54 +0100 Subject: [PATCH 01/14] Add zoom and scale functionality to xrdp_bitmap_load() --- xrdp/xrdp.h | 27 +++++- xrdp/xrdp_bitmap.c | 213 +++++++++++++++++++++++++++++++++++++++++- xrdp/xrdp_login_wnd.c | 6 +- xrdp/xrdp_types.h | 10 ++ 4 files changed, 250 insertions(+), 6 deletions(-) diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index f096538894..109da5b5aa 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -201,8 +201,33 @@ int xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused); int xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height); +/** + * Loads a bitmap from a file and (optionally) transforms it + * + * @param self from rdp_bitmap_create() + * @param filename Filename to load + * @param[in] palette For 8-bit conversions. Currently unused + * @param background Background color for alpha-blending + * @param transform Transform to apply to the image after loading + * @param twidth target width if transform != XBLT_NONE + * @param theight target height if transform != XBLT_NONE + * @return 0 for success. + * + * The background color is only used if the specified image contains + * an alpha layer + * + * After a successful call, the bitmap is resized to the image file size. + * + * If the call is not successful, the bitmap will be in an indeterminate + * state and should not be used. + */ int -xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette); +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, + const int *palette, + int background, + enum xrdp_bitmap_load_transform transform, + int twidth, + int theight); int xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y); int diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 2721fd5fa8..25ca751007 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -119,6 +119,12 @@ xrdp_bitmap_create(int width, int height, int bpp, int Bpp = 0; self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); + if (self == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: no memory"); + return self; + } + self->type = type; self->width = width; self->height = height; @@ -403,7 +409,7 @@ xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused) /*****************************************************************************/ static int -xrdp_bitmap_get_index(struct xrdp_bitmap *self, int *palette, int color) +xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) { int r = 0; int g = 0; @@ -458,12 +464,177 @@ xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height) return 0; } +/**************************************************************************//** + * Private routine to swap pixel data between two pixmaps + * @param a First bitmap + * @param b Second bitmap + * + * The main use-case for this routine is to modify an existing bitmap using + * the following logic:- + * - Create a temporary WND_TYPE_BITMAP + * - Process the data in a bitmap in some way, moving it to the temporary + * - Call this routine + * - Delete the temporary + * + */ +static void +swap_pixel_data(struct xrdp_bitmap *a, struct xrdp_bitmap *b) +{ + int tmp_width = a->width; + int tmp_height = a->height; + int tmp_bpp = a->bpp; + int tmp_line_size = a->line_size; + char *tmp_data = a->data; + int tmp_do_not_free_data = a->do_not_free_data; + + a->width = b->width; + a->height = b->height; + a->bpp = b->bpp; + a->line_size = b->line_size; + a->data = b->data; + a->do_not_free_data = b->do_not_free_data; + + b->width = tmp_width; + b->height = tmp_height; + b->bpp = tmp_bpp; + b->line_size = tmp_line_size; + b->data = tmp_data; + b->do_not_free_data = tmp_do_not_free_data; +} + +/**************************************************************************//** + * Scales a bitmap image + * + * @param self Bitmap to scale + * @param target_width target width + * @param target_height target height + * @return 0 for success + */ +static int +xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height) +{ + int src_width = self->width; + int src_height = self->height; + + if (src_width != targ_width || src_height != targ_height) + { + struct xrdp_bitmap *target = + xrdp_bitmap_create(targ_width, targ_height, + self->bpp, WND_TYPE_BITMAP, 0); + int targ_x, targ_y; + + if (target == NULL) + { + /* Error is logged */ + return 1; + } + + /* For each pixel in the target pixmap, scale to one in the source */ + for (targ_x = 0 ; targ_x < targ_width; ++targ_x) + { + int src_x = targ_x * src_width / targ_width; + for (targ_y = 0 ; targ_y < targ_height; ++targ_y) + { + int src_y = targ_y * src_height / targ_height; + int pixel = xrdp_bitmap_get_pixel(self, src_x, src_y); + xrdp_bitmap_set_pixel(target, targ_x, targ_y, pixel); + } + } + swap_pixel_data(self, target); + xrdp_bitmap_delete(target); + } + + return 0; +} + +/**************************************************************************//** + * Zooms a bitmap image + * + * @param self Bitmap to zoom + * @param target_width target width + * @param target_height target height + * @return 0 for success + * + * This works the same way as a scaled image, but the aspect ratio is + * maintained by removing pixels from the top-and-bottom, + * or the left-and-right before scaling. + */ +static int +xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) +{ + int src_width = self->width; + int src_height = self->height; + double targ_ratio = (double)targ_width / targ_height; + double src_ratio = (double)src_width / src_height; + + unsigned int chop_width; + unsigned int chop_left_margin; + unsigned int chop_height; + unsigned int chop_top_margin; + + int result = 0; + + if (src_ratio > targ_ratio) + { + /* Source is relatively wider than source. Select a box + * narrower than the source, but the same height */ + chop_width = (int)(targ_ratio * src_height + .5); + chop_left_margin = (src_width - chop_width) / 2; + chop_height = src_height; + chop_top_margin = 0; + } + else + { + /* Source is relatively taller than source (or same shape) */ + chop_width = src_width; + chop_left_margin = 0; + chop_height = (int)(src_width / targ_ratio + .5); + chop_top_margin = (src_height - chop_height) / 2; + } + + /* Only chop the image if there's a need to */ + if (chop_top_margin != 0 || chop_left_margin != 0) + { + struct xrdp_bitmap *chopbox; + chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp, + WND_TYPE_BITMAP, 0); + if (chopbox == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory"); + result = 1; + } + else + { + result = xrdp_bitmap_copy_box(self, chopbox, + chop_left_margin, chop_top_margin, + chop_width, chop_height); + if (result != 0) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box"); + } + else + { + swap_pixel_data(self, chopbox); + } + xrdp_bitmap_delete(chopbox); + } + } + + if (result == 0) + { + result = xrdp_bitmap_scale(self, targ_width, targ_height); + } + + return result; +} + /*****************************************************************************/ /* load a bmp file */ /* return 0 ok */ /* return 1 error */ -int -xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette) +static int +xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, + const int *palette) { int fd = 0; int len = 0; @@ -804,6 +975,42 @@ xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, int *palette) return 0; } +/*****************************************************************************/ +int +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, + const int *palette, + int background, + enum xrdp_bitmap_load_transform transform, + int twidth, + int theight) +{ + /* this is the default bmp-only implementation if a graphics library + * isn't built in */ + + int result = xrdp_bitmap_load_bmp(self, filename, palette); + if (result == 0) + { + switch (transform) + { + case XBLT_NONE: + break; + + case XBLT_SCALE: + result = xrdp_bitmap_scale(self, twidth, theight); + break; + + case XBLT_ZOOM: + result = xrdp_bitmap_zoom(self, twidth, theight); + break; + + default: + LOG(LOG_LEVEL_WARNING, "Invalid bitmap transform %d specified", + transform); + } + } + return result; +} + /*****************************************************************************/ int xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y) diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index 0d640f85b3..1022dfff20 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -740,7 +740,8 @@ xrdp_login_wnd_create(struct xrdp_wm *self) XRDP_SHARE_PATH, globals->ls_background_image); } LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName); - xrdp_bitmap_load(but, fileName, self->palette); + xrdp_bitmap_load(but, fileName, self->palette, + globals->ls_top_window_bg_color, XBLT_NONE, 0, 0); but->parent = self->screen; but->owner = self->screen; but->left = self->screen->width - but->width; @@ -762,7 +763,8 @@ xrdp_login_wnd_create(struct xrdp_wm *self) g_snprintf(globals->ls_logo_filename, 255, "%s/ad256.bmp", XRDP_SHARE_PATH); } - xrdp_bitmap_load(but, globals->ls_logo_filename, self->palette); + xrdp_bitmap_load(but, globals->ls_logo_filename, self->palette, + globals->ls_bg_color, XBLT_NONE, 0, 0); but->parent = self->login_window; but->owner = self->login_window; but->left = globals->ls_logo_x_pos; diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 39d9996473..149b037914 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -168,6 +168,16 @@ struct xrdp_mod struct source_info *si; }; +/** + * Transform to apply to loaded images + */ +enum xrdp_bitmap_load_transform +{ + XBLT_NONE = 0, + XBLT_SCALE, + XBLT_ZOOM +}; + /* header for bmp file */ struct xrdp_bmp_header { From 2c841d06031230140319f6f283f07934295b70f5 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 7 Jul 2021 09:43:42 +0100 Subject: [PATCH 02/14] Split xrdp_bitmap.c into separate files for testing --- xrdp/Makefile.am | 2 + xrdp/xrdp.h | 67 +-- xrdp/xrdp_bitmap.c | 1048 ------------------------------------- xrdp/xrdp_bitmap_common.c | 509 ++++++++++++++++++ xrdp/xrdp_bitmap_load.c | 585 +++++++++++++++++++++ 5 files changed, 1131 insertions(+), 1080 deletions(-) create mode 100644 xrdp/xrdp_bitmap_common.c create mode 100644 xrdp/xrdp_bitmap_load.c diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index 1a065d7ef2..2eb010ebc7 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -43,6 +43,8 @@ xrdp_SOURCES = \ xrdp.c \ xrdp.h \ xrdp_bitmap.c \ + xrdp_bitmap_load.c \ + xrdp_bitmap_common.c \ xrdp_cache.c \ xrdp_encoder.c \ xrdp_encoder.h \ diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 109da5b5aa..04a11e3929 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -185,7 +185,7 @@ int xrdp_region_get_rect(struct xrdp_region *self, int index, struct xrdp_rect *rect); -/* xrdp_bitmap.c */ +/* xrdp_bitmap_common.c */ struct xrdp_bitmap * xrdp_bitmap_create(int width, int height, int bpp, int type, struct xrdp_wm *wm); @@ -195,39 +195,8 @@ xrdp_bitmap_create_with_data(int width, int height, struct xrdp_wm *wm); void xrdp_bitmap_delete(struct xrdp_bitmap *self); -struct xrdp_bitmap * -xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id); -int -xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused); int xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height); -/** - * Loads a bitmap from a file and (optionally) transforms it - * - * @param self from rdp_bitmap_create() - * @param filename Filename to load - * @param[in] palette For 8-bit conversions. Currently unused - * @param background Background color for alpha-blending - * @param transform Transform to apply to the image after loading - * @param twidth target width if transform != XBLT_NONE - * @param theight target height if transform != XBLT_NONE - * @return 0 for success. - * - * The background color is only used if the specified image contains - * an alpha layer - * - * After a successful call, the bitmap is resized to the image file size. - * - * If the call is not successful, the bitmap will be in an indeterminate - * state and should not be used. - */ -int -xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, - const int *palette, - int background, - enum xrdp_bitmap_load_transform transform, - int twidth, - int theight); int xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y); int @@ -236,6 +205,12 @@ int xrdp_bitmap_copy_box(struct xrdp_bitmap *self, struct xrdp_bitmap *dest, int x, int y, int cx, int cy); + +/* xrdp_bitmap.c */ +struct xrdp_bitmap * +xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id); +int +xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused); int xrdp_bitmap_hash_crc(struct xrdp_bitmap *self); int @@ -264,6 +239,34 @@ xrdp_bitmap_get_screen_clip(struct xrdp_bitmap *self, struct xrdp_rect *rect, int *dx, int *dy); +/* xrdp_bitmap_load.c */ +/** + * Loads a bitmap from a file and (optionally) transforms it + * + * @param self from rdp_bitmap_create() + * @param filename Filename to load + * @param[in] palette For 8-bit conversions. Currently unused + * @param background Background color for alpha-blending + * @param transform Transform to apply to the image after loading + * @param twidth target width if transform != XBLT_NONE + * @param theight target height if transform != XBLT_NONE + * @return 0 for success. + * + * The background color is only used if the specified image contains + * an alpha layer + * + * After a successful call, the bitmap is resized to the image file size. + * + * If the call is not successful, the bitmap will be in an indeterminate + * state and should not be used. + */ +int +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, + const int *palette, + int background, + enum xrdp_bitmap_load_transform transform, + int twidth, + int theight); /* xrdp_painter.c */ struct xrdp_painter * xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session); diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c index 25ca751007..2d68edf9ed 100644 --- a/xrdp/xrdp_bitmap.c +++ b/xrdp/xrdp_bitmap.c @@ -25,8 +25,6 @@ #include #endif -#include - #include "xrdp.h" #include "log.h" #include "string_calls.h" @@ -86,264 +84,6 @@ static const unsigned int g_crc_table[256] = (in_crc) = g_crc_table[((in_crc) ^ (in_pixel)) & 0xff] ^ ((in_crc) >> 8) #define CRC_END(in_crc) (in_crc) = ((in_crc) ^ 0xFFFFFFFF) -/*****************************************************************************/ -/* Allocate bitmap for specified dimensions, checking for int overflow */ -static char * -alloc_bitmap_data(int width, int height, int Bpp) -{ - char *result = NULL; - if (width > 0 && height > 0 && Bpp > 0) - { - int len = width; - /* g_malloc() currently takes an 'int' size */ - if (len < INT_MAX / height) - { - len *= height; - if (len < INT_MAX / Bpp) - { - len *= Bpp; - result = (char *)malloc(len); - } - } - } - - return result; -} - -/*****************************************************************************/ -struct xrdp_bitmap * -xrdp_bitmap_create(int width, int height, int bpp, - int type, struct xrdp_wm *wm) -{ - struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; - int Bpp = 0; - - self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); - if (self == NULL) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: no memory"); - return self; - } - - self->type = type; - self->width = width; - self->height = height; - self->bpp = bpp; - Bpp = 4; - - switch (bpp) - { - case 8: - Bpp = 1; - break; - case 15: - Bpp = 2; - break; - case 16: - Bpp = 2; - break; - } - - if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) - { - self->data = alloc_bitmap_data(width, height, Bpp); - if (self->data == NULL) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d", - width, height, Bpp); - g_free(self); - return NULL; - } - } - -#if defined(XRDP_PAINTER) - if (self->type == WND_TYPE_SCREEN) /* noorders */ - { - LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_bitmap_create: noorders"); - self->data = alloc_bitmap_data(width, height, Bpp); - if (self->data == NULL) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d", - width, height, Bpp); - g_free(self); - return NULL; - } - } -#endif - - if (self->type != WND_TYPE_BITMAP) - { - self->child_list = list_create(); - } - - self->line_size = width * Bpp; - - if (self->type == WND_TYPE_COMBO) - { - self->string_list = list_create(); - self->string_list->auto_free = 1; - self->data_list = list_create(); - self->data_list->auto_free = 1; - } - - self->wm = wm; - return self; -} - -/*****************************************************************************/ -struct xrdp_bitmap * -xrdp_bitmap_create_with_data(int width, int height, - int bpp, char *data, - struct xrdp_wm *wm) -{ - struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; - int Bpp; -#if defined(NEED_ALIGN) - tintptr data_as_int; -#endif - - self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); - self->type = WND_TYPE_BITMAP; - self->width = width; - self->height = height; - self->bpp = bpp; - self->wm = wm; - - Bpp = 4; - switch (bpp) - { - case 8: - Bpp = 1; - break; - case 15: - Bpp = 2; - break; - case 16: - Bpp = 2; - break; - } - self->line_size = width * Bpp; - -#if defined(NEED_ALIGN) - data_as_int = (tintptr) data; - if (((bpp >= 24) && (data_as_int & 3)) || - (((bpp == 15) || (bpp == 16)) && (data_as_int & 1))) - { - /* got to copy data here, it's not aligned - other calls in this file assume alignment */ - self->data = (char *)g_malloc(width * height * Bpp, 0); - g_memcpy(self->data, data, width * height * Bpp); - return self; - } -#endif - self->data = data; - self->do_not_free_data = 1; - return self; -} - -/*****************************************************************************/ -void -xrdp_bitmap_delete(struct xrdp_bitmap *self) -{ - int i = 0; - struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL; - - if (self == 0) - { - return; - } - - if (self->wm != 0) - { - if (self->wm->focused_window != 0) - { - if (self->wm->focused_window->focused_control == self) - { - self->wm->focused_window->focused_control = 0; - } - } - - if (self->wm->focused_window == self) - { - self->wm->focused_window = 0; - } - - if (self->wm->dragging_window == self) - { - self->wm->dragging_window = 0; - } - - if (self->wm->button_down == self) - { - self->wm->button_down = 0; - } - - if (self->wm->popup_wnd == self) - { - self->wm->popup_wnd = 0; - } - - if (self->wm->login_window == self) - { - self->wm->login_window = 0; - } - - if (self->wm->log_wnd == self) - { - self->wm->log_wnd = 0; - } - } - - if (self->child_list != 0) - { - for (i = self->child_list->count - 1; i >= 0; i--) - { - xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]); - } - - list_delete(self->child_list); - } - - if (self->parent != 0) - { - i = list_index_of(self->parent->child_list, (long)self); - - if (i >= 0) - { - list_remove_item(self->parent->child_list, i); - } - } - - if (self->string_list != 0) /* for combo */ - { - list_delete(self->string_list); - } - - if (self->data_list != 0) /* for combo */ - { - for (i = 0; i < self->data_list->count; i++) - { - mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i); - - if (mod_data != 0) - { - list_delete(mod_data->names); - list_delete(mod_data->values); - } - } - - list_delete(self->data_list); - } - - if (!self->do_not_free_data) - { - g_free(self->data); - } - - g_free(self->caption1); - g_free(self); -} - /*****************************************************************************/ struct xrdp_bitmap * xrdp_bitmap_get_child_by_id(struct xrdp_bitmap *self, int id) @@ -407,794 +147,6 @@ xrdp_bitmap_set_focus(struct xrdp_bitmap *self, int focused) return 0; } -/*****************************************************************************/ -static int -xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) -{ - int r = 0; - int g = 0; - int b = 0; - - r = (color & 0xff0000) >> 16; - g = (color & 0x00ff00) >> 8; - b = (color & 0x0000ff) >> 0; - r = (r >> 5) << 0; - g = (g >> 5) << 3; - b = (b >> 6) << 6; - return (b | g | r); -} - -/*****************************************************************************/ -/* returns error */ -int -xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height) -{ - int Bpp = 0; - - if ((width == self->width) && (height == self->height)) - { - return 0; - } - - if (self->do_not_free_data) - { - return 1; - } - - self->width = width; - self->height = height; - Bpp = 4; - - switch (self->bpp) - { - case 8: - Bpp = 1; - break; - case 15: - Bpp = 2; - break; - case 16: - Bpp = 2; - break; - } - - g_free(self->data); - self->data = (char *)g_malloc(width * height * Bpp, 0); - self->line_size = width * Bpp; - return 0; -} - -/**************************************************************************//** - * Private routine to swap pixel data between two pixmaps - * @param a First bitmap - * @param b Second bitmap - * - * The main use-case for this routine is to modify an existing bitmap using - * the following logic:- - * - Create a temporary WND_TYPE_BITMAP - * - Process the data in a bitmap in some way, moving it to the temporary - * - Call this routine - * - Delete the temporary - * - */ -static void -swap_pixel_data(struct xrdp_bitmap *a, struct xrdp_bitmap *b) -{ - int tmp_width = a->width; - int tmp_height = a->height; - int tmp_bpp = a->bpp; - int tmp_line_size = a->line_size; - char *tmp_data = a->data; - int tmp_do_not_free_data = a->do_not_free_data; - - a->width = b->width; - a->height = b->height; - a->bpp = b->bpp; - a->line_size = b->line_size; - a->data = b->data; - a->do_not_free_data = b->do_not_free_data; - - b->width = tmp_width; - b->height = tmp_height; - b->bpp = tmp_bpp; - b->line_size = tmp_line_size; - b->data = tmp_data; - b->do_not_free_data = tmp_do_not_free_data; -} - -/**************************************************************************//** - * Scales a bitmap image - * - * @param self Bitmap to scale - * @param target_width target width - * @param target_height target height - * @return 0 for success - */ -static int -xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height) -{ - int src_width = self->width; - int src_height = self->height; - - if (src_width != targ_width || src_height != targ_height) - { - struct xrdp_bitmap *target = - xrdp_bitmap_create(targ_width, targ_height, - self->bpp, WND_TYPE_BITMAP, 0); - int targ_x, targ_y; - - if (target == NULL) - { - /* Error is logged */ - return 1; - } - - /* For each pixel in the target pixmap, scale to one in the source */ - for (targ_x = 0 ; targ_x < targ_width; ++targ_x) - { - int src_x = targ_x * src_width / targ_width; - for (targ_y = 0 ; targ_y < targ_height; ++targ_y) - { - int src_y = targ_y * src_height / targ_height; - int pixel = xrdp_bitmap_get_pixel(self, src_x, src_y); - xrdp_bitmap_set_pixel(target, targ_x, targ_y, pixel); - } - } - swap_pixel_data(self, target); - xrdp_bitmap_delete(target); - } - - return 0; -} - -/**************************************************************************//** - * Zooms a bitmap image - * - * @param self Bitmap to zoom - * @param target_width target width - * @param target_height target height - * @return 0 for success - * - * This works the same way as a scaled image, but the aspect ratio is - * maintained by removing pixels from the top-and-bottom, - * or the left-and-right before scaling. - */ -static int -xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) -{ - int src_width = self->width; - int src_height = self->height; - double targ_ratio = (double)targ_width / targ_height; - double src_ratio = (double)src_width / src_height; - - unsigned int chop_width; - unsigned int chop_left_margin; - unsigned int chop_height; - unsigned int chop_top_margin; - - int result = 0; - - if (src_ratio > targ_ratio) - { - /* Source is relatively wider than source. Select a box - * narrower than the source, but the same height */ - chop_width = (int)(targ_ratio * src_height + .5); - chop_left_margin = (src_width - chop_width) / 2; - chop_height = src_height; - chop_top_margin = 0; - } - else - { - /* Source is relatively taller than source (or same shape) */ - chop_width = src_width; - chop_left_margin = 0; - chop_height = (int)(src_width / targ_ratio + .5); - chop_top_margin = (src_height - chop_height) / 2; - } - - /* Only chop the image if there's a need to */ - if (chop_top_margin != 0 || chop_left_margin != 0) - { - struct xrdp_bitmap *chopbox; - chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp, - WND_TYPE_BITMAP, 0); - if (chopbox == NULL) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory"); - result = 1; - } - else - { - result = xrdp_bitmap_copy_box(self, chopbox, - chop_left_margin, chop_top_margin, - chop_width, chop_height); - if (result != 0) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box"); - } - else - { - swap_pixel_data(self, chopbox); - } - xrdp_bitmap_delete(chopbox); - } - } - - if (result == 0) - { - result = xrdp_bitmap_scale(self, targ_width, targ_height); - } - - return result; -} - -/*****************************************************************************/ -/* load a bmp file */ -/* return 0 ok */ -/* return 1 error */ -static int -xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, - const int *palette) -{ - int fd = 0; - int len = 0; - int i = 0; - int j = 0; - int k = 0; - int color = 0; - int size = 0; - int palette1[256]; - char type1[4]; - struct xrdp_bmp_header header; - struct stream *s = (struct stream *)NULL; - - g_memset(palette1, 0, sizeof(int) * 256); - g_memset(type1, 0, sizeof(char) * 4); - g_memset(&header, 0, sizeof(struct xrdp_bmp_header)); - - if (!g_file_exist(filename)) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "does not exist", filename); - return 1; - } - - fd = g_file_open(filename); - - if (fd != -1) - { - /* read file type */ - if (g_file_read(fd, type1, 2) != 2) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "read error", filename); - g_file_close(fd); - return 1; - } - - if ((type1[0] != 'B') || (type1[1] != 'M')) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "not BMP file", filename); - g_file_close(fd); - return 1; - } - - /* read file size */ - make_stream(s); - init_stream(s, 8192); - if (g_file_read(fd, s->data, 4) != 4) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: missing length in file %s", - filename); - free_stream(s); - g_file_close(fd); - return 1; - } - s->end = s->data + 4; - in_uint32_le(s, size); - /* read bmp header */ - if (g_file_seek(fd, 14) < 0) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: seek error in file %s", - filename); - free_stream(s); - g_file_close(fd); - return 1; - } - init_stream(s, 8192); - len = g_file_read(fd, s->data, 40); /* size better be 40 */ - if (len != 40) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: " - "unexpected read length %d in file %s", - len, filename); - free_stream(s); - g_file_close(fd); - return 1; - } - s->end = s->data + len; - in_uint32_le(s, header.size); - in_uint32_le(s, header.image_width); - in_uint32_le(s, header.image_height); - in_uint16_le(s, header.planes); - in_uint16_le(s, header.bit_count); - in_uint32_le(s, header.compression); - in_uint32_le(s, header.image_size); - in_uint32_le(s, header.x_pels_per_meter); - in_uint32_le(s, header.y_pels_per_meter); - in_uint32_le(s, header.clr_used); - in_uint32_le(s, header.clr_important); - - if ((header.bit_count != 4) && (header.bit_count != 8) && - (header.bit_count != 24)) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error bitmap file [%s] " - "bad bpp %d", filename, header.bit_count); - free_stream(s); - g_file_close(fd); - return 1; - } - - if (header.bit_count == 24) /* 24 bit bitmap */ - { - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s", - filename); - } - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height * 3; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width * 3; - k = g_file_read(fd, s->data + i * size, size); - - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = k; - in_uint8(s, k); - color |= k << 8; - in_uint8(s, k); - color |= k << 16; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - else if (header.bit_count == 8) /* 8 bit bitmap */ - { - /* read palette */ - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s", - filename); - } - size = header.clr_used * sizeof(int); - - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - len = g_file_read(fd, s->data, size); - if (len != size) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: " - "unexpected read length in file %s", - filename); - } - - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width; - k = g_file_read(fd, s->data + i * size, size); - - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = palette1[k]; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - else if (header.bit_count == 4) /* 4 bit bitmap */ - { - /* read palette */ - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: seek error in file %s", - filename); - } - size = header.clr_used * sizeof(int); - - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - len = g_file_read(fd, s->data, size); - if (len != size) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: " - "unexpected read length in file %s", - filename); - } - - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = (header.image_width * header.image_height) / 2; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width / 2; - k = g_file_read(fd, s->data + i * size, size); - - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_load: error bitmap " - "file [%s] read", filename); - } - } - - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - if ((j & 1) == 0) - { - in_uint8(s, k); - color = (k >> 4) & 0xf; - } - else - { - color = k & 0xf; - } - - color = palette1[color]; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - - g_file_close(fd); - free_stream(s); - } - else - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_load: error loading bitmap " - "from file [%s]", filename); - return 1; - } - - return 0; -} - -/*****************************************************************************/ -int -xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, - const int *palette, - int background, - enum xrdp_bitmap_load_transform transform, - int twidth, - int theight) -{ - /* this is the default bmp-only implementation if a graphics library - * isn't built in */ - - int result = xrdp_bitmap_load_bmp(self, filename, palette); - if (result == 0) - { - switch (transform) - { - case XBLT_NONE: - break; - - case XBLT_SCALE: - result = xrdp_bitmap_scale(self, twidth, theight); - break; - - case XBLT_ZOOM: - result = xrdp_bitmap_zoom(self, twidth, theight); - break; - - default: - LOG(LOG_LEVEL_WARNING, "Invalid bitmap transform %d specified", - transform); - } - } - return result; -} - -/*****************************************************************************/ -int -xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y) -{ - if (self == 0) - { - return 0; - } - - if (self->data == 0) - { - return 0; - } - - if (x >= 0 && x < self->width && y >= 0 && y < self->height) - { - if (self->bpp == 8) - { - return GETPIXEL8(self->data, x, y, self->width); - } - else if (self->bpp == 15 || self->bpp == 16) - { - return GETPIXEL16(self->data, x, y, self->width); - } - else if (self->bpp >= 24) - { - return GETPIXEL32(self->data, x, y, self->width); - } - } - - return 0; -} - -/*****************************************************************************/ -int -xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel) -{ - if (self == 0) - { - return 0; - } - - if (self->data == 0) - { - return 0; - } - - if (x >= 0 && x < self->width && y >= 0 && y < self->height) - { - if (self->bpp == 8) - { - SETPIXEL8(self->data, x, y, self->width, pixel); - } - else if (self->bpp == 15 || self->bpp == 16) - { - SETPIXEL16(self->data, x, y, self->width, pixel); - } - else if (self->bpp >= 24) - { - SETPIXEL32(self->data, x, y, self->width, pixel); - } - } - - return 0; -} - -/*****************************************************************************/ -/* copy part of self at x, y to 0, 0 in dest */ -/* returns error */ -int -xrdp_bitmap_copy_box(struct xrdp_bitmap *self, - struct xrdp_bitmap *dest, - int x, int y, int cx, int cy) -{ - int i; - int destx; - int desty; - int incs; - int incd; - tui8 *s8; - tui8 *d8; - tui16 *s16; - tui16 *d16; - tui32 *s32; - tui32 *d32; - - if (self == 0) - { - return 1; - } - - if (dest == 0) - { - return 1; - } - - if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) - { - return 1; - } - - if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) - { - return 1; - } - - if (self->bpp != dest->bpp) - { - return 1; - } - - destx = 0; - desty = 0; - - if (!check_bounds(self, &x, &y, &cx, &cy)) - { - return 1; - } - - if (!check_bounds(dest, &destx, &desty, &cx, &cy)) - { - return 1; - } - - if (self->bpp >= 24) - { - s32 = ((tui32 *)(self->data)) + (self->width * y + x); - d32 = ((tui32 *)(dest->data)) + (dest->width * desty + destx); - incs = self->width - cx; - incd = dest->width - cx; - - for (i = 0; i < cy; i++) - { - g_memcpy(d32, s32, cx * 4); - s32 += cx; - d32 += cx; - - s32 += incs; - d32 += incd; - } - - } - else if (self->bpp == 15 || self->bpp == 16) - { - s16 = ((tui16 *)(self->data)) + (self->width * y + x); - d16 = ((tui16 *)(dest->data)) + (dest->width * desty + destx); - incs = self->width - cx; - incd = dest->width - cx; - - for (i = 0; i < cy; i++) - { - g_memcpy(d16, s16, cx * 2); - s16 += cx; - d16 += cx; - - s16 += incs; - d16 += incd; - } - } - else if (self->bpp == 8) - { - s8 = ((tui8 *)(self->data)) + (self->width * y + x); - d8 = ((tui8 *)(dest->data)) + (dest->width * desty + destx); - incs = self->width - cx; - incd = dest->width - cx; - - for (i = 0; i < cy; i++) - { - g_memcpy(d8, s8, cx); - s8 += cx; - d8 += cx; - - s8 += incs; - d8 += incd; - } - } - else - { - return 1; - } - - return 0; -} - /*****************************************************************************/ int xrdp_bitmap_hash_crc(struct xrdp_bitmap *self) diff --git a/xrdp/xrdp_bitmap_common.c b/xrdp/xrdp_bitmap_common.c new file mode 100644 index 0000000000..836ba819e1 --- /dev/null +++ b/xrdp/xrdp_bitmap_common.c @@ -0,0 +1,509 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Common bitmap functions for all xrdp_bitmap*.c files + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include + +#include "xrdp.h" + +/*****************************************************************************/ +/* Allocate bitmap for specified dimensions, checking for int overflow */ +static char * +alloc_bitmap_data(int width, int height, int Bpp) +{ + char *result = NULL; + if (width > 0 && height > 0 && Bpp > 0) + { + int len = width; + /* g_malloc() currently takes an 'int' size */ + if (len < INT_MAX / height) + { + len *= height; + if (len < INT_MAX / Bpp) + { + len *= Bpp; + result = (char *)malloc(len); + } + } + } + + return result; +} + +/*****************************************************************************/ +struct xrdp_bitmap * +xrdp_bitmap_create(int width, int height, int bpp, + int type, struct xrdp_wm *wm) +{ + struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; + int Bpp = 0; + + self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); + if (self == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: no memory"); + return self; + } + + self->type = type; + self->width = width; + self->height = height; + self->bpp = bpp; + Bpp = 4; + + switch (bpp) + { + case 8: + Bpp = 1; + break; + case 15: + Bpp = 2; + break; + case 16: + Bpp = 2; + break; + } + + if (self->type == WND_TYPE_BITMAP || self->type == WND_TYPE_IMAGE) + { + self->data = alloc_bitmap_data(width, height, Bpp); + if (self->data == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d", + width, height, Bpp); + g_free(self); + return NULL; + } + } + +#if defined(XRDP_PAINTER) + if (self->type == WND_TYPE_SCREEN) /* noorders */ + { + LOG_DEVEL(LOG_LEVEL_INFO, "xrdp_bitmap_create: noorders"); + self->data = alloc_bitmap_data(width, height, Bpp); + if (self->data == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_create: size overflow %dx%dx%d", + width, height, Bpp); + g_free(self); + return NULL; + } + } +#endif + + if (self->type != WND_TYPE_BITMAP) + { + self->child_list = list_create(); + } + + self->line_size = width * Bpp; + + if (self->type == WND_TYPE_COMBO) + { + self->string_list = list_create(); + self->string_list->auto_free = 1; + self->data_list = list_create(); + self->data_list->auto_free = 1; + } + + self->wm = wm; + return self; +} + +/*****************************************************************************/ +struct xrdp_bitmap * +xrdp_bitmap_create_with_data(int width, int height, + int bpp, char *data, + struct xrdp_wm *wm) +{ + struct xrdp_bitmap *self = (struct xrdp_bitmap *)NULL; + int Bpp; +#if defined(NEED_ALIGN) + tintptr data_as_int; +#endif + + self = (struct xrdp_bitmap *)g_malloc(sizeof(struct xrdp_bitmap), 1); + self->type = WND_TYPE_BITMAP; + self->width = width; + self->height = height; + self->bpp = bpp; + self->wm = wm; + + Bpp = 4; + switch (bpp) + { + case 8: + Bpp = 1; + break; + case 15: + Bpp = 2; + break; + case 16: + Bpp = 2; + break; + } + self->line_size = width * Bpp; + +#if defined(NEED_ALIGN) + data_as_int = (tintptr) data; + if (((bpp >= 24) && (data_as_int & 3)) || + (((bpp == 15) || (bpp == 16)) && (data_as_int & 1))) + { + /* got to copy data here, it's not aligned + other calls in this file assume alignment */ + self->data = (char *)g_malloc(width * height * Bpp, 0); + g_memcpy(self->data, data, width * height * Bpp); + return self; + } +#endif + self->data = data; + self->do_not_free_data = 1; + return self; +} + +/*****************************************************************************/ +void +xrdp_bitmap_delete(struct xrdp_bitmap *self) +{ + int i = 0; + struct xrdp_mod_data *mod_data = (struct xrdp_mod_data *)NULL; + + if (self == 0) + { + return; + } + + if (self->wm != 0) + { + if (self->wm->focused_window != 0) + { + if (self->wm->focused_window->focused_control == self) + { + self->wm->focused_window->focused_control = 0; + } + } + + if (self->wm->focused_window == self) + { + self->wm->focused_window = 0; + } + + if (self->wm->dragging_window == self) + { + self->wm->dragging_window = 0; + } + + if (self->wm->button_down == self) + { + self->wm->button_down = 0; + } + + if (self->wm->popup_wnd == self) + { + self->wm->popup_wnd = 0; + } + + if (self->wm->login_window == self) + { + self->wm->login_window = 0; + } + + if (self->wm->log_wnd == self) + { + self->wm->log_wnd = 0; + } + } + + if (self->child_list != 0) + { + for (i = self->child_list->count - 1; i >= 0; i--) + { + xrdp_bitmap_delete((struct xrdp_bitmap *)self->child_list->items[i]); + } + + list_delete(self->child_list); + } + + if (self->parent != 0) + { + i = list_index_of(self->parent->child_list, (long)self); + + if (i >= 0) + { + list_remove_item(self->parent->child_list, i); + } + } + + if (self->string_list != 0) /* for combo */ + { + list_delete(self->string_list); + } + + if (self->data_list != 0) /* for combo */ + { + for (i = 0; i < self->data_list->count; i++) + { + mod_data = (struct xrdp_mod_data *)list_get_item(self->data_list, i); + + if (mod_data != 0) + { + list_delete(mod_data->names); + list_delete(mod_data->values); + } + } + + list_delete(self->data_list); + } + + if (!self->do_not_free_data) + { + g_free(self->data); + } + + g_free(self->caption1); + g_free(self); +} + +/*****************************************************************************/ +/* returns error */ +int +xrdp_bitmap_resize(struct xrdp_bitmap *self, int width, int height) +{ + int Bpp = 0; + + if ((width == self->width) && (height == self->height)) + { + return 0; + } + + if (self->do_not_free_data) + { + return 1; + } + + self->width = width; + self->height = height; + Bpp = 4; + + switch (self->bpp) + { + case 8: + Bpp = 1; + break; + case 15: + Bpp = 2; + break; + case 16: + Bpp = 2; + break; + } + + g_free(self->data); + self->data = (char *)g_malloc(width * height * Bpp, 0); + self->line_size = width * Bpp; + return 0; +} + +/*****************************************************************************/ +int +xrdp_bitmap_get_pixel(struct xrdp_bitmap *self, int x, int y) +{ + if (self == 0) + { + return 0; + } + + if (self->data == 0) + { + return 0; + } + + if (x >= 0 && x < self->width && y >= 0 && y < self->height) + { + if (self->bpp == 8) + { + return GETPIXEL8(self->data, x, y, self->width); + } + else if (self->bpp == 15 || self->bpp == 16) + { + return GETPIXEL16(self->data, x, y, self->width); + } + else if (self->bpp >= 24) + { + return GETPIXEL32(self->data, x, y, self->width); + } + } + + return 0; +} + +/*****************************************************************************/ +int +xrdp_bitmap_set_pixel(struct xrdp_bitmap *self, int x, int y, int pixel) +{ + if (self == 0) + { + return 0; + } + + if (self->data == 0) + { + return 0; + } + + if (x >= 0 && x < self->width && y >= 0 && y < self->height) + { + if (self->bpp == 8) + { + SETPIXEL8(self->data, x, y, self->width, pixel); + } + else if (self->bpp == 15 || self->bpp == 16) + { + SETPIXEL16(self->data, x, y, self->width, pixel); + } + else if (self->bpp >= 24) + { + SETPIXEL32(self->data, x, y, self->width, pixel); + } + } + + return 0; +} + +/*****************************************************************************/ +/* copy part of self at x, y to 0, 0 in dest */ +/* returns error */ +int +xrdp_bitmap_copy_box(struct xrdp_bitmap *self, + struct xrdp_bitmap *dest, + int x, int y, int cx, int cy) +{ + int i; + int destx; + int desty; + int incs; + int incd; + tui8 *s8; + tui8 *d8; + tui16 *s16; + tui16 *d16; + tui32 *s32; + tui32 *d32; + + if (self == 0) + { + return 1; + } + + if (dest == 0) + { + return 1; + } + + if (self->type != WND_TYPE_BITMAP && self->type != WND_TYPE_IMAGE) + { + return 1; + } + + if (dest->type != WND_TYPE_BITMAP && dest->type != WND_TYPE_IMAGE) + { + return 1; + } + + if (self->bpp != dest->bpp) + { + return 1; + } + + destx = 0; + desty = 0; + + if (!check_bounds(self, &x, &y, &cx, &cy)) + { + return 1; + } + + if (!check_bounds(dest, &destx, &desty, &cx, &cy)) + { + return 1; + } + + if (self->bpp >= 24) + { + s32 = ((tui32 *)(self->data)) + (self->width * y + x); + d32 = ((tui32 *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + + for (i = 0; i < cy; i++) + { + g_memcpy(d32, s32, cx * 4); + s32 += cx; + d32 += cx; + + s32 += incs; + d32 += incd; + } + + } + else if (self->bpp == 15 || self->bpp == 16) + { + s16 = ((tui16 *)(self->data)) + (self->width * y + x); + d16 = ((tui16 *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + + for (i = 0; i < cy; i++) + { + g_memcpy(d16, s16, cx * 2); + s16 += cx; + d16 += cx; + + s16 += incs; + d16 += incd; + } + } + else if (self->bpp == 8) + { + s8 = ((tui8 *)(self->data)) + (self->width * y + x); + d8 = ((tui8 *)(dest->data)) + (dest->width * desty + destx); + incs = self->width - cx; + incd = dest->width - cx; + + for (i = 0; i < cy; i++) + { + g_memcpy(d8, s8, cx); + s8 += cx; + d8 += cx; + + s8 += incs; + d8 += incd; + } + } + else + { + return 1; + } + + return 0; +} diff --git a/xrdp/xrdp_bitmap_load.c b/xrdp/xrdp_bitmap_load.c new file mode 100644 index 0000000000..304dfba29d --- /dev/null +++ b/xrdp/xrdp_bitmap_load.c @@ -0,0 +1,585 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2014 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Load xrdp_bitmap from file + */ + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include "xrdp.h" +#include "log.h" + +/**************************************************************************//** + * Private routine to swap pixel data between two pixmaps + * @param a First bitmap + * @param b Second bitmap + * + * The main use-case for this routine is to modify an existing bitmap using + * the following logic:- + * - Create a temporary WND_TYPE_BITMAP + * - Process the data in a bitmap in some way, moving it to the temporary + * - Call this routine + * - Delete the temporary + * + */ +static void +swap_pixel_data(struct xrdp_bitmap *a, struct xrdp_bitmap *b) +{ + int tmp_width = a->width; + int tmp_height = a->height; + int tmp_bpp = a->bpp; + int tmp_line_size = a->line_size; + char *tmp_data = a->data; + int tmp_do_not_free_data = a->do_not_free_data; + + a->width = b->width; + a->height = b->height; + a->bpp = b->bpp; + a->line_size = b->line_size; + a->data = b->data; + a->do_not_free_data = b->do_not_free_data; + + b->width = tmp_width; + b->height = tmp_height; + b->bpp = tmp_bpp; + b->line_size = tmp_line_size; + b->data = tmp_data; + b->do_not_free_data = tmp_do_not_free_data; +} + +/**************************************************************************//** + * Scales a bitmap image + * + * @param self Bitmap to scale + * @param target_width target width + * @param target_height target height + * @return 0 for success + */ +static int +xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height) +{ + int src_width = self->width; + int src_height = self->height; + + if (src_width != targ_width || src_height != targ_height) + { + struct xrdp_bitmap *target = + xrdp_bitmap_create(targ_width, targ_height, + self->bpp, WND_TYPE_BITMAP, 0); + int targ_x, targ_y; + + if (target == NULL) + { + /* Error is logged */ + return 1; + } + + /* For each pixel in the target pixmap, scale to one in the source */ + for (targ_x = 0 ; targ_x < targ_width; ++targ_x) + { + int src_x = targ_x * src_width / targ_width; + for (targ_y = 0 ; targ_y < targ_height; ++targ_y) + { + int src_y = targ_y * src_height / targ_height; + int pixel = xrdp_bitmap_get_pixel(self, src_x, src_y); + xrdp_bitmap_set_pixel(target, targ_x, targ_y, pixel); + } + } + swap_pixel_data(self, target); + xrdp_bitmap_delete(target); + } + + return 0; +} + +/**************************************************************************//** + * Zooms a bitmap image + * + * @param self Bitmap to zoom + * @param target_width target width + * @param target_height target height + * @return 0 for success + * + * This works the same way as a scaled image, but the aspect ratio is + * maintained by removing pixels from the top-and-bottom, + * or the left-and-right before scaling. + */ +static int +xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) +{ + int src_width = self->width; + int src_height = self->height; + double targ_ratio = (double)targ_width / targ_height; + double src_ratio = (double)src_width / src_height; + + unsigned int chop_width; + unsigned int chop_left_margin; + unsigned int chop_height; + unsigned int chop_top_margin; + + int result = 0; + + if (src_ratio > targ_ratio) + { + /* Source is relatively wider than source. Select a box + * narrower than the source, but the same height */ + chop_width = (int)(targ_ratio * src_height + .5); + chop_left_margin = (src_width - chop_width) / 2; + chop_height = src_height; + chop_top_margin = 0; + } + else + { + /* Source is relatively taller than source (or same shape) */ + chop_width = src_width; + chop_left_margin = 0; + chop_height = (int)(src_width / targ_ratio + .5); + chop_top_margin = (src_height - chop_height) / 2; + } + + /* Only chop the image if there's a need to */ + if (chop_top_margin != 0 || chop_left_margin != 0) + { + struct xrdp_bitmap *chopbox; + chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp, + WND_TYPE_BITMAP, 0); + if (chopbox == NULL) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory"); + result = 1; + } + else + { + result = xrdp_bitmap_copy_box(self, chopbox, + chop_left_margin, chop_top_margin, + chop_width, chop_height); + if (result != 0) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box"); + } + else + { + swap_pixel_data(self, chopbox); + } + xrdp_bitmap_delete(chopbox); + } + } + + if (result == 0) + { + result = xrdp_bitmap_scale(self, targ_width, targ_height); + } + + return result; +} + +/*****************************************************************************/ +static int +xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) +{ + int r = 0; + int g = 0; + int b = 0; + + r = (color & 0xff0000) >> 16; + g = (color & 0x00ff00) >> 8; + b = (color & 0x0000ff) >> 0; + r = (r >> 5) << 0; + g = (g >> 5) << 3; + b = (b >> 6) << 6; + return (b | g | r); +} + +/*****************************************************************************/ +/* load a bmp file */ +/* return 0 ok */ +/* return 1 error */ +static int +xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, + const int *palette) +{ + int fd = 0; + int len = 0; + int i = 0; + int j = 0; + int k = 0; + int color = 0; + int size = 0; + int palette1[256]; + char type1[4]; + struct xrdp_bmp_header header; + struct stream *s = (struct stream *)NULL; + + g_memset(palette1, 0, sizeof(int) * 256); + g_memset(type1, 0, sizeof(char) * 4); + g_memset(&header, 0, sizeof(struct xrdp_bmp_header)); + + if (!g_file_exist(filename)) + { + LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] does not exist", + __func__, filename); + return 1; + } + + fd = g_file_open(filename); + + if (fd == -1) + { + LOG(LOG_LEVEL_ERROR, "%s: error loading bitmap from file [%s]", + __func__, filename); + return 1; + } + + /* read file type */ + if (g_file_read(fd, type1, 2) != 2) + { + LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] read error", + __func__, filename); + g_file_close(fd); + return 1; + } + + if ((type1[0] != 'B') || (type1[1] != 'M')) + { + LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] not BMP file", + __func__, filename); + g_file_close(fd); + return 1; + } + + /* read file size */ + make_stream(s); + init_stream(s, 8192); + if (g_file_read(fd, s->data, 4) != 4) + { + LOG(LOG_LEVEL_ERROR, "%s: missing length in file %s", + __func__, filename); + free_stream(s); + g_file_close(fd); + return 1; + } + s->end = s->data + 4; + in_uint32_le(s, size); + /* read bmp header */ + if (g_file_seek(fd, 14) < 0) + { + LOG(LOG_LEVEL_ERROR, "%s: seek error in file %s", + __func__, filename); + free_stream(s); + g_file_close(fd); + return 1; + } + init_stream(s, 8192); + len = g_file_read(fd, s->data, 40); /* size better be 40 */ + if (len != 40) + { + LOG(LOG_LEVEL_ERROR, "%s: unexpected read length %d in file %s", + __func__, len, filename); + free_stream(s); + g_file_close(fd); + return 1; + } + s->end = s->data + len; + in_uint32_le(s, header.size); + in_uint32_le(s, header.image_width); + in_uint32_le(s, header.image_height); + in_uint16_le(s, header.planes); + in_uint16_le(s, header.bit_count); + in_uint32_le(s, header.compression); + in_uint32_le(s, header.image_size); + in_uint32_le(s, header.x_pels_per_meter); + in_uint32_le(s, header.y_pels_per_meter); + in_uint32_le(s, header.clr_used); + in_uint32_le(s, header.clr_important); + + if ((header.bit_count != 4) && (header.bit_count != 8) && + (header.bit_count != 24)) + { + LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] bad bpp %d", + __func__, filename, header.bit_count); + free_stream(s); + g_file_close(fd); + return 1; + } + + if (header.bit_count == 24) /* 24 bit bitmap */ + { + if (g_file_seek(fd, 14 + header.size) < 0) + { + LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", + __func__, filename); + } + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = header.image_width * header.image_height * 3; + init_stream(s, size); + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, size); + s->end = s->data + size; + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width * 3; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", + __func__, filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + in_uint8(s, k); + color = k; + in_uint8(s, k); + color |= k << 8; + in_uint8(s, k); + color |= k << 16; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + else if (header.bit_count == 8) /* 8 bit bitmap */ + { + /* read palette */ + if (g_file_seek(fd, 14 + header.size) < 0) + { + LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", + __func__, filename); + } + size = header.clr_used * sizeof(int); + + init_stream(s, size); + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, size); + s->end = s->data + size; + + len = g_file_read(fd, s->data, size); + if (len != size) + { + LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s", + __func__, filename); + } + + for (i = 0; i < header.clr_used; i++) + { + in_uint32_le(s, palette1[i]); + } + + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = header.image_width * header.image_height; + init_stream(s, size); + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, size); + s->end = s->data + size; + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", + __func__, filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + in_uint8(s, k); + color = palette1[k]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + else if (header.bit_count == 4) /* 4 bit bitmap */ + { + /* read palette */ + if (g_file_seek(fd, 14 + header.size) < 0) + { + LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", + __func__, filename); + } + size = header.clr_used * sizeof(int); + + init_stream(s, size); + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, size); + s->end = s->data + size; + + len = g_file_read(fd, s->data, size); + if (len != size) + { + LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s", + __func__, filename); + } + + for (i = 0; i < header.clr_used; i++) + { + in_uint32_le(s, palette1[i]); + } + + xrdp_bitmap_resize(self, header.image_width, header.image_height); + size = (header.image_width * header.image_height) / 2; + init_stream(s, size); + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, size); + s->end = s->data + size; + + /* read data */ + for (i = header.image_height - 1; i >= 0; i--) + { + size = header.image_width / 2; + k = g_file_read(fd, s->data + i * size, size); + + if (k != size) + { + LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", + __func__, filename); + } + } + + for (i = 0; i < self->height; i++) + { + for (j = 0; j < self->width; j++) + { + if ((j & 1) == 0) + { + in_uint8(s, k); + color = (k >> 4) & 0xf; + } + else + { + color = k & 0xf; + } + + color = palette1[color]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, i, color); + } + } + } + + g_file_close(fd); + free_stream(s); + + return 0; +} + +/*****************************************************************************/ +int +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, + const int *palette, + int background, + enum xrdp_bitmap_load_transform transform, + int twidth, + int theight) +{ + /* this is the default bmp-only implementation if a graphics library + * isn't built in */ + + int result = xrdp_bitmap_load_bmp(self, filename, palette); + if (result == 0) + { + switch (transform) + { + case XBLT_NONE: + break; + + case XBLT_SCALE: + result = xrdp_bitmap_scale(self, twidth, theight); + break; + + case XBLT_ZOOM: + result = xrdp_bitmap_zoom(self, twidth, theight); + break; + + default: + LOG(LOG_LEVEL_WARNING, "Invalid bitmap transform %d specified", + transform); + } + } + return result; +} From f87502872deb881bc81a66c2c904168b1a2ccb55 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 7 Jul 2021 16:48:31 +0100 Subject: [PATCH 03/14] Rework and simplify xrdp_bitmap_load_bmp() --- xrdp/xrdp_bitmap_load.c | 554 +++++++++++++++++++++------------------- 1 file changed, 298 insertions(+), 256 deletions(-) diff --git a/xrdp/xrdp_bitmap_load.c b/xrdp/xrdp_bitmap_load.c index 304dfba29d..5384c87c7d 100644 --- a/xrdp/xrdp_bitmap_load.c +++ b/xrdp/xrdp_bitmap_load.c @@ -25,6 +25,9 @@ #include "xrdp.h" #include "log.h" +/* Rounds up to the nearest multiple of 4 */ +#define ROUND4(x) (((x) + 3) / 4 * 4) + /**************************************************************************//** * Private routine to swap pixel data between two pixmaps * @param a First bitmap @@ -153,8 +156,15 @@ xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) chop_top_margin = (src_height - chop_height) / 2; } - /* Only chop the image if there's a need to */ - if (chop_top_margin != 0 || chop_left_margin != 0) + /* Only chop the image if there's a need to, and if it will look + * meaningful */ + if (chop_width < 1 || chop_height < 1) + { + LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_zoom: Ignoring pathological" + " request (%dx%d) -> (%dx%d)", src_width, src_height, + targ_width, targ_height); + } + else if (chop_top_margin != 0 || chop_left_margin != 0) { struct xrdp_bitmap *chopbox; chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp, @@ -206,29 +216,245 @@ xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) return (b | g | r); } +/**************************************************************************//** + * reads the palette from a bmp file with a palette embedded in it + * + * @pre The read position in the file is at the end of the bmp DIB header. + * + * @param filename Name of file + * @param fd File descriptor for file + * @param header Pointer to BMP header info struct + * @param palette output. Must be at least 256 elements + */ +static void +read_palette(const char *filename, int fd, + const struct xrdp_bmp_header *header, int *palette) +{ + struct stream *s; + int clr_used; + int palette_size; + int len; + int i; + + /* Find the number of colors used in the bitmap */ + if (header->clr_used != 0) + { + clr_used = header->clr_used; + /* Is the header value sane? */ + if (clr_used < 0 || clr_used > 256) + { + clr_used = 256; + LOG(LOG_LEVEL_WARNING, "%s : Invalid palette size %d in file %s", + __func__, header->clr_used, filename); + } + } + else if (header->bit_count == 4) + { + clr_used = 16; + } + else + { + clr_used = 256; + } + + palette_size = clr_used * 4; + + make_stream(s); + init_stream(s, palette_size); + + /* Pre-fill the buffer, so if we get short reads we're + * not working with uninitialised data */ + g_memset(s->data, 0, palette_size); + s->end = s->data + palette_size; + + len = g_file_read(fd, s->data, palette_size); + if (len != palette_size) + { + LOG(LOG_LEVEL_WARNING, "%s: unexpected read length in file %s", + __func__, filename); + } + + for (i = 0; i < clr_used; ++i) + { + in_uint32_le(s, palette[i]); + } + + free_stream(s); +} + +/**************************************************************************//** + * Process a row of data from a 24-bit bmp file + * + * @param self Bitmap we're filling in + * @param s Stream containing bitmap data + * @param in_palette Palette from bmp file (unused) + * @param out_palette Palette for output bitmap + * @param row Row number + */ +static void +process_row_data_24bit(struct xrdp_bitmap *self, + struct stream *s, + const int *in_palette, + const int *out_palette, + int row) +{ + int j; + int k; + int color; + + for (j = 0; j < self->width; ++j) + { + in_uint8(s, k); + color = k; + in_uint8(s, k); + color |= k << 8; + in_uint8(s, k); + color |= k << 16; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, out_palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, row, color); + } +} + +/**************************************************************************//** + * Process a row of data from an 8-bit bmp file + * + * @param self Bitmap we're filling in + * @param s Stream containing bitmap data + * @param in_palette Palette from bmp file + * @param out_palette Palette for output bitmap + * @param row Row number + */ +static void +process_row_data_8bit(struct xrdp_bitmap *self, + struct stream *s, + const int *in_palette, + const int *out_palette, + int row) +{ + int j; + int k; + int color; + + for (j = 0; j < self->width; ++j) + { + in_uint8(s, k); + color = in_palette[k]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, out_palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, row, color); + } +} + +/**************************************************************************//** + * Process a row of data from an 4-bit bmp file + * + * @param self Bitmap we're filling in + * @param s Stream containing bitmap data + * @param in_palette Palette from bmp file + * @param out_palette Palette for output bitmap + * @param row Row number + */ +static void +process_row_data_4bit(struct xrdp_bitmap *self, + struct stream *s, + const int *in_palette, + const int *out_palette, + int row) +{ + int j; + int k = 0; + int color; + + for (j = 0; j < self->width; ++j) + { + if ((j & 1) == 0) + { + in_uint8(s, k); + color = (k >> 4) & 0xf; + } + else + { + color = k & 0xf; + } + + color = in_palette[color]; + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, out_palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, j, row, color); + } +} + /*****************************************************************************/ /* load a bmp file */ /* return 0 ok */ /* return 1 error */ static int xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, - const int *palette) + const int *out_palette) { int fd = 0; int len = 0; - int i = 0; - int j = 0; - int k = 0; - int color = 0; - int size = 0; - int palette1[256]; - char type1[4]; - struct xrdp_bmp_header header; + int row = 0; + int row_size = 0; + int bmp_palette[256] = {0}; + char fixed_header[14] = {0}; + struct xrdp_bmp_header header = {0}; struct stream *s = (struct stream *)NULL; - - g_memset(palette1, 0, sizeof(int) * 256); - g_memset(type1, 0, sizeof(char) * 4); - g_memset(&header, 0, sizeof(struct xrdp_bmp_header)); + /* Pointer to row data processing function */ + void (*process_row_data)(struct xrdp_bitmap * self, + struct stream * s, + const int *in_palette, + const int *out_palette, + int row); if (!g_file_exist(filename)) { @@ -246,8 +472,8 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, return 1; } - /* read file type */ - if (g_file_read(fd, type1, 2) != 2) + /* read the fixed file header */ + if (g_file_read(fd, fixed_header, 14) != 14) { LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] read error", __func__, filename); @@ -255,7 +481,7 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, return 1; } - if ((type1[0] != 'B') || (type1[1] != 'M')) + if ((fixed_header[0] != 'B') || (fixed_header[1] != 'M')) { LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] not BMP file", __func__, filename); @@ -263,29 +489,9 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, return 1; } - /* read file size */ + /* read information header */ make_stream(s); init_stream(s, 8192); - if (g_file_read(fd, s->data, 4) != 4) - { - LOG(LOG_LEVEL_ERROR, "%s: missing length in file %s", - __func__, filename); - free_stream(s); - g_file_close(fd); - return 1; - } - s->end = s->data + 4; - in_uint32_le(s, size); - /* read bmp header */ - if (g_file_seek(fd, 14) < 0) - { - LOG(LOG_LEVEL_ERROR, "%s: seek error in file %s", - __func__, filename); - free_stream(s); - g_file_close(fd); - return 1; - } - init_stream(s, 8192); len = g_file_read(fd, s->data, 40); /* size better be 40 */ if (len != 40) { @@ -308,238 +514,74 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, in_uint32_le(s, header.clr_used); in_uint32_le(s, header.clr_important); - if ((header.bit_count != 4) && (header.bit_count != 8) && - (header.bit_count != 24)) + if (header.compression != 0) { - LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] bad bpp %d", - __func__, filename, header.bit_count); - free_stream(s); - g_file_close(fd); - return 1; + LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s]" + " unsupported compression value %d", + __func__, filename, header.compression); } - if (header.bit_count == 24) /* 24 bit bitmap */ + if (g_file_seek(fd, 14 + header.size) < 0) { - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", - __func__, filename); - } - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height * 3; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width * 3; - k = g_file_read(fd, s->data + i * size, size); - - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", - __func__, filename); - } - } - - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = k; - in_uint8(s, k); - color |= k << 8; - in_uint8(s, k); - color |= k << 16; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } + LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", + __func__, filename); } - else if (header.bit_count == 8) /* 8 bit bitmap */ - { - /* read palette */ - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", - __func__, filename); - } - size = header.clr_used * sizeof(int); - - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - len = g_file_read(fd, s->data, size); - if (len != size) - { - LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s", - __func__, filename); - } - - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = header.image_width * header.image_height; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; + /* Validate the bit count for the file, read any palette, and + * dtermine the row size and row processing function */ + switch (header.bit_count) + { + case 24: + row_size = ROUND4(header.image_width * 3); + process_row_data = process_row_data_24bit; + break; + + case 8: + read_palette(filename, fd, &header, bmp_palette); + row_size = ROUND4(header.image_width); + process_row_data = process_row_data_8bit; + break; + + case 4: + read_palette(filename, fd, &header, bmp_palette); + /* The storage for a row is a complex calculation for 4 bit pixels. + * a width of 1-8 pixels takes 4 bytes + * a width of 9-16 pixels takes 8 bytes, etc + * So bytes = (width + 7) / 8 * 4 + */ + row_size = ((header.image_width + 7) / 8 * 4); + process_row_data = process_row_data_4bit; + break; + + default: + LOG(LOG_LEVEL_ERROR, "%s: error bitmap file [%s] bad bpp %d", + __func__, filename, header.bit_count); + free_stream(s); + g_file_close(fd); + return 1; + } - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width; - k = g_file_read(fd, s->data + i * size, size); + xrdp_bitmap_resize(self, header.image_width, header.image_height); - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", - __func__, filename); - } - } + /* Set up the row data buffer. Pre fill it, so if we get short reads + * we're not working with uninitialised data */ + init_stream(s, row_size); + g_memset(s->data, 0, row_size); + s->end = s->data + row_size; - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - in_uint8(s, k); - color = palette1[k]; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } - } - else if (header.bit_count == 4) /* 4 bit bitmap */ + /* read and process the pixel data a row at a time */ + for (row = header.image_height - 1; row >= 0; row--) { - /* read palette */ - if (g_file_seek(fd, 14 + header.size) < 0) - { - LOG(LOG_LEVEL_WARNING, "%s: seek error in file %s", - __func__, filename); - } - size = header.clr_used * sizeof(int); + len = g_file_read(fd, s->data, row_size); - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - len = g_file_read(fd, s->data, size); - if (len != size) + if (len != row_size) { - LOG(LOG_LEVEL_ERROR, "%s: unexpected read length in file %s", + LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", __func__, filename); } - for (i = 0; i < header.clr_used; i++) - { - in_uint32_le(s, palette1[i]); - } - - xrdp_bitmap_resize(self, header.image_width, header.image_height); - size = (header.image_width * header.image_height) / 2; - init_stream(s, size); - /* Pre-fill the buffer, so if we get short reads we're - * not working with uninitialised data */ - g_memset(s->data, 0, size); - s->end = s->data + size; - - /* read data */ - for (i = header.image_height - 1; i >= 0; i--) - { - size = header.image_width / 2; - k = g_file_read(fd, s->data + i * size, size); - - if (k != size) - { - LOG(LOG_LEVEL_WARNING, "%s: error bitmap file [%s] read", - __func__, filename); - } - } - - for (i = 0; i < self->height; i++) - { - for (j = 0; j < self->width; j++) - { - if ((j & 1) == 0) - { - in_uint8(s, k); - color = (k >> 4) & 0xf; - } - else - { - color = k & 0xf; - } - - color = palette1[color]; - - if (self->bpp == 8) - { - color = xrdp_bitmap_get_index(self, palette, color); - } - else if (self->bpp == 15) - { - color = COLOR15((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - else if (self->bpp == 16) - { - color = COLOR16((color & 0xff0000) >> 16, - (color & 0x00ff00) >> 8, - (color & 0x0000ff) >> 0); - } - - xrdp_bitmap_set_pixel(self, j, i, color); - } - } + s->p = s->data; + (*process_row_data)(self, s, bmp_palette, out_palette, row); } g_file_close(fd); From 47737c7d13f2a848153b8f929c777dc61fa57b7a Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 7 Jul 2021 11:36:29 +0100 Subject: [PATCH 04/14] Add unit tests for xrdp_bitmap_load() --- configure.ac | 1 + tests/Makefile.am | 3 +- tests/xrdp/Makefile.am | 37 +++++ tests/xrdp/test_24bit.bmp | Bin 0 -> 196662 bytes tests/xrdp/test_4bit.bmp | Bin 0 -> 32888 bytes tests/xrdp/test_8bit.bmp | Bin 0 -> 66614 bytes tests/xrdp/test_bitmap_load.c | 282 +++++++++++++++++++++++++++++++++ tests/xrdp/test_not4_24bit.bmp | Bin 0 -> 11710 bytes tests/xrdp/test_not4_4bit.bmp | Bin 0 -> 2102 bytes tests/xrdp/test_not4_8bit.bmp | Bin 0 -> 5046 bytes tests/xrdp/test_xrdp.h | 8 + tests/xrdp/test_xrdp_main.c | 62 ++++++++ 12 files changed, 392 insertions(+), 1 deletion(-) create mode 100644 tests/xrdp/Makefile.am create mode 100644 tests/xrdp/test_24bit.bmp create mode 100644 tests/xrdp/test_4bit.bmp create mode 100644 tests/xrdp/test_8bit.bmp create mode 100644 tests/xrdp/test_bitmap_load.c create mode 100644 tests/xrdp/test_not4_24bit.bmp create mode 100644 tests/xrdp/test_not4_4bit.bmp create mode 100644 tests/xrdp/test_not4_8bit.bmp create mode 100644 tests/xrdp/test_xrdp.h create mode 100644 tests/xrdp/test_xrdp_main.c diff --git a/configure.ac b/configure.ac index 0081ff4953..49bd601362 100644 --- a/configure.ac +++ b/configure.ac @@ -454,6 +454,7 @@ AC_CONFIG_FILES([ tests/Makefile tests/common/Makefile tests/memtest/Makefile + tests/xrdp/Makefile tools/Makefile tools/devel/Makefile tools/devel/tcp_proxy/Makefile diff --git a/tests/Makefile.am b/tests/Makefile.am index c5342cd855..42b0df1c86 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,4 +4,5 @@ EXTRA_DIST = \ SUBDIRS = \ common \ - memtest + memtest \ + xrdp diff --git a/tests/xrdp/Makefile.am b/tests/xrdp/Makefile.am new file mode 100644 index 0000000000..c1868ad291 --- /dev/null +++ b/tests/xrdp/Makefile.am @@ -0,0 +1,37 @@ +AM_CPPFLAGS = \ + -I$(top_builddir) \ + -I$(top_srcdir)/xrdp \ + -I$(top_srcdir)/libxrdp \ + -I$(top_srcdir)/common + +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ + $(top_srcdir)/tap-driver.sh + +PACKAGE_STRING="XRDP daemon" + +EXTRA_DIST = \ + test_4bit.bmp \ + test_8bit.bmp \ + test_24bit.bmp \ + test_not4_4bit.bmp \ + test_not4_8bit.bmp \ + test_not4_24bit.bmp + +TESTS = test_xrdp +check_PROGRAMS = test_xrdp + +test_xrdp_SOURCES = \ + test_xrdp.h \ + test_xrdp_main.c \ + test_bitmap_load.c + +test_xrdp_CFLAGS = \ + -D IMAGEDIR=\"$(srcdir)\" \ + @CHECK_CFLAGS@ + +test_xrdp_LDADD = \ + $(top_builddir)/xrdp/xrdp_bitmap_load.o \ + $(top_builddir)/xrdp/xrdp_bitmap_common.o \ + $(top_builddir)/xrdp/funcs.o \ + $(top_builddir)/common/libcommon.la \ + @CHECK_LIBS@ diff --git a/tests/xrdp/test_24bit.bmp b/tests/xrdp/test_24bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..2125d824858733161b00579e2bdfe635ff891a0b GIT binary patch literal 196662 zcmeIyF^&@f5Jb^gaS3t~BEmfYIrl$~!6431Px?LbNOsg!-B14c>+|{Yyr0iM@AvnY zkALsS^Y#7f@AK`)^Ss~x&+B>av)sVzp6Le8|8@h@2C>9#Z@SZa081$i~=S|E6c*A;nMNb^{25 zY>e&oZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@S zZa081$i~=S|E6c*A;nMNb^{25Y>e&oZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@SZa081$i~=S|E6c*A;nMNb^{25Y>e&oZ+aFUQv3vN zH-Iq6#@Jr}rf12C>9#Z@SZa081$i~=S|E6c* zA;nMNb^{25Y>e&oZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@SZa081$i~=S|E6c*A;nMNb^{25Y>e&oZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@SZa081$i~=S|E6c*A;nMNb^{25Y>e&o zZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@SZa081 z$i~=S|E6c*A;nMNb^{25Y>e&oZ+aFUQv3vNH-Iq6#@Jr}rf12C>9#Z@SZa081$i~=SKR-R|PAUFUf;`P6(b~+hnIKUJ(b^0+6+4;NEAY}Hp7ky5`_@0&9GyFL?J|LGwhfk zQ3%o63_B)B6hgE%!;T3Og%GXHuw#NmAw+94?3f@?2+`UMJ0?gJLbNu+jtLTl5UtIy zV}e8>L~Aqbm>^LI(b^0+6+4;NEAY} zHp7ky5`_@0&9GyFL?J|LGwhfkQ3%o63_B)B6hgE%!;T3Og%GXHuw#NmAw+94?3f@? z2+`UMJ0?gJLbNu+jtLTl5UtIyV}e8>L~Aqbm>^LI(b^0+6+4;NEAY}Hp7ky5`_@0&9GyFL?J|LGwhfkQ3%o63_B)B6hgE% z!;T3Og%GXHuw#NmAw+94?3f@?2+`UMJ0?gJLbNu+jtLTl5UtIyV}e8>L~Aqbm>^LI z(b^0+6+4;NEAY}Hp7ky5`_@0&9GyF zL?J|LGwhfkQ3%o63_B)B6hgE%!;T3Og%GXHuw#NmAw+94?3f@?2+`UMJ0?gJLbNu+ zjtLTl5UtIyV}e8>L~Aqbm>^LI(b^0 z+6+4;NEAY}Hp7ky5`_@0&9GyFL?J|LGwhfkQ3%o63_B)B6hgE%!;T3Og%GXHuw#Nm zAw+94?3f@?2+`UMJ0?gJLbNu+jtLTl5UtIyV}e8>L~Aqbm>^LI(b^0+6+4;NEAY}Hp7ky5`_@0&9GyFL?J|LGwhfkQ3%o6 z3_B)B6hgE%!;T3Og%GXHuw#NmAw+94?3f@?2+`UMJ0?gJLbNu+jtLTl5UtIyV}e8> zL~Aqbm>^LI(b^0+6+4;NEAY}Hp7ky z5`_@0&9GyFL?J|LGwhfkQ3%o63_B)B6hgE%!;T3Og%GXHuw#NmAw+94?3f@?2+`UM zJ0?gJLbNu+jtLTl5UtIyV}e8>L~Aqbm>^LI(b^0+6+4;NEAY}Hp7ky5`_@0&9GyFL?J|LGwhfkQ3%o63_B)B6hgE%!;T3O lg%GXHuw#NmAw+94?3f@?2+`UMJ0?gJLbNu+jtSC)@EbOUm_`5q literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_4bit.bmp b/tests/xrdp/test_4bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..9506afaf77a401809477742f914920b1edc3ca1d GIT binary patch literal 32888 zcmeI!!EM4o6h+ZNN+;Q5l_IiFJFMM?Tc8RGpeOQeOKIS2?|>ZxGG97*^Tf~ZeOu?c z&-v@Px?RU@eH^dW+SdB~zK-+t|7kv$=i0XG&z$FSj%_`k&-vheKG*wwT+K0$I>%{IN?U-_Fr`7;62Z~vQq z{a5}>p!}JD>DPazU;mXq6DWTsVEXl+>DPbd&jiY!37CHUXZrPD`7?p?X9A{Q|CxUM zSN=?({F#91*MFv8|CK)zD1Rnk`t_gb*MH^D1j?TYn120d`t@J=GlBAF0;XU8nST9O z{!F0!nSklnf2Lpml|K_GewGJC1)e-vshE0n^{hzwx*KF@VUQfBqy;{!D=I z=VqJ!X#e9sAb%4;{_=19?SBj)^5>sF36wt*ApE)6ruX|Re-kKwCSdyQf77r3%AX08 zKNB$h`p@+1zw&1S<0HP)35(bzy2$KCQ$xN!1U`s)35)^p9z#d x6EOYy&-ClR@@E3&&jd`r{xkjhul$)n`7;62um4QH{wsebQ2tE7^u7Pq`U7}?-7o+E literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_8bit.bmp b/tests/xrdp/test_8bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..50d4a746f596dbc561124d3d1b53bccf35b241ec GIT binary patch literal 66614 zcmeH}v5liQ7zMutE^rwHoH%lLG2z@juoRZUz;GRmU4sLbaOtiWkmq08HB9m(jVRq6 zPW!)kdf4B7|NiZ*p4<0tRlhthp11H;KRxfbz17dZ)))8v|If3EN6mQ;o_Se&@7jOw z`tjGFRjtDS{-Q0|aH@Ji177q26BcYZRimIm2i}Yc3pSkpKDTjp7%*YMhEv7MS`9i3 zn6O~O;fE|}&|$!Y1shHkk2(!H44ANB!>L~UnAPC9516oE!?~B%8fS+A6BcYZ_p*EA z>@Z-$f(_?JG8$)x0TUK%I5)1@I6DlOuwcWvQLe_>VZek18_tb+H_i?NCM?)+z7+J+ zI6DlOuwcWf$@R}_@Lc(T=e}UWso4q|bQmyU!G?3S^~Tv@z=Q=G&Q&@ZXNLh37Hl|I zHy<)*hXE57Y&f?Ht8sQ1Fk!)lb8E62XNLh37Hl|Q6`H4Ub{H^W!G=?t>)+L&!+;43 zp8L7gYK^nQfC&pWoLjrzI6DlOuwcWvl^l(;!+;43Hk@16**H54n6O~Oxm8|`v%`Q1 z3pSiv^W8W*44AO$$3L(7gMT;q|EgYJk9xhHSHS)GBc49x8$W}3lP~{My?8!6*Y73} z|84@V{m*>=UH#cV`3oTHkN@~r6G;Ev1XTHaxO?^a{XhQQ1k!&u0oQ)^&$XZZPygKn z(tkGr*M9cjwV(Y@|J?-Ae>VZwe)iwBpZ!n&-2~EqHv!jv_TROi{ZIeh1k!&u0oQ)^ z-?g9pPygKn(tkGr*M9cjwV(Y@|J?-Ae>VZwe)iwBpZ!n&-2~EqHv!jv_TROi{ZIeh z1k!&u0oQ)^-?g9pPygKn(tkGr*M9cjwV(Y@|J?-Ae>VZwe)iwBpZ!n&-2~EqHv!jv z_TROi{ZIeh1k!&u0oQ)^-?g9pPygKn(tkGr*M9cjwV(Y@|J?-Ae>VZwe)iwBpZ!n& z-2~EqHv!jv_TROi{ZIeh1k!&u0oQ)^-?g9pPygKn(tkGr*M9cjwV(Y@|J?-Ae>VZw ze)iwB|9ZX4w-5OyU;ev%`5(D{H-Y$f6L9Un=lk#K&;H3@09k+h$G@6D`tK&7%ICw~ ztN+OU$pwgiHvw6HzW=WN?4SGvkoCuZ{HqD1|84@Rd_LU0`uzSM|84^5zng$-Kl|s} z&;FA#zRYd`z%+Ry%{|84^5 zzng$-Kl|_6&;FA#zRYd`z% z+Ry%{|84^5zng$-Kl|_6&;FA#zRYd`z%+Ry%{|84^5zng$-Kl|_6&;FA#zRYd`z%+Ry%{|84^5zng$-Kl|_6|M>V9){xa* literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_bitmap_load.c b/tests/xrdp/test_bitmap_load.c new file mode 100644 index 0000000000..a26ce49062 --- /dev/null +++ b/tests/xrdp/test_bitmap_load.c @@ -0,0 +1,282 @@ +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include "test_xrdp.h" +#include "xrdp.h" + +/* Where the image files are located */ +#ifndef IMAGEDIR +#define IMAGEDIR "." +#endif + +/* Handy color definitions. These are variables so they are displayed + * in assert messages if tests fail */ +static int RED = COLOR24RGB(255, 0, 0); +static int GREEN = COLOR24RGB(0, 255, 0); +static int BLUE = COLOR24RGB(0, 0, 255); +static int WHITE = COLOR24RGB(255, 255, 255); + +/* Virtual desktop maxima and minima [MS-RDPBCGR] 2.2.1.3.6 */ +#define MAX_VDESKTOP_WIDTH 32766 +#define MAX_VDESKTOP_HEIGHT 32766 +#define MIN_VDESKTOP_WIDTH 200 +#define MIN_VDESKTOP_HEIGHT 200 + +/* Characteristics of the test bitmap(s) */ +#define TEST_BM_WIDTH 256 +#define TEST_BM_HEIGHT 256 + +#define TEST_NOT4_BM_WIDTH 62 +#define TEST_NOT4_BM_HEIGHT 62 + +#define TEST_BM_TOP_LEFT_PIXEL RED +#define TEST_BM_TOP_RIGHT_PIXEL GREEN +#define TEST_BM_BOTTOM_LEFT_PIXEL BLUE +#define TEST_BM_BOTTOM_RIGHT_PIXEL WHITE + +void setup(void) +{ +} + +void teardown(void) +{ +} + +/* Tests an error is returned for a non-existent file */ +START_TEST(test_bitmap_load__with_invalid_image__fail) +{ + struct xrdp_wm *wm = NULL; + int result; + + struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm); + + ck_assert_ptr_ne(bm, NULL); + + result = xrdp_bitmap_load(bm, "/dev/null", NULL, 0, XBLT_NONE, 0, 0); + + ck_assert_int_ne(result, 0); + + xrdp_bitmap_delete(bm); +} +END_TEST + +/* Checks a particular pixmap value is expected */ +static void +check_pixel(struct xrdp_bitmap *bm, int i, int j, int expected) +{ + int pixel = xrdp_bitmap_get_pixel(bm, i, j); + if (pixel != expected) + { + ck_abort_msg("Pixmap (%d,%d) expected %06x, got %06x", + i, j, expected, pixel); + } +} + +/* Check we can load bitmaps of various depths with various transforms */ +static void +load_and_transform_bm(int depth, + enum xrdp_bitmap_load_transform transform, + int twidth, int theight) +{ + struct xrdp_wm *wm = NULL; + int result; + + int width; + int height; + + char name[256]; + int top_left_pixel; + int top_right_pixel; + int bottom_left_pixel; + int bottom_right_pixel; + + struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm); + + ck_assert_ptr_ne(bm, NULL); + + g_snprintf(name, sizeof(name), IMAGEDIR "/test_%dbit.bmp", depth); + result = xrdp_bitmap_load(bm, name, NULL, 0, transform, twidth, theight); + + ck_assert_int_eq(result, 0); + + /* Bitmap right size? */ + if (transform == XBLT_NONE) + { + width = TEST_BM_WIDTH; + height = TEST_BM_HEIGHT; + ck_assert_int_eq(bm->width, TEST_BM_WIDTH); + ck_assert_int_eq(bm->height, TEST_BM_HEIGHT); + } + else + { + width = twidth; + height = theight; + ck_assert_int_eq(bm->width, twidth); + ck_assert_int_eq(bm->height, theight); + } + + /* Corners OK? */ + top_left_pixel = xrdp_bitmap_get_pixel(bm, 0, 0); + top_right_pixel = xrdp_bitmap_get_pixel(bm, width - 1, 0); + bottom_left_pixel = xrdp_bitmap_get_pixel(bm, 0, height - 1); + bottom_right_pixel = xrdp_bitmap_get_pixel(bm, width - 1, height - 1); + + ck_assert_int_eq(top_left_pixel, TEST_BM_TOP_LEFT_PIXEL); + ck_assert_int_eq(top_right_pixel, TEST_BM_TOP_RIGHT_PIXEL); + ck_assert_int_eq(bottom_left_pixel, TEST_BM_BOTTOM_LEFT_PIXEL); + ck_assert_int_eq(bottom_right_pixel, TEST_BM_BOTTOM_RIGHT_PIXEL); + + xrdp_bitmap_delete(bm); +} + +/* Check we can load bitmaps that aren't a multiple of 4 pixels wide */ +static void +load_not4_bm(int depth) +{ + struct xrdp_wm *wm = NULL; + int result; + + const int width = TEST_NOT4_BM_WIDTH; + const int height = TEST_NOT4_BM_HEIGHT; + + char name[256]; + int i; + int j; + + struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm); + + ck_assert_ptr_ne(bm, NULL); + + g_snprintf(name, sizeof(name), IMAGEDIR "/test_not4_%dbit.bmp", depth); + result = xrdp_bitmap_load(bm, name, NULL, 0, XBLT_NONE, 0, 0); + + ck_assert_int_eq(result, 0); + + /* Bitmap right size? */ + ck_assert_int_eq(bm->width, TEST_NOT4_BM_WIDTH); + ck_assert_int_eq(bm->height, TEST_NOT4_BM_HEIGHT); + + /* Check all data */ + for (i = 0 ; i < width / 2 ; ++i) + { + for (j = 0 ; j < height / 2 ; ++j) + { + check_pixel(bm, i, j, TEST_BM_TOP_LEFT_PIXEL); + check_pixel(bm, i + width / 2, j, TEST_BM_TOP_RIGHT_PIXEL); + check_pixel(bm, i, j + height / 2, TEST_BM_BOTTOM_LEFT_PIXEL); + check_pixel(bm, i + width / 2, j + height / 2, + TEST_BM_BOTTOM_RIGHT_PIXEL); + } + } + + xrdp_bitmap_delete(bm); +} + +START_TEST(test_bitmap_load__4_bit__ok) +{ + load_and_transform_bm(4, XBLT_NONE, 0, 0); +} +END_TEST + +START_TEST(test_bitmap_load__8_bit__ok) +{ + load_and_transform_bm(8, XBLT_NONE, 0, 0); +} +END_TEST + +START_TEST(test_bitmap_load__24_bit__ok) +{ + load_and_transform_bm(24, XBLT_NONE, 0, 0); +} +END_TEST + +START_TEST(test_bitmap_load__max_width_zoom__ok) +{ + load_and_transform_bm(24, + XBLT_ZOOM, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__max_height_zoom__ok) +{ + load_and_transform_bm(24, + XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__min_zoom__ok) +{ + load_and_transform_bm(24, + XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__max_width_scale__ok) +{ + load_and_transform_bm(24, + XBLT_SCALE, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__max_height_scale__ok) +{ + load_and_transform_bm(24, + XBLT_SCALE, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__min_scale__ok) +{ + load_and_transform_bm(24, + XBLT_SCALE, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); +} +END_TEST + +START_TEST(test_bitmap_load__not_4_pixels_wide_4_bit__ok) +{ + load_not4_bm(4); +} +END_TEST + +START_TEST(test_bitmap_load__not_4_pixels_wide_8_bit__ok) +{ + load_not4_bm(8); +} +END_TEST + +START_TEST(test_bitmap_load__not_4_pixels_wide_24_bit__ok) +{ + load_not4_bm(24); +} +END_TEST + +/******************************************************************************/ +Suite * +make_suite_test_bitmap_load(void) +{ + Suite *s; + TCase *tc_bitmap_load; + + s = suite_create("BitmapLoad"); + + tc_bitmap_load = tcase_create("xrdp_bitmap_load"); + tcase_add_checked_fixture(tc_bitmap_load, setup, teardown); + tcase_add_test(tc_bitmap_load, test_bitmap_load__with_invalid_image__fail); + tcase_add_test(tc_bitmap_load, test_bitmap_load__4_bit__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__8_bit__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__24_bit__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__max_width_zoom__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__max_height_zoom__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__min_zoom__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__max_width_scale__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__max_height_scale__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__min_scale__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_4_bit__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_8_bit__ok); + tcase_add_test(tc_bitmap_load, test_bitmap_load__not_4_pixels_wide_24_bit__ok); + + suite_add_tcase(s, tc_bitmap_load); + + return s; +} diff --git a/tests/xrdp/test_not4_24bit.bmp b/tests/xrdp/test_not4_24bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fa21f24fd8a42c9a4f43d8fb05565bc4244dc37b GIT binary patch literal 11710 zcmeI$p$-Bu5QO37E$|o&NF)N!EAwilSHR7zx(ViQt`)P%rrG<>+~fJW)LOTBp69-Q z_o0p}-;UGuvwy*;3O*yaq8FddlZ(51bJR4{85DqujBo;fN% R8a~J&Fq%G4GsvLJ9{_^P&-wrW literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_not4_8bit.bmp b/tests/xrdp/test_not4_8bit.bmp new file mode 100644 index 0000000000000000000000000000000000000000..87405a37e467f5dde1b8de37540609f2eb8a3f85 GIT binary patch literal 5046 zcmeIzF^<$g5QX7~L_kKs1xg|zA|ym5a_&$^siRbYI0A9SoPnT@u<0&Hv;VkPgq?%h z_UG4Yk7uUKwVp3uf4tMRe0nW?VD$OLE4{gn=UeIh$K^Wkcb5{IGFPx?sP0z(YCZh? zE}0|12`e;4a>2mB1BpUoq!0`a{)j}OF)yEMq$7|hG)7{mGB^T>LSy)ng253;6dEJ3 zX$+1)qR<$*_?j}@*Fd7sm^C#s(h*1$8ndSDMmhqCLSt4*!bnFTQE1F6R~qREBnpjL zr7R;IfkdG(tITbrBakRG=DGzwMmhqCLSvN7KV`VjJaAtNjZvCla0C*C#;n`sMmhqC zLSxn~4I>?aM4>V3cJm>bjzFT&nAHkpq$7|hG-kC)8|ern3XQp1D91=gAW>+Hn)$a3 zjzFStUuU(J8R-Zl3XNH9=SDgLi9%ymONNn-K%&r?)vjrzBakRGX0>t|=?EkWjahBp zMmhqC(!=kYzVW)`{iNHq>2|x1z + +Suite *make_suite_test_bitmap_load(void); + +#endif /* TEST_XRDP_H */ diff --git a/tests/xrdp/test_xrdp_main.c b/tests/xrdp/test_xrdp_main.c new file mode 100644 index 0000000000..eb118a1e7f --- /dev/null +++ b/tests/xrdp/test_xrdp_main.c @@ -0,0 +1,62 @@ +/** + * xrdp: A Remote Desktop Protocol server. + * + * Copyright (C) Jay Sorg 2004-2021 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test driver for XRDP routines + * + * If you want to run this driver under valgrind to check for memory leaks, + * use the following command line:- + * + * CK_FORK=no valgrind --leak-check=full --show-leak-kinds=all \ + * .libs/test_xrdp + * + * without the 'CK_FORK=no', memory still allocated by the test driver will + * be logged + */ + +#if defined(HAVE_CONFIG_H) +#include "config_ac.h" +#endif + +#include "log.h" +#include "os_calls.h" +#include "test_xrdp.h" +#include + +int main (void) +{ + int number_failed; + SRunner *sr; + struct log_config *logging; + + /* Configure the logging sub-system so that functions can use + * the log functions as appropriate */ + logging = log_config_init_for_console(LOG_LEVEL_INFO, + g_getenv("TEST_LOG_LEVEL")); + log_start_from_param(logging); + log_config_free(logging); + + sr = srunner_create (make_suite_test_bitmap_load()); + + srunner_set_tap(sr, "-"); + srunner_run_all (sr, CK_ENV); + number_failed = srunner_ntests_failed(sr); + srunner_free(sr); + + log_end(); + + return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} From 1606cdfb8e733445a2c18f211fbbdc68dd08f1b2 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 30 Jun 2021 13:48:00 +0100 Subject: [PATCH 05/14] Added -with-imlib2 to configure.ac --- configure.ac | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/configure.ac b/configure.ac index 49bd601362..01ac0cb97d 100644 --- a/configure.ac +++ b/configure.ac @@ -166,6 +166,8 @@ AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin], [], [enable_rdpsndaudin=no]) AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes]) +AC_ARG_WITH(imlib2, AC_HELP_STRING([--with-imlib2=ARG], [imlib2 library to use (yes/no/auto/)]),,) + # Obsolete options AC_ARG_ENABLE(xrdpdebug, AS_HELP_STRING([--enable-xrdpdebug], [This option is no longer supported - use --enable-devel-all])) @@ -216,6 +218,48 @@ AC_CHECK_HEADER([security/_pam_types.h], AC_CHECK_HEADER([security/pam_constants.h], [AC_DEFINE([HAVE_PAM_CONSTANTS_H], 1, [Using OpenPAM], [])]) +# Find imlib2 +case "$with_imlib2" in + no) AC_MSG_NOTICE([imlib2 will not be supported]) + use_imlib2=no + ;; + '' | auto) + PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10], + [use_imlib2=yes], + [use_imlib2=no]) + ;; + yes) + PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10], + [use_imlib2=yes], + [AC_MSG_ERROR([please install libimlib2-dev or imlib2-devel])]) + ;; + *) + AC_MSG_CHECKING([for imlib2 in $with_imlib2]) + if test -d $with_imlib2/lib; then + IMLIB2_LIBS="-L $with_imlib2/lib -lImlib2" + elif test -d $with_imlib2/lib64; then + IMLIB2_LIBS="-L $with_imlib2/lib64 -lImlib2" + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Can't find libImlib2 in $with_imlib2]) + fi + + if test -f $with_imlib2/include/Imlib2.h; then + IMLIB2_CFLAGS="-I $with_imlib2/include" + else + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Can't find $with_imlib2/include/Imlib2.h]) + fi + AC_MSG_RESULT([yes]) + AC_SUBST([IMLIB2_LIBS]) + AC_SUBST([IMLIB2_CFLAGS]) + use_imlib2=yes +esac + +if test x$use_imlib2 = xyes; then + AC_DEFINE([USE_IMLIB2],1, [Compile with imlib2 support]) +fi + # Check only one auth mechanism is specified, and give it a name auth_cnt=0 auth_mech="Builtin" @@ -486,6 +530,12 @@ echo " vsock $enable_vsock" echo " auth mechanism $auth_mech" echo " rdpsndaudin $enable_rdpsndaudin" echo +if test x$use_imlib2 = xyes; then + echo " with imlib2 yes" +else + echo " with imlib2 no" +fi +echo echo " development logging $devel_logging" echo " development streamcheck $devel_streamcheck" echo "" From 8f8b4c5868d392c6a77f72adec86cae830f69acb Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 12 Jul 2021 15:27:03 +0100 Subject: [PATCH 06/14] Add imlib2 support to xrdp_bitmap_load.c --- tests/xrdp/Makefile.am | 4 +- xrdp/Makefile.am | 4 +- xrdp/xrdp.h | 3 +- xrdp/xrdp_bitmap_load.c | 610 +++++++++++++++++++++++++++++++++++----- 4 files changed, 549 insertions(+), 72 deletions(-) diff --git a/tests/xrdp/Makefile.am b/tests/xrdp/Makefile.am index c1868ad291..56cbce7c8a 100644 --- a/tests/xrdp/Makefile.am +++ b/tests/xrdp/Makefile.am @@ -2,7 +2,8 @@ AM_CPPFLAGS = \ -I$(top_builddir) \ -I$(top_srcdir)/xrdp \ -I$(top_srcdir)/libxrdp \ - -I$(top_srcdir)/common + -I$(top_srcdir)/common \ + $(IMLIB2_CFLAGS) LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \ $(top_srcdir)/tap-driver.sh @@ -34,4 +35,5 @@ test_xrdp_LDADD = \ $(top_builddir)/xrdp/xrdp_bitmap_common.o \ $(top_builddir)/xrdp/funcs.o \ $(top_builddir)/common/libcommon.la \ + $(IMLIB2_LIBS) \ @CHECK_LIBS@ diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am index 2eb010ebc7..63968e4544 100644 --- a/xrdp/Makefile.am +++ b/xrdp/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS = \ -DXRDP_SOCKET_PATH=\"${socketdir}\" \ -I$(top_builddir) \ -I$(top_srcdir)/common \ - -I$(top_srcdir)/libxrdp + -I$(top_srcdir)/libxrdp \ + $(IMLIB2_CFLAGS) XRDP_EXTRA_LIBS = @@ -61,6 +62,7 @@ xrdp_SOURCES = \ xrdp_LDADD = \ $(top_builddir)/common/libcommon.la \ $(top_builddir)/libxrdp/libxrdp.la \ + $(IMLIB2_LIBS) \ $(XRDP_EXTRA_LIBS) xrdpsysconfdir=$(sysconfdir)/xrdp diff --git a/xrdp/xrdp.h b/xrdp/xrdp.h index 04a11e3929..32da64dbd9 100644 --- a/xrdp/xrdp.h +++ b/xrdp/xrdp.h @@ -253,7 +253,8 @@ xrdp_bitmap_get_screen_clip(struct xrdp_bitmap *self, * @return 0 for success. * * The background color is only used if the specified image contains - * an alpha layer + * an alpha layer. It is in HCOLOR format, and the bpp must correspond to + * the bpp used to create 'self'. * * After a successful call, the bitmap is resized to the image file size. * diff --git a/xrdp/xrdp_bitmap_load.c b/xrdp/xrdp_bitmap_load.c index 5384c87c7d..c454a1c92c 100644 --- a/xrdp/xrdp_bitmap_load.c +++ b/xrdp/xrdp_bitmap_load.c @@ -22,12 +22,122 @@ #include #endif +#ifdef USE_IMLIB2 +# include +#endif + #include "xrdp.h" #include "log.h" /* Rounds up to the nearest multiple of 4 */ #define ROUND4(x) (((x) + 3) / 4 * 4) +/* Are we using the builtin BMP format-only loader */ + +#ifdef USE_BUILTIN_LOADER +# undef USE_BUILTIN_LOADER +#endif + +#ifndef USE_IMLIB2 +# define USE_BUILTIN_LOADER +#endif + +/** + * Describes a box within an image + */ +struct box +{ + int left_margin; + int width; + int top_margin; + int height; +}; + +/**************************************************************************//** + * Calculates a zoom box, from source and destination image dimensions + * + * The zoom box is the largest centred part of the source image which + * preserves the aspect ratio of the destination image. We find it + * by cutting off the left and right sides of the source, or the top + * and bottom. + * + * @param src_width Width of source image + * @param src_height Height of source image + * @param dst_width Width of destination image + * @param dst_height Height of destination image + * @param[out] zb_return Zoom box + * @return 0 for success + */ +static int +calculate_zoom_box(int src_width, int src_height, + int dst_width, int dst_height, + struct box *zb_return) +{ + int result = 1; + struct box zb; + + if (dst_height == 0 || src_height == 0) + { + LOG(LOG_LEVEL_ERROR, "Can't zoom to or from zero-width images"); + } + else + { + double dst_ratio = (double)dst_width / dst_height; + double src_ratio = (double)src_width / src_height; + + if (src_ratio > dst_ratio) + { + /* Source is relatively wider than source. Select a box + * narrower than the source, but the same height */ + zb.width = (int)(dst_ratio * src_height + .5); + zb.left_margin = (src_width - zb.width) / 2; + zb.height = src_height; + zb.top_margin = 0; + } + else + { + /* Source is relatively taller than source (or same shape) */ + zb.width = src_width; + zb.left_margin = 0; + zb.height = (int)(src_width / dst_ratio + .5); + zb.top_margin = (src_height - zb.height) / 2; + } + + /* Only allow meaningful zoom boxes */ + if (zb.width < 1 || zb.height < 1) + { + LOG(LOG_LEVEL_WARNING, "Ignoring pathological zoom" + " request (%dx%d) -> (%dx%d)", src_width, src_height, + dst_width, dst_height); + } + else + { + *zb_return = zb; + result = 0; + } + } + + return result; +} + +/*****************************************************************************/ +static int +xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) +{ + int r = 0; + int g = 0; + int b = 0; + + r = (color & 0xff0000) >> 16; + g = (color & 0x00ff00) >> 8; + b = (color & 0x0000ff) >> 0; + r = (r >> 5) << 0; + g = (g >> 5) << 3; + b = (b >> 6) << 6; + return (b | g | r); +} + +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Private routine to swap pixel data between two pixmaps * @param a First bitmap @@ -65,7 +175,9 @@ swap_pixel_data(struct xrdp_bitmap *a, struct xrdp_bitmap *b) b->data = tmp_data; b->do_not_free_data = tmp_do_not_free_data; } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Scales a bitmap image * @@ -110,7 +222,10 @@ xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height) return 0; } +#endif /* USE_BUILTIN_LOADER */ + +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Zooms a bitmap image * @@ -126,68 +241,39 @@ xrdp_bitmap_scale(struct xrdp_bitmap *self, int targ_width, int targ_height) static int xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) { - int src_width = self->width; - int src_height = self->height; - double targ_ratio = (double)targ_width / targ_height; - double src_ratio = (double)src_width / src_height; - - unsigned int chop_width; - unsigned int chop_left_margin; - unsigned int chop_height; - unsigned int chop_top_margin; + struct box zb; int result = 0; - if (src_ratio > targ_ratio) + if (calculate_zoom_box(self->width, self->height, + targ_width, targ_height, &zb) == 0) { - /* Source is relatively wider than source. Select a box - * narrower than the source, but the same height */ - chop_width = (int)(targ_ratio * src_height + .5); - chop_left_margin = (src_width - chop_width) / 2; - chop_height = src_height; - chop_top_margin = 0; - } - else - { - /* Source is relatively taller than source (or same shape) */ - chop_width = src_width; - chop_left_margin = 0; - chop_height = (int)(src_width / targ_ratio + .5); - chop_top_margin = (src_height - chop_height) / 2; - } - - /* Only chop the image if there's a need to, and if it will look - * meaningful */ - if (chop_width < 1 || chop_height < 1) - { - LOG(LOG_LEVEL_WARNING, "xrdp_bitmap_zoom: Ignoring pathological" - " request (%dx%d) -> (%dx%d)", src_width, src_height, - targ_width, targ_height); - } - else if (chop_top_margin != 0 || chop_left_margin != 0) - { - struct xrdp_bitmap *chopbox; - chopbox = xrdp_bitmap_create(chop_width, chop_height, self->bpp, - WND_TYPE_BITMAP, 0); - if (chopbox == NULL) - { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory"); - result = 1; - } - else + /* Need to chop anything? */ + if (zb.top_margin != 0 || zb.left_margin != 0) { - result = xrdp_bitmap_copy_box(self, chopbox, - chop_left_margin, chop_top_margin, - chop_width, chop_height); - if (result != 0) + struct xrdp_bitmap *zbitmap; + zbitmap = xrdp_bitmap_create(zb.width, zb.height, self->bpp, + WND_TYPE_BITMAP, 0); + if (zbitmap == NULL) { - LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box"); + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: no memory"); + result = 1; } else { - swap_pixel_data(self, chopbox); + result = xrdp_bitmap_copy_box(self, zbitmap, + zb.left_margin, zb.top_margin, + zb.width, zb.height); + if (result != 0) + { + LOG(LOG_LEVEL_ERROR, "xrdp_bitmap_zoom: can't copy box"); + } + else + { + swap_pixel_data(self, zbitmap); + } + xrdp_bitmap_delete(zbitmap); } - xrdp_bitmap_delete(chopbox); } } @@ -198,24 +284,9 @@ xrdp_bitmap_zoom(struct xrdp_bitmap *self, int targ_width, int targ_height) return result; } +#endif /* USE_BUILTIN_LOADER */ -/*****************************************************************************/ -static int -xrdp_bitmap_get_index(struct xrdp_bitmap *self, const int *palette, int color) -{ - int r = 0; - int g = 0; - int b = 0; - - r = (color & 0xff0000) >> 16; - g = (color & 0x00ff00) >> 8; - b = (color & 0x0000ff) >> 0; - r = (r >> 5) << 0; - g = (g >> 5) << 3; - b = (b >> 6) << 6; - return (b | g | r); -} - +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * reads the palette from a bmp file with a palette embedded in it * @@ -281,7 +352,9 @@ read_palette(const char *filename, int fd, free_stream(s); } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Process a row of data from a 24-bit bmp file * @@ -331,7 +404,9 @@ process_row_data_24bit(struct xrdp_bitmap *self, xrdp_bitmap_set_pixel(self, j, row, color); } } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Process a row of data from an 8-bit bmp file * @@ -377,7 +452,9 @@ process_row_data_8bit(struct xrdp_bitmap *self, xrdp_bitmap_set_pixel(self, j, row, color); } } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /**************************************************************************//** * Process a row of data from an 4-bit bmp file * @@ -432,7 +509,9 @@ process_row_data_4bit(struct xrdp_bitmap *self, xrdp_bitmap_set_pixel(self, j, row, color); } } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /*****************************************************************************/ /* load a bmp file */ /* return 0 ok */ @@ -589,7 +668,9 @@ xrdp_bitmap_load_bmp(struct xrdp_bitmap *self, const char *filename, return 0; } +#endif /* USE_BUILTIN_LOADER */ +#ifdef USE_BUILTIN_LOADER /*****************************************************************************/ int xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, @@ -623,5 +704,396 @@ xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, transform); } } + + return result; +} +#endif /* USE_BUILTIN_LOADER */ + +#ifdef USE_IMLIB2 +/**************************************************************************//** + * Log an error from the Imlib2 library + * + * @param level Log level to use + * @param filename file we're trying to load + * @param lerr Error return from imlib2 + */ +static void +log_imlib2_error(enum logLevels level, const char *filename, + Imlib_Load_Error lerr) +{ + const char *msg; + char buff[256]; + + switch (lerr) + { + case IMLIB_LOAD_ERROR_NONE: + msg = "No error"; + break; + case IMLIB_LOAD_ERROR_FILE_DOES_NOT_EXIST: + msg = "No such file"; + break; + case IMLIB_LOAD_ERROR_PERMISSION_DENIED_TO_READ: + msg = "Permission denied"; + break; + case IMLIB_LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT: + msg = "Unrecognised file format"; + break; + case IMLIB_LOAD_ERROR_FILE_IS_DIRECTORY: + case IMLIB_LOAD_ERROR_PATH_TOO_LONG: + case IMLIB_LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT: + case IMLIB_LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE: + case IMLIB_LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS: + msg = "Bad filename"; + break; + case IMLIB_LOAD_ERROR_OUT_OF_MEMORY: + msg = " No memory"; + break; + case IMLIB_LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS: + msg = "No file decriptors"; + break; + case IMLIB_LOAD_ERROR_OUT_OF_DISK_SPACE: + msg = "No disk space"; + break; + case IMLIB_LOAD_ERROR_UNKNOWN: + msg = "Unknown error"; + break; + default: + g_snprintf(buff, sizeof(buff), "Unrecognised code %d", lerr); + msg = buff; + } + + LOG(LOG_LEVEL_ERROR, "Error loading %s [%s]", filename, msg); +} +#endif /* USE_IMLIB2 */ + +#ifdef USE_IMLIB2 +/**************************************************************************//** + * Blend an imlib2 image onto a background of the specified color + * + * The current context image is merged. On return the new image is the + * current context image, and the old image is deleted. + * + * @param filename Filename we're working on (for error reporting) + * @param r Background red + * @param g Background green + * @param g Background blue + * + * @return 0 for success. On failure the current context image is unchanged. + */ +static int +blend_imlib_image_onto_background(const char *filename, int r, int g, int b) +{ + int result = 0; + Imlib_Image img = imlib_context_get_image(); + + if (img == NULL) + { + LOG(LOG_LEVEL_ERROR, "No context for blending image"); + result = 1; + } + else + { + int width = imlib_image_get_width(); + int height = imlib_image_get_height(); + + /* Create a suitable image to merge this one onto */ + Imlib_Image bg = imlib_create_image(width, height); + if (bg == NULL) + { + log_imlib2_error(LOG_LEVEL_ERROR, filename, + IMLIB_LOAD_ERROR_OUT_OF_MEMORY); + result = 1; + } + else + { + imlib_context_set_image(bg); + imlib_context_set_color(r, g, b, 0xff); + imlib_image_fill_rectangle(0, 0, width, height); + imlib_blend_image_onto_image(img, 0, + 0, 0, width, height, + 0, 0, width, height); + imlib_context_set_image(img); + imlib_free_image(); + imlib_context_set_image(bg); + } + } + return result; +} +#endif /* USE_IMLIB2 */ + +#ifdef USE_IMLIB2 +/**************************************************************************//** + * Scales an imlib2 image + * + * The current context image is scaled. On return the new image is the + * current context image, and the old image is deleted. + * + * @param filename Filename we're working on (for error reporting) + * @param twidth target width + * @param theight target height + * @return 0 for success + */ +static int +scale_imlib_image(const char *filename, int twidth, int theight) +{ + int result = 0; + Imlib_Image img = imlib_context_get_image(); + + if (img == NULL) + { + LOG(LOG_LEVEL_ERROR, "No context for scaling image"); + result = 1; + } + else + { + int width = imlib_image_get_width(); + int height = imlib_image_get_height(); + + Imlib_Image newimg = imlib_create_cropped_scaled_image( + 0, 0, width, height, twidth, theight); + if (newimg == NULL) + { + log_imlib2_error(LOG_LEVEL_ERROR, filename, + IMLIB_LOAD_ERROR_OUT_OF_MEMORY); + result = 1; + } + else + { + imlib_free_image(); + imlib_context_set_image(newimg); + } + } + return result; +} +#endif /* USE_IMLIB2 */ + +#ifdef USE_IMLIB2 +/**************************************************************************//** + * Zooms an imlib2 image + * + * @param filename Filename we're working on (for error reporting) + * @param twidth target width + * @param theight target height + * @return 0 for success + */ +static int +zoom_imlib_image(const char *filename, int twidth, int theight) +{ + int result = 0; + Imlib_Image img = imlib_context_get_image(); + + if (img == NULL) + { + LOG(LOG_LEVEL_ERROR, "No context for zooming image"); + result = 1; + } + else + { + struct box zb; + Imlib_Image newimg = NULL; + int width = imlib_image_get_width(); + int height = imlib_image_get_height(); + + if (calculate_zoom_box(width, height, + twidth, theight, &zb) == 0) + { + newimg = imlib_create_cropped_scaled_image( + zb.left_margin, zb.top_margin, + zb.width, zb.height, twidth, theight); + } + else + { + /* Can't zoom - scale the image instead */ + newimg = imlib_create_cropped_scaled_image( + 0, 0, width, height, twidth, theight); + } + if (newimg == NULL) + + { + log_imlib2_error(LOG_LEVEL_ERROR, filename, + IMLIB_LOAD_ERROR_OUT_OF_MEMORY); + result = 1; + } + else + { + imlib_free_image(); + imlib_context_set_image(newimg); + } + } + return result; +} +#endif /* USE_IMLIB2 */ + +#ifdef USE_IMLIB2 +/**************************************************************************//** + * Copies imlib2 image data to a bitmap + * + * @param self bitmap to copy data to + * @param out_palette Palette for output bitmap + * @return 0 for success + */ +static int +copy_imlib_data_to_bitmap(struct xrdp_bitmap *self, + const int *out_palette) +{ + int result = 0; + Imlib_Image img = imlib_context_get_image(); + + if (img == NULL) + { + LOG(LOG_LEVEL_ERROR, "No context for zooming image"); + result = 1; + } + else + { + int width = imlib_image_get_width(); + int height = imlib_image_get_height(); + int i; + int j; + DATA32 *bdata; + int color; + xrdp_bitmap_resize(self, width, height); + + bdata = imlib_image_get_data_for_reading_only(); + for (j = 0 ; j < height; ++j) + { + for (i = 0 ; i < width ; ++i) + { + color = (*bdata++ & 0xffffff); + + if (self->bpp == 8) + { + color = xrdp_bitmap_get_index(self, out_palette, color); + } + else if (self->bpp == 15) + { + color = COLOR15((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + else if (self->bpp == 16) + { + color = COLOR16((color & 0xff0000) >> 16, + (color & 0x00ff00) >> 8, + (color & 0x0000ff) >> 0); + } + + xrdp_bitmap_set_pixel(self, i, j, color); + } + } + } + + return result; +} +#endif /* USE_IMLIB2 */ + +#ifdef USE_IMLIB2 +/** + * Converts an xrdp HCOLOR into RGB values used by imlib2 + * + * @param hcolor Color to convert + * @param bpp Bits-per-pixel for the hcolor + * @param[out] r Red value + * @param[out] g Green value + * @param[out] b Blue value + */ +static void hcolor_to_rgb(int hcolor, int bpp, int *r, int *g, int *b) +{ + switch (bpp) + { + case 8: + *r = (hcolor & 0x7) << 5; + *g = (hcolor & 0x38) << 2; + *b = (hcolor & 0xc0); + break; + + case 15: + SPLITCOLOR15(*r, *g, *b, hcolor); + break; + + case 16: + SPLITCOLOR16(*r, *g, *b, hcolor); + break; + + default: + /* Beware : HCOLOR is BGR, not RGB */ + *r = hcolor & 0xff; + *g = (hcolor >> 8) & 0xff; + *b = (hcolor >> 16) & 0xff; + break; + } +} +#endif + +#ifdef USE_IMLIB2 +/*****************************************************************************/ +int +xrdp_bitmap_load(struct xrdp_bitmap *self, const char *filename, + const int *palette, + int background, + enum xrdp_bitmap_load_transform transform, + int twidth, + int theight) +{ + int result = 0; + Imlib_Load_Error lerr; + int free_context_image = 0; /* Set if we've got an image loaded */ + Imlib_Image img = imlib_load_image_with_error_return(filename, &lerr); + + /* Load the image */ + if (img == NULL) + { + log_imlib2_error(LOG_LEVEL_ERROR, filename, lerr); + result = 1; + } + else + { + imlib_context_set_image(img); + free_context_image = 1; + } + + /* Sort out the background */ + if (result == 0 && imlib_image_has_alpha()) + { + int r; + int g; + int b; + hcolor_to_rgb(background, self->bpp, &r, &g, &b); + + result = blend_imlib_image_onto_background(filename, r, g, b); + } + + if (result == 0) + { + switch (transform) + { + case XBLT_NONE: + break; + + case XBLT_SCALE: + result = scale_imlib_image(filename, twidth, theight); + break; + + case XBLT_ZOOM: + result = zoom_imlib_image(filename, twidth, theight); + break; + + default: + LOG(LOG_LEVEL_WARNING, "Invalid bitmap transform %d specified", + transform); + } + } + + if (result == 0) + { + result = copy_imlib_data_to_bitmap(self, palette); + } + + if (free_context_image) + { + imlib_free_image(); + } + return result; } +#endif /* USE_IMLIB2 */ From 19d49e3622c5703feefc9c337fe295a8e1c77ff2 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 22 Jul 2021 15:16:11 +0100 Subject: [PATCH 07/14] Added code to cope with dithering in xrdp_bitmap_load tests --- tests/xrdp/test_bitmap_load.c | 130 ++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 44 deletions(-) diff --git a/tests/xrdp/test_bitmap_load.c b/tests/xrdp/test_bitmap_load.c index a26ce49062..cc453fa153 100644 --- a/tests/xrdp/test_bitmap_load.c +++ b/tests/xrdp/test_bitmap_load.c @@ -35,6 +35,15 @@ static int WHITE = COLOR24RGB(255, 255, 255); #define TEST_BM_BOTTOM_LEFT_PIXEL BLUE #define TEST_BM_BOTTOM_RIGHT_PIXEL WHITE +/* + * Scaling bitmaps properly will introduce color changes with dithering. + * Also some filetypes use compression, and these do not represent colors + * perfectly. + * + * This is the Pythagorean distance we allow between two colors for them to + * be considered close enough to each other */ +#define MAX_SIMILAR_COLOR_DISTANCE 3 + void setup(void) { } @@ -68,16 +77,44 @@ check_pixel(struct xrdp_bitmap *bm, int i, int j, int expected) int pixel = xrdp_bitmap_get_pixel(bm, i, j); if (pixel != expected) { - ck_abort_msg("Pixmap (%d,%d) expected %06x, got %06x", + ck_abort_msg("Pixmap (%d,%d) expected 0x%06x, got 0x%06x", i, j, expected, pixel); } } -/* Check we can load bitmaps of various depths with various transforms */ +/* Calculates whether two colors are close enough to be considered the same */ static void -load_and_transform_bm(int depth, - enum xrdp_bitmap_load_transform transform, - int twidth, int theight) +check_is_close_color(struct xrdp_bitmap *bm, int i, int j, int expected) +{ + int pixel = xrdp_bitmap_get_pixel(bm, i, j); + int r1; + int g1; + int b1; + int r2; + int g2; + int b2; + int variance; + + SPLITCOLOR32(r1, g1, b1, pixel); + SPLITCOLOR32(r2, g2, b2, expected); + + variance = ((r1 - r2) * (r1 - r2) + + (g1 - g2) * (g1 - g2) + + (b1 - b2) * (b1 - b2)); + + if (variance > MAX_SIMILAR_COLOR_DISTANCE * MAX_SIMILAR_COLOR_DISTANCE) + { + ck_abort_msg("Pixmap (%d,%d) expected 0x%06x, got 0x%06x" + " which exceeds distance of %d", + i, j, expected, pixel, MAX_SIMILAR_COLOR_DISTANCE); + } +} + +/* Check we can load images of various depths with various transforms */ +static void +load_and_transform_img(const char *name, + enum xrdp_bitmap_load_transform transform, + int twidth, int theight) { struct xrdp_wm *wm = NULL; int result; @@ -85,18 +122,15 @@ load_and_transform_bm(int depth, int width; int height; - char name[256]; - int top_left_pixel; - int top_right_pixel; - int bottom_left_pixel; - int bottom_right_pixel; + char full_name[256]; struct xrdp_bitmap *bm = xrdp_bitmap_create(4, 4, 32, WND_TYPE_IMAGE, wm); ck_assert_ptr_ne(bm, NULL); - g_snprintf(name, sizeof(name), IMAGEDIR "/test_%dbit.bmp", depth); - result = xrdp_bitmap_load(bm, name, NULL, 0, transform, twidth, theight); + g_snprintf(full_name, sizeof(full_name), IMAGEDIR "/%s", name); + result = xrdp_bitmap_load(bm, full_name, NULL, HCOLOR(bm->bpp, WHITE), + transform, twidth, theight); ck_assert_int_eq(result, 0); @@ -116,23 +150,18 @@ load_and_transform_bm(int depth, ck_assert_int_eq(bm->height, theight); } - /* Corners OK? */ - top_left_pixel = xrdp_bitmap_get_pixel(bm, 0, 0); - top_right_pixel = xrdp_bitmap_get_pixel(bm, width - 1, 0); - bottom_left_pixel = xrdp_bitmap_get_pixel(bm, 0, height - 1); - bottom_right_pixel = xrdp_bitmap_get_pixel(bm, width - 1, height - 1); - - ck_assert_int_eq(top_left_pixel, TEST_BM_TOP_LEFT_PIXEL); - ck_assert_int_eq(top_right_pixel, TEST_BM_TOP_RIGHT_PIXEL); - ck_assert_int_eq(bottom_left_pixel, TEST_BM_BOTTOM_LEFT_PIXEL); - ck_assert_int_eq(bottom_right_pixel, TEST_BM_BOTTOM_RIGHT_PIXEL); + /* Corners OK? Allow for dithering */ + check_is_close_color(bm, 0, 0, TEST_BM_TOP_LEFT_PIXEL); + check_is_close_color(bm, width - 1, 0, TEST_BM_TOP_RIGHT_PIXEL); + check_is_close_color(bm, 0, height - 1, TEST_BM_BOTTOM_LEFT_PIXEL); + check_is_close_color(bm, width - 1, height - 1, TEST_BM_BOTTOM_RIGHT_PIXEL); xrdp_bitmap_delete(bm); } /* Check we can load bitmaps that aren't a multiple of 4 pixels wide */ static void -load_not4_bm(int depth) +load_not4_img(const char *name) { struct xrdp_wm *wm = NULL; int result; @@ -140,7 +169,7 @@ load_not4_bm(int depth) const int width = TEST_NOT4_BM_WIDTH; const int height = TEST_NOT4_BM_HEIGHT; - char name[256]; + char full_name[256]; int i; int j; @@ -148,8 +177,9 @@ load_not4_bm(int depth) ck_assert_ptr_ne(bm, NULL); - g_snprintf(name, sizeof(name), IMAGEDIR "/test_not4_%dbit.bmp", depth); - result = xrdp_bitmap_load(bm, name, NULL, 0, XBLT_NONE, 0, 0); + g_snprintf(full_name, sizeof(full_name), IMAGEDIR "/%s", name); + result = xrdp_bitmap_load(bm, full_name, NULL, HCOLOR(bm->bpp, WHITE), + XBLT_NONE, 0, 0); ck_assert_int_eq(result, 0); @@ -175,79 +205,91 @@ load_not4_bm(int depth) START_TEST(test_bitmap_load__4_bit__ok) { - load_and_transform_bm(4, XBLT_NONE, 0, 0); + load_and_transform_img("test_4bit.bmp", XBLT_NONE, 0, 0); } END_TEST START_TEST(test_bitmap_load__8_bit__ok) { - load_and_transform_bm(8, XBLT_NONE, 0, 0); + load_and_transform_img("test_8bit.bmp", XBLT_NONE, 0, 0); } END_TEST START_TEST(test_bitmap_load__24_bit__ok) { - load_and_transform_bm(24, XBLT_NONE, 0, 0); + load_and_transform_img("test_24bit.bmp", XBLT_NONE, 0, 0); } END_TEST START_TEST(test_bitmap_load__max_width_zoom__ok) { - load_and_transform_bm(24, - XBLT_ZOOM, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_ZOOM, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__max_height_zoom__ok) { - load_and_transform_bm(24, - XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__min_zoom__ok) { - load_and_transform_bm(24, - XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_ZOOM, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__max_width_scale__ok) { - load_and_transform_bm(24, - XBLT_SCALE, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_SCALE, MAX_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__max_height_scale__ok) { - load_and_transform_bm(24, - XBLT_SCALE, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_SCALE, MIN_VDESKTOP_WIDTH, MAX_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__min_scale__ok) { - load_and_transform_bm(24, - XBLT_SCALE, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); + load_and_transform_img("test_24bit.bmp", + XBLT_SCALE, MIN_VDESKTOP_WIDTH, MIN_VDESKTOP_HEIGHT); } END_TEST START_TEST(test_bitmap_load__not_4_pixels_wide_4_bit__ok) { - load_not4_bm(4); + load_not4_img("test_not4_4bit.bmp"); } END_TEST START_TEST(test_bitmap_load__not_4_pixels_wide_8_bit__ok) { - load_not4_bm(8); + load_not4_img("test_not4_8bit.bmp"); } END_TEST START_TEST(test_bitmap_load__not_4_pixels_wide_24_bit__ok) { - load_not4_bm(24); + load_not4_img("test_not4_24bit.bmp"); +} +END_TEST + +START_TEST(test_png_load__blend_ok) +{ + load_and_transform_img("test_alpha_blend.png", XBLT_NONE, 0, 0); +} +END_TEST + +START_TEST(test_jpg_load__ok) +{ + load_and_transform_img("test1.jpg", XBLT_NONE, 0, 0); } END_TEST From 2d123d519d0a81034fadf999d65b1cc574d408dd Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 22 Jul 2021 15:23:30 +0100 Subject: [PATCH 08/14] Add imlib2 to CI --- .cirrus.yml | 4 ++-- .github/workflows/build.yml | 2 +- scripts/install_xrdp_build_dependencies_with_apt.sh | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.cirrus.yml b/.cirrus.yml index cfeb53ade2..5ac17b2eac 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -6,11 +6,11 @@ FreeBSD_task: freebsd_instance: image_family: freebsd-12-2 prepare_script: - - pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check + - pkg install -y $SSL git autoconf automake libtool pkgconf opus jpeg-turbo fdk-aac pixman libX11 libXfixes libXrandr nasm fusefs-libs check imlib2 - git submodule update --init --recursive configure_script: - ./bootstrap - - env CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure --localstatedir=/var --enable-strict-locations --with-pkgconfigdir=/usr/local/libdata/pkgconfig --enable-strict-locations --enable-ipv6 --enable-opus --enable-jpeg --enable-fdkaac --enable-painter --enable-pixman --enable-fuse + - env CPPFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./configure --localstatedir=/var --enable-strict-locations --with-pkgconfigdir=/usr/local/libdata/pkgconfig --enable-strict-locations --enable-ipv6 --enable-opus --enable-jpeg --enable-fdkaac --enable-painter --enable-pixman --enable-fuse --with-imlib2 build_script: - make -j $(sysctl -n hw.ncpu || echo 4) install_script: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11ef2a8aad..5d59f11eaf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -94,7 +94,7 @@ jobs: --disable-pixman" CONF_FLAGS_amd64_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame --enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter - --enable-pixman" + --enable-pixman --with-imlib2" CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame --enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter --disable-pixman --host=i686-linux" diff --git a/scripts/install_xrdp_build_dependencies_with_apt.sh b/scripts/install_xrdp_build_dependencies_with_apt.sh index 3d48172453..da907e1b6f 100755 --- a/scripts/install_xrdp_build_dependencies_with_apt.sh +++ b/scripts/install_xrdp_build_dependencies_with_apt.sh @@ -50,6 +50,7 @@ in libjpeg-dev \ libmp3lame-dev \ libfdk-aac-dev \ + libimlib2-dev \ libopus-dev \ libpixman-1-dev" ;; From 971f91129059e5d8704502bc83d94e83dfda9e66 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Fri, 23 Jul 2021 11:41:04 +0100 Subject: [PATCH 09/14] Add xrdp_bitmap_load() jpg and png test cases --- tests/xrdp/Makefile.am | 4 +++- tests/xrdp/test1.jpg | Bin 0 -> 2152 bytes tests/xrdp/test_alpha_blend.png | Bin 0 -> 1131 bytes tests/xrdp/test_bitmap_load.c | 9 +++++++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/xrdp/test1.jpg create mode 100644 tests/xrdp/test_alpha_blend.png diff --git a/tests/xrdp/Makefile.am b/tests/xrdp/Makefile.am index 56cbce7c8a..2a2742d066 100644 --- a/tests/xrdp/Makefile.am +++ b/tests/xrdp/Makefile.am @@ -16,7 +16,9 @@ EXTRA_DIST = \ test_24bit.bmp \ test_not4_4bit.bmp \ test_not4_8bit.bmp \ - test_not4_24bit.bmp + test_not4_24bit.bmp \ + test1.jpg \ + test_alpha_blend.png TESTS = test_xrdp check_PROGRAMS = test_xrdp diff --git a/tests/xrdp/test1.jpg b/tests/xrdp/test1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..93434c002513ff5dd9e3fd503d59d05f122be5ce GIT binary patch literal 2152 zcmd^|R|qW`7pV5KOepTv2J8e_CkGWvC_CcBh-*=G-Rzp+G3` zp%-l!zYf@YNP)~G{S{uxM774gXl#c;wYmvOr97#6nA9Ew`lop z%JNZGFBHnCLq9_BYWd*LfHY+3-o|<=cWEwWZ~(dws`|Yc$i4>5ji~DHF;$%#2gDiR zSvZ~Fp8)JX$Ul;MX01G%S? zeWMtU773wg;$oXNGg*X=H<&$fw{zD zE-WHj9Z+}?CgT}3BjOJWqG6b24GE*n$72z)z@58+5^jQ=zlUH0E$kORW^&Jf4 z79>%k5uUxmhm3mKGLTHaRT}=E9hV+H(vGkHJbX`sipiNF4(#dJ7tLX)`eoH196Ue7 zK{Q@`sX2;9HzzcB(G}I!f20V_l1W-TNI-(-D2FDD=>%-y3VCUT$XE?qRw1Mn8F$gw uq;|=uU^QE5m(*-)-vt_PZdYA4`mJ70-uY_0t}qqSic^tNEc48{V)_pxR8nC8 literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_alpha_blend.png b/tests/xrdp/test_alpha_blend.png new file mode 100644 index 0000000000000000000000000000000000000000..66a7176e4b264a40cd7c7c391cfb9009a579a2a9 GIT binary patch literal 1131 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$5xn)7d$|)7e>}peR2rGbfdS zL1SX=L|c!;4l+mMgSRS$vUhh_q^!`35)duCq9wA>X@zK1slm=K+_OwnH1+zLvJW2Y zKf0>9d-FQJbxjIC7#}@*w&aD9>OXzWEgfGU?2v!|&i36sMyIVOOjhU0TqwEib7WDH z)?O{PI6(*dDuXV*nUTlls2sgmRCD+6@$0)e&S%xWJAZL)nhx6!mq(FlGt54+ef+X4 zx8R;S-^M*_gyswP&n$6#XpFG7@0m}_+-zKB!c6CW zYMpXi>$&c^sEub{eSf0QllEn5>blD^PCVTaO)P?3r!*FDNDD@l2I;6|*xx#2|KgWw zk>(SvhKb3Hsu>ev?SIJsd3WuUpI?RNL5&Ol9$CmAc1RFk5i0Zi_l?3V^@jhFJ1$B8 z3lg32Q)Ta^3y0ht-kTK^-n}rz_CXQ5M1@gGaG9#Tui|Xhd*@%wzT|LU_rlg^U&HPn zf5|*y$+}182M#J4Oj`WrtJwQ@Iq%-yH~#vsjv?qy(JZcy=b3={XE)7O>#DZ3b-9{(N9v!x6SOzEC3jv*Dd-d=0u zWH8`hK6vAAx!-kxJ<^I(mtS7;aLvbG%WZ`lfa(}H7!(+&#h{)^a2E}bksD5{td;be wf8fReeg**s2T(>~p%R07Cc#}aU`9^+A(6rMcjhk6rwl;g>FVdQ&MBb@07@Jb-~a#s literal 0 HcmV?d00001 diff --git a/tests/xrdp/test_bitmap_load.c b/tests/xrdp/test_bitmap_load.c index cc453fa153..ebb59c004d 100644 --- a/tests/xrdp/test_bitmap_load.c +++ b/tests/xrdp/test_bitmap_load.c @@ -299,6 +299,7 @@ make_suite_test_bitmap_load(void) { Suite *s; TCase *tc_bitmap_load; + TCase *tc_other_load; s = suite_create("BitmapLoad"); @@ -320,5 +321,13 @@ make_suite_test_bitmap_load(void) suite_add_tcase(s, tc_bitmap_load); +#ifdef USE_IMLIB2 + tc_other_load = tcase_create("xrdp_other_load"); + tcase_add_checked_fixture(tc_other_load, setup, teardown); + tcase_add_test(tc_other_load, test_png_load__blend_ok); + tcase_add_test(tc_other_load, test_jpg_load__ok); + suite_add_tcase(s, tc_other_load); +#endif + return s; } From d998ce7b5b157051253fe2d7515e64ff23658cf9 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Wed, 4 Aug 2021 18:41:42 +0100 Subject: [PATCH 10/14] Add additional background and logo parameters to xrdp.ini --- xrdp/xrdp.ini.in | 19 ++++++++- xrdp/xrdp_login_wnd.c | 95 +++++++++++++++++++++++++++++++++++++++---- xrdp/xrdp_types.h | 8 +++- 3 files changed, 111 insertions(+), 11 deletions(-) diff --git a/xrdp/xrdp.ini.in b/xrdp/xrdp.ini.in index c84aad13c2..c3ae197d84 100644 --- a/xrdp/xrdp.ini.in +++ b/xrdp/xrdp.ini.in @@ -123,12 +123,27 @@ ls_height=430 ; login screen background color in RGB format ls_bg_color=dedede -; optional background image filename (bmp format). +; optional background image filename. BMP format is always supported, +; but other formats will be supported if xrdp is build with imlib2 +; The transform can be one of the following:- +; none : No transformation. Image is placed in bottom-right corner +; of the screen. +; scale : Image is scaled to the screen size. The image aspect +; ratio is not preserved. +; zoom : Image is scaled to the screen size. The image aspect +; ratio is preserved by clipping the image. #ls_background_image= +#ls_background_transform=none ; logo -; full path to bmp-file or file in shared folder +; full path to file or file in shared folder. BMP format is always supported, +; but other formats will be supported if xrdp is build with imlib2 +; For transform values, see 'ls_background_transform'. The logo width and +; logo height are ignored for a transform of 'none'. ls_logo_filename= +#ls_logo_transform=none +#ls_logo_width=240 +#ls_logo_height=140 ls_logo_x_pos=55 ls_logo_y_pos=50 diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index 1022dfff20..de872a3963 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -740,12 +740,27 @@ xrdp_login_wnd_create(struct xrdp_wm *self) XRDP_SHARE_PATH, globals->ls_background_image); } LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName); - xrdp_bitmap_load(but, fileName, self->palette, - globals->ls_top_window_bg_color, XBLT_NONE, 0, 0); + if (globals->ls_background_transform == XBLT_NONE) + { + xrdp_bitmap_load(but, fileName, self->palette, + globals->ls_top_window_bg_color, + globals->ls_background_transform, + 0, 0); + /* Place the background in the bottom right corner */ + but->left = self->screen->width - but->width; + but->top = self->screen->height - but->height; + } + else + { + xrdp_bitmap_load(but, fileName, self->palette, + globals->ls_top_window_bg_color, + globals->ls_background_transform, + self->screen->width, self->screen->height); + but->left = 0; + but->top = 0; + } but->parent = self->screen; but->owner = self->screen; - but->left = self->screen->width - but->width; - but->top = self->screen->height - but->height; list_add_item(self->screen->child_list, (long)but); } @@ -764,7 +779,10 @@ xrdp_login_wnd_create(struct xrdp_wm *self) } xrdp_bitmap_load(but, globals->ls_logo_filename, self->palette, - globals->ls_bg_color, XBLT_NONE, 0, 0); + globals->ls_bg_color, + globals->ls_logo_transform, + globals->ls_logo_width, + globals->ls_logo_height); but->parent = self->login_window; but->owner = self->login_window; but->left = globals->ls_logo_x_pos; @@ -833,6 +851,42 @@ xrdp_login_wnd_create(struct xrdp_wm *self) return 0; } +/** + * Map a bitmap transform string to a value + * + * @param param Param we're trying to read + * @param str String we're trying to map + * + * @return enum xrdp_bitmap_load_transform value + * + * A warning is logged if the string is not recognised + *****************************************************************************/ +static enum xrdp_bitmap_load_transform +bitmap_transform_str_to_val(const char *param, const char *str) +{ + enum xrdp_bitmap_load_transform rv; + if (g_strcmp(str, "none") == 0) + { + rv = XBLT_NONE; + } + else if (g_strcmp(str, "scale") == 0) + { + rv = XBLT_SCALE; + } + else if (g_strcmp(str, "zoom") == 0) + { + rv = XBLT_ZOOM; + } + else + { + LOG(LOG_LEVEL_WARNING, "Param '%s' has unrecognised value '%s'" + " - assuming 'none'", param, str); + rv = XBLT_NONE; + } + + return rv; +} + /** * Load configuration from xrdp.ini file * @@ -868,6 +922,8 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp) globals->ls_bg_color = HCOLOR(bpp, xrdp_wm_htoi("dedede")); globals->ls_width = 350; globals->ls_height = 350; + globals->ls_background_transform = XBLT_NONE; + globals->ls_logo_transform = XBLT_NONE; globals->ls_logo_x_pos = 63; globals->ls_logo_y_pos = 50; globals->ls_label_x_pos = 30; @@ -1105,16 +1161,39 @@ load_xrdp_config(struct xrdp_config *config, const char *xrdp_ini, int bpp) globals->ls_title[255] = 0; } + else if (g_strncmp(n, "ls_background_image", 255) == 0) + { + g_strncpy(globals->ls_background_image, v, 255); + globals->ls_background_image[255] = 0; + } + + else if (g_strncmp(n, "ls_background_transform", 255) == 0) + { + globals->ls_background_transform = + bitmap_transform_str_to_val(n, v); + } + else if (g_strncmp(n, "ls_logo_filename", 255) == 0) { g_strncpy(globals->ls_logo_filename, v, 255); globals->ls_logo_filename[255] = 0; } - else if (g_strncmp(n, "ls_background_image", 255) == 0) + + else if (g_strncmp(n, "ls_logo_transform", 255) == 0) { - g_strncpy(globals->ls_background_image, v, 255); - globals->ls_background_image[255] = 0; + globals->ls_logo_transform = bitmap_transform_str_to_val(n, v); + } + + else if (g_strncmp(n, "ls_logo_width", 64) == 0) + { + globals->ls_logo_width = g_atoi(v); } + + else if (g_strncmp(n, "ls_logo_height", 64) == 0) + { + globals->ls_logo_height = g_atoi(v); + } + else if (g_strncmp(n, "ls_logo_x_pos", 64) == 0) { globals->ls_logo_x_pos = g_atoi(v); diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h index 149b037914..692a7190d6 100644 --- a/xrdp/xrdp_types.h +++ b/xrdp/xrdp_types.h @@ -644,8 +644,14 @@ struct xrdp_cfg_globals int ls_width; /* window width */ int ls_height; /* window height */ int ls_bg_color; /* background color */ - char ls_logo_filename[256]; /* logo filename */ char ls_background_image[256]; /* background image file name */ + enum xrdp_bitmap_load_transform ls_background_transform; + /* transform to apply to background image */ + char ls_logo_filename[256]; /* logo filename */ + enum xrdp_bitmap_load_transform ls_logo_transform; + /* transform to apply to logo */ + int ls_logo_width; /* logo width (optional) */ + int ls_logo_height; /* logo height (optional) */ int ls_logo_x_pos; /* logo x co-ordinate */ int ls_logo_y_pos; /* logo y co-ordinate */ int ls_label_x_pos; /* x pos of labels */ From 82b8c0a78e2ab50193fb03473bfd9f208662ce06 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 5 Aug 2021 14:25:00 +0100 Subject: [PATCH 11/14] Background login image on the primary monitor only --- xrdp/xrdp_login_wnd.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index de872a3963..0dcb8db8b8 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -643,7 +643,9 @@ xrdp_login_wnd_create(struct xrdp_wm *self) int log_width; int log_height; int regular; - int primary_x_offset; + int primary_width; /* Dimensions of primary screen */ + int primary_height; + int primary_x_offset; /* Offset of centre of primary screen */ int primary_y_offset; int index; int x; @@ -653,8 +655,10 @@ xrdp_login_wnd_create(struct xrdp_wm *self) globals = &self->xrdp_config->cfg_globals; - primary_x_offset = self->screen->width / 2; - primary_y_offset = self->screen->height / 2; + primary_width = self->screen->width; + primary_height = self->screen->height; + primary_x_offset = primary_width / 2; + primary_y_offset = primary_height / 2; log_width = globals->ls_width; log_height = globals->ls_height; @@ -686,8 +690,10 @@ xrdp_login_wnd_create(struct xrdp_wm *self) cx = self->client_info->minfo_wm[index].right; cy = self->client_info->minfo_wm[index].bottom; - primary_x_offset = x + ((cx - x) / 2); - primary_y_offset = y + ((cy - y) / 2); + primary_width = cx - x; + primary_height = cy - y; + primary_x_offset = x + (primary_width / 2); + primary_y_offset = y + (primary_height / 2); break; } } @@ -747,17 +753,17 @@ xrdp_login_wnd_create(struct xrdp_wm *self) globals->ls_background_transform, 0, 0); /* Place the background in the bottom right corner */ - but->left = self->screen->width - but->width; - but->top = self->screen->height - but->height; + but->left = primary_x_offset + (primary_width / 2) - but->width; + but->top = primary_y_offset + (primary_height / 2) - but->height; } else { xrdp_bitmap_load(but, fileName, self->palette, globals->ls_top_window_bg_color, globals->ls_background_transform, - self->screen->width, self->screen->height); - but->left = 0; - but->top = 0; + primary_width, primary_height); + but->left = primary_x_offset - (primary_width / 2); + but->top = primary_y_offset - (primary_height / 2); } but->parent = self->screen; but->owner = self->screen; From ed6e71a54f86912b0085eea1b5b296bd3c2c2e07 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Thu, 5 Aug 2021 15:52:49 +0100 Subject: [PATCH 12/14] Disable the login screen background if the client has disabled wallpaper --- xrdp/xrdp_login_wnd.c | 77 +++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 29 deletions(-) diff --git a/xrdp/xrdp_login_wnd.c b/xrdp/xrdp_login_wnd.c index 0dcb8db8b8..bf25391241 100644 --- a/xrdp/xrdp_login_wnd.c +++ b/xrdp/xrdp_login_wnd.c @@ -731,43 +731,62 @@ xrdp_login_wnd_create(struct xrdp_wm *self) { /* Load the background image. */ /* If no file is specified no default image will be loaded. */ - /* We only load the image if bpp > 8 */ - if (globals->ls_background_image[0] != 0 && self->screen->bpp > 8) + /* We only load the image if bpp > 8, and if the user hasn't + * disabled wallpaer in the performance settings */ + if (globals->ls_background_image[0] != 0) { - char fileName[256] ; - but = xrdp_bitmap_create(4, 4, self->screen->bpp, WND_TYPE_IMAGE, self); - if (globals->ls_background_image[0] == '/') + if (self->screen->bpp <= 8) { - g_snprintf(fileName, 255, "%s", globals->ls_background_image); + LOG(LOG_LEVEL_INFO, "Login background not loaded for bpp=%d", + self->screen->bpp); } - else - { - g_snprintf(fileName, 255, "%s/%s", - XRDP_SHARE_PATH, globals->ls_background_image); - } - LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName); - if (globals->ls_background_transform == XBLT_NONE) + else if ((self->client_info->rdp5_performanceflags & + RDP5_NO_WALLPAPER) != 0) { - xrdp_bitmap_load(but, fileName, self->palette, - globals->ls_top_window_bg_color, - globals->ls_background_transform, - 0, 0); - /* Place the background in the bottom right corner */ - but->left = primary_x_offset + (primary_width / 2) - but->width; - but->top = primary_y_offset + (primary_height / 2) - but->height; + LOG(LOG_LEVEL_INFO, "Login background not loaded as client " + "has requested PERF_DISABLE_WALLPAPER"); } else { - xrdp_bitmap_load(but, fileName, self->palette, - globals->ls_top_window_bg_color, - globals->ls_background_transform, - primary_width, primary_height); - but->left = primary_x_offset - (primary_width / 2); - but->top = primary_y_offset - (primary_height / 2); + char fileName[256] ; + but = xrdp_bitmap_create(4, 4, self->screen->bpp, + WND_TYPE_IMAGE, self); + if (globals->ls_background_image[0] == '/') + { + g_snprintf(fileName, 255, "%s", + globals->ls_background_image); + } + else + { + g_snprintf(fileName, 255, "%s/%s", + XRDP_SHARE_PATH, globals->ls_background_image); + } + LOG(LOG_LEVEL_DEBUG, "We try to load the following background file: %s", fileName); + if (globals->ls_background_transform == XBLT_NONE) + { + xrdp_bitmap_load(but, fileName, self->palette, + globals->ls_top_window_bg_color, + globals->ls_background_transform, + 0, 0); + /* Place the background in the bottom right corner */ + but->left = primary_x_offset + (primary_width / 2) - + but->width; + but->top = primary_y_offset + (primary_height / 2) - + but->height; + } + else + { + xrdp_bitmap_load(but, fileName, self->palette, + globals->ls_top_window_bg_color, + globals->ls_background_transform, + primary_width, primary_height); + but->left = primary_x_offset - (primary_width / 2); + but->top = primary_y_offset - (primary_height / 2); + } + but->parent = self->screen; + but->owner = self->screen; + list_add_item(self->screen->child_list, (long)but); } - but->parent = self->screen; - but->owner = self->screen; - list_add_item(self->screen->child_list, (long)but); } /* if logo image not specified, use default */ From e35507125cb5589f16c2129a1c950cfc286e0d02 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 9 Aug 2021 11:59:33 +0100 Subject: [PATCH 13/14] Address review comments and re-test --- configure.ac | 18 +++++++----------- tests/xrdp/test_bitmap_load.c | 4 ++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/configure.ac b/configure.ac index 01ac0cb97d..796193ab24 100644 --- a/configure.ac +++ b/configure.ac @@ -166,7 +166,7 @@ AC_ARG_ENABLE(rdpsndaudin, AS_HELP_STRING([--enable-rdpsndaudin], [], [enable_rdpsndaudin=no]) AM_CONDITIONAL(XRDP_RDPSNDAUDIN, [test x$enable_rdpsndaudin = xyes]) -AC_ARG_WITH(imlib2, AC_HELP_STRING([--with-imlib2=ARG], [imlib2 library to use (yes/no/auto/)]),,) +AC_ARG_WITH(imlib2, AC_HELP_STRING([--with-imlib2=ARG], [imlib2 library to use for non-BMP backgrounds (ARG=yes/no/)]),,) # Obsolete options AC_ARG_ENABLE(xrdpdebug, AS_HELP_STRING([--enable-xrdpdebug], @@ -220,25 +220,19 @@ AC_CHECK_HEADER([security/pam_constants.h], # Find imlib2 case "$with_imlib2" in - no) AC_MSG_NOTICE([imlib2 will not be supported]) + '' | no) AC_MSG_NOTICE([imlib2 will not be supported]) use_imlib2=no ;; - '' | auto) - PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10], - [use_imlib2=yes], - [use_imlib2=no]) - ;; yes) PKG_CHECK_MODULES([IMLIB2], [imlib2 >= 1.4.10], [use_imlib2=yes], [AC_MSG_ERROR([please install libimlib2-dev or imlib2-devel])]) ;; - *) - AC_MSG_CHECKING([for imlib2 in $with_imlib2]) + /*) AC_MSG_CHECKING([for imlib2 in $with_imlib2]) if test -d $with_imlib2/lib; then - IMLIB2_LIBS="-L $with_imlib2/lib -lImlib2" + IMLIB2_LIBS="-L$with_imlib2/lib -lImlib2" elif test -d $with_imlib2/lib64; then - IMLIB2_LIBS="-L $with_imlib2/lib64 -lImlib2" + IMLIB2_LIBS="-L$with_imlib2/lib64 -lImlib2" else AC_MSG_RESULT([no]) AC_MSG_ERROR([Can't find libImlib2 in $with_imlib2]) @@ -254,6 +248,8 @@ case "$with_imlib2" in AC_SUBST([IMLIB2_LIBS]) AC_SUBST([IMLIB2_CFLAGS]) use_imlib2=yes + ;; + *) AC_MSG_ERROR([--with-imlib2 needs yes/no or absolute path]) esac if test x$use_imlib2 = xyes; then diff --git a/tests/xrdp/test_bitmap_load.c b/tests/xrdp/test_bitmap_load.c index ebb59c004d..42b5a32593 100644 --- a/tests/xrdp/test_bitmap_load.c +++ b/tests/xrdp/test_bitmap_load.c @@ -281,6 +281,7 @@ START_TEST(test_bitmap_load__not_4_pixels_wide_24_bit__ok) } END_TEST +#ifdef USE_IMLIB2 START_TEST(test_png_load__blend_ok) { load_and_transform_img("test_alpha_blend.png", XBLT_NONE, 0, 0); @@ -292,6 +293,7 @@ START_TEST(test_jpg_load__ok) load_and_transform_img("test1.jpg", XBLT_NONE, 0, 0); } END_TEST +#endif /******************************************************************************/ Suite * @@ -299,7 +301,9 @@ make_suite_test_bitmap_load(void) { Suite *s; TCase *tc_bitmap_load; +#ifdef USE_IMLIB2 TCase *tc_other_load; +#endif s = suite_create("BitmapLoad"); From aa43a005e30691ddc079f33a5f24f143ee08b8a1 Mon Sep 17 00:00:00 2001 From: matt335672 <30179339+matt335672@users.noreply.github.com> Date: Mon, 9 Aug 2021 12:00:06 +0100 Subject: [PATCH 14/14] Add --with-imlib2 to i386 CI --- .github/workflows/build.yml | 2 +- scripts/install_xrdp_build_dependencies_with_apt.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5d59f11eaf..6f3986360e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -97,7 +97,7 @@ jobs: --enable-pixman --with-imlib2" CONF_FLAGS_i386_max: "--enable-ipv6 --enable-jpeg --enable-fuse --enable-mp3lame --enable-fdkaac --enable-opus --enable-rfxcodec --enable-painter - --disable-pixman --host=i686-linux" + --disable-pixman --with-imlib2 --host=i686-linux" PKG_CONFIG_PATH_i386: "/usr/lib/i386-linux-gnu/pkgconfig" CFLAGS_i386: "-m32" diff --git a/scripts/install_xrdp_build_dependencies_with_apt.sh b/scripts/install_xrdp_build_dependencies_with_apt.sh index da907e1b6f..89b59a211d 100755 --- a/scripts/install_xrdp_build_dependencies_with_apt.sh +++ b/scripts/install_xrdp_build_dependencies_with_apt.sh @@ -67,6 +67,7 @@ in libgl1-mesa-dev:i386 \ libglu1-mesa-dev:i386 \ libjpeg-dev:i386 \ + libimlib2-dev:i386 \ libmp3lame-dev:i386 \ libfdk-aac-dev:i386 \ libopus-dev:i386 \