]> code.delx.au - refind/blobdiff - libeg/image.c
Fixed bugs in mkrlconf and refind-install that could cause kernel
[refind] / libeg / image.c
index 13bb758d857173f6b63aafcd1df87819c261a926..c61f34847dbeeb5cedd5d22c9ce3783f1a030ed6 100644 (file)
  * (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 "refit_call_wrapper.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)
+#define FP_MULTIPLIER (UINTN) 65536
+#else
+#define FP_MULTIPLIER (UINTN) 4096
+#endif
+
+#ifndef __MAKEWITH_GNUEFI
+#define LibLocateHandle gBS->LocateHandleBuffer
+#define LibOpenRoot EfiLibOpenRoot
+#endif
+
 //
 // Basic image handling
 //
 EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
 {
     EG_IMAGE        *NewImage;
-    
+
     NewImage = (EG_IMAGE *) AllocatePool(sizeof(EG_IMAGE));
     if (NewImage == NULL)
         return NULL;
     NewImage->PixelData = (EG_PIXEL *) AllocatePool(Width * Height * sizeof(EG_PIXEL));
     if (NewImage->PixelData == NULL) {
-        FreePool(NewImage);
+        egFreeImage(NewImage);
         return NULL;
     }
-    
+
     NewImage->Width = Width;
     NewImage->Height = Height;
     NewImage->HasAlpha = HasAlpha;
@@ -65,20 +106,21 @@ EG_IMAGE * egCreateImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha)
 EG_IMAGE * egCreateFilledImage(IN UINTN Width, IN UINTN Height, IN BOOLEAN HasAlpha, IN EG_PIXEL *Color)
 {
     EG_IMAGE        *NewImage;
-    
+
     NewImage = egCreateImage(Width, Height, HasAlpha);
     if (NewImage == NULL)
         return NULL;
-    
+
     egFillImage(NewImage, Color);
     return NewImage;
 }
 
 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;
 
@@ -86,6 +128,98 @@ EG_IMAGE * egCopyImage(IN EG_IMAGE *Image)
     return NewImage;
 }
 
+// Returns a smaller image composed of the specified crop area from the larger area.
+// If the specified area is larger than is in the original, returns NULL.
+EG_IMAGE * egCropImage(IN EG_IMAGE *Image, IN UINTN StartX, IN UINTN StartY, IN UINTN Width, IN UINTN Height) {
+   EG_IMAGE *NewImage = NULL;
+   UINTN x, y;
+
+   if (((StartX + Width) > Image->Width) || ((StartY + Height) > Image->Height))
+      return NULL;
+
+   NewImage = egCreateImage(Width, Height, Image->HasAlpha);
+   if (NewImage == NULL)
+      return NULL;
+
+   for (y = 0; y < Height; y++) {
+      for (x = 0; x < Width; x++) {
+         NewImage->PixelData[y * NewImage->Width + x] = Image->PixelData[(y + StartY) * Image->Width + x + StartX];
+      }
+   }
+   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) {
@@ -99,8 +233,7 @@ VOID egFreeImage(IN EG_IMAGE *Image)
 // 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;
@@ -109,16 +242,17 @@ EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName,
     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)) {
-//        Print(L"Returning %d from egLoadFile() because of an error on open!\n", Status);
         return Status;
     }
 
     FileInfo = LibFileInfo(FileHandle);
     if (FileInfo == NULL) {
         refit_call1_wrapper(FileHandle->Close, FileHandle);
-//        Print(L"LibFileInfo() returned NULL!\n");
         return EFI_NOT_FOUND;
     }
     ReadSize = FileInfo->FileSize;
@@ -132,7 +266,7 @@ EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName,
         refit_call1_wrapper(FileHandle->Close, FileHandle);
         return EFI_OUT_OF_RESOURCES;
     }
