注:本人已购买韦东山老师第三期项目视频,内容来源《数码相框项目视频》,只用于学习记录,如有侵权,请联系删除。

1. 数码相框效果图

根据上一节的数码相框需求框架可得出的大致效果图如下图所示:

    上图的图标都是经过缩小的图标,实际上这些图标的分辨率都是比较大的,例如方形的图标分辨率为 128*128;但是我们 Jz2440 开发板的 LCD 只有 480 * 272,如果按实际图片的尺寸大小显示,显然是不可取的,所以需要进行 图片缩放 ;另外上图图标的格式为 bmp 格式的图标,要在 LCD 上显示这种格式的图片,就涉及到了 bmp 格式的图片解码。

2. BMP 格式图片解码

(1) 关于 BMP 格式图片的数据分析可以查看这个两篇博客:bitmap格式分析、BMP图像数据格式详解。

(2) 这里需要注意的是 LCD 是从左上角开始显示图像的,而 BMP 图片像素数据的存储是从左下角开始的,如下图所示。因此在显示BMP图片时需要从BMP图片的左上角开始读取数据发送给LCD显示:

(3) BMP 格式图片解码代码:
① 在 pic_operation.h 中定义像素数据结构体 T_PixelDatas、文件解析结构体 T_PicFileParser,代码如下:

#ifndef _PIC_OPERATION_H
#define _PIC_OPERATION_Htypedef struct PixelDatas{int iWidth;int iHeight;int iBpp;int iLineBytes;unsigned char *aucPixelDatas;
}T_PixelDatas, *PT_PixelDatas;typedef struct PicFileParser{char *name;int (*isSupport)(unsigned char *aFileHead);int (*GetPixelDatas)(unsigned char *aFileHead, PT_PixelDatas tPixelDatas);int (*FreePixelDatas)(PT_PixelDatas tPixelDatas);
}T_PicFileParser, *PT_PicFileParser;int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic);
int PicMerge(int iX, int iY, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic);#endif /* _PIC_OPERATION_H */

② bmp解码代码如下:bmp.c

#include <pic_operation.h>
#include <stdlib.h>
#include <string.h>
#include <config.h>#pragma pack(push)  /* 将当前pack设置压栈保存 */
#pragma pack(1)     /* 必须在结构体定义之前使用 *//* bmp 文件头部 */
typedef struct tagBITMAPFILEHEADER { /* bmfh */unsigned short bfType;  /* 由于更快的访问bfType, 此时的bfType被4字节对齐 */unsigned long bfSize;unsigned short bfReserved1;unsigned short bfReserved2;unsigned long bfOffBits;
} BITMAPFILEHEADER;#pragma pack(pop) /* 恢复先前的pack设置 *//* bmp 位图信息头部 */
typedef struct tagBITMAPINFOHEADER { /* bmih */unsigned long  biSize;unsigned long  biWidth;unsigned long  biHeight;unsigned short biPlanes;unsigned short biBitCount;unsigned long  biCompression;unsigned long  biSizeImage;unsigned long  biXPelsPerMeter;unsigned long  biYPelsPerMeter;unsigned long  biClrUsed;unsigned long  biClrImportant;
} BITMAPINFOHEADER;/* bmp 文件开头的标记为 0x4D42* 以此判断是否支持BMP格式*/
static int isBMPFormat(unsigned char *aFileHead)
{if (aFileHead[0] != 0x42 || aFileHead[1] != 0x4D){return 0;}else{return -1;}
}/* 从BMP图片获取一行数据 */
static int ConvertOneLineFrmBMP(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{unsigned int dwRed;unsigned int dwGreen;unsigned int dwBlue;unsigned int dwColor;unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;unsigned int *pwDstDatas32bpp   = (unsigned int *)pudDstDatas;int i;int pos = 0;if (iSrcBpp != 24){return -1;}if (iDstBpp == 24){memcpy(pudDstDatas, pudSrcDatas, iWidth * 3);}else {for (i = 0; i < iWidth; i++){dwBlue  = pudSrcDatas[pos++];dwGreen = pudSrcDatas[pos++];dwRed   = pudSrcDatas[pos++];if (iDstBpp == 32){dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;*pwDstDatas32bpp = dwColor;pwDstDatas32bpp++;}else if (iDstBpp == 16){dwRed   = dwRed >> 3;dwGreen = dwGreen >> 2;dwBlue  = dwBlue >> 3;dwColor = (dwRed << 11) | (dwGreen << 5) | dwBlue;*pwDstDatas16bpp = dwColor;pwDstDatas16bpp++;}}}return 0;
}/* 获取BMP图片像素数据 * ptPixelDatas->iBpp 是输入的参数,它决定从BMP得到的数据要转换为该格式*/
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas)
{BITMAPFILEHEADER *ptBITMAPFILEHEADER;BITMAPINFOHEADER *ptBITMAPINFOHEADER;int iWidth;int iHeight;int iBMPBpp;int y;unsigned char *pucSrc;unsigned char *pucDest;int iLineWidthAlign;int iLineWidthReal;ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));iWidth  = ptBITMAPINFOHEADER->biWidth;iHeight = ptBITMAPINFOHEADER->biHeight;iBMPBpp = ptBITMAPINFOHEADER->biBitCount;if (iBMPBpp != 24){return -1;}ptPixelDatas->iWidth  = iWidth;ptPixelDatas->iHeight = iHeight;ptPixelDatas->aucPixelDatas = malloc(iWidth * iHeight * ptPixelDatas->iBpp / 8);ptPixelDatas->iLineBytes = iWidth * ptPixelDatas->iBpp / 8;if (ptPixelDatas->aucPixelDatas == NULL){return -1;}iLineWidthReal = iWidth * iBMPBpp / 8;iLineWidthAlign = (iLineWidthReal + 3) & ~0x03; /* 4字节对齐 */pucSrc = aFileHead +ptBITMAPFILEHEADER->bfOffBits;pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign; /* 把pucSrc指向图片数据的最后一行 */pucDest = ptPixelDatas->aucPixelDatas;for (y = 0; y < iHeight; y++){ConvertOneLineFrmBMP(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);pucSrc -= iLineWidthAlign;pucDest += ptPixelDatas->iLineBytes;}return 0;
}static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{free(ptPixelDatas->aucPixelDatas);return 0;
}T_PicFileParser g_tBMPParser = {.name           = "bmp",.isSupport      = isBMPFormat,.GetPixelDatas  = GetPixelDatasFrmBMP,.FreePixelDatas = FreePixelDatasForBMP,
};

