BUAA-Soft-2023-Summer / Soft-Summer-2023

北航软件学院 2023 夏《程序设计实践》 小学期仓库
17 stars 0 forks source link

EasyX 如何正确绘制透明图片? #1

Closed Lord-Turmoil closed 1 year ago

Lord-Turmoil commented 1 year ago

在绘制带有透明背景的 png 图片时,并没有透明效果,且背景会变成黑色,应该如何解决?

Lord-Turmoil commented 1 year ago

解决方法

EasyX 本身不支持绘制透明图片,但是你可以通过操作绘图缓冲区实现这一功能。其原理是通过获得图像的各个颜色通道,通过透明颜色混合公式,直接绘制到缓冲区。

更多内容可以参考以下文章:

第一篇文章方法二中的函数在图像超出屏幕时可能有 Bug,这里给出一个无 Bug 的实现。

函数声明

// image.h

#include <easyx.h>

void PutAlphaImage(int x, int y, IMAGE* pSrcImage);
void PutAlphaImage(IMAGE* pDstImage, int x, int y, IMAGE* pSrcImage);

// Parse R, G, B in a color.
#define PA(color) (((color) & 0xFF000000) >> 24)
#define PB(color) (((color) & 0x00FF0000) >> 16)
#define PG(color) (((color) & 0x0000FF00) >> 8)
#define PR(color) (((color) & 0x000000FF))

/********************************************************************
** Get the "alpha-ed" color.
**   s: Color of the source image.
**   d: Color of the destination image.
**   a: Alpha value.
*/
#define ARGB(s, d, a) RGB((PR(s) * a + PR(d) * (255 - a)) >> 8, (PG(s) * a + PG(d) * (255 - a)) >> 8, (PB(s) * a + PB(d) * (255 - a)) >> 8)

函数实现

// image.cpp

void PutAlphaImage(int x, int y, IMAGE* pSrcImage)
{
    PutAlphaImage(nullptr, x, y, pSrcImage);
}

void PutAlphaImage(IMAGE* pDstImage, int x, int y, IMAGE* pSrcImage)
{
    DWORD* pDestBuffer = GetImageBuffer(pDstImage);
    const DWORD* pSrcBuffer = GetImageBuffer(pSrcImage);
    const int srcWidth = pSrcImage->getwidth();
    const int srcHeight = pSrcImage->getheight();
    const int destWidth = pDstImage ? pDstImage->getwidth() : getwidth();
    const int destHeight = pDstImage ? pDstImage->getheight() : getheight();

    int destX = x;
    int destY = y;

    if ((destX + srcWidth < 0) || (destY + srcHeight < 0) || (destX >= destWidth) || (destY >= destHeight))
    {
        return;
    }

    const int width = min(destX + srcWidth, destWidth) - max(destX, 0);
    const int height = min(destY + srcHeight, destHeight) - max(destY, 0);
    if (destX < 0)
    {
        pSrcBuffer -= destX;
        destX = 0;
    }
    if (destY < 0)
    {
        pSrcBuffer -= destY * srcWidth;
        destY = 0;
    }
    pDestBuffer += destWidth * destY + destX;

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            const int alpha = (pSrcBuffer[j] & 0xff000000) >> 24;
            pDestBuffer[j] = ARGB(pSrcBuffer[j], pDestBuffer[j], alpha);
        }

        pDestBuffer += destWidth;
        pSrcBuffer += srcWidth;
    }
}