-    
+
     Status = refit_call3_wrapper(FileHandle->Read, FileHandle, &BufferSize, Buffer);
     refit_call1_wrapper(FileHandle->Close, FileHandle);
     if (EFI_ERROR(Status)) {
@@ -142,18 +276,17 @@ EFI_STATUS egLoadFile(IN EFI_FILE* BaseDir, IN CHAR16 *FileName,
 
     *FileData = Buffer;
     *FileDataLength = BufferSize;
-//    Print(L"In egLoadFile(), Returning EFI_SUCCESS\n");
     return EFI_SUCCESS;
 }
 
 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;
     EFI_HANDLE          *Handles;
-    
+
     Status = LibLocateHandle(ByProtocol, &ESPGuid, NULL, &HandleCount, &Handles);
     if (!EFI_ERROR(Status) && HandleCount > 0) {
         *RootDir = LibOpenRoot(Handles[0]);
@@ -178,7 +311,7 @@ EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
     }
 
     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;
 
@@ -193,34 +326,18 @@ EFI_STATUS egSaveFile(IN EFI_FILE* BaseDir OPTIONAL, IN CHAR16 *FileName,
 // Loading images from files and embedded data
 //
 
-static CHAR16 * egFindExtension(IN CHAR16 *FileName)
-{
-    UINTN i;
-    
-    for (i = StrLen(FileName); i >= 0; i--) {
-        if (FileName[i] == '.')
-            return FileName + i + 1;
-        if (FileName[i] == '/' || FileName[i] == '\\')
-            break;
-    }
-    return FileName + StrLen(FileName);
-}
-
-static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength,
-                              IN CHAR16 *Format, IN UINTN IconSize, IN BOOLEAN WantAlpha)
+// Decode the specified image data. The IconSize parameter is relevant only
+// for ICNS, for which it selects which ICNS sub-image is decoded.
+// Returns a pointer to the resulting EG_IMAGE or NULL if decoding failed.
+static EG_IMAGE * egDecodeAny(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN IconSize, IN BOOLEAN WantAlpha)
 {
    EG_IMAGE        *NewImage = NULL;
 
-   // Note: The UEFI implementation in Gigabyte's Hybrid EFI is buggy and does
-   // a case-sensitive comparison in StriCmp rather than the case-insensitive
-   // comparison that the spec says should be done. As a workaround, we repeat
-   // the comparison twice here.
-   // dispatch by extension
-   if ((StriCmp(Format, L"BMP") == 0) || (StriCmp(Format, L"bmp") == 0)) {
+   NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha);
+   if (NewImage == NULL)
+      NewImage = egDecodePNG(FileData, FileDataLength, IconSize, WantAlpha);
+   if (NewImage == NULL)
       NewImage = egDecodeBMP(FileData, FileDataLength, IconSize, WantAlpha);
-   } else if ((StriCmp(Format, L"ICNS") == 0) || (StriCmp(Format, L"icns") == 0)) {
-      NewImage = egDecodeICNS(FileData, FileDataLength, IconSize, WantAlpha);
-   } // if/else
 
    return NewImage;
 }
@@ -241,43 +358,84 @@ EG_IMAGE * egLoadImage(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN BOOLEAN Wan
         return NULL;
 
     // decode it
-    NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FileName), 128, WantAlpha);
+    NewImage = egDecodeAny(FileData, FileDataLength, 128 /* arbitrary value */, WantAlpha);
     FreePool(FileData);
 
     return NewImage;
 }
 
-EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *FileName, IN UINTN IconSize)
+// Load an icon from (BaseDir)/Path, extracting the icon of size IconSize x IconSize.
+// Returns a pointer to the image data, or NULL if the icon could not be loaded.
+EG_IMAGE * egLoadIcon(IN EFI_FILE* BaseDir, IN CHAR16 *Path, IN UINTN IconSize)
 {
     EFI_STATUS      Status;
     UINT8           *FileData;
     UINTN           FileDataLength;
-    EG_IMAGE        *NewImage;
+    EG_IMAGE        *Image, *NewImage;
 
-    if (BaseDir == NULL || FileName == NULL)
+    if (BaseDir == NULL || Path == NULL)
         return NULL;
 
     // load file
-    Status = egLoadFile(BaseDir, FileName, &FileData, &FileDataLength);
-    if (EFI_ERROR(Status)) {
-//        Print(L"In egLoadIcon(), Status = %d after egLoadFile(); aborting load!\n", Status);
-        return NULL;
-    }
+    Status = egLoadFile(BaseDir, Path, &FileData, &FileDataLength);
+    if (EFI_ERROR(Status))
+       return NULL;
 
     // decode it
-    NewImage = egDecodeAny(FileData, FileDataLength, egFindExtension(FileName), IconSize, TRUE);
-//    Print(L"Done with egDecodeAny(), used extension '%s'\n", egFindExtension(FileName));
-//    if (NewImage == NULL)
-//       Print(L"Returning NULL from egLoadIcon()\n");
+    Image = egDecodeAny(FileData, FileDataLength, IconSize, TRUE);
     FreePool(FileData);
+    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;
-}
-
-EG_IMAGE * egDecodeImage(IN UINT8 *FileData, IN UINTN FileDataLength, IN CHAR16 *Format, IN BOOLEAN WantAlpha)
-{
-    return egDecodeAny(FileData, FileDataLength, Format, 128, WantAlpha);
-}
+    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
+// os_linux, GlobalConfig.IconsDir is myicons, DEFAULT_ICONS_DIR is icons, and
+// ICON_EXTENSIONS is "icns,png", this function will return myicons/os_linux.icns,
+// myicons/os_linux.png, icons/os_linux.icns, or icons/os_linux.png, in that
+// 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) {
+   EG_IMAGE *Image = NULL;
+
+   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()
 
 EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEAN WantAlpha)
 {
@@ -285,26 +443,26 @@ EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEA
     UINT8               *CompData;
     UINTN               CompLen;
     UINTN               PixelCount;
-    
+
     // sanity check
     if (EmbeddedImage->PixelMode > EG_MAX_EIPIXELMODE ||
         (EmbeddedImage->CompressMode != EG_EICOMPMODE_NONE && EmbeddedImage->CompressMode != EG_EICOMPMODE_RLE))
         return NULL;
-    
+
     // allocate image structure and pixel buffer
     NewImage = egCreateImage(EmbeddedImage->Width, EmbeddedImage->Height, WantAlpha);
     if (NewImage == NULL)
         return NULL;
-    
+
     CompData = (UINT8 *)EmbeddedImage->Data;   // drop const
     CompLen  = EmbeddedImage->DataLength;
     PixelCount = EmbeddedImage->Width * EmbeddedImage->Height;
-    
+
     // FUTURE: for EG_EICOMPMODE_EFICOMPRESS, decompress whole data block here
-    
+
     if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY ||
         EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA) {
-        
+
         // copy grayscale plane and expand
         if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
             egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
@@ -314,10 +472,10 @@ EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEA
         }
         egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, g), PixelCount);
         egCopyPlane(PLPTR(NewImage, r), PLPTR(NewImage, b), PixelCount);
-        
+
     } else if (EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR ||
                EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA) {
-        
+
         // copy color planes
         if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
             egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, r), PixelCount);
@@ -331,20 +489,20 @@ EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEA
             egInsertPlane(CompData, PLPTR(NewImage, b), PixelCount);
             CompData += PixelCount;
         }
-        
+
     } else {
-        
+
         // set color planes to black
         egSetPlane(PLPTR(NewImage, r), 0, PixelCount);
         egSetPlane(PLPTR(NewImage, g), 0, PixelCount);
         egSetPlane(PLPTR(NewImage, b), 0, PixelCount);
-        
+
     }
-    
+
     if (WantAlpha && (EmbeddedImage->PixelMode == EG_EIPIXELMODE_GRAY_ALPHA ||
                       EmbeddedImage->PixelMode == EG_EIPIXELMODE_COLOR_ALPHA ||
                       EmbeddedImage->PixelMode == EG_EIPIXELMODE_ALPHA)) {
-        
+
         // copy alpha plane
         if (EmbeddedImage->CompressMode == EG_EICOMPMODE_RLE) {
             egDecompressIcnsRLE(&CompData, &CompLen, PLPTR(NewImage, a), PixelCount);
@@ -352,11 +510,11 @@ EG_IMAGE * egPrepareEmbeddedImage(IN EG_EMBEDDED_IMAGE *EmbeddedImage, IN BOOLEA
             egInsertPlane(CompData, PLPTR(NewImage, a), PixelCount);
             CompData += PixelCount;
         }
-        
+
     } else {
         egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount);
     }
-    
+
     return NewImage;
 }
 
@@ -386,11 +544,11 @@ VOID egFillImage(IN OUT EG_IMAGE *CompImage, IN EG_PIXEL *Color)
     UINTN       i;
     EG_PIXEL    FillColor;
     EG_PIXEL    *PixelPtr;
-    
+
     FillColor = *Color;
     if (!CompImage->HasAlpha)
         FillColor.a = 0;
