/** @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 #include // 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; }