STM32F7 DAM2D alpha像素混合(同时有对应的软件Alpha像素混合代码)

alpha像素混合可以在一个图层上面显示另外一张带透明的图片,以上一篇文章中的ICO图标解析为例.


//ICO解码所需的填充接口-会执行像素混合
void ICO_FillPoint_CallBack(GRAM_HANDLE* pHandle, u16 OffsetX, u16 OffsetY, void* pSourceImage, u16 SourceWidth, u16 SourceHeight)
{
    static u32 offset;
	static DMA2D_PixelMixing_Parm mMixingParm;		//混合所需参数
	
	
	offset = (u32)pHandle->Width * OffsetY + OffsetX;
	offset *= pHandle->PixelByteSize;
	//=====参数初始化======
	//公共配置
	mMixingParm.ImageWidth				=	SourceWidth;						//待传输的像素图像宽度,单位像素
	mMixingParm.ImageHeight				=	SourceHeight;						//待传输的像素图像高度,单位像素
	//输入的背景配置
	mMixingParm.InBackImageAddr			=	pHandle->GRAM_Addr + offset;		//输入的背景图像开始地址(通过地址控制开始的X,Y坐标)
	mMixingParm.InBackImageOffsetX		=	pHandle->Width - SourceWidth;		//输入的背景图像跳过的X坐标值
	mMixingParm.InBackAlpha				=	0xFF;								//输入的背景图像的固定Alpha值,是否使用根据InBackAlphaMode配置决定
	mMixingParm.InBackColorMode			=	pHandle->ColorMode;					//输入的背景图像的颜色模式
	mMixingParm.InBackAlphaMode			=	DMA2D_ALPHA_NULL;					//输入的背景图像Alpha模式
	//输入的前景配置
	mMixingParm.InForeImageAddr			=	(u32)pSourceImage;					//输入的前景图像开始地址(通过地址控制开始的X,Y坐标)
	mMixingParm.InForeImageOffsetX		=	0x00;								//输入的前景图像跳过的X坐标值
	mMixingParm.InForeAlpha				=	0xFF;								//输入的前景图像的固定Alpha值,是否使用根据InForeAlphaMode配置决定
	mMixingParm.InForeColorMode			=	DMA2D_COLOR_ARGB8888;				//输入的前景图像的颜色模式
	mMixingParm.InForeAlphaMode			=	DMA2D_ALPHA_NULL;					//输入的前景图像Alpha模式
	//输出配置
	mMixingParm.OutImageAddr			=	pHandle->GRAM_Addr + offset;		//输出的图像开始地址(通过地址控制开始的X,Y坐标)
	mMixingParm.OutImageOffsetX			=	pHandle->Width - SourceWidth;		//输出的图像跳过的X坐标值
	mMixingParm.OutColorMode			=	pHandle->ColorMode;					//输出的图像的颜色模式
	
	DMA2D_WaitTransferComplete(5);					//需要等待上一次传输完成-不等待可能会出现乱点
	DMA2D_FillImage_PixelMixing(&mMixingParm);		//DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
}

上面这个是ICO解码的数据填充函数,输入的数据是ARGB格式,带透明信息,原本屏幕已经显示了一张底图,然后这个接口会自动对底图与新图进行Alpha混合,实现2个图片带透明度的叠加.

DMA2D_FillImage_PixelMixing()函数有硬件的,也提供一个对应的软件实现版本.

先上STM32F7的硬件DMA2D像素混合代码


/*************************************************************************************************************************
* 函数			:	void DMA2D_WaitTransferComplete(u32 TimeOutMs)
* 功能			:	等待DMA2D传输完成
* 参数			:	TimeOutMs:超时时间
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2019-10-30
* 最后修改时间 	: 	2019-10-30
* 说明			:	超时后会取消传输
					2020-03-13:修改为通过传输启动状态来判断传输结束,由于传输结束,终止,出错后会自动清除启动位,如果没有启动,也不存在超时,比较灵活
*************************************************************************************************************************/
void DMA2D_WaitTransferComplete(u32 TimeOutMs)
{
	u32 timeout = 0;
	
	//while((DMA2D->ISR & (1<<1)) == 0)	//等待传输完成
	while(DMA2D->CR & BIT0)				//等待传输结束
	{
		timeout++;
		SYS_DelayMS(1);					//延时1ms
		if(timeout > TimeOutMs)
		{
			DMA2D_Abort();				//终止传输
			break;						//超时退出
		}
	}  
	DMA2D->IFCR |= 1<<1;				//清除传输完成标志 	
}