-    
+
     PixelPtr = CompImage->PixelData;
     for (i = 0; i < CompImage->Width * CompImage->Height; i++, PixelPtr++)
         *PixelPtr = FillColor;
@@ -405,14 +563,14 @@ VOID egFillImageArea(IN OUT EG_IMAGE *CompImage,
     EG_PIXEL    FillColor;
     EG_PIXEL    *PixelPtr;
     EG_PIXEL    *PixelBasePtr;
-    
+
     egRestrictImageArea(CompImage, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
-    
+
     if (AreaWidth > 0) {
         FillColor = *Color;
         if (!CompImage->HasAlpha)
             FillColor.a = 0;
-        
+
         PixelBasePtr = CompImage->PixelData + AreaPosY * CompImage->Width + AreaPosX;
         for (y = 0; y < AreaHeight; y++) {
             PixelPtr = PixelBasePtr;
@@ -429,7 +587,7 @@ VOID egRawCopy(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
 {
     UINTN       x, y;
     EG_PIXEL    *TopPtr, *CompPtr;
-    
+
     for (y = 0; y < Height; y++) {
         TopPtr = TopBasePtr;
         CompPtr = CompBasePtr;
@@ -451,7 +609,7 @@ VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
     UINTN       Alpha;
     UINTN       RevAlpha;
     UINTN       Temp;
-    
+
     for (y = 0; y < Height; y++) {
         TopPtr = TopBasePtr;
         CompPtr = CompBasePtr;
@@ -479,46 +637,22 @@ VOID egRawCompose(IN OUT EG_PIXEL *CompBasePtr, IN EG_PIXEL *TopBasePtr,
 VOID egComposeImage(IN OUT EG_IMAGE *CompImage, IN EG_IMAGE *TopImage, IN UINTN PosX, IN UINTN PosY)
 {
     UINTN       CompWidth, CompHeight;
-    
+
     CompWidth  = TopImage->Width;
     CompHeight = TopImage->Height;
     egRestrictImageArea(CompImage, PosX, PosY, &CompWidth, &CompHeight);
-    
+
     // compose
     if (CompWidth > 0) {
-        if (CompImage->HasAlpha) {
-            CompImage->HasAlpha = FALSE;
-            egSetPlane(PLPTR(CompImage, a), 0, CompImage->Width * CompImage->Height);
-        }
-        
-        if (TopImage->HasAlpha)
+        if (TopImage->HasAlpha) {
             egRawCompose(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
                          CompWidth, CompHeight, CompImage->Width, TopImage->Width);
-        else
+        } else {
             egRawCopy(CompImage->PixelData + PosY * CompImage->Width + PosX, TopImage->PixelData,
                       CompWidth, CompHeight, CompImage->Width, TopImage->Width);
+        }
     }
-}
-
-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;
-    }
-    egComposeImage(NewImage, Image, 0, 0);
-    egFreeImage(Image);
-    
-    return NewImage;
-}
+} /* VOID egComposeImage() */
 
 //
 // misc internal functions
@@ -527,7 +661,7 @@ EG_IMAGE * egEnsureImageSize(IN EG_IMAGE *Image, IN UINTN Width, IN UINTN Height
 VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
 {
     UINTN i;
-    
+
     for (i = 0; i < PixelCount; i++) {
         *DestPlanePtr = *SrcDataPtr++;
         DestPlanePtr += 4;
@@ -537,7 +671,7 @@ VOID egInsertPlane(IN UINT8 *SrcDataPtr, IN UINT8 *DestPlanePtr, IN UINTN PixelC
 VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)
 {
     UINTN i;
-    
+
     for (i = 0; i < PixelCount; i++) {
         *DestPlanePtr = Value;
         DestPlanePtr += 4;
@@ -547,7 +681,7 @@ VOID egSetPlane(IN UINT8 *DestPlanePtr, IN UINT8 Value, IN UINTN PixelCount)
 VOID egCopyPlane(IN UINT8 *SrcPlanePtr, IN UINT8 *DestPlanePtr, IN UINTN PixelCount)
 {
     UINTN i;
-    
+
     for (i = 0; i < PixelCount; i++) {
         *DestPlanePtr = *SrcPlanePtr;
         DestPlanePtr += 4, SrcPlanePtr += 4;