From 153afb2bcbdb1a98961d7daa8d3539dde05dacc1 Mon Sep 17 00:00:00 2001 From: srs5694 Date: Wed, 16 Jan 2013 02:09:29 -0500 Subject: [PATCH] Support for auto-selecting text color (white or black) depending on background color. --- NEWS.txt | 3 +++ libeg/libeg.h | 7 +++++- libeg/screen.c | 2 +- libeg/text.c | 34 +++++++++++++++++++++++---- mkdistrib | 2 +- refind.spec | 2 +- refind/main.c | 2 +- refind/menu.c | 64 +++++++++++++++++++++++++++++++++----------------- 8 files changed, 84 insertions(+), 32 deletions(-) diff --git a/NEWS.txt b/NEWS.txt index 6b940ff..d8b20a1 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,9 @@ 0.6.5 (1/??/2013): ------------------ +- Improved text color support: rEFInd now uses black text against light + backgrounds and white text against dark backgrounds. + - Added support for PNGs as banners, icons, and selectors. - Added icon for ALT Linux. diff --git a/libeg/libeg.h b/libeg/libeg.h index 088afdd..7e2c990 100644 --- a/libeg/libeg.h +++ b/libeg/libeg.h @@ -43,6 +43,11 @@ /* types */ +typedef enum ColorTypes { + white, + black +} Colors; + /* This should be compatible with EFI_UGA_PIXEL */ typedef struct { UINT8 b, g, r, a; @@ -115,7 +120,7 @@ VOID egFillImageArea(IN OUT EG_IMAGE *CompImage, VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY); VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height); -VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY); +VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness); VOID egClearScreen(IN EG_PIXEL *Color); VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY); diff --git a/libeg/screen.c b/libeg/screen.c index 9f159e1..cd97397 100644 --- a/libeg/screen.c +++ b/libeg/screen.c @@ -446,7 +446,7 @@ VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor) { BoxWidth = egScreenWidth; BoxHeight = 2 * FONT_CELL_HEIGHT; Box = egCreateFilledImage(BoxWidth, BoxHeight, FALSE, BGColor); - egRenderText(Text, Box, FONT_CELL_WIDTH, FONT_CELL_HEIGHT / 2); + egRenderText(Text, Box, FONT_CELL_WIDTH, FONT_CELL_HEIGHT / 2, (BGColor->r + BGColor->g + BGColor->b) / 3); egDrawImage(Box, (egScreenWidth - BoxWidth) / 2, (egScreenHeight - BoxHeight) / 2); } // if non-NULL inputs } // VOID egDisplayMessage() diff --git a/libeg/text.c b/libeg/text.c index 93551b2..c723710 100644 --- a/libeg/text.c +++ b/libeg/text.c @@ -41,7 +41,8 @@ #define FONT_CELL_WIDTH (7) #define FONT_CELL_HEIGHT (12) -static EG_IMAGE *FontImage = NULL; +static EG_IMAGE *BlackFontImage = NULL; +static EG_IMAGE *WhiteFontImage = NULL; // // Text rendering @@ -55,8 +56,9 @@ VOID egMeasureText(IN CHAR16 *Text, OUT UINTN *Width, OUT UINTN *Height) *Height = FONT_CELL_HEIGHT; } -VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY) +VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN UINTN PosY, IN UINT8 BGBrightness) { + EG_IMAGE *FontImage; EG_PIXEL *BufferPtr; EG_PIXEL *FontPixelData; UINTN BufferLineOffset, FontLineOffset; @@ -72,9 +74,31 @@ VOID egRenderText(IN CHAR16 *Text, IN OUT EG_IMAGE *CompImage, IN UINTN PosX, IN if (TextLength * FONT_CELL_WIDTH + PosX > CompImage->Width) TextLength = (CompImage->Width - PosX) / FONT_CELL_WIDTH; - // load the font - if (FontImage == NULL) - FontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); + if (BGBrightness < 128) { + if (WhiteFontImage == NULL) { + WhiteFontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); + if (WhiteFontImage == NULL) + return; + for (i = 0; i < (WhiteFontImage->Width * WhiteFontImage->Height); i++) { + WhiteFontImage->PixelData[i].r = 255 - WhiteFontImage->PixelData[i].r; + WhiteFontImage->PixelData[i].g = 255 - WhiteFontImage->PixelData[i].g; + WhiteFontImage->PixelData[i].b = 255 - WhiteFontImage->PixelData[i].b; +// WhiteFontImage->PixelData[i].a = 255 - WhiteFontImage->PixelData[i].a; + } // for + } // if + FontImage = WhiteFontImage; + } else { + if (BlackFontImage == NULL) + BlackFontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); + if (BlackFontImage == NULL) + return; + FontImage = BlackFontImage; + } // if/else + +// // load the font +// if (FontImage == NULL) { +// FontImage = egPrepareEmbeddedImage(&egemb_font, TRUE); +// } // if font not yet loaded. // render it BufferPtr = CompImage->PixelData; diff --git a/mkdistrib b/mkdistrib index af3ed1d..52d07ff 100755 --- a/mkdistrib +++ b/mkdistrib @@ -46,7 +46,7 @@ make clean # Prepare a place and copy files there.... mkdir -p ../snapshots/$1/refind-$1/icons -cp --preserve=timestamps icons/*.icns icons/*.png ../snapshots/$1/refind-$1/icons/ +cp --preserve=timestamps icons/*.icns ../snapshots/$1/refind-$1/icons/ cp -a docs images keys include EfiLib libeg mok refind filesystems refind.spec install.sh mkrlconf.sh mvrefind.sh CREDITS.txt NEWS.txt BUILDING.txt COPYING.txt LICENSE.txt README.txt refind.inf Make.tiano Make.common Makefile refind.conf-sample ../snapshots/$1/refind-$1 # Go there and prepare a souce code zip file.... diff --git a/refind.spec b/refind.spec index ed0ccff..24dfd91 100644 --- a/refind.spec +++ b/refind.spec @@ -1,6 +1,6 @@ Summary: EFI boot manager software Name: refind -Version: 0.6.4.2 +Version: 0.6.4.7 Release: 1%{?dist} License: GPLv3 URL: http://www.rodsbooks.com/refind/ diff --git a/refind/main.c b/refind/main.c index 4638a62..4de35d8 100644 --- a/refind/main.c +++ b/refind/main.c @@ -128,7 +128,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.4.6"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.6.4.7"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012 Roderick W. Smith"); diff --git a/refind/menu.c b/refind/menu.c index 39c9020..cf2bafd 100644 --- a/refind/menu.c +++ b/refind/menu.c @@ -636,26 +636,46 @@ static VOID TextMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, // Display a submenu -static VOID DrawSubmenuText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos) +static VOID DrawText(IN CHAR16 *Text, IN BOOLEAN Selected, IN UINTN FieldWidth, IN UINTN XPos, IN UINTN YPos) { -// UINTN TextWidth = TEXT_XMARGIN * 2 + StrLen(Text) * FONT_CELL_WIDTH; EG_IMAGE *TextBuffer; + EG_PIXEL Bg; TextBuffer = egCreateImage(FieldWidth, TEXT_LINE_HEIGHT, FALSE); egFillImage(TextBuffer, &MenuBackgroundPixel); + Bg = MenuBackgroundPixel; if (Selected) { // draw selection bar background egFillImageArea(TextBuffer, 0, 0, FieldWidth, TextBuffer->Height, &SelectionBackgroundPixel); + Bg = SelectionBackgroundPixel; } // render the text - egRenderText(Text, TextBuffer, TEXT_XMARGIN, TEXT_YMARGIN); + egRenderText(Text, TextBuffer, TEXT_XMARGIN, TEXT_YMARGIN, (Bg.r + Bg.g + Bg.b) / 3); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); // BltImage(TextBuffer, XPos, YPos); } -static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) +// Finds the average brightness of the input Image. +// NOTE: Passing an Image that covers the whole screen can strain the +// capacity of a UINTN on a 32-bit system with a very large display. +// As the intended use for this function is to handle a single text +// string's background, this shouldn't be a problem, but it may need +// addressing if it's applied more broadly.... +static UINT8 AverageBrightness(EG_IMAGE *Image) { + UINTN i; + UINTN Sum = 0; + + if (Image != NULL) { + for (i = 0; i < (Image->Width * Image->Height); i++) { + Sum += (Image->PixelData[i].r + Image->PixelData[i].g + Image->PixelData[i].b); + } + } // if + return (UINT8) (Sum / (Image->Width * Image->Height * 3)); +} // UINT8 AverageBrightness() + +static VOID DrawTextWithTransparency(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) { UINTN TextWidth, TextPosX; EG_IMAGE *TextBuffer; @@ -668,7 +688,7 @@ static VOID DrawMainMenuText(IN CHAR16 *Text, IN UINTN XPos, IN UINTN YPos) TextPosX = 0; else TextPosX = (TextBuffer->Width - TextWidth) / 2; - egRenderText(Text, TextBuffer, TextPosX, 0); + egRenderText(Text, TextBuffer, TextPosX, 0, AverageBrightness(TextBuffer)); egDrawImageWithTransparency(TextBuffer, NULL, XPos, YPos, TextBuffer->Width, TextBuffer->Height); } @@ -762,8 +782,8 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta Window = egCreateFilledImage(MenuWidth, MenuHeight, FALSE, BackgroundPixel); egDrawImage(Window, EntriesPosX, EntriesPosY); egMeasureText(Screen->Title, &ItemWidth, NULL); - DrawSubmenuText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * FONT_CELL_WIDTH, - EntriesPosX + (MenuWidth - ItemWidth) / 2, EntriesPosY += TEXT_LINE_HEIGHT); + DrawText(Screen->Title, FALSE, (StrLen(Screen->Title) + 2) * FONT_CELL_WIDTH, + EntriesPosX + (MenuWidth - ItemWidth) / 2, EntriesPosY += TEXT_LINE_HEIGHT); if (Screen->TitleImage) { BltImageAlpha(Screen->TitleImage, EntriesPosX, EntriesPosY + TEXT_LINE_HEIGHT * 2, BackgroundPixel); EntriesPosX += (Screen->TitleImage->Width + TITLEICON_SPACING); @@ -771,7 +791,7 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta EntriesPosY += (TEXT_LINE_HEIGHT * 2); if (Screen->InfoLineCount > 0) { for (i = 0; i < (INTN)Screen->InfoLineCount; i++) { - DrawSubmenuText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY); + DrawText(Screen->InfoLines[i], FALSE, LineWidth, EntriesPosX, EntriesPosY); EntriesPosY += TEXT_LINE_HEIGHT; } EntriesPosY += TEXT_LINE_HEIGHT; // also add a blank line @@ -785,27 +805,27 @@ static VOID GraphicsMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *Sta case MENU_FUNCTION_PAINT_ALL: for (i = 0; i <= State->MaxIndex; i++) { - DrawSubmenuText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, - EntriesPosX, EntriesPosY + i * TEXT_LINE_HEIGHT); + DrawText(Screen->Entries[i]->Title, (i == State->CurrentSelection), LineWidth, EntriesPosX, + EntriesPosY + i * TEXT_LINE_HEIGHT); } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { if ((Screen->Hint1 != NULL) && (StrLen(Screen->Hint1) > 0)) - DrawMainMenuText(Screen->Hint1, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 3)); + DrawTextWithTransparency(Screen->Hint1, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 3)); if ((Screen->Hint2 != NULL) && (StrLen(Screen->Hint2) > 0)) - DrawMainMenuText(Screen->Hint2, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 2)); + DrawTextWithTransparency(Screen->Hint2, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 2)); } // if break; case MENU_FUNCTION_PAINT_SELECTION: // redraw selection cursor - DrawSubmenuText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth, - EntriesPosX, EntriesPosY + State->PreviousSelection * TEXT_LINE_HEIGHT); - DrawSubmenuText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth, - EntriesPosX, EntriesPosY + State->CurrentSelection * TEXT_LINE_HEIGHT); + DrawText(Screen->Entries[State->PreviousSelection]->Title, FALSE, LineWidth, + EntriesPosX, EntriesPosY + State->PreviousSelection * TEXT_LINE_HEIGHT); + DrawText(Screen->Entries[State->CurrentSelection]->Title, TRUE, LineWidth, + EntriesPosX, EntriesPosY + State->CurrentSelection * TEXT_LINE_HEIGHT); break; case MENU_FUNCTION_PAINT_TIMEOUT: - DrawSubmenuText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY); + DrawText(ParamText, FALSE, LineWidth, EntriesPosX, TimeoutPosY); break; } @@ -849,12 +869,12 @@ static VOID PaintAll(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, UINTN } } if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) - DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title, + DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_HINTS)) { - DrawMainMenuText(Screen->Hint1, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 3)); - DrawMainMenuText(Screen->Hint2, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 2)); + DrawTextWithTransparency(Screen->Hint1, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 3)); + DrawTextWithTransparency(Screen->Hint2, (UGAWidth - LAYOUT_TEXT_WIDTH) / 2, UGAHeight - (FONT_CELL_HEIGHT * 2)); } // if } // static VOID PaintAll() @@ -882,7 +902,7 @@ static VOID PaintSelection(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, DrawMainMenuEntry(Screen->Entries[State->PreviousSelection], FALSE, itemPosX[XSelectPrev], YPosPrev); DrawMainMenuEntry(Screen->Entries[State->CurrentSelection], TRUE, itemPosX[XSelectCur], YPosCur); if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) - DrawMainMenuText(Screen->Entries[State->CurrentSelection]->Title, + DrawTextWithTransparency(Screen->Entries[State->CurrentSelection]->Title, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY); } else { // Current selection not visible; must redraw the menu.... MainMenuStyle(Screen, State, MENU_FUNCTION_PAINT_ALL, NULL); @@ -1021,7 +1041,7 @@ VOID MainMenuStyle(IN REFIT_MENU_SCREEN *Screen, IN SCROLL_STATE *State, IN UINT case MENU_FUNCTION_PAINT_TIMEOUT: if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_LABEL)) - DrawMainMenuText(ParamText, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY + TEXT_LINE_HEIGHT); + DrawTextWithTransparency(ParamText, (UGAWidth - LAYOUT_TEXT_WIDTH) >> 1, textPosY + TEXT_LINE_HEIGHT); break; } -- 2.39.2