/*************************************************************************************************************************
* 函数			:	void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
* 功能			:	DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
* 参数			:	pParm:所需的参数,见DMA2D_PixelMixing_Parm
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-03-13
* 最后修改时间 	: 	2020-03-13
* 说明			:	用于填充图形,不会等待是否传输成功,需要调用DMA2D_WaitTransferComplete()等待传输结束
*************************************************************************************************************************/
void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
{
	
	SYS_DeviceClockEnable(DEV_DMA2D, TRUE);						//使能DMA2D时钟

	DMA2D->CR = 1<<2;											//配置寄存器先复位-停止传输
	//传输模式设置
	DMA2D->CR = DMA2D_MODE_MEM_MIXED<<16;						//存储器到存储器模式-激活像素混合
	//背景图像设置
	DMA2D->BGPFCCR = ((u32)pParm->InBackAlpha&0XFF) << 24;		//设置固定Alpha值
	DMA2D->BGPFCCR |= (pParm->InBackAlphaMode & 0x03) << 16;	//Alpha 模式 (Alpha mode)
	DMA2D->BGPFCCR |= (pParm->InBackColorMode & 0x0f) << 0;		//颜色模式
	DMA2D->BGOR = pParm->InBackImageOffsetX;					//背DD景层偏移寄存器
	DMA2D->BGMAR = pParm->InBackImageAddr;						//背景层存储器地址寄存器
	//前景图像设置
	DMA2D->FGPFCCR = ((u32)pParm->InForeAlpha&0XFF) << 24;		//设置固定Alpha值
	DMA2D->FGPFCCR |= (pParm->InForeAlphaMode & 0x03) << 16;	//Alpha 模式 (Alpha mode)
	DMA2D->FGPFCCR |= (pParm->InForeColorMode & 0x0f) << 0;		//颜色模式
	DMA2D->FGOR = pParm->InForeImageOffsetX;					//前景层偏移寄存器
	DMA2D->FGMAR = pParm->InForeImageAddr;						//前景层存储器地址寄存器
	//输出设置
	DMA2D->OPFCCR = pParm->OutColorMode & 0x07;					//输出颜色模式
	DMA2D->OMAR = pParm->OutImageAddr;							//输出存储器地址
	DMA2D->OOR = pParm->OutImageOffsetX;						//输出偏移寄存器
	//公共配置
	DMA2D->NLR = pParm->ImageWidth;								//待传输的像素图像宽度,单位像素
	DMA2D->NLR <<= 16;
	DMA2D->NLR |= pParm->ImageHeight;							//待传输的像素图像高度,单位像素

	DMA2D_Start();												//开始传输
}
/*************************************************************************************************************
 * 文件名		:	dma2d.H
 * 功能			:	STM32F7 DMA2D驱动
 * 作者			:	[email protected]
 * 创建时间		:	2019-10-29
 * 最后修改时间	:	2019-10-29
 * 详细:			
*************************************************************************************************************/	
#ifndef __DMA2D_H_
#define	__DMA2D_H_	   
#include "system.h"


typedef enum
{
	DMA2D_MODE_MEM		= 	0,		//存储器到存储器(仅限 FG前景色 获取)
	DMA2D_MODE_MEM_PFC	=	1,		//存储器到存储器并执行 PFC(仅限 FG PFC 激活时的 FG 获取)
	DMA2D_MODE_MEM_MIXED=	2,		//存储器到存储器并执行混合(执行 PFC 和混合时的 FG 和 BG 获取)
	DMA2D_MODE_REG		=	3,		//寄存器到存储器(无 FG 和 BG,仅输出阶段激活)
}DMA2D_MODE;

//颜色模式
typedef enum
{
	DMA2D_COLOR_ARGB8888 	= 0,
	DMA2D_COLOR_RGB888 		= 1,
	DMA2D_COLOR_RGB565 		= 2,
	/*DMA2D_COLOR_ARGB1555 	= 3,
	DMA2D_COLOR_ARGB4444 	= 4,
	DMA2D_COLOR_L8 			= 5,	//8 位 Luminance
	DMA2D_COLOR_AL44 		= 6,	//4 位 Alpha,4 位 Luminance
	DMA2D_COLOR_AL88 		= 7,	//8 位 Alpha,8 位 Luminance
	DMA2D_COLOR_L4 			= 8,	//4 位 Luminance
	DMA2D_COLOR_A8 			= 9,	//8 位 Alpha
	DMA2D_COLOR_A4 			= 10,	//4 位 Alpha*/
}DMA2D_COLOR_MODE;