3. BMP 格式图片缩放

(1) 关于图像的缩放算法,可以参考博客:图像缩放算法。
(2) 在图像缩放算法这博客中,有写到图片的缩放原理如下图所示:根据原图和缩放后图片的比例相同的原理,通过缩放后图片的 x、y 坐标求出原图的Sx、Sy坐标,然后取出原图(Sx,Sy)坐标的颜色值赋值给缩放图片的(x,y)坐标。

由此可以得出基本的代码框架如下图所示:

由于图片的像素是一行一行的读取的,在上图的 for 的第二层循环中,由于 y 的值是不变的,所有为了节省计算,优化如下:

另外,对与图片的每一列,x 的值是相等的,我们可以事先算出每一列 x 的值,存放在一个 table 里面,这样就不用每执行一次第二层for循环都重新计算 Sx 的值,从而节省计算时间,优化如下:

(3) 图片缩放的代码如下:zoom.c

#include <pic_operation.h>
#include <stdlib.h>
#include <string.h>int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic)
{unsigned long dwDstWidth = ptZoomPic->iWidth;unsigned long *pdwSrcXTable = malloc(sizeof(unsigned long) * dwDstWidth);unsigned long x;unsigned long y;unsigned long dwSrcY;unsigned char *pucDest;unsigned char *pucSrc;unsigned long dwPixelBytes = ptOriginPic->iBpp / 8;if (ptOriginPic->iBpp != ptZoomPic->iBpp){free(pdwSrcXTable);return -1;}for (x = 0; x < dwDstWidth; x++){pdwSrcXTable[x] = x * ptOriginPic->iWidth / ptZoomPic->iWidth;}for (y = 0; y < ptZoomPic->iHeight; y++){dwSrcY  = y *  ptOriginPic->iHeight / ptZoomPic->iHeight;pucDest = ptZoomPic->aucPixelDatas + y * ptZoomPic->iLineBytes;pucSrc  = ptOriginPic->aucPixelDatas + dwSrcY * ptOriginPic->iLineBytes;for (x = 0; x < dwDstWidth; x++){/* 原图坐标:SrcX_Table[x], dwSrcY* 缩放坐标:x, y*/memcpy(pucDest + x * dwPixelBytes , pucSrc + pdwSrcXTable[x] * dwPixelBytes, dwPixelBytes);}}free(pdwSrcXTable);return 0;
}

图片经过缩小后得到一个小的数组,如何把这个小的数组放到大的 framebuffer里呢?代码如下:merge.c

