Home | History | Annotate | Download | only in BmpImageDecoderLib
      1 /** @file
      2   This library provides BMP image decoding capability.
      3 
      4 Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available under
      6 the terms and conditions of the BSD License that accompanies this distribution.
      7 The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php.
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Uefi.h>
     16 #include <IndustryStandard/Bmp.h>
     17 #include <Protocol/GraphicsOutput.h>
     18 #include <Library/BaseLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 #include <Library/DebugLib.h>
     21 #include <Library/ImageDecoderLib.h>
     22 
     23 /**
     24   Convert a *.BMP graphics image to a callee allocated GOP blt buffer.
     25 
     26   @param  ImageFormat   Format of the image file.
     27   @param  BmpImage      Pointer to BMP file.
     28   @param  BmpImageSize  Number of bytes in BmpImage.
     29   @param  GopBlt        Buffer containing GOP version of BmpImage.
     30   @param  GopBltSize    Size of GopBlt in bytes.
     31   @param  PixelWidth    Width of GopBlt/BmpImage in pixels.
     32   @param  PixelHeight   Height of GopBlt/BmpImage in pixels.
     33 
     34   @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
     35   @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL.
     36   @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
     37   @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
     38 
     39 **/
     40 EFI_STATUS
     41 EFIAPI
     42 BmpImageDecoderLibConvertBmpToGopBlt (
     43   IN  IMAGE_FORMAT                  ImageFormat,
     44   IN  UINT8                         *BmpImage,
     45   IN  UINTN                         BmpImageSize,
     46   OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt,
     47   OUT UINTN                         *GopBltSize,
     48   OUT UINTN                         *PixelWidth,
     49   OUT UINTN                         *PixelHeight
     50   )
     51 {
     52   UINT8                         *Image;
     53   UINT8                         *ImageHeader;
     54   BMP_IMAGE_HEADER              *BmpHeader;
     55   BMP_COLOR_MAP                 *BmpColorMap;
     56   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
     57   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
     58   UINT64                        BltBufferSize;
     59   UINTN                         Index;
     60   UINTN                         Height;
     61   UINTN                         Width;
     62   UINTN                         ImageIndex;
     63   UINT32                        DataSizePerLine;
     64   UINT32                        ColorMapNum;
     65 
     66   ASSERT ((GopBlt != NULL) && (GopBltSize != NULL));
     67 
     68   if ((ImageFormat != ImageFormatBmp) && (ImageFormat != ImageFormatUnknown)) {
     69     return EFI_UNSUPPORTED;
     70   }
     71 
     72   if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
     73     return EFI_UNSUPPORTED;
     74   }
     75 
     76   BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
     77 
     78   if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
     79     return EFI_UNSUPPORTED;
     80   }
     81 
     82   //
     83   // Doesn't support compress.
     84   //
     85   if (BmpHeader->CompressionType != 0) {
     86     return EFI_UNSUPPORTED;
     87   }
     88 
     89   //
     90   // Only support BITMAPINFOHEADER format.
     91   // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
     92   //
     93   if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
     94     return EFI_UNSUPPORTED;
     95   }
     96 
     97   //
     98   // The data size in each line must be 4 byte alignment.
     99   //
    100   DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
    101   BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
    102   if (BltBufferSize > (UINT32) ~0) {
    103     return EFI_INVALID_PARAMETER;
    104   }
    105 
    106   if ((BmpHeader->Size != BmpImageSize) ||
    107       (BmpHeader->Size < BmpHeader->ImageOffset) ||
    108       (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
    109     return EFI_INVALID_PARAMETER;
    110   }
    111 
    112   //
    113   // Calculate Color Map offset in the image.
    114   //
    115   Image       = BmpImage;
    116   BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
    117   if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
    118     return EFI_INVALID_PARAMETER;
    119   }
    120 
    121   if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
    122     switch (BmpHeader->BitPerPixel) {
    123       case 1:
    124         ColorMapNum = 2;
    125         break;
    126       case 4:
    127         ColorMapNum = 16;
    128         break;
    129       case 8:
    130         ColorMapNum = 256;
    131         break;
    132       default:
    133         ColorMapNum = 0;
    134         break;
    135       }
    136     //
    137     // BMP file may has padding data between the bmp header section and the bmp data section.
    138     //
    139     if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
    140       return EFI_INVALID_PARAMETER;
    141     }
    142   }
    143 
    144   //
    145   // Calculate graphics image data address in the image
    146   //
    147   Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
    148   ImageHeader   = Image;
    149 
    150   //
    151   // Calculate the BltBuffer needed size.
    152   //
    153   BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
    154   //
    155   // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
    156   //
    157   if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
    158     return EFI_UNSUPPORTED;
    159   }
    160   BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
    161 
    162   *GopBltSize = (UINTN) BltBufferSize;
    163   *GopBlt     = AllocatePool (*GopBltSize);
    164   if (*GopBlt == NULL) {
    165     return EFI_OUT_OF_RESOURCES;
    166   }
    167 
    168   *PixelWidth   = BmpHeader->PixelWidth;
    169   *PixelHeight  = BmpHeader->PixelHeight;
    170 
    171   //
    172   // Convert image from BMP to Blt buffer format
    173   //
    174   BltBuffer = *GopBlt;
    175   for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
    176     Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
    177     for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
    178       switch (BmpHeader->BitPerPixel) {
    179       case 1:
    180         //
    181         // Convert 1-bit (2 colors) BMP to 24-bit color
    182         //
    183         for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
    184           Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
    185           Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
    186           Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
    187           Blt++;
    188           Width++;
    189         }
    190 
    191         Blt--;
    192         Width--;
    193         break;
    194 
    195       case 4:
    196         //
    197         // Convert 4-bit (16 colors) BMP Palette to 24-bit color
    198         //
    199         Index       = (*Image) >> 4;
    200         Blt->Red    = BmpColorMap[Index].Red;
    201         Blt->Green  = BmpColorMap[Index].Green;
    202         Blt->Blue   = BmpColorMap[Index].Blue;
    203         if (Width < (BmpHeader->PixelWidth - 1)) {
    204           Blt++;
    205           Width++;
    206           Index       = (*Image) & 0x0f;
    207           Blt->Red    = BmpColorMap[Index].Red;
    208           Blt->Green  = BmpColorMap[Index].Green;
    209           Blt->Blue   = BmpColorMap[Index].Blue;
    210         }
    211         break;
    212 
    213       case 8:
    214         //
    215         // Convert 8-bit (256 colors) BMP Palette to 24-bit color
    216         //
    217         Blt->Red    = BmpColorMap[*Image].Red;
    218         Blt->Green  = BmpColorMap[*Image].Green;
    219         Blt->Blue   = BmpColorMap[*Image].Blue;
    220         break;
    221 
    222       case 24:
    223         //
    224         // It is 24-bit BMP.
    225         //
    226         Blt->Blue   = *Image++;
    227         Blt->Green  = *Image++;
    228         Blt->Red    = *Image;
    229         break;
    230 
    231       default:
    232         //
    233         // Other bit format BMP is not supported.
    234         //
    235         return EFI_UNSUPPORTED;
    236         break;
    237       };
    238 
    239     }
    240 
    241     ImageIndex = (UINTN) (Image - ImageHeader);
    242     if ((ImageIndex % 4) != 0) {
    243       //
    244       // Bmp Image starts each row on a 32-bit boundary!
    245       //
    246       Image = Image + (4 - (ImageIndex % 4));
    247     }
    248   }
    249 
    250   return EFI_SUCCESS;
    251 }
    252 
    253 /**
    254   Initialize BmpImageDecoderLib library.
    255 
    256   @param ImageHandle     The image handle.
    257   @param SystemTable     The system table.
    258 
    259   @retval EFI_SUCCESS    The BmpImageDecoderLib library is initialized correctly.
    260   @return Other value if failed to initialize the BmpImageDecoderLib library.
    261 **/
    262 EFI_STATUS
    263 EFIAPI
    264 BmpImageDecoderLibConstructor (
    265   IN EFI_HANDLE                            ImageHandle,
    266   IN EFI_SYSTEM_TABLE                      *SystemTable
    267 )
    268 {
    269   RegisterImageDecoder (BmpImageDecoderLibConvertBmpToGopBlt);
    270   return EFI_SUCCESS;
    271 }
    272 
    273