* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/*
+ * Modifications copyright (c) 2012-2015 Roderick W. Smith
+ *
+ * Modifications distributed under the terms of the GNU General Public
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
+ *
+ */
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#include "libegint.h"
#include "../refind/global.h"
#include "../refind/lib.h"
#include "../refind/screen.h"
+#include "../refind/mystrings.h"
#include "../include/refit_call_wrapper.h"
#include "lodepng.h"
#define MAX_FILE_SIZE (1024*1024*1024)
+// Multiplier for pseudo-floating-point operations in egScaleImage().
+// A value of 4096 should keep us within limits on 32-bit systems, but I've
+// seen some minor artifacts at this level, so give it a bit more precision
+// on 64-bit systems....
+#if defined(EFIX64) | defined(EFIAARCH64)
+#define FP_MULTIPLIER (UINTN) 65536
+#else
+#define FP_MULTIPLIER (UINTN) 4096
+#endif
+
#ifndef __MAKEWITH_GNUEFI
#define LibLocateHandle gBS->LocateHandleBuffer
#define LibOpenRoot EfiLibOpenRoot
return NULL;
NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL));
if (NewImage->PixelData == NULL) {
- FreePool(NewImage);
+ egFreeImage(NewImage);
return NULL;
}
EG_IMAGE * egCopyImage(IN EG_IMAGE *Image)
{
- EG_IMAGE *NewImage;
+ EG_IMAGE *NewImage = NULL;
- NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha);
+ if (Image != NULL)
+ NewImage = egCreateImage(Image->Width, Image->Height, Image->HasAlpha);
if (NewImage == NULL)
return NULL;
return NewImage;
} // EG_IMAGE * egCropImage()
+// The following function implements a bilinear image scaling algorithm, based on
+// code presented at http://tech-algorithm.com/articles/bilinear-image-scaling/.
+// Resize an image; returns pointer to resized image if successful, NULL otherwise.
+// Calling function is responsible for freeing allocated memory.
+// NOTE: x_ratio, y_ratio, x_diff, and y_diff should really be float values;
+// however, I've found that my 32-bit Mac Mini has a buggy EFI (or buggy CPU?), which
+// causes this function to hang on float-to-UINT8 conversions on some (but not all!)
+// float values. Therefore, this function uses integer arithmetic but multiplies
+// all values by FP_MULTIPLIER to achieve something resembling the sort of precision
+// needed for good results.
+EG_IMAGE * egScaleImage(IN EG_IMAGE *Image, IN UINTN NewWidth, IN UINTN NewHeight) {
+ EG_IMAGE *NewImage = NULL;
+ EG_PIXEL a, b, c, d;
+ UINTN x, y, Index ;
+ UINTN i, j;
+ UINTN Offset = 0;
+ UINTN x_ratio, y_ratio, x_diff, y_diff;
+
+ if ((Image == NULL) || (Image->Height == 0) || (Image->Width == 0) || (NewWidth == 0) || (NewHeight == 0))
+ return NULL;
+
+ if ((Image->Width == NewWidth) && (Image->Height == NewHeight))
+ return (egCopyImage(Image));
+
+ NewImage = egCreateImage(NewWidth, NewHeight, Image->HasAlpha);
+ if (NewImage == NULL)
+ return NULL;
+
+ x_ratio = ((Image->Width - 1) * FP_MULTIPLIER) / NewWidth;
+ y_ratio = ((Image->Height - 1) * FP_MULTIPLIER) / NewHeight;
+
+ for (i = 0; i < NewHeight; i++) {
+ for (j = 0; j < NewWidth; j++) {
+ x = (j * (Image->Width - 1)) / NewWidth;
+ y = (i * (Image->Height - 1)) / NewHeight;
+ x_diff = (x_ratio * j) - x * FP_MULTIPLIER;
+ y_diff = (y_ratio * i) - y * FP_MULTIPLIER;
+ Index = ((y * Image->Width) + x);
+ a = Image->PixelData[Index];
+ b = Image->PixelData[Index + 1];
+ c = Image->PixelData[Index + Image->Width];
+ d = Image->PixelData[Index + Image->Width + 1];
+
+ // blue element
+ NewImage->PixelData[Offset].b = ((a.b) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.b) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.b) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.b) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // green element
+ NewImage->PixelData[Offset].g = ((a.g) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.g) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.g) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.g) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // red element
+ NewImage->PixelData[Offset].r = ((a.r) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.r) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.r) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.r) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+
+ // alpha element
+ NewImage->PixelData[Offset++].a = ((a.a) * (FP_MULTIPLIER - x_diff) * (FP_MULTIPLIER - y_diff) +
+ (b.a) * (x_diff) * (FP_MULTIPLIER - y_diff) +
+ (c.a) * (y_diff) * (FP_MULTIPLIER - x_diff) +
+ (d.a) * (x_diff * y_diff)) / (FP_MULTIPLIER * FP_MULTIPLIER);
+ } // for (j...)
+ } // for (i...)
+ return NewImage;
+} // EG_IMAGE * egScaleImage()
+
VOID egFreeImage(IN EG_IMAGE *Image)
{
if (Image != NULL) {
// Basic file operations
//
-EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength)
+EFI_STATUS egLoadFile(IN EFI_FILE *BaseDir, IN CHAR16 *FileName, OUT UINT8 **FileData, OUT UINTN *FileDataLength)
{
EFI_STATUS Status;
EFI_FILE_HANDLE FileHandle;
UINTN BufferSize;
UINT8 *Buffer;
+ if ((BaseDir == NULL) || (FileName == NULL))
+ return EFI_NOT_FOUND;
+
Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName, EFI_FILE_MODE_READ, 0);
if (EFI_ERROR(Status)) {
return Status;
static EFI_GUID ESPGuid = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
-static EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir)
+EFI_STATUS egFindESP(OUT EFI_FILE_HANDLE *RootDir)
{
EFI_STATUS Status;
UINTN HandleCount = 0;
}
Status = refit_call5_wrapper(BaseDir->Open, BaseDir, &FileHandle, FileName,
- EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0);
if (EFI_ERROR(Status))
return Status;
return NULL;
// decode it
- NewImage = egDecodeAny(FileData, FileDataLength, 128, WantAlpha);
+ NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha);
FreePool(FileData);
return NewImage;
EFI_STATUS Status;
UINT8 *FileData;
UINTN FileDataLength;
- EG_IMAGE *NewImage;
+ EG_IMAGE *Image, *NewImage;
if (BaseDir == NULL || Path == NULL)
return NULL;
return NULL;
// decode it
- NewImage = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
+ Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
FreePool(FileData);
- if ((NewImage->Width != IconSize) || (NewImage->Height != IconSize)) {
- Print(L"Warning: Attempt to load icon of the wrong size from '%s'\n", Path);
- MyFreePool(NewImage);
- NewImage = NULL;
+ if ((Image->Width != IconSize) || (Image->Height != IconSize)) {
+ NewImage = egScaleImage(Image, IconSize, IconSize);
+ if (!NewImage)
+ Print(L"Warning: Unable to scale icon of the wrong size from '%s'\n", Path);
+ egFreeImage(Image);
+ Image = NewImage;
}
- return NewImage;
+ return Image;
} // EG_IMAGE *egLoadIcon()
+// Returns an icon of any type from the specified subdirectory using the specified
+// base name. All directory references are relative to BaseDir. For instance, if
+// SubdirName is "myicons" and BaseName is "os_linux", this function will return
+// an image based on "myicons/os_linux.icns" or "myicons/os_linux.png", in that
+// order of preference. Returns NULL if no such file is a valid icon file.
+EG_IMAGE * egLoadIconAnyType(IN EFI_FILE *BaseDir, IN CHAR16 *SubdirName, IN CHAR16 *BaseName, IN UINTN IconSize) {
+ EG_IMAGE *Image = NULL;
+ CHAR16 *Extension;
+ CHAR16 FileName[256];
+ UINTN i = 0;
+
+ while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) {
+ SPrint(FileName, 255, L"%s\\%s.%s", SubdirName, BaseName, Extension);
+ Image = egLoadIcon(BaseDir, FileName, IconSize);
+ MyFreePool(Extension);
+ } // while()
+
+ return Image;
+} // EG_IMAGE *egLoadIconAnyType()
+
// Returns an icon with any extension in ICON_EXTENSIONS from either the directory
// specified by GlobalConfig.IconsDir or DEFAULT_ICONS_DIR. The input BaseName
// should be the icon name without an extension. For instance, if BaseName is
// order of preference. Returns NULL if no such icon can be found. All file
// references are relative to SelfDir.
EG_IMAGE * egFindIcon(IN CHAR16 *BaseName, IN UINTN IconSize) {
- CHAR16 *LoadDir, *Extension;
- CHAR16 FileName[256];
- UINTN i;
EG_IMAGE *Image = NULL;
- if (GlobalConfig.IconsDir != NULL)
- LoadDir = GlobalConfig.IconsDir;
- else
- LoadDir = StrDuplicate(DEFAULT_ICONS_DIR);
-
- while ((LoadDir != NULL) && (Image == NULL)) {
- i = 0;
- while (((Extension = FindCommaDelimited(ICON_EXTENSIONS, i++)) != NULL) && (Image == NULL)) {
- SPrint(FileName, 255, L"%s\\%s.%s", LoadDir, BaseName, Extension);
- Image = egLoadIcon(SelfDir, FileName, IconSize);
- MyFreePool(Extension);
- } // while()
- if (LoadDir == GlobalConfig.IconsDir) {
- LoadDir = StrDuplicate(DEFAULT_ICONS_DIR);
- } else {
- MyFreePool(LoadDir);
- LoadDir = NULL;
- } // if/else
- } // while()
+ if (GlobalConfig.IconsDir != NULL) {
+ Image = egLoadIconAnyType(SelfDir, GlobalConfig.IconsDir, BaseName, IconSize);
+ }
+
+ if (Image == NULL) {
+ Image = egLoadIconAnyType(SelfDir, DEFAULT_ICONS_DIR, BaseName, IconSize);
+ }
+
return Image;
} // EG_IMAGE * egFindIcon()
}
} /* VOID egComposeImage() */
-EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height, IN EG_PIXEL *Color)
-{
- EG_IMAGE *NewImage;
-
- if (Image == NULL)
- return NULL;
- if (Image->Width == Width && Image->Height == Height)
- return Image;
-
- NewImage = egCreateFilledImage(Width, Height, Image->HasAlpha, Color);
- if (NewImage == NULL) {
- egFreeImage(Image);
- return NULL;
- }
- Image->HasAlpha = FALSE;
- egComposeImage(NewImage, Image, 0, 0);
- egFreeImage(Image);
-
- return NewImage;
-}
-
//
// misc internal functions
//