CloverBootloader/Protocols/AppleImageCodec/load_bmp.c
2019-09-03 12:58:42 +03:00

297 lines
9.7 KiB
C

/*
* libeg/load_bmp.c
* Loading function for BMP images
*
* Copyright (c) 2006 Christoph Pfisterer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Christoph Pfisterer nor the names of the
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
//#include "libegint.h"
#include "picopng.h"
#define DBG(...)
// BMP structures
#pragma pack(1)
typedef struct {
UINT8 Blue;
UINT8 Green;
UINT8 Red;
UINT8 Alpha;
} BMP_COLOR_MAP;
typedef struct {
CHAR8 CharB;
CHAR8 CharM;
UINT32 Size;
UINT16 Reserved[2];
UINT32 ImageOffset;
UINT32 HeaderSize;
INT32 PixelWidth;
INT32 PixelHeight;
UINT16 Planes; // Must be 1
UINT16 BitPerPixel; // 1, 4, 8, 24, or 32
UINT32 CompressionType;
UINT32 ImageSize; // Compressed image size in bytes
UINT32 XPixelsPerMeter;
UINT32 YPixelsPerMeter;
UINT32 NumberOfColors;
UINT32 ImportantColors;
} BMP_IMAGE_HEADER;
#pragma pack()
//
// Load BMP image
//
EG_IMAGE * egDecodeBMP(IN UINT8 *FileData, IN UINTN FileDataLength, IN BOOLEAN WantAlpha)
{
EG_IMAGE *NewImage;
BMP_IMAGE_HEADER *BmpHeader;
BMP_COLOR_MAP *BmpColorMap;
INT32 x, y;
INT32 RealPixelHeight, RealPixelWidth;
UINT8 *ImagePtr;
UINT8 *ImagePtrBase;
UINTN ImageLineOffset;
UINT8 ImageValue = 0;
UINT8 AlphaValue;
EFI_UGA_PIXEL *PixelPtr;
UINTN Index, BitIndex;
// read and check header
if (FileDataLength < sizeof(BMP_IMAGE_HEADER) || FileData == NULL)
return NULL;
BmpHeader = (BMP_IMAGE_HEADER *) FileData;
if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M')
return NULL;
if (BmpHeader->BitPerPixel != 1 && BmpHeader->BitPerPixel != 4 &&
BmpHeader->BitPerPixel != 8 && BmpHeader->BitPerPixel != 24 &&
BmpHeader->BitPerPixel != 32)
return NULL;
// 32-bit images are always stored uncompressed
if (BmpHeader->CompressionType > 0 && BmpHeader->BitPerPixel != 32)
return NULL;
// calculate parameters
ImageLineOffset = BmpHeader->PixelWidth;
if (BmpHeader->BitPerPixel == 32)
ImageLineOffset *= 4;
else if (BmpHeader->BitPerPixel == 24)
ImageLineOffset *= 3;
else if (BmpHeader->BitPerPixel == 1)
ImageLineOffset = (ImageLineOffset + 7) >> 3;
else if (BmpHeader->BitPerPixel == 4)
ImageLineOffset = (ImageLineOffset + 1) >> 1;
if ((ImageLineOffset % 4) != 0)
ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
// check bounds
RealPixelHeight = BmpHeader->PixelHeight > 0 ? BmpHeader->PixelHeight : -BmpHeader->PixelHeight;
RealPixelWidth = BmpHeader->PixelWidth > 0 ? BmpHeader->PixelWidth : -BmpHeader->PixelWidth;
if (BmpHeader->ImageOffset + ImageLineOffset * RealPixelHeight > FileDataLength)
return NULL;
// allocate image structure and buffer
NewImage = egCreateImage(RealPixelWidth, RealPixelHeight, WantAlpha);
if (NewImage == NULL)
return NULL;
AlphaValue = WantAlpha ? 255 : 0;
// convert image
BmpColorMap = (BMP_COLOR_MAP *)(FileData + sizeof(BMP_IMAGE_HEADER));
ImagePtrBase = FileData + BmpHeader->ImageOffset;
for (y = 0; y < RealPixelHeight; y++) {
ImagePtr = ImagePtrBase;
ImagePtrBase += ImageLineOffset;
// vertically mirror
if (BmpHeader->PixelHeight != RealPixelHeight) {
PixelPtr = NewImage->PixelData + y * RealPixelWidth;
} else {
PixelPtr = NewImage->PixelData + (RealPixelHeight - 1 - y) * RealPixelWidth;
}
switch (BmpHeader->BitPerPixel) {
case 1:
for (x = 0; x < RealPixelWidth; x++) {
BitIndex = x & 0x07;
if (BitIndex == 0)
ImageValue = *ImagePtr++;
Index = (ImageValue >> (7 - BitIndex)) & 0x01;
PixelPtr->Blue = BmpColorMap[Index].Blue;
PixelPtr->Green = BmpColorMap[Index].Green;
PixelPtr->Red = BmpColorMap[Index].Red;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
}
break;
case 4:
for (x = 0; x <= RealPixelWidth - 2; x += 2) {
ImageValue = *ImagePtr++;
Index = ImageValue >> 4;
PixelPtr->Blue = BmpColorMap[Index].Blue;
PixelPtr->Green = BmpColorMap[Index].Green;
PixelPtr->Red = BmpColorMap[Index].Red;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
Index = ImageValue & 0x0f;
PixelPtr->Blue = BmpColorMap[Index].Blue;
PixelPtr->Green = BmpColorMap[Index].Green;
PixelPtr->Red = BmpColorMap[Index].Red;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
}
if (x < RealPixelWidth) {
ImageValue = *ImagePtr++;
Index = ImageValue >> 4;
PixelPtr->Blue = BmpColorMap[Index].Blue;
PixelPtr->Green = BmpColorMap[Index].Green;
PixelPtr->Red = BmpColorMap[Index].Red;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
}
break;
case 8:
for (x = 0; x < RealPixelWidth; x++) {
Index = *ImagePtr++;
PixelPtr->Blue = BmpColorMap[Index].Blue;
PixelPtr->Green = BmpColorMap[Index].Green;
PixelPtr->Red = BmpColorMap[Index].Red;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
}
break;
case 24:
for (x = 0; x < RealPixelWidth; x++) {
PixelPtr->Blue = *ImagePtr++;
PixelPtr->Green = *ImagePtr++;
PixelPtr->Red = *ImagePtr++;
PixelPtr->Reserved = AlphaValue;
PixelPtr++;
}
break;
case 32:
for (x = 0; x < RealPixelWidth; x++) {
PixelPtr->Blue = *ImagePtr++;
PixelPtr->Green = *ImagePtr++;
PixelPtr->Red = *ImagePtr++;
PixelPtr->Reserved = *ImagePtr++;
if (!WantAlpha)
PixelPtr->Reserved = 255 - PixelPtr->Reserved;
PixelPtr++;
}
}
}
return NewImage;
}
//
// Save BMP image
//
VOID egEncodeBMP(IN EG_IMAGE *Image, OUT UINT8 **FileDataReturn, OUT UINTN *FileDataLengthReturn)
{
BMP_IMAGE_HEADER *BmpHeader;
UINT8 *FileData;
UINT64 FileDataLength;
UINT8 *ImagePtr;
UINT8 *ImagePtrBase;
UINT64 ImageLineOffset;
EFI_UGA_PIXEL *PixelPtr;
INT64 x, y;
ImageLineOffset = MultU64x32(Image->Width, 3);
// if ((ImageLineOffset % 4) != 0)
// ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset % 4));
if ((ImageLineOffset & 3) != 0) {
ImageLineOffset = ImageLineOffset + (4 - (ImageLineOffset & 3));
}
// allocate buffer for file data
FileDataLength = sizeof(BMP_IMAGE_HEADER) + MultU64x64(Image->Height, ImageLineOffset);
FileData = AllocateZeroPool((UINTN)FileDataLength);
if (FileData == NULL) {
Print(L"Error allocate %d bytes\n", FileDataLength);
*FileDataReturn = NULL;
*FileDataLengthReturn = 0;
return;
}
// fill header
BmpHeader = (BMP_IMAGE_HEADER *)FileData;
BmpHeader->CharB = 'B';
BmpHeader->CharM = 'M';
BmpHeader->Size = (UINT32)FileDataLength;
BmpHeader->ImageOffset = sizeof(BMP_IMAGE_HEADER);
BmpHeader->HeaderSize = 40;
BmpHeader->PixelWidth = (UINT32)Image->Width;
BmpHeader->PixelHeight = (UINT32)Image->Height;
BmpHeader->Planes = 1;
BmpHeader->BitPerPixel = 24;
BmpHeader->CompressionType = 0;
BmpHeader->XPixelsPerMeter = 0xb13;
BmpHeader->YPixelsPerMeter = 0xb13;
// fill pixel buffer
ImagePtrBase = FileData + BmpHeader->ImageOffset;
for (y = 0; y < Image->Height; y++) {
ImagePtr = ImagePtrBase;
ImagePtrBase += ImageLineOffset;
// PixelPtr = Image->PixelData + (Image->Height - 1 - y) * Image->Width;
PixelPtr = Image->PixelData + (INT32)(Image->Height - 1 - y) * (INT32)Image->Width;
for (x = 0; x < Image->Width; x++) {
*ImagePtr++ = PixelPtr->Blue;
*ImagePtr++ = PixelPtr->Green;
*ImagePtr++ = PixelPtr->Red;
PixelPtr++;
}
}
*FileDataReturn = FileData;
*FileDataLengthReturn = (UINTN)FileDataLength;
}
/* EOF */