more image functions

Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
This commit is contained in:
Sergey Isakov 2020-02-26 16:59:10 +03:00
parent f4457dc741
commit d6885d3f2a
2 changed files with 327 additions and 155 deletions

View File

@ -1,147 +1,316 @@
#include "XImage.h"
XImage::XImage()
{
Width = 0;
Height = 0;
HasAlpha = true;
}
XImage::XImage(UINTN W, UINTN H, bool A)
{
Width = W;
Height = H;
HasAlpha = A;
PixelData.CheckSize(GetWidth()*GetHeight());
}
XImage::~XImage()
{
}
const XArray<EFI_GRAPHICS_OUTPUT_BLT_PIXEL>& XImage::GetData() const
{
return PixelData;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* XImage::GetPixelPtr(UINTN x, UINTN y)
{
return &PixelData[x + y * Width];
}
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& XImage::GetPixel(UINTN x, UINTN y) const
{
return PixelData[x + y * Width];
}
UINTN XImage::GetWidth() const
{
return Width;
}
UINTN XImage::GetHeight() const
{
return Height;
}
UINTN XImage::GetSize() const
{
return Width * Height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
void XImage::Fill(EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color)
{
for (UINTN y = 0; y < Height; ++y)
for (UINTN x = 0; x < Width; ++x)
PixelData[y * Width + x] = Color;
}
void XImage::FillArea(EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color, const EgRect& Rect)
{
for (UINTN y = Rect.Ypos; y < Height && (y - Rect.Ypos) < Rect.Height; ++y) {
// EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Ptr = PixelData + y * Width + Rect.Xpos;
for (UINTN x = Rect.Xpos; x < Width && (x - Rect.Xpos) < Rect.Width; ++x)
// *Ptr++ = Color;
PixelData[y * Width + x] = Color;
#include "XImage.h"
XImage::XImage()
{
Width = 0;
Height = 0;
}
XImage::XImage(UINTN W, UINTN H)
{
Width = W;
Height = H;
PixelData.CheckSize(GetWidth()*GetHeight());
}
#if 0
UINT8 Smooth(UINT8* P, int a01, int a10, int a11, int a21, int a12, int dx, int dy, float scale)
{
return (UINT8)((*(p + a01) * (scale - dx) * 3 + *(p + a10) * (scale - dy) * 3 + *(p + a21) * dx * 3 +
*(p + a12) * dy * 3 + *(p + a11) * 2 *scale) / (scale * 8));
}
#endif
XImage::XImage(const XImage& Image, float scale)
{
Width = (UINTN)(Image.GetWidth() * scale);
Height = (UINTN)(Image.GetHeight() * scale);
PixelData.CheckSize(GetWidth()*GetHeight());
#if 0
UINTN Offset = OFFSET_OF(EFI_GRAPHICS_OUTPUT_BLT_PIXEL, Blue);
dst.Blue = Smooth(&src.Blue, a01, a10, a11, a21, a12, dx, dy, scale);
#define SMOOTH(P) \
do { \
((PIXEL*)dst_ptr)->P = (BYTE)((a01.P * (cx - dx) * 3 + a10.P * (cy - dy) * 3 + \
a21.P * dx * 3 + a12.P * dy * 3 + a11.P * (cx + cy)) / ((cx + cy) * 4)); \
} while(0)
UINT x, y, z;
PIXEL a10, a11, a12, a01, a21;
int fx, cx, lx, dx, fy, cy, ly, dy;
fx = (dst_size->width << PRECISION) / src_size->width;
fy = (dst_size->height << PRECISION) / src_size->height;
if (!fx || !fy) {
return;
}
}
void XImage::Compose(int PosX, int PosY, const XImage& TopImage, bool Lowest) //lowest image is opaque
{
UINT32 TopAlpha;
UINT32 RevAlpha;
UINT32 FinalAlpha;
UINT32 Temp;
for (UINTN y = PosY; y < Height && (y - PosY) < TopImage.GetHeight(); ++y) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL& CompPtr = *GetPixelPtr(PosX, y); // I assign a ref to avoid the operator ->. Compiler will produce the same anyway.
for (UINTN x = PosX; x < Width && (x - PosX) < TopImage.GetWidth(); ++x) {
TopAlpha = TopImage.GetPixel(x-PosX, y-PosY).Reserved;
RevAlpha = 255 - TopAlpha;
FinalAlpha = (255*255 - RevAlpha*(255 - CompPtr.Reserved)) / 255;
//final alpha =(1-(1-x)*(1-y)) =(255*255-(255-topA)*(255-compA))/255
Temp = (CompPtr.Blue * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Blue * TopAlpha);
CompPtr.Blue = (UINT8)(Temp / 255);
Temp = (CompPtr.Green * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Green * TopAlpha);
CompPtr.Green = (UINT8)(Temp / 255);
Temp = (CompPtr.Red * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Red * TopAlpha);
CompPtr.Red = (UINT8)(Temp / 255);
if (Lowest) {
CompPtr.Reserved = 255;
} else {
CompPtr.Reserved = (UINT8)FinalAlpha;
cx = ((fx - 1) >> PRECISION) + 1;
cy = ((fy - 1) >> PRECISION) + 1;
for (z = 0; z < dst_size->depth; z++)
{
BYTE * dst_slice_ptr = dst + z * dst_slice_pitch;
const BYTE *src_slice_ptr = src + src_slice_pitch * (z * src_size->depth / dst_size->depth);
for (y = 0; y < dst_size->height; y++)
{
BYTE * dst_ptr = dst_slice_ptr + y * dst_row_pitch;
const BYTE *src_row_ptr = src_slice_ptr + src_row_pitch * (y * src_size->height / dst_size->height);
ly = (y << PRECISION) / fy;
dy = y - ((ly * fy) >> PRECISION);
for (x = 0; x < dst_size->width; x++)
{
const BYTE *src_ptr = src_row_ptr + (x * src_size->width / dst_size->width) * src_format->bytes_per_pixel;
lx = (x << PRECISION) / fx;
dx = x - ((lx * fx) >> PRECISION);
a11 = *(PIXEL*)src_ptr;
a10 = (y == 0) ? a11 : (*(PIXEL*)(src_ptr - src_row_pitch));
a01 = (x == 0) ? a11 : (*(PIXEL*)(src_ptr - src_format->bytes_per_pixel));
a21 = (x == dst_size->width) ? a11 : (*(PIXEL*)(src_ptr + src_format->bytes_per_pixel));
a12 = (y == dst_size->height) ? a11 : (*(PIXEL*)(src_ptr + src_row_pitch));
SMOOTH(r);
SMOOTH(g);
SMOOTH(b);
SMOOTH(a);
dst_ptr += dst_format->bytes_per_pixel;
}
}
}
}
}
void XImage::FlipRB(bool WantAlpha)
}
#endif
}
XImage::~XImage()
{
}
const XArray<EFI_GRAPHICS_OUTPUT_BLT_PIXEL>& XImage::GetData() const
{
return PixelData;
}
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* XImage::GetPixelPtr(UINTN x, UINTN y)
{
return &PixelData[x + y * Width];
}
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& XImage::GetPixel(UINTN x, UINTN y) const
{
return PixelData[x + y * Width];
}
UINTN XImage::GetWidth() const
{
return Width;
}
UINTN XImage::GetHeight() const
{
return Height;
}
UINTN XImage::GetSize() const
{
return Width * Height * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
}
void XImage::Fill(const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& Color)
{
for (UINTN y = 0; y < Height; ++y)
for (UINTN x = 0; x < Width; ++x)
PixelData[y * Width + x] = Color;
}
void XImage::FillArea(const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& Color, const EgRect& Rect)
{
for (UINTN y = Rect.Ypos; y < Height && (y - Rect.Ypos) < Rect.Height; ++y) {
// EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Ptr = PixelData + y * Width + Rect.Xpos;
for (UINTN x = Rect.Xpos; x < Width && (x - Rect.Xpos) < Rect.Width; ++x)
// *Ptr++ = Color;
PixelData[y * Width + x] = Color;
}
}
void XImage::Compose(int PosX, int PosY, const XImage& TopImage, bool Lowest) //lowest image is opaque
{
UINT32 TopAlpha;
UINT32 RevAlpha;
UINT32 FinalAlpha;
UINT32 Temp;
for (UINTN y = PosY; y < Height && (y - PosY) < TopImage.GetHeight(); ++y) {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL& CompPtr = *GetPixelPtr(PosX, y); // I assign a ref to avoid the operator ->. Compiler will produce the same anyway.
for (UINTN x = PosX; x < Width && (x - PosX) < TopImage.GetWidth(); ++x) {
TopAlpha = TopImage.GetPixel(x-PosX, y-PosY).Reserved;
RevAlpha = 255 - TopAlpha;
FinalAlpha = (255*255 - RevAlpha*(255 - CompPtr.Reserved)) / 255;
//final alpha =(1-(1-x)*(1-y)) =(255*255-(255-topA)*(255-compA))/255
Temp = (CompPtr.Blue * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Blue * TopAlpha);
CompPtr.Blue = (UINT8)(Temp / 255);
Temp = (CompPtr.Green * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Green * TopAlpha);
CompPtr.Green = (UINT8)(Temp / 255);
Temp = (CompPtr.Red * RevAlpha) + (TopImage.GetPixel(x-PosX, y-PosY).Red * TopAlpha);
CompPtr.Red = (UINT8)(Temp / 255);
if (Lowest) {
CompPtr.Reserved = 255;
} else {
CompPtr.Reserved = (UINT8)FinalAlpha;
}
}
}
}
void XImage::FlipRB(bool WantAlpha)
{
UINTN ImageSize = (Width * Height);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Pixel = GetPixelPtr(0,0);
for (UINTN i = 0; i < ImageSize; ++i) {
UINT8 Temp = Pixel->Blue;
Pixel->Blue = Pixel->Red;
Pixel->Red = Temp;
if (!WantAlpha) Pixel->Reserved = 0xFF;
Pixel++;
}
}
/*
* The function converted plain array into XImage object
*/
unsigned XImage::FromPNG(const uint8_t * Data, UINTN Length)
{
uint8_t * PixelPtr = (uint8_t *)&PixelData[0];
unsigned Error = eglodepng_decode(&PixelPtr, &Width, &Height, Data, Length);
FlipRB(true);
return Error;
}
/*
* The function creates new array Data and inform about it size to be saved
* as a file.
* The caller is responsible to free the array.
*/
unsigned XImage::ToPNG(uint8_t** Data, UINTN& OutSize)
{
size_t FileDataLength = 0;
FlipRB(false);
uint8_t * PixelPtr = (uint8_t *)&PixelData[0];
unsigned Error = eglodepng_encode(Data, &FileDataLength, PixelPtr, Width, Height);
OutSize = FileDataLength;
return Error;
}
// Screen operations
/*
* The function to get image from screen. Used in screenshot (full screen), Pointer (small area) and Draw (small area)
* XImage must be created with UGAWidth, UGAHeight as egGetScreenSize(&UGAWidth, &UGAHeight); with PixelData allocated
* egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
* egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
*
* be careful about alpha. This procedure can produce alpha = 0 which means full transparent
*/
void XImage::GetArea(const EgRect& Rect)
{
GetArea(Rect.Xpos, Rect.Ypos, Rect.Width, Rect.Height);
}
void XImage::GetArea(UINTN x, UINTN y, UINTN W, UINTN H)
{
EFI_STATUS Status;
EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID;
EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL;
EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
Status = EfiLibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
if (EFI_ERROR(Status)) {
GraphicsOutput = NULL;
Status = EfiLibLocateProtocol(&UgaDrawProtocolGuid, (VOID **)&UgaDraw);
if (EFI_ERROR(Status))
UgaDraw = NULL;
}
INTN AreaWidth = (x + W > Width) ? (Width - x) : W;
INTN AreaHeight = (y + H > Height) ? (Height - y) : H;
if (GraphicsOutput != NULL) {
INTN LineBytes = GraphicsOutput->Mode->Info->HorizontalResolution * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
GraphicsOutput->Blt(GraphicsOutput,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&PixelData[0],
EfiBltVideoToBltBuffer,
x, y, 0, 0, AreaWidth, AreaHeight, LineBytes);
}
else if (UgaDraw != NULL) {
UINT32 LineWidth = 0;
UINT32 ScreenHeight = 0;
UINT32 Depth = 0;
UINT32 RefreshRate = 60;
EFI_STATUS Status = UgaDraw->GetMode(UgaDraw, &LineWidth, &ScreenHeight, &Depth, &RefreshRate);
if (EFI_ERROR(Status)) {
return; // graphics not available
}
UgaDraw->Blt(UgaDraw,
(EFI_UGA_PIXEL *)&PixelData[0],
EfiUgaVideoToBltBuffer,
x, y, 0, 0, AreaWidth, AreaHeight, LineWidth * sizeof(EFI_UGA_PIXEL));
}
Width = AreaWidth;
Height = AreaHeight;
}
void XImage::Draw(int x, int y, float scale)
{
UINTN ImageSize = (Width * Height);
EFI_GRAPHICS_OUTPUT_BLT_PIXEL* Pixel = GetPixelPtr(0,0);
for (UINTN i = 0; i < ImageSize; ++i) {
UINT8 Temp = Pixel->Blue;
Pixel->Blue = Pixel->Red;
Pixel->Red = Temp;
if (!WantAlpha) Pixel->Reserved = 0xFF;
Pixel++;
}
}
/*
* The function converted plain array into XImage object
*/
unsigned XImage::FromPNG(const uint8_t * Data, UINTN Length, bool WantAlpha)
{
uint8_t * PixelPtr = (uint8_t *)&PixelData[0];
unsigned Error = eglodepng_decode(&PixelPtr, &Width, &Height, Data, Length);
FlipRB(WantAlpha);
return Error;
}
/*
* The function creates new array Data and inform about it size to be saved
* as a file.
* The caller is responsible to free the array.
*/
unsigned XImage::ToPNG(uint8_t** Data, UINTN& OutSize)
{
size_t FileDataLength = 0;
FlipRB(false);
uint8_t * PixelPtr = (uint8_t *)&PixelData[0];
unsigned Error = eglodepng_encode(Data, &FileDataLength, PixelPtr, Width, Height);
OutSize = FileDataLength;
return Error;
}
//prepare images
INTN UGAWidth = 0;
INTN UGAHeight = 0;
egGetScreenSize(&UGAWidth, &UGAHeight);
XImage Background(UGAWidth, UGAHeight);
Background.GetArea(x, y, Width, Height);
XImage Top(*this, scale);
Background.Compose(x, y, Top, true);
UINTN AreaWidth = (x + Width > Background.GetWidth()) ? (Background.GetWidth() - x) : Width;
UINTN AreaHeight = (y + Height > Background.GetHeight()) ? (Background.GetHeight() - y) : Height;
// prepare protocols
EFI_STATUS Status;
EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID;
EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL;
EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
Status = EfiLibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
if (EFI_ERROR(Status)) {
GraphicsOutput = NULL;
Status = EfiLibLocateProtocol(&UgaDrawProtocolGuid, (VOID **)&UgaDraw);
if (EFI_ERROR(Status))
UgaDraw = NULL;
}
//output combined image
if (GraphicsOutput != NULL) {
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Background.GetPixelPtr(0, 0),
EfiBltBufferToVideo,
0, 0, x, y,
AreaWidth, AreaHeight, Background.GetWidth() * 4);
}
else if (UgaDraw != NULL) {
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)Background.GetPixelPtr(0, 0), EfiUgaBltBufferToVideo,
0, 0, x, y,
AreaWidth, AreaHeight, Background.GetWidth() * 4);
}
}