//Alpha 模式
typedef enum
{
	DMA2D_ALPHA_NULL	=	0,//不修改层图像的 alpha 通道值
	DMA2D_ALPHA_REPLACE	=	1,//原始层图像的 alpha 通道值替换为 ALPHA[7: 0]
	DMA2D_ALPHA_PRODUCT	=	2,//原始层图像的 alpha 通道值替换为 ALPHA[7: 0] 与原始 alpha 通道值的乘积
}DMA2D_ALPHA_MODE;

//像素混合模式下DMA图形填充所需参数
typedef struct
{
	//公共配置
	u16 ImageWidth;						//待传输的像素图像宽度,单位像素
	u16 ImageHeight;					//待传输的像素图像高度,单位像素
	//输入的背景配置
	u32 InBackImageAddr;				//输入的背景图像开始地址(通过地址控制开始的X,Y坐标)
	u32 InBackImageOffsetX;				//输入的背景图像跳过的X坐标值
	u32 InBackAlpha;					//输入的背景图像的固定Alpha值,是否使用根据InBackAlphaMode配置决定
	DMA2D_COLOR_MODE InBackColorMode;	//输入的背景图像的颜色模式
	DMA2D_ALPHA_MODE InBackAlphaMode;	//输入的背景图像Alpha模式
	//输入的前景配置
	u32 InForeImageAddr;				//输入的前景图像开始地址(通过地址控制开始的X,Y坐标)
	u32 InForeImageOffsetX;				//输入的前景图像跳过的X坐标值
	u32 InForeAlpha;					//输入的前景图像的固定Alpha值,是否使用根据InForeAlphaMode配置决定
	DMA2D_COLOR_MODE InForeColorMode;	//输入的前景图像的颜色模式
	DMA2D_ALPHA_MODE InForeAlphaMode;	//输入的前景图像Alpha模式
	//输出配置
	u32 OutImageAddr;					//输出的图像开始地址(通过地址控制开始的X,Y坐标)
	u32 OutImageOffsetX;				//输出的图像跳过的X坐标值
	DMA2D_COLOR_MODE OutColorMode;		//输出的图像的颜色模式
}DMA2D_PixelMixing_Parm;



__inline void DMA2D_Abort(void) {DMA2D->CR |= BIT2;}		//终止传输
__inline void DMA2D_Suspend(void) {DMA2D->CR |= BIT1;}		//挂起传输
__inline void DMA2D_Start(void) {DMA2D->CR |= BIT0;}		//开始传输


void DMA2D_WaitTransferComplete(u32 TimeOutMs);																			//等待DMA2D传输完成

void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm);	//DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)

#endif //__DMA2D_H_

下面是C语言软件实现的alpha混合,功能与使用完全一致

//RGB888 转 RGB565
#ifndef RGB565
#define RGB565(color) ((((color) >> 19) & 0x1f) << 11) \
                                            |((((color) >> 10) & 0x3f) << 5) \
                                            |(((color) >> 3) & 0x1f) 
#endif //RGB565


//RGB565转RGB888
#ifndef RGB888
#define RGB888(color) ((((color) >> 8) & 0xF8) << 16) \
                                            |((((color) >> 3) & 0xFC) << 8) \
                                            |(((color) << 3) & 0xFC) 
#endif //RGB888


//RGB888转ARGB8888
#ifndef RGB888toARGB
#define RGB888toARGB(color) (color|0xFF000000) 
#endif //RGB888toARGB


//ARGB 格式数据定义
typedef struct
{
    u8 mB;
    u8 mG;
    u8 mR;
    u8 mA;
}ARGB_DATA_TYPE;

//获取一个像素的数据长度
static u8 DMA2D_GetPidexByteSize(DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888: return 4;
        case DMA2D_COLOR_RGB888: return 3;
        default: return 2;
    }
}

//转换一个像素为ARGB格式
static u32 __inline DMA2D_ConvPidexToARGB(u32 Color, DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888:  //输入像素为ARGB8888,不用转换
        {
            return Color;
        }
        case DMA2D_COLOR_RGB888:    //输入像素为RGB888,加上alpha通道数据
        {
            return RGB888toARGB(Color);
        }
        default:  //输入像素为RGB565
        {
            return RGB888toARGB(RGB888(Color));
        }
    }
}