#include <pic_operation.h>
#include <string.h>/* 把小图片合并到大图片的(iX,iY)坐标中* (iX,iY)坐标是小图片合并到大图的坐标*/
int PicMerge(int iX, int iY, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic)
{int i;unsigned char *pucSrc;unsigned char *pucDst;if ((ptSmallPic->iWidth > ptBigPic->iWidth) || (ptSmallPic->iHeight > ptBigPic->iHeight) ||(ptSmallPic->iBpp != ptBigPic->iBpp)){return -1;}pucSrc = ptSmallPic->aucPixelDatas;pucDst = ptBigPic->aucPixelDatas + iY * ptBigPic->iLineBytes + iX * ptBigPic->iBpp / 8;for (i = 0; i < ptSmallPic->iHeight; i++){memcpy(pucDst, pucSrc, ptSmallPic->iLineBytes);pucSrc += ptSmallPic->iLineBytes;pucDst += ptBigPic->iLineBytes;}return 0;
}

4. LCD 显示bmp格式图片

在 main.c 中,显示一幅原图和原图长宽缩小1/2的图片,代码如下:

#include <fonts_manager.h>
#include <disp_manager.h>
#include <input_manager.h>
#include <debug_manager.h>
#include <pic_operation.h>
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>/* ./digitpic <bmp_file> */
int main(int argc, char **argv)
{int iFdBmp;int iRet;PT_DispOpr ptDispOpr;unsigned char *pucBMPmem;struct stat tBMPStat;extern T_PicFileParser g_tBMPParser;T_PixelDatas tPixelDatas;T_PixelDatas tPixelDatasSmall;T_PixelDatas tPixelDatasFB;if (argc != 2){printf("%s <bmp_file>\n", argv[0]);return -1;}DebugInit();InitDebugChannel();DisplayInit();ptDispOpr = GetDispOpr("fb");ptDispOpr->DeviceInit();ptDispOpr->CleanScreen(0x00);/* 打开BMP文件 */iFdBmp = open(argv[1], O_RDWR);if (iFdBmp == -1){DBG_PRINTF("can't open %s!\n", argv[1]);return -1;}fstat(iFdBmp, &tBMPStat);pucBMPmem = (unsigned char *)mmap(NULL, tBMPStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFdBmp, 0);if (pucBMPmem == (unsigned char *)-1){DBG_PRINTF("mmap error!\n");return -1;      }/* 提取BMP文件的RGB数据、缩放,在LCD显示出来 */iRet = g_tBMPParser.isSupport(pucBMPmem);if (iRet == 0){DBG_PRINTF("%s is not bmp file!\n", argv[1]);return -1;         }tPixelDatas.iBpp = ptDispOpr->iBpp;iRet = g_tBMPParser.GetPixelDatas(pucBMPmem, &tPixelDatas);if (iRet){DBG_PRINTF("GetPixelDatas error!\n");return -1;         }tPixelDatasFB.iWidth        = ptDispOpr->iXres;tPixelDatasFB.iHeight       = ptDispOpr->iYres;tPixelDatasFB.iBpp          = ptDispOpr->iBpp;tPixelDatasFB.iLineBytes    = ptDispOpr->iXres * ptDispOpr->iBpp / 8;tPixelDatasFB.aucPixelDatas = ptDispOpr->pucDispMem;PicMerge(0, 0, &tPixelDatas, &tPixelDatasFB);/* 缩小到原来的1/4 */tPixelDatasSmall.iWidth     = tPixelDatas.iWidth / 2;tPixelDatasSmall.iHeight    = tPixelDatas.iHeight / 2;tPixelDatasSmall.iBpp       = tPixelDatas.iBpp;tPixelDatasSmall.iLineBytes = tPixelDatasSmall.iWidth * tPixelDatasSmall.iBpp / 8;tPixelDatasSmall.aucPixelDatas = malloc(tPixelDatasSmall.iLineBytes * tPixelDatasSmall.iHeight);PicZoom(&tPixelDatas, &tPixelDatasSmall);PicMerge(128, 128, &tPixelDatasSmall, &tPixelDatasFB);free(tPixelDatasSmall.aucPixelDatas);return 0;
}

5. 测试

把编译好程序拷贝到开发板,运行:./digitpic browse_mode.bmp,运行结果如下图所示:

数码相框(十八、bmp数据提取用于图标显示)相关推荐

  1. Python爬虫之(八)数据提取-Beautiful Soup

    Beautiful Soup的简介 Beautiful Soup提供一些简单的.python式的函数用来处理导航.搜索.修改分析树等功能.它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单 ...

  2. 十八、数据容器、数据访问宽度、端口(计算机对数据处理方式:读取、写入、运算;数据可存放三个地方:CPU内部、内存、端口)

    1. 数据容器 计算机的基本功能是对数据进行处理,处理的方式有:读取.写入.运算. 所处理的数据可以存在于三个地方:CPU内部.内存.端口. 汇编代码中表达数据的位置方式: a 立即数         ...

  3. 机器学习基础(二十八) —— 数据规格化

    数据规格化(Scaling)又称数据尺度归一化,就是将特征的某个属性(特征向量的某一维)的取值范围映射到一个特定范围之内,以消除数值型属性因大小范围不一而影响基于距离的分类方法结果的公正性. 可以毫不 ...

  4. oracle笔记(十八)数据完整性约束

    数据完整性 数据库不仅仅是存储数据,它也必须保证所保存的数据的正确性.如果数据不正确或不一致,那么该数据的完整性可能会遭到破坏,从而给数据库本身的可靠性带来意想不到的问题. 为了维护数据库中的数据完成 ...

  5. Python实战从入门到精通第十八讲——改变对象的字符串显示

    想改变对象实例的打印或显示输出,让它们更具可读性. 要改变一个实例的字符串表示,可重新定义它的 __str__() 和 __repr__() 方法.例如: lass Pair:def __init__ ...

  6. 10、数码相框编写程序之图标显示

    文章目录 1.bmp数据提取 1.1.bmp 文件格式 1.2.文件信息头 1.3.位图信息头 1.4.RGB 颜色阵列 1.5.关于pic_operation.h 1.6.关于bmp.c 2.图片缩 ...

  7. 谷粒学院16万字笔记+1600张配图(十八)——统计分析

    项目源码与所需资料 链接:https://pan.baidu.com/s/1azwRyyFwXz5elhQL0BhkCA?pwd=8z59 提取码:8z59 文章目录 demo18-统计分析 1.需求 ...

  8. 跟燕十八学习PHP-第十五天-php增删改查表数据

    /** 燕十八 公益PHP培训 课堂地址:YY频道88354001 学习社区:www.zixue.it **/ <!DOCTYPE html PUBLIC "-//W3C//DTD X ...

  9. spring可用于数据层吗_Spring XD用于数据提取

    spring可用于数据层吗 Spring XD是一个功能强大的工具,它是一组可安装的Spring Boot服务,可以独立运行,在YARN或EC2之上运行. Spring XD还包括一个管理UI网站和一 ...

最新文章

  1. asp.net学习之 数据绑定控件--List数据绑定控件
  2. C++中floor,ceil , round , rint用法
  3. DataTables选择多行
  4. 同事反馈环:为什么度量和会议还不够充分
  5. Boost Part III. 函数对象与高级编程 Library 10. Lambda 用法 switch_statement
  6. LibJson数据解析方法
  7. boost::hana::duplicate用法的测试程序
  8. STM32的ADC采集的引脚汇总
  9. 《java从入门到精通》pdf
  10. 服务器之后加码存储,浪潮信息重磅发布新一代 G6 存储平台
  11. lua学习之类型与值篇
  12. 捋一捋20201217
  13. [Python2] List-comprehensions 列表推导式
  14. solr 6.4 mysql_solr6.4.1搜索引擎(2)首次同步mysql数据库
  15. Android OpenCV竖屏处理策略和底层代码修改
  16. HTML中的单行注释标签是,html如何单行和多行注释呢 ?
  17. android usb otg 查看,android USB OTG功能如何打开及实现
  18. SQL server Date函数之DATEADD()函数
  19. MATLAB中interp2参数使用指南
  20. minio搭建文件存储服务

热门文章

  1. 零基础玩转ROS小车
  2. 拆书帮第14期训练营——作业六:第一周复盘
  3. 如何让一个2008年的电脑可以正常服役
  4. 电话销售有哪些注意事项 电话销售不能做的事
  5. (转)一个睡五分钟等于六个钟头的方法
  6. 《锋味》谢霆锋柬埔寨吃蜘蛛 邓紫棋为大象唱“泡沫”
  7. ajax无刷新聊天室,实现一个无刷新的基于ajax的简易聊天室
  8. 企业电子名片小程序哪家?市面上哪一款名片小程序更好用?
  9. 解决word打空格不能出现下划线
  10. android投屏到windows系统上面,仅仅投屏