View File

@ -8,6 +8,7 @@ This class will replace EG_IMAGE structure and methods
#include "../cpp_foundation/XToolsCommon.h"
#include "../cpp_foundation/XArray.h"
#include "lodepng.h"
#include "FloatLib.h"
#include <Platform.h>
#if 0 //ndef EFI_GRAPHICS_OUTPUT_BLT_PIXEL
@ -17,13 +18,13 @@ typedef struct {
UINT8 Red;
UINT8 Reserved; //this is Alpha. 0 means full transparent, 0xFF means opaque
} EFI_GRAPHICS_OUTPUT_BLT_PIXEL;
#endif
/*
typedef union {
EFI_GRAPHICS_OUTPUT_BLT_PIXEL Pixel;
UINT32 Raw;
} EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION;
*/
#endif
typedef struct {
UINTN Xpos;
@ -38,12 +39,11 @@ protected:
UINTN Width;
UINTN Height;
XArray<EFI_GRAPHICS_OUTPUT_BLT_PIXEL> PixelData;
bool HasAlpha;
public:
XImage();
XImage(UINTN W, UINTN H, bool HasAlpha);
// XImage(UINTN W, UINTN H, bool HasAlpha, UINT32 Color); //egCreateFilledImage
// XImage(VOID *Data);
XImage(UINTN W, UINTN H);
XImage(const XImage& Image, float scale);
~XImage();
protected:
@ -58,12 +58,15 @@ public:
UINTN GetWidth() const;
UINTN GetHeight() const;
void Fill(EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color = { 0, 0, 0, 0 });
void FillArea(EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color, const EgRect& Rect);
void Compose(int PosX, int PosY, const XImage& TopImage, bool Lowest);
void Fill(const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& Color = { 0, 0, 0, 0 });
void FillArea(const EFI_GRAPHICS_OUTPUT_BLT_PIXEL& Color, const EgRect& Rect);
void Compose(int PosX, int PosY, const XImage& TopImage, bool Lowest); //instead of compose we can Back.Draw(...) + Top.Draw(...)
void FlipRB(bool WantAlpha);
unsigned FromPNG(const uint8_t * Data, UINTN Lenght, bool WantAlpha); //WantAlpha always true?
unsigned FromPNG(const uint8_t * Data, UINTN Lenght);
unsigned ToPNG(uint8_t** Data, UINTN& OutSize);
void GetArea(const EgRect& Rect);
void GetArea(UINTN x, UINTN y, UINTN W, UINTN H);
void Draw(int x, int y, float scale);
};
#endif //__XSTRINGW_H__