//处理一个像素的Alpha设置
static void __inline DMA2D_PidexAlphaModeHandle(u32 *pColor, u8 Alpha, DMA2D_ALPHA_MODE AlphaMode)
{
    u16 temp;
    ARGB_DATA_TYPE* pPidex = (ARGB_DATA_TYPE*)pColor;

    switch (AlphaMode)
    {
        case DMA2D_ALPHA_REPLACE ://原始前景层图像的 alpha 通道值替换为 ALPHA[7: 0]
        {
            pPidex->mA = Alpha;
        }break;
        case DMA2D_ALPHA_PRODUCT ://原始前景层图像的 alpha 通道值替换为 ALPHA[7: 0] 与原始 alpha 通道值的乘积
        {
            temp = Alpha;
            temp *= pPidex->mA;
            pPidex->mA = temp / 255;
        }break;
        default: break;//不修改前景层图像的 alpha 通道值      
    }
}

//进行2个像素混合,必须是ARGB888格式
static void __inline DMA2D_PixelMixing(ARGB_DATA_TYPE* pInBackPidex, ARGB_DATA_TYPE* pInForePidex, ARGB_DATA_TYPE* pOutPidex)
{
    ARGB_DATA_TYPE tempARGB;
    //先计算底层(背景默认为黑色)-底层有个黑色幕布,如果背景层的Alpha不是255,会先进行计算
    if (pInBackPidex->mA < 255)
    {
        tempARGB.mR = ((u32)(pInBackPidex->mA) * pInBackPidex->mR) / 255;
        tempARGB.mG = ((u32)(pInBackPidex->mA) * pInBackPidex->mG) / 255;
        tempARGB.mB = ((u32)(pInBackPidex->mA) * pInBackPidex->mB) / 255;
    }
    else
    {
        memcpy(&tempARGB, pInBackPidex, 4);         //不用计算混合,直接使用背景层
    }
   
    //背景层与前景层混合
    pOutPidex->mR = (((u32)(pInForePidex->mA) * pInForePidex->mR) + (u32)(255 - pInForePidex->mA) * tempARGB.mR) / 255;
    pOutPidex->mG = (((u32)(pInForePidex->mA) * pInForePidex->mG) + (u32)(255 - pInForePidex->mA) * tempARGB.mG) / 255;
    pOutPidex->mB = (((u32)(pInForePidex->mA) * pInForePidex->mB) + (u32)(255 - pInForePidex->mA) * tempARGB.mB) / 255;
    pOutPidex->mA = 0xFF;   //混合后的最终图像不需要Alpha了,因为屏幕显示只需要RGB即可
}

//将ARGB8888数据格式转换为输出所需格式
static u32 __inline DMA2D_ARGBtOConvPidex(u32 Color, DMA2D_COLOR_MODE ColorMode)
{
    switch (ColorMode)
    {
        case DMA2D_COLOR_ARGB8888:  //输出像素为ARGB8888,不用转换
        {
            return Color;
        }
        case DMA2D_COLOR_RGB888:    //输出像素为RGB888,去掉alpha通道数据
        {
            return Color & 0x00FFFFFF;
        }
        default:  //输出像素为RGB565
        {
            return RGB565(Color);
        }
    }
}

