/************************************************************************************************************************* * 函数 : ICO_ERROR ICO_Decode(ICO_Decode_Parm* pDecodeParm) * 功能 : ICO图片软解析(全部解析) * 参数 : pDecodeParm:相关参数(见ICO_Decode_Parm) * 返回 : ICO_ERROR * 依赖 : 底层 * 时间 : 2011-09-19 * 最后修改时间 : 2020-02-19 * 说明 : 输入缓冲区最小要给128字节 *************************************************************************************************************************/ ICO_ERROR ICO_Decode(ICO_Decode_Parm* pDecodeParm) { ICO_FILE_HEADER* pIcoHeader; //图片文件头 ICO_DecodeDataType mDecodeTempData; //图片解析所需的临时变量 ICO_ERROR mIcoError = ICO_OK; //图片解析状态 u32 temp; float ftemp; u32 ActualReadCount; ICO_BMP_HEADER* pICO_BmpHeader;
if (pDecodeParm == NULL || pDecodeParm->InFileBuff == NULL || pDecodeParm->InFileBuffSize < 128 || pDecodeParm->InFileSize == 0 || ((pDecodeParm->isLoadFile == TRUE) && pDecodeParm->Func_ReadFile == NULL) || ((pDecodeParm->isLoadFile == TRUE) && pDecodeParm->pInFileHandle == NULL) || pDecodeParm->Func_FillPoint == NULL) { DEBUG("ICO解析失败:无效的参数(请提供正确的:pDecodeParm,缓冲区,缓冲区大小,文件大小,读取文件回调与文件句柄(前提是使能了文件加载),画点接口)\r\n"); return ICO_PARM_ERROR; } if (pDecodeParm->isLoadFile == TRUE) //需要加载文件 { if (pDecodeParm->InFileBuffSize >= pDecodeParm->InFileSize) //缓冲区比文件大,可以一次加载完文件的所有数据 { mDecodeTempData.ThisReadCount = pDecodeParm->InFileSize; //本次要读取的数据大小 mDecodeTempData.isStageLoadFile = FALSE; //图片文件一次加载完成了,不需要再加载了 } else { mDecodeTempData.ThisReadCount = 128; //本次要读取的数据大小 mDecodeTempData.isStageLoadFile = TRUE; //需要分段加载文件 }
if (pDecodeParm->Func_ReadFile(pDecodeParm->pInFileHandle, 0, pDecodeParm->InFileBuff, mDecodeTempData.ThisReadCount, &ActualReadCount) == FALSE) { DEBUG("ICO解析失败:加载文件失败\r\n"); return ICO_FILE_ERROR; //文件加载失败 } else if (mDecodeTempData.ThisReadCount != ActualReadCount) { DEBUG("ICO解析失败:文件加载不全\r\n"); return ICO_FILE_ERROR; //文件加载失败 } } else { mDecodeTempData.isStageLoadFile = FALSE; //图片文件已经提前加载了,不需要再加载了 }
//基本数据初始化 pIcoHeader = (ICO_FILE_HEADER*)pDecodeParm->InFileBuff; //得到ICO的头部信息 if (pIcoHeader->idType != 1) { DEBUG("ICO解析失败:不是有效的ICO图标文件\r\n"); return ICO_ILLEGAL_ERROR; //不支持 } if (pIcoHeader->idCount == 0) { DEBUG("ICO解析失败:图标数量为0\r\n"); return ICO_ILLEGAL_ERROR; //不支持 } if (pIcoHeader->IcoInfoBuff[0].wBitCount != 32) { DEBUG("ICO解析失败:只支持32bit的非压缩ARGB图标解析\r\n"); return ICO_ILLEGAL_ERROR; //不支持 }
mDecodeTempData.mIcoInfo.bfOffBits = pIcoHeader->IcoInfoBuff[0].dwImageOffset; //位图数据偏移地址偏移 pICO_BmpHeader = (ICO_BMP_HEADER*)&pDecodeParm->InFileBuff[mDecodeTempData.mIcoInfo.bfOffBits]; //获取bmp头信息 /****************************************************/ //调试 uart_printf("\r\n"); uart_printf("位图大小:%d\r\n", pICO_BmpHeader->bmfHeaderSize); uart_printf("颜色深度:%d\r\n", pICO_BmpHeader->biBitCount); uart_printf("水平分辨率:%d\r\n", pICO_BmpHeader->biWidth); uart_printf("垂直分辨率:%d\r\n", pICO_BmpHeader->biHeight); uart_printf("数据大小:%luB\r\n", pICO_BmpHeader->biSizeImage); uart_printf("位图压缩:%d\r\n", pICO_BmpHeader->biCompression); /*****************************************************/ if (pICO_BmpHeader->bmfHeaderSize != 40 || pICO_BmpHeader->biCompression != 0 || pICO_BmpHeader->biBitCount != 32) { DEBUG("ICO解析失败:只支持32bit的非压缩ARGB图标解析(位图信息错误)\r\n"); return ICO_ILLEGAL_ERROR; //不支持 } mDecodeTempData.mIcoInfo.biSizeImage = pICO_BmpHeader->biSizeImage; //图像数据大小 mDecodeTempData.mIcoInfo.biWidth = pICO_BmpHeader->biWidth; //图片宽度 mDecodeTempData.mIcoInfo.biHeight = pICO_BmpHeader->biHeight/2; //图片高度,位图的高度翻倍了 mDecodeTempData.mIcoInfo.biBitCount = pICO_BmpHeader->biBitCount; //颜色深度
mDecodeTempData.pDecodeParm = pDecodeParm; //记录输入的参数 mDecodeTempData.ThisReadCount = 0; //此次读取的文件大小复位 mDecodeTempData.ThisReadStartOffset = 0; //此次读取的文件开始偏移复位-相对于整个文件内的偏移 /****************************************************/ //调试 uart_printf("\r\n地址偏移:%d\r\n", mDecodeTempData.mIcoInfo.bfOffBits); uart_printf("颜色深度:%d\r\n", mDecodeTempData.mIcoInfo.biBitCount); uart_printf("水平分辨率:%d\r\n", mDecodeTempData.mIcoInfo.biWidth); uart_printf("垂直分辨率:%d\r\n", mDecodeTempData.mIcoInfo.biHeight); uart_printf("数据大小:%luB\r\n", mDecodeTempData.mIcoInfo.biSizeImage); uart_printf("图像标志:0x%04X\r\n", pIcoHeader->idType); uart_printf("图形数量:%d\r\n\r\n", pIcoHeader->idCount); /*****************************************************/
//计算缩放比例 ftemp = pDecodeParm->OutRGB_ImageWidth; ftemp /= (float)mDecodeTempData.mIcoInfo.biWidth; //水平缩放率 if (ftemp > 1) ftemp = 1; //只能缩小,不能放大 mDecodeTempData.ScaleFactor = pDecodeParm->OutRGB_ImageHeight; mDecodeTempData.ScaleFactor /= (float)mDecodeTempData.mIcoInfo.biHeight; //垂直缩放率 if (mDecodeTempData.ScaleFactor > 1) mDecodeTempData.ScaleFactor = 1; //只能缩小,不能放大 if (ftemp < mDecodeTempData.ScaleFactor) //水平缩放比例大,会导致垂直方向无法填充满 { mDecodeTempData.offsetX = 0; mDecodeTempData.offsetY = (pDecodeParm->OutRGB_ImageHeight - (ftemp * mDecodeTempData.mIcoInfo.biHeight)) / 2; //计算居中坐标 mDecodeTempData.ScaleFactor = ftemp; //使用较小的那个缩放率进行缩放 } else //垂直方向缩放比例大,会导致垂直方向无法填充满 { mDecodeTempData.offsetY = 0; mDecodeTempData.offsetX = (pDecodeParm->OutRGB_ImageWidth - (mDecodeTempData.ScaleFactor * mDecodeTempData.mIcoInfo.biWidth)) / 2; //计算居中坐标 //使用较小的那个缩放率进行缩放 }
uart_printf("图片缩放率:%f\r\n", mDecodeTempData.ScaleFactor); mDecodeTempData.FactorCumulaX = 0.0f; //X方向缩放累加计数器,浮点型,每当增1后显示当前列 mDecodeTempData.FactorCumulaY = 0.0f; //Y方向缩放累加计数器,浮点型,每当增1后显示当前行 mDecodeTempData.LastFactorCumulaIntX = 0; //X方向缩放累加计数器,整形数,用于记录上一次的值,用于对比是否发生了增量(+1) mDecodeTempData.LastFactorCumulaIntY = 0; //Y方向缩放累加计数器,整形数,用于记录上一次的值,用于对比是否发生了增量(+1) if (mDecodeTempData.ScaleFactor != 1.0f) { mDecodeTempData.isZoom = TRUE; //需要缩放 mDecodeTempData.isDisplayThisPixel = FALSE; //当前行列不能显示 } else { mDecodeTempData.isZoom = FALSE; //不需要缩放 mDecodeTempData.isDisplayThisPixel = TRUE; //当前行列能显示 }
//初始化坐标-坐标显示范围由图片的真实宽度高度*缩放系数得到,ico从左下角开始解析 mDecodeTempData.IcoY = mDecodeTempData.mIcoInfo.biHeight * mDecodeTempData.ScaleFactor - 1; //ICO解析计数,变为0后解析完成
//输入指针初始化 mDecodeTempData.FileOffset = mDecodeTempData.mIcoInfo.bfOffBits + pICO_BmpHeader->bmfHeaderSize; //文件偏移(位图偏移加位图信息块大小) if (mDecodeTempData.isStageLoadFile == FALSE) //不需要分段加载,直接解析内存中的数据 { mDecodeTempData.InData32bit = (u32*)&pDecodeParm->InFileBuff[mDecodeTempData.FileOffset]; //跳到图片数据区 } else //需要分包加载图片,计算一次读取的数据数量 { mDecodeTempData.OneReadCount = pDecodeParm->InFileBuffSize / 4; mDecodeTempData.OneReadCount *= 4; mDecodeTempData.ThisReadStartOffset = mDecodeTempData.mIcoInfo.bfOffBits + pICO_BmpHeader->bmfHeaderSize; //文件偏移(位图偏移加位图信息块大小) //读取第一包数据 if (pDecodeParm->Func_ReadFile(pDecodeParm->pInFileHandle, mDecodeTempData.ThisReadStartOffset+0, pDecodeParm->InFileBuff, mDecodeTempData.OneReadCount, &mDecodeTempData.ThisReadCount) == FALSE) { mIcoError = ICO_FILE_ERROR; DEBUG("读取ICO图片文件失败\r\n"); goto end_loop; } //读取的第一包数据,初始化相关信息 mDecodeTempData.InData32bit = (u32*)&pDecodeParm->InFileBuff[0]; //跳到图片数据区-图片是分段加载的,起点就是正文处 } //输出像素 switch (pDecodeParm->OutRGB_ColorMode) //输出像素数据格式 { case PIC_COLOR_ARGB8888: //32bit格式输出 { mDecodeTempData.OutPixelByte = 4; //4字节 }break; case PIC_COLOR_RGB888: //24bit格式输出 { mDecodeTempData.OutPixelByte = 3; //3字节 }break; default: //默认为RGB555 { mDecodeTempData.OutPixelByte = 2; //2字节 }break; }
//需要缩放,那就先找到下一个能显示的行 if (mDecodeTempData.isZoom) //需要缩放 { mIcoError = ICO_DecodeZoom_NextValidRow(&mDecodeTempData); //子流程-ICO解析跳转到下一个能被显示的行(用于缩放) if (mIcoError != ICO_OK) { goto end_loop; } }
//计算画点坐标初值, 让图片居中显示 mDecodeTempData.xPos = pDecodeParm->OutRGB_PixelOffsetX + mDecodeTempData.offsetX; //屏幕X坐标起始位置 //Y坐标偏移从左下角开始 mDecodeTempData.yPos = mDecodeTempData.IcoY + pDecodeParm->OutRGB_PixelOffsetY + mDecodeTempData.offsetY;
mDecodeTempData.CachePixelSize = pDecodeParm->DecodeBuffSize / mDecodeTempData.OutPixelByte; //计算像素缓冲区大小-像素大小 mDecodeTempData.CachePixelCount = 0; //缓存的像素计数器清零 mDecodeTempData.FillPixelXpos = mDecodeTempData.xPos; //填充图形开始坐标X值
//只支持32bit 非压缩ico解析 mIcoError = ICO_Decode32bit_Module(&mDecodeTempData); //子流程-32bit位图解析(从内存中读取图片数据,然后解析到内存中)
end_loop: return mIcoError; }
|