353 lines
9.5 KiB
C
353 lines
9.5 KiB
C
/** @file
|
|
SnapScree driver for capature screen image to BMP file.
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 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 "Efi.h"
|
|
//#include "EfiDriverLib.h"
|
|
#include <Uefi.h>
|
|
|
|
#include "SnapBmp.h"
|
|
#include "SnapLib.h"
|
|
#include <Guid/FileInfo.h>
|
|
#include <Protocol/SimpleFileSystem.h>
|
|
|
|
//#include EFI_PROTOCOL_DEFINITION (FileInfo)
|
|
//#include EFI_PROTOCOL_DEFINITION (SimpleFileSystem)
|
|
|
|
BMP_IMAGE_HEADER mBmpImageHeaderTemplate = {
|
|
'B', // CharB
|
|
'M', // CharM
|
|
0, // Size will be updated at runtime
|
|
{0, 0}, // Reserved
|
|
sizeof (BMP_IMAGE_HEADER), // ImageOffset
|
|
sizeof (BMP_IMAGE_HEADER) - EFI_FIELD_OFFSET (BMP_IMAGE_HEADER, HeaderSize), // HeaderSize
|
|
0, // PixelWidth will be updated at runtime
|
|
0, // PixelHeight will be updated at runtime
|
|
1, // Planes
|
|
24, // BitPerPixel
|
|
0, // CompressionType
|
|
0, // ImageSize will be updated at runtime
|
|
0, // XPixelsPerMeter
|
|
0, // YPixelsPerMeter
|
|
0, // NumberOfColors
|
|
0 // ImportantColors
|
|
};
|
|
|
|
EFI_STATUS
|
|
ObtainBmpFileNameByTime (
|
|
CHAR16 *FileName,
|
|
UINTN Size
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TIME EfiTime;
|
|
CHAR16 Buffer[5];
|
|
|
|
if (FileName == NULL)
|
|
return EFI_INVALID_PARAMETER;
|
|
|
|
if (Size < BMP_TIME_FILE_NAME_SIZE)
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
|
|
Status = gRT->GetTime (&EfiTime, NULL);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ValueToString (EfiTime.Year, 4, Buffer, VTS_LEAD_0);
|
|
StrCpyS (FileName, Size / sizeof(CHAR16), Buffer);
|
|
|
|
ValueToString (EfiTime.Month, 2, Buffer, VTS_LEAD_0);
|
|
StrCatS (FileName, Size / sizeof(CHAR16),Buffer);
|
|
|
|
ValueToString (EfiTime.Day, 2, Buffer, VTS_LEAD_0);
|
|
StrCatS (FileName, Size / sizeof(CHAR16), Buffer);
|
|
|
|
ValueToString (EfiTime.Hour, 2, Buffer, VTS_LEAD_0);
|
|
StrCatS (FileName, Size / sizeof(CHAR16), Buffer);
|
|
|
|
ValueToString (EfiTime.Minute, 2, Buffer, VTS_LEAD_0);
|
|
StrCatS (FileName, Size / sizeof(CHAR16), Buffer);
|
|
|
|
ValueToString (EfiTime.Second, 2, Buffer, VTS_LEAD_0);
|
|
StrCatS (FileName, Size / sizeof(CHAR16), Buffer);
|
|
|
|
StrCatS (FileName, Size / sizeof(CHAR16), L".BMP");
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BmpCreate (
|
|
EFI_HANDLE FsHandle,
|
|
CHAR16 *FileName,
|
|
BMP_FILE **ABmpFile
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
BMP_FILE *BmpFile;
|
|
|
|
// Test SimpleFileSystem Handle
|
|
Status = gBS->OpenProtocol (
|
|
FsHandle,
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
|
|
);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// allocate memory for BMP_FILE intance
|
|
BmpFile = AllocateZeroPool (sizeof(BMP_FILE) + StrSize(FileName));
|
|
if (BmpFile == NULL)
|
|
return EFI_OUT_OF_RESOURCES;
|
|
|
|
// initialize object members
|
|
BmpFile->FsHandle = FsHandle;
|
|
BmpFile->FileName = (CHAR16 *)((UINT8 *)BmpFile + sizeof (BMP_FILE));
|
|
StrCpyS(BmpFile->FileName, StrSize(FileName) / sizeof(CHAR16), FileName);
|
|
|
|
// return BMP_FILE object
|
|
*ABmpFile = BmpFile;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BmpBltBufferToImage (
|
|
BMP_FILE *Bmp,
|
|
UINTN Width,
|
|
UINTN Height,
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer,
|
|
UINTN BufferWidth
|
|
)
|
|
{
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltPixel;
|
|
UINTN PaddingSize;
|
|
UINTN BmpSize;
|
|
UINT8 *BmpBuffer;
|
|
UINT8 *Image;
|
|
UINTN Col;
|
|
UINTN Row;
|
|
|
|
if (Bmp->BmpHeader != NULL)
|
|
FreePool (Bmp->BmpHeader);
|
|
|
|
//
|
|
// Allocate memory for BMP file.
|
|
//
|
|
PaddingSize = Width & 0x3;
|
|
BmpSize = (Width * 3 + PaddingSize) * Height + sizeof (BMP_IMAGE_HEADER);
|
|
BmpBuffer = AllocateZeroPool (BmpSize);
|
|
if (BmpBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
mBmpImageHeaderTemplate.Size = (UINT32) BmpSize;
|
|
mBmpImageHeaderTemplate.ImageSize = (UINT32) BmpSize - sizeof (BMP_IMAGE_HEADER);
|
|
mBmpImageHeaderTemplate.PixelWidth = (UINT32) Width;
|
|
mBmpImageHeaderTemplate.PixelHeight = (UINT32) Height;
|
|
CopyMem (BmpBuffer, &mBmpImageHeaderTemplate, sizeof (BMP_IMAGE_HEADER));
|
|
|
|
//
|
|
// Convert BLT buffer to BMP file.
|
|
//
|
|
Image = BmpBuffer + sizeof (BMP_IMAGE_HEADER);
|
|
for (Row = 0; Row < Height; Row++) {
|
|
BltPixel = &BltBuffer[(Height - Row - 1) * BufferWidth];
|
|
|
|
for (Col = 0; Col < Width; Col++) {
|
|
*Image++ = BltPixel->Blue;
|
|
*Image++ = BltPixel->Green;
|
|
*Image++ = BltPixel->Red;
|
|
BltPixel++;
|
|
}
|
|
|
|
//
|
|
// Padding for 4 byte alignment.
|
|
//
|
|
Image += PaddingSize;
|
|
}
|
|
|
|
// set Bmp Object member
|
|
Bmp->BmpHeader = (BMP_IMAGE_HEADER *) BmpBuffer;
|
|
Bmp->BmpImage = BmpBuffer + sizeof (BMP_IMAGE_HEADER);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BmpScreenToImage (
|
|
BMP_FILE *Bmp,
|
|
UINTN X,
|
|
UINTN Y,
|
|
UINTN Width,
|
|
UINTN Height
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE VgaHandle;
|
|
UINTN BltSize;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop = NULL;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer = NULL;
|
|
EFI_TPL OriginalTPL;
|
|
UINTN BufferWidth;
|
|
|
|
//
|
|
// get the VGA GOP protocol
|
|
//
|
|
Status = GetActiveVgaHandle (&VgaHandle);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (VgaHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&Gop);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
if (Width == MAX_VGA_MODE_WIDTH)
|
|
Width = Gop->Mode->Info->HorizontalResolution;
|
|
|
|
if (Height == MAX_VGA_MODE_HEIGHT)
|
|
Height = Gop->Mode->Info->VerticalResolution;
|
|
|
|
|
|
if (Gop->Mode->Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor
|
|
&& Gop->Mode->FrameBufferBase != 0
|
|
&& Gop->Mode->FrameBufferSize >= (Gop->Mode->Info->PixelsPerScanLine * Height * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
|
|
BufferWidth = Gop->Mode->Info->PixelsPerScanLine;
|
|
} else {
|
|
BufferWidth = Width;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for Blt Buffer and Get Video Image
|
|
//
|
|
BltSize = BufferWidth * Height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
|
|
BltBuffer = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)AllocatePool (BltSize);
|
|
if (BltBuffer == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Capture full screen image
|
|
//
|
|
|
|
// RaiseTPL is needed, Mouse cursor use timer event for refresh cursor.
|
|
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
|
|
|
|
if (Gop->Mode->Info->PixelFormat == PixelBlueGreenRedReserved8BitPerColor
|
|
&& Gop->Mode->FrameBufferBase != 0
|
|
&& Gop->Mode->FrameBufferSize >= BltSize) {
|
|
Gop->Blt (Gop, BltBuffer, EfiBltVideoToBltBuffer, 0, 0, 0, 0, Width, Height, 0);
|
|
}
|
|
|
|
gBS->RestoreTPL (OriginalTPL);
|
|
Status = BmpBltBufferToImage (Bmp, Width, Height, BltBuffer, BufferWidth);
|
|
|
|
FreePool (BltBuffer);
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BmpSaveToFile (
|
|
BMP_FILE *Bmp
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Sfs;
|
|
EFI_FILE *RootFs = NULL;
|
|
EFI_FILE *FileHandle = NULL;
|
|
UINTN BmpSize;
|
|
UINT8 Buffer[MAX_FILE_INFO_SIZE];
|
|
UINTN BufferSize = MAX_FILE_INFO_SIZE;
|
|
EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *) Buffer;
|
|
|
|
// Check the BMP image is already
|
|
if (Bmp->BmpHeader == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Locate the SimpleFileSystem protocol for save image to file
|
|
//
|
|
Status = gBS->HandleProtocol (Bmp->FsHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Sfs);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
|
|
// Caculate BMP file size
|
|
BmpSize = Bmp->BmpHeader->ImageSize + sizeof(BMP_IMAGE_HEADER);
|
|
|
|
//
|
|
// Save image to .BMP file
|
|
//
|
|
Status = Sfs->OpenVolume (Sfs, &RootFs);
|
|
if (EFI_ERROR(Status)) {
|
|
goto EXIT;
|
|
}
|
|
|
|
Status = RootFs->Open (RootFs, &FileHandle, Bmp->FileName, EFI_FILE_MODE_CREATE | EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = EFI_NO_MEDIA;
|
|
goto EXIT;
|
|
}
|
|
|
|
Status = FileHandle->Write (FileHandle, &BmpSize, Bmp->BmpHeader);
|
|
if (EFI_ERROR(Status)) {
|
|
Status = EFI_NO_MEDIA;
|
|
goto EXIT;
|
|
}
|
|
|
|
// When open a exist file the file size may be large than BMP file, So make sure file size is BMP file size.
|
|
FileHandle->GetInfo (FileHandle, &gEfiFileInfoGuid, &BufferSize, FileInfo);
|
|
|
|
BufferSize = (UINTN)FileInfo->Size;
|
|
|
|
FileInfo->PhysicalSize = BmpSize;
|
|
FileHandle->SetInfo (FileHandle, &gEfiFileInfoGuid, BufferSize, FileInfo);
|
|
|
|
EXIT:
|
|
|
|
// Close file
|
|
if (FileHandle != NULL)
|
|
FileHandle->Close (FileHandle);
|
|
|
|
if (RootFs != NULL)
|
|
RootFs->Close (RootFs);
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS
|
|
BmpDestroy (
|
|
BMP_FILE *Bmp
|
|
)
|
|
{
|
|
if (Bmp == NULL)
|
|
return EFI_SUCCESS;
|
|
|
|
if (Bmp->BmpHeader != NULL)
|
|
FreePool (Bmp->BmpHeader);
|
|
|
|
FreePool (Bmp);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|