/*************************************************************************************************************************
* 函数			:	void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm *pParm)
* 功能			:	DMA2D进行矩形图形填充(会执行像素格式转换与Alpha混合)
* 参数			:	pParm:所需的参数,见DMA2D_PixelMixing_Parm
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	[email protected]
* 时间			:	2020-03-14
* 最后修改时间 	: 	2020-03-14
* 说明			:	用于填充图形,实现STM32F7的 DMA2D像素混合功能
*************************************************************************************************************************/
void DMA2D_FillImage_PixelMixing(DMA2D_PixelMixing_Parm* pParm)
{
    u32 x, y;
    //像素点缓冲区
    u32 InBackPidex;                //输入的背景像素
    u32 InForePidex;                //输入的前景像素
    u32 OutPidex;                   //输出的像素
    //像素点指针-用于alpha混合
    ARGB_DATA_TYPE* pInBackPidex;   //输入的背景像素ARGB格式指针
    ARGB_DATA_TYPE* pInForePidex;   //输入的前景像素ARGB格式指针
    ARGB_DATA_TYPE* pOutPidex;      //输出的像素ARGB格式指针
    //像素大小-单位字节
    u8 InBackPidexSize;                //输入的背景像素
    u8 InForePidexSize;                //输入的前景像素
    u8 OutPidexSize;                   //输出的像素
    //当前处理的像素位置指针-字节指针
    u8* pInBackPidexBytePoint;         //输入的背景像素处理位置指针
    u8* pInForePidexBytePoint;         //输入的前景像素处理位置指针
    u8* pOutPidexBytePoint;            //输出的像素字节指针

    //像素指针初始化
    pInBackPidex = (ARGB_DATA_TYPE*)&InBackPidex;   //输入的背景像素
    pInForePidex = (ARGB_DATA_TYPE*)&InForePidex;   //输入的前景像素
    pOutPidex = (ARGB_DATA_TYPE*)&OutPidex;         //输出的像素
    //像素大小初始化
    InBackPidexSize = DMA2D_GetPidexByteSize(pParm->InBackColorMode);                //输入的背景像素
    InForePidexSize = DMA2D_GetPidexByteSize(pParm->InForeColorMode);                //输入的前景像素
    OutPidexSize = DMA2D_GetPidexByteSize(pParm->OutColorMode);                      //输出的像素
    //像素处理位置指针初始化
    pInBackPidexBytePoint = (u8*)pParm->InBackImageAddr;                             //输入的背景像素处理位置指针
    pInForePidexBytePoint = (u8*)pParm->InForeImageAddr;                             //输入的前景像素处理位置指针
    pOutPidexBytePoint = (u8*)pParm->OutImageAddr;                                   //输出的像素字节指针

    for (y = 0; y < pParm->ImageHeight; y++)
    {
        for (x = 0; x < pParm->ImageWidth; x++)
        {
            //像素数据初始化为0
            InBackPidex = 0; InForePidex = 0; OutPidex = 0;
            //读取一个背景像素,转换为ARGB格式
            memcpy(&InBackPidex, pInBackPidexBytePoint, InBackPidexSize);                           //读取一个输入的背景像素
            InBackPidex = DMA2D_ConvPidexToARGB(InBackPidex, pParm->InBackColorMode);               //转换为ARGB
            DMA2D_PidexAlphaModeHandle(&InBackPidex, pParm->InBackAlpha, pParm->InBackAlphaMode);   //处理一个像素的Alpha设置
            pInBackPidexBytePoint += InBackPidexSize;                                               //指针跳到下一个像素
            //读取一个前景像素,转换为ARGB格式
            memcpy(&InForePidex, pInForePidexBytePoint, InForePidexSize);                           //读取一个输入的前景像素
            InForePidex = DMA2D_ConvPidexToARGB(InForePidex, pParm->InForeColorMode);               //转换为ARGB
            DMA2D_PidexAlphaModeHandle(&InForePidex, pParm->InForeAlpha, pParm->InForeAlphaMode);   //处理一个像素的Alpha设置
            pInForePidexBytePoint += InForePidexSize;                                               //指针跳到下一个像素
            //Alpha混合
            DMA2D_PixelMixing(pInBackPidex, pInForePidex, pOutPidex);                               //进行2个像素混合,必须是ARGB888格式
            //输出像素转换
            OutPidex = DMA2D_ARGBtOConvPidex(OutPidex, pParm->OutColorMode);                        //将ARGB8888数据格式转换为输出所需格式
            //拷贝最终数据到输出缓冲区中
            memcpy(pOutPidexBytePoint, &OutPidex, OutPidexSize);
            pOutPidexBytePoint += OutPidexSize;                                                     //指针跳到下一个像素
        }
        //一行处理完了,需要跳过一些X值
        pInBackPidexBytePoint += pParm->InBackImageOffsetX * InBackPidexSize;
        pInForePidexBytePoint += pParm->InForeImageOffsetX * InForePidexSize;
        pOutPidexBytePoint += pParm->OutImageOffsetX * OutPidexSize;
    }
    
}

测试时,背景图片与后面的ICO透明图标都在一个图层上面显示

BMP_Show("C:\\system\\BL01.bmp", pLTDC_Layer1_GRAM_HANDLE, 0, 0, 0, 0, &pErrorStr);

ICO_Show("C:\\256x256.ico", pLTDC_Layer1_GRAM_HANDLE, 1, 1, 256, 256, &pErrorStr);

2个图片都是显示在LTDC_Layer1上,下面是开发板效果

STM32F7 DAM2D alpha像素混合(同时有对应的软件Alpha像素混合代码)_第1张图片

这个是PC端,使用win32调用软件接口,效果与F7硬件DMA2D效果完全一致.

STM32F7 DAM2D alpha像素混合(同时有对应的软件Alpha像素混合代码)_第2张图片

你可能感兴趣的:(CortexM3(STM32),VC++,.NET)