alder_lake_bios/Insyde/InsydeModulePkg/Library/H2OImageDecoderLib/H2OPcxDecoder/H2OPcxDecoder.c

211 lines
7.0 KiB
C

/** @file
The instance of PCX Decoder Library
;******************************************************************************
;* Copyright (c) 2020, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "H2OImageDecoderLibCommon.h"
#include <Library/DebugLib.h>
#include <Guid/Pcx.h>
// 256 color, 256*3 bytes Palette.
#define COLOR_NUMBER 256
#define PALETTE_SIZE 0x300
/**
Convert a *.PCX graphics image to a UGA blt buffer.
If it isn't a PCX format graphics, it will return error.
@param [in] This
@param [in] ImageData Pointer to PCX file
@param [in] ImageDataSize Number of bytes in ImageData
@param [out] DecodedData Buffer containing UGA version of BmpImage.
@param [out] DecodedDataSize Size of DecodedData in bytes.
@param [out] Height Height of DecodedData/BmpImage in pixels
@param [out] Width Width of DecodedData/BmpImage in pixels
@retval EFI_SUCCESS DecodedData and DecodedDataSize are returned.
@retval EFI_UNSUPPORTED ImageData is not a valid *.PCX image
**/
EFI_STATUS
EFIAPI
H2OHiiPcxDecode (
IN UINT8 *ImageData,
IN UINTN ImageDataSize,
OUT UINT8 **DecodedData,
OUT UINTN *DecodedDataSize,
OUT UINTN *Height,
OUT UINTN *Width
)
{
UINT8 *PcxBuffer = NULL;
EFI_UGA_PIXEL *ImageBuffer = NULL;
PCX_IMAGE_HEADER *PcxHeader = NULL;
EFI_UGA_PIXEL Palette[COLOR_NUMBER];
UINTN NPlane;
UINTN BytesPerLine;
UINTN TotalBytes;
UINTN LineBreak;
UINTN Index;
UINTN Total;
UINTN Counter;
UINTN Tmp;
UINT64 BltBufferSize;
Total = 0;
Index = 0;
LineBreak = 0;
//
// check if it is a PCX format file.
// Manufacturer 0x0A - ZSoft
// Version 0x05 - Version 3.0
// Encodeing 0x01 - run length encoding
// BitsPerPixel 0x08 - Number of bits to represent a pixel
//
PcxHeader = (PCX_IMAGE_HEADER *)ImageData;
PcxBuffer = (UINT8 *)ImageData;
if ((PcxHeader->Manufacturer != 0x0A) ||
(PcxHeader->Version != 0x05) ||
(PcxHeader->Encoding != 0x01) ||
(PcxHeader->BitsPerPixel != 0x08)) {
return EFI_UNSUPPORTED;
}
//
// Count Width,Height...from header
//
*Width = PcxHeader->Xmax - PcxHeader->Xmin + 0x1;
*Height= PcxHeader->Ymax - PcxHeader->Ymin + 0x1;
NPlane = PcxHeader->NPlanes;
BytesPerLine = PcxHeader->BytesPerLine;
TotalBytes = NPlane * BytesPerLine;
//
// Set palette from the end of pcx image.
//
for (Tmp = 0; Tmp < COLOR_NUMBER; Tmp ++) {
Palette[Tmp].Red = PcxBuffer[ImageDataSize - PALETTE_SIZE + Tmp * 3];
Palette[Tmp].Green = PcxBuffer[ImageDataSize - PALETTE_SIZE + Tmp * 3 + 1];
Palette[Tmp].Blue = PcxBuffer[ImageDataSize - PALETTE_SIZE + Tmp * 3 + 2];
Palette[Tmp].Reserved = 0;
}
//
// read form the end of Header
//
PcxBuffer = &PcxBuffer[sizeof(PCX_IMAGE_HEADER)];
BltBufferSize = (*Width) * (*Height) * sizeof (EFI_UGA_PIXEL);
if (BltBufferSize >= 0x100000000LL) {
return EFI_UNSUPPORTED;
}
ImageBuffer = (EFI_UGA_PIXEL *)H2OImageDecoderLibAllocateMem ((UINTN) BltBufferSize);
ASSERT (ImageBuffer != NULL);
if (ImageBuffer == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// 24/32 -Bit .PCX Files.
// 24 bit images are stored as version 5 or above as 8 bit, 3 plane images.
// 32 bit images are stored as version 5 or above as 8 bit, 4 plane images.
// 24/32 bit images do not contain a palette.
// Bit planes are ordered as lines of red, green, blue in that order.
//
if (((PcxHeader->NPlanes == 0x03) || (PcxHeader->NPlanes == 0x04)) && (PcxHeader->BitsPerPixel == 0x08)) {
UINT8 *ScanLine;
UINTN Xaxis;
UINTN Yaxis;
UINTN i;
UINT8 Value;
ScanLine = (UINT8 *)H2OImageDecoderLibAllocateZeroMem ((UINTN) TotalBytes + 0x32);
if (ScanLine == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Yaxis = 0; Yaxis < *Height; Yaxis++) {
i = 0;
while (i < TotalBytes) {
Counter = 1;
Value = PcxBuffer[Index];
if ((Value & 0xC0) == 0xC0) {
Counter = (UINTN) (Value & 0x3F);
Index++;
Value = PcxBuffer[Index];
}
while ((i < TotalBytes) && Counter--) {
ScanLine[i++] = Value;
}
Index++;
}
if (PcxHeader->NPlanes == 0x03) {
for (Xaxis = 0; Xaxis < *Width; Xaxis++) {
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Red = ScanLine[Xaxis];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Green = ScanLine[Xaxis + BytesPerLine];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Blue = ScanLine[Xaxis + (BytesPerLine << 1)];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Reserved = 0xFF;
}
} else {
for (Xaxis = 0; Xaxis < *Width; Xaxis++) {
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Red = ScanLine[Xaxis];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Green = ScanLine[Xaxis + BytesPerLine];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Blue = ScanLine[Xaxis + (BytesPerLine << 1)];
ImageBuffer[(Yaxis * (*Width)) + Xaxis].Reserved = ScanLine[Xaxis + BytesPerLine * 3];
}
}
}
*DecodedData = (UINT8 *)ImageBuffer;
*DecodedDataSize = (UINTN) BltBufferSize;
H2OImageDecoderLibFreeMem (ScanLine, (UINTN) TotalBytes + 0x32);
return EFI_SUCCESS;
}
while (Total < ((*Width) * (*Height))) {
//
// skip the blank area at the end of scanline
//
if (LineBreak == (*Width)) {
while (LineBreak < TotalBytes) {
LineBreak++;
Index++;
}
LineBreak = 0;
}
//
// decode the color map
//
if ((PcxBuffer[Index] & 0xC0) == 0xC0) {
Counter = (UINTN) (PcxBuffer[Index] & 0x3F);
Index++;
for (Tmp = 0; Tmp < Counter; Tmp++) {
ImageBuffer[Total] = Palette[PcxBuffer[Index]];
Total++;
LineBreak++;
if (LineBreak == (*Width)) {
break;
}
}
} else {
ImageBuffer[Total] = Palette[PcxBuffer[Index]];
Total++;
LineBreak++;
}
Index++;
}
//
// Set return buffer
//
*DecodedData = (UINT8 *)ImageBuffer;
*DecodedDataSize = (UINTN) BltBufferSize;
return EFI_SUCCESS;
}