Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Shumin Qiu <shumin.qiu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19082 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			273 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This library provides BMP image decoding capability.
 | 
						|
 | 
						|
Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials are licensed and made available under
 | 
						|
the terms and conditions of the BSD License that accompanies this distribution.
 | 
						|
The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include <Uefi.h>
 | 
						|
#include <IndustryStandard/Bmp.h>
 | 
						|
#include <Protocol/GraphicsOutput.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/ImageDecoderLib.h>
 | 
						|
 | 
						|
/**
 | 
						|
  Convert a *.BMP graphics image to a callee allocated GOP blt buffer.
 | 
						|
 | 
						|
  @param  ImageFormat   Format of the image file.
 | 
						|
  @param  BmpImage      Pointer to BMP file.
 | 
						|
  @param  BmpImageSize  Number of bytes in BmpImage.
 | 
						|
  @param  GopBlt        Buffer containing GOP version of BmpImage.
 | 
						|
  @param  GopBltSize    Size of GopBlt in bytes.
 | 
						|
  @param  PixelWidth    Width of GopBlt/BmpImage in pixels.
 | 
						|
  @param  PixelHeight   Height of GopBlt/BmpImage in pixels.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER GopBlt or GopBltSize is NULL.
 | 
						|
  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
BmpImageDecoderLibConvertBmpToGopBlt (
 | 
						|
  IN  IMAGE_FORMAT                  ImageFormat,
 | 
						|
  IN  UINT8                         *BmpImage,
 | 
						|
  IN  UINTN                         BmpImageSize,
 | 
						|
  OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL **GopBlt,
 | 
						|
  OUT UINTN                         *GopBltSize,
 | 
						|
  OUT UINTN                         *PixelWidth,
 | 
						|
  OUT UINTN                         *PixelHeight
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8                         *Image;
 | 
						|
  UINT8                         *ImageHeader;
 | 
						|
  BMP_IMAGE_HEADER              *BmpHeader;
 | 
						|
  BMP_COLOR_MAP                 *BmpColorMap;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
 | 
						|
  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
 | 
						|
  UINT64                        BltBufferSize;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINTN                         Height;
 | 
						|
  UINTN                         Width;
 | 
						|
  UINTN                         ImageIndex;
 | 
						|
  UINT32                        DataSizePerLine;
 | 
						|
  UINT32                        ColorMapNum;
 | 
						|
 | 
						|
  ASSERT ((GopBlt != NULL) && (GopBltSize != NULL));
 | 
						|
 | 
						|
  if ((ImageFormat != ImageFormatBmp) && (ImageFormat != ImageFormatUnknown)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
 | 
						|
 | 
						|
  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Doesn't support compress.
 | 
						|
  //
 | 
						|
  if (BmpHeader->CompressionType != 0) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Only support BITMAPINFOHEADER format.
 | 
						|
  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
 | 
						|
  //
 | 
						|
  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The data size in each line must be 4 byte alignment.
 | 
						|
  //
 | 
						|
  DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
 | 
						|
  BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
 | 
						|
  if (BltBufferSize > (UINT32) ~0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((BmpHeader->Size != BmpImageSize) || 
 | 
						|
      (BmpHeader->Size < BmpHeader->ImageOffset) ||
 | 
						|
      (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate Color Map offset in the image.
 | 
						|
  //
 | 
						|
  Image       = BmpImage;
 | 
						|
  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
 | 
						|
  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
 | 
						|
    switch (BmpHeader->BitPerPixel) {
 | 
						|
      case 1:
 | 
						|
        ColorMapNum = 2;
 | 
						|
        break;
 | 
						|
      case 4:
 | 
						|
        ColorMapNum = 16;
 | 
						|
        break;
 | 
						|
      case 8:
 | 
						|
        ColorMapNum = 256;
 | 
						|
        break;
 | 
						|
      default:
 | 
						|
        ColorMapNum = 0;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    //
 | 
						|
    // BMP file may has padding data between the bmp header section and the bmp data section.
 | 
						|
    //
 | 
						|
    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate graphics image data address in the image
 | 
						|
  //
 | 
						|
  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
 | 
						|
  ImageHeader   = Image;
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate the BltBuffer needed size.
 | 
						|
  //
 | 
						|
  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
 | 
						|
  //
 | 
						|
  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
 | 
						|
  //
 | 
						|
  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
 | 
						|
 | 
						|
  *GopBltSize = (UINTN) BltBufferSize;
 | 
						|
  *GopBlt     = AllocatePool (*GopBltSize);
 | 
						|
  if (*GopBlt == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  *PixelWidth   = BmpHeader->PixelWidth;
 | 
						|
  *PixelHeight  = BmpHeader->PixelHeight;
 | 
						|
 | 
						|
  //
 | 
						|
  // Convert image from BMP to Blt buffer format
 | 
						|
  //
 | 
						|
  BltBuffer = *GopBlt;
 | 
						|
  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
 | 
						|
    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
 | 
						|
    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
 | 
						|
      switch (BmpHeader->BitPerPixel) {
 | 
						|
      case 1:
 | 
						|
        //
 | 
						|
        // Convert 1-bit (2 colors) BMP to 24-bit color
 | 
						|
        //
 | 
						|
        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
 | 
						|
          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
 | 
						|
          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
 | 
						|
          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
 | 
						|
          Blt++;
 | 
						|
          Width++;
 | 
						|
        }
 | 
						|
 | 
						|
        Blt--;
 | 
						|
        Width--;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 4:
 | 
						|
        //
 | 
						|
        // Convert 4-bit (16 colors) BMP Palette to 24-bit color
 | 
						|
        //
 | 
						|
        Index       = (*Image) >> 4;
 | 
						|
        Blt->Red    = BmpColorMap[Index].Red;
 | 
						|
        Blt->Green  = BmpColorMap[Index].Green;
 | 
						|
        Blt->Blue   = BmpColorMap[Index].Blue;
 | 
						|
        if (Width < (BmpHeader->PixelWidth - 1)) {
 | 
						|
          Blt++;
 | 
						|
          Width++;
 | 
						|
          Index       = (*Image) & 0x0f;
 | 
						|
          Blt->Red    = BmpColorMap[Index].Red;
 | 
						|
          Blt->Green  = BmpColorMap[Index].Green;
 | 
						|
          Blt->Blue   = BmpColorMap[Index].Blue;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
 | 
						|
      case 8:
 | 
						|
        //
 | 
						|
        // Convert 8-bit (256 colors) BMP Palette to 24-bit color
 | 
						|
        //
 | 
						|
        Blt->Red    = BmpColorMap[*Image].Red;
 | 
						|
        Blt->Green  = BmpColorMap[*Image].Green;
 | 
						|
        Blt->Blue   = BmpColorMap[*Image].Blue;
 | 
						|
        break;
 | 
						|
 | 
						|
      case 24:
 | 
						|
        //
 | 
						|
        // It is 24-bit BMP.
 | 
						|
        //
 | 
						|
        Blt->Blue   = *Image++;
 | 
						|
        Blt->Green  = *Image++;
 | 
						|
        Blt->Red    = *Image;
 | 
						|
        break;
 | 
						|
 | 
						|
      default:
 | 
						|
        //
 | 
						|
        // Other bit format BMP is not supported.
 | 
						|
        //
 | 
						|
        return EFI_UNSUPPORTED;
 | 
						|
        break;
 | 
						|
      };
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    ImageIndex = (UINTN) (Image - ImageHeader);
 | 
						|
    if ((ImageIndex % 4) != 0) {
 | 
						|
      //
 | 
						|
      // Bmp Image starts each row on a 32-bit boundary!
 | 
						|
      //
 | 
						|
      Image = Image + (4 - (ImageIndex % 4));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize BmpImageDecoderLib library.
 | 
						|
 | 
						|
  @param ImageHandle     The image handle.
 | 
						|
  @param SystemTable     The system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS    The BmpImageDecoderLib library is initialized correctly.
 | 
						|
  @return Other value if failed to initialize the BmpImageDecoderLib library.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
BmpImageDecoderLibConstructor (
 | 
						|
  IN EFI_HANDLE                            ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE                      *SystemTable
 | 
						|
)
 | 
						|
{
 | 
						|
  RegisterImageDecoder (BmpImageDecoderLibConvertBmpToGopBlt);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |