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

1. LCD 如何显示一张图片?

假如下图是是我们的 JZ2440 开发板,它有一个块显存、LCD控制器、LCD显示屏,LCD是如何显示张图片的呢?

如上图所示:

  • ① 图片的颜色数据存放在显存,LCD 控制器会自动从显存取出图片的一个个颜色数据发送给LCD,取到最后又从头开始的循环取数据,最终把一张图片的全部颜色数据发送到LCD上,从而在LCD显示出该图片;
  • ② 显存存放的数据是RGB数据;
  • ③ RGB数据:由R(红)、G(绿)、蓝(B)三种颜色数据组成,每一种RGB数据代表一种颜色;
  • ④ 我们通常得到的图片是 jpg 格式的图片,它是一种压缩的图片,但图片的损失很少,我们几乎看不出来,因此jgp格式的图片在我们的生活中大量使用。

2. jpg 格式的图片如何在LCD显示?

  • (1) 把 jpg 格式的图片解压出 RGB 原始数据(实际上bmp格式的图片存放的就是RGB原始数据);

  • (2) 如何解压?使用libjpeg库,libjpeg库是使用C语言实现的读写 jpeg 文件的库,使用 libjpeg 的应用程序是以 “scanline” 为单位进行图像处理的;

  • (3) libjpeg 库 jpeg 解压的操作:

    • ① 分配和初始化一个decompression结构体;
    • ② 指定源文件;
    • ③ 调用jpeg_read_header获取jpg头部信息;
    • ④ 设置解压参数,比如放大、缩小;
    • ⑤ 启动解压:jpeg_start_decompress(...)
    • ⑥ 循环调用 jpeg_read_scanlines(...)
    • ⑦ 循环结束后,调用 jpeg_finish_decompress(...)
    • ⑧ 释放 decompression 结构体;
  • (4) jpeg 数据格式:libjpeg 处理的图片一般是一个矩形,如下图所示,矩形里面是一行一行的数据,每一行数据称为 scanline;每行数据里是一个个的像素,每个像素值包含:component (对于 RGB 值则有 3 个 component,对于灰度值则只有 1 个 component);

  • ⑤ libjpeg 压缩:即是把上图的二维数据压缩成 jpeg 图片;解压:即是把 jpeg 图片恢复成上图的二维数组;

3. libjpeg 库安装

本人的 libjpeg 是使用 buildroot 编译的,然后再把 libjpeg 对应的库和头文件复制到系统的 arm-linux-gcc 检查工具链里的,具体操作,可以查看本人博客:Buildroot 移植 libjpeg 到 Jz2440。

4. 编写程序

(1) 打印获取到的图片的信息,代码如下:(参考 libjpeg 库里的 example.txt 和 libjpeg.txt 里的 jpg 图片解码章节)

#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>/* 1.分配和初始化一个decompression结构体* 2.指定源文件* 3.调用jpeg_read_header获取jpg头部信息* 4.设置解压参数,比如放大、缩小* 5.启动解压:jpeg_start_decompress(...)* 6.循环调用jpeg_read_scanlines(...)* 7.循环结束后,调用jpeg_finish_decompress(...)* 8.释放decompression结构体*//** Usage: jpeg2rgb <jpg_file>*/
int main(int argc, char **argv)
{struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;FILE *infile;/* 1.分配和初始化一个decompression结构体 */cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);/* 2.指定源文件 */if ((infile = fopen(argv[1], "rb")) == NULL) {fprintf(stderr, "can't open %s\n", argv[1]);return -1;}jpeg_stdio_src(&cinfo, infile);/* 3.调用jpeg_read_header获取jpg头部信息 */jpeg_read_header(&cinfo, TRUE);/* 源信息 */printf("image_with = %d\n", cinfo.image_width);printf("image_height = %d\n", cinfo.image_height);printf("num_components = %d\n", cinfo.num_components);/* 4.设置解压参数,比如放大、缩小  *//*  5.启动解压:jpeg_start_decompress(...) */jpeg_start_decompress(&cinfo);/* 输出的图像信息 */printf("output_width = %d\n", cinfo.output_width);printf("output_height = %d\n", cinfo.output_height);printf("output_components = %d\n", cinfo.output_components);/* 6.循环调用jpeg_read_scanlines(...)来一行一行地获得解压数据 *//* 7.循环结束后,调用jpeg_finish_decompress(...) */jpeg_finish_decompress(&cinfo);/* 8.释放decompression结构体 */jpeg_destroy_decompress(&cinfo);return 0;
}

使用 arm-linux-gcc 编译之后,拷贝到开发板运行:./jpeg2rgb 1.jpg (注:1.jpg 是一张 800 * 600 像素的 jpg 格式的图片),运行结果如下图所示:

(2) 图片放缩:获取到 jpg 格式的图片后,我们需要设置图片的缩放因子,jpeg_decompress_struct 结构体有两个成员变量是关于设置图片缩放因子的:scale_num、scale_denom,缩放因子 = scale_num/scale_denom。这里我们通过标准输入设置图片的缩放因子,代码如下:

#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>/* 1.分配和初始化一个decompression结构体* 2.指定源文件* 3.调用jpeg_read_header获取jpg头部信息* 4.设置解压参数,比如放大、缩小* 5.启动解压:jpeg_start_decompress(...)* 6.循环调用jpeg_read_scanlines(...)* 7.循环结束后,调用jpeg_finish_decompress(...)* 8.释放decompression结构体*//** Usage: jpeg2rgb <jpg_file>*/
int main(int argc, char **argv)
{struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;FILE *infile;/* 1.分配和初始化一个decompression结构体 */cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);/* 2.指定源文件 */if ((infile = fopen(argv[1], "rb")) == NULL) {fprintf(stderr, "can't open %s\n", argv[1]);return -1;}jpeg_stdio_src(&cinfo, infile);/* 3.调用jpeg_read_header获取jpg头部信息 */jpeg_read_header(&cinfo, TRUE);/* 源信息 */printf("image_with = %d\n", cinfo.image_width);printf("image_height = %d\n", cinfo.image_height);printf("num_components = %d\n", cinfo.num_components);/* 4.设置解压参数,比如放大、缩小(需要设置连个参数:scale_num, scale_denom)* 缩放因子:scale_num/scale_denom*/printf("enter M/N:\n");scanf("%d/%d",&cinfo.scale_num, &cinfo.scale_denom);printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);/*  5.启动解压:jpeg_start_decompress(...) */jpeg_start_decompress(&cinfo);/* 输出的图像信息 */printf("output_width = %d\n", cinfo.output_width);printf("output_height = %d\n", cinfo.output_height);printf("output_components = %d\n", cinfo.output_components);/* 6.循环调用jpeg_read_scanlines(...)来一行一行地获得解压数据 *//* 7.循环结束后,调用jpeg_finish_decompress(...) */jpeg_finish_decompress(&cinfo);/* 8.释放decompression结构体 */jpeg_destroy_decompress(&cinfo);return 0;
}

程序编译之后,拷贝到开发板运行:./jpeg2rgb_scale 1.jpg ,然后输入不同的缩放因子,观察输出的结果,如下图所示:

从上图可以看出,并不支持所有的缩放比例,例如上图的 1/5 缩放比例,输出的结果并不对应。在 libjpeg.txt 也有相关的说明,如下图所示:

(3) 在 LCD 显示 jpg 格式的图片:在上一个程序的基础上,我们添加 LCD 显示部分的代码,由于 libjpeg 解压 jpg 格式图片时是一行一行的处理图片的像素的,所以,我么需要编写一个 LCD 显示一行像素的函数,函数如下:

/* iXStart: 一行的x的起始坐标* iXEnd:一行的x的结束坐标* iY:一行的y坐标* pucRGBArray:一行像素的buffer指针*/
static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray)
{int i = iXStart * 3;int iX;unsigned int dwColor;if(iY >= g_tVar.yres)return -1;if(iXStart >= g_tVar.xres)return -1;if(iXEnd >= g_tVar.xres){iXEnd = g_tVar.xres;}for (iX = iXStart; iX < iXEnd; iX++){/* 0xRRGGBB */dwColor = (pucRGBArray[i] << 16) | (pucRGBArray[i+1] << 8) | pucRGBArray[i+2];i += 3;FBShowPixel(iX, iY, dwColor);}return 0;
}

LCD 显示 jpg 格式的图片的整体代码如下:

#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>
#include <stdlib.h>#define FB_DEVICE_NAME  "/dev/fb0"
#define DBG_PRINTF      printfstatic int g_iFBFb;
static struct fb_var_screeninfo g_tVar;
static struct fb_fix_screeninfo g_tFix;
static unsigned int g_dwScreenSize;
static unsigned char *g_pucFbMem;
static int g_iLineWidth;
static int g_iPixelWidth;static int FBDeviceInit(void)
{int ret;g_iFBFb = open(FB_DEVICE_NAME, O_RDWR);if (g_iFBFb < 0){DBG_PRINTF("can't open %s\n", FB_DEVICE_NAME);return -1;}ret = ioctl(g_iFBFb, FBIOGET_VSCREENINFO, &g_tVar);if (ret < 0){DBG_PRINTF("can't get fb's var\n");return -1;}ret = ioctl(g_iFBFb, FBIOGET_FSCREENINFO, &g_tFix);if (ret < 0){DBG_PRINTF("can't get fb's fix\n");return -1;}g_dwScreenSize = g_tVar.xres * g_tVar.yres * g_tVar.bits_per_pixel / 8;g_iLineWidth   = g_tVar.xres * g_tVar.bits_per_pixel / 8;g_iPixelWidth  = g_tVar.bits_per_pixel / 8;g_pucFbMem = (unsigned char *)mmap(NULL, g_dwScreenSize, PROT_READ | PROT_WRITE, MAP_SHARED, g_iFBFb, 0);if (g_pucFbMem == (unsigned char*)-1){DBG_PRINTF("can't mmap\n");return -1;}  return 0;
}static int FBShowPixel(int iPenX, int iPenY, unsigned int dwColor)
{unsigned char  *pucPen8 = g_pucFbMem + iPenY * g_iLineWidth + iPenX * g_iPixelWidth;unsigned short *pwPen16;unsigned int   *pdwPen32;int iRed, iGreen, iBlue;pwPen16  = (unsigned short *)pucPen8;pdwPen32 = (unsigned int *)pucPen8;switch(g_tVar.bits_per_pixel){case 8:  {*pucPen8 = dwColor; /*对于8BPP:color 为调色板的索引值,其颜色取决于调色板的数值*/break; }case 16:{iRed   = (dwColor >> 16) & 0xff;iGreen = (dwColor >> 8)  & 0xff;iBlue  = (dwColor >> 0)  & 0xff;dwColor = ((iRed >> 3) << 11) | ((iGreen >> 2) << 5) | (iBlue >> 3); /*格式:RGB565*/*pwPen16 = dwColor;break;}case 32: {*pdwPen32 = dwColor;break;}default:{DBG_PRINTF("can't surport %dbpp", g_tVar.bits_per_pixel);return -1;break;}}return 0;
}static int FBCleanScreen(unsigned int dwBackColor)
{unsigned char  *pucPen8 = g_pucFbMem;unsigned short *pwPen16;unsigned int   *pdwPen32;int iRed, iGreen, iBlue;int i = 0;pwPen16  = (unsigned short *)pucPen8;pdwPen32 = (unsigned int *)pucPen8;switch(g_tVar.bits_per_pixel){case 8:  {memset(pucPen8, dwBackColor, g_dwScreenSize);break; }case 16:{iRed = (dwBackColor >> 16) & 0xff;iGreen = (dwBackColor >> 8)  & 0xff;iBlue    = (dwBackColor >> 0)  & 0xff;dwBackColor = ((iRed >> 3) << 11) | ((iGreen >> 2) << 5) | (iBlue >> 3); /*格式:RGB565*/while (i < g_dwScreenSize){*pwPen16 = dwBackColor;pwPen16++;i += 2;//DBG_PRINTF("g_dwScreenSize:%d\n", g_dwScreenSize);}break;}case 32: {while (i < g_dwScreenSize){*pdwPen32 = dwBackColor;pdwPen32++;i += 4;}break;}default:{DBG_PRINTF("can't surport %dbpp", g_tVar.bits_per_pixel);return -1;break;}}return 0;
}/* 具体实现前面已有代码 */
static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray)
{...
}/* 1.分配和初始化一个decompression结构体* 2.指定源文件* 3.调用jpeg_read_header获取jpg头部信息* 4.设置解压参数,比如放大、缩小* 5.启动解压:jpeg_start_decompress(...)* 6.循环调用jpeg_read_scanlines(...)* 7.循环结束后,调用jpeg_finish_decompress(...)* 8.释放decompression结构体*//** Usage: jpeg2rgb <jpg_file>*/
int main(int argc, char **argv)
{struct jpeg_decompress_struct cinfo;struct jpeg_error_mgr jerr;FILE *infile;int row_stride;unsigned char *buffer;/* fb 设备初始化 */if (0 != FBDeviceInit()){DBG_PRINTF("FBDeviceInit error\n");return -1;}/* 清屏 */FBCleanScreen(0);/* 1.分配和初始化一个decompression结构体 */cinfo.err = jpeg_std_error(&jerr);jpeg_create_decompress(&cinfo);/* 2.指定源文件 */if ((infile = fopen(argv[1], "rb")) == NULL) {fprintf(stderr, "can't open %s\n", argv[1]);return -1;}jpeg_stdio_src(&cinfo, infile);/* 3.调用jpeg_read_header获取jpg头部信息 */jpeg_read_header(&cinfo, TRUE);/* 源信息 */printf("image_with = %d\n", cinfo.image_width);printf("image_height = %d\n", cinfo.image_height);printf("num_components = %d\n", cinfo.num_components);/* 4.设置解压参数,比如放大、缩小(需要设置连个参数:scale_num, scale_denom)* 缩放因子:scale_num/scale_denom,下面的设置为缩小1/2*/printf("enter M/N:\n");scanf("%d/%d",&cinfo.scale_num, &cinfo.scale_denom);printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);/*  5.启动解压:jpeg_start_decompress(...) */jpeg_start_decompress(&cinfo);/* 输出的图像信息 */printf("output_width = %d\n", cinfo.output_width);printf("output_height = %d\n", cinfo.output_height);printf("output_components = %d\n", cinfo.output_components);/* 一行的数据长度 */row_stride = cinfo.output_width * cinfo.output_components;buffer = (unsigned char *)malloc(row_stride);/* 6.循环调用jpeg_read_scanlines(...)来一行一行地获得解压数据 */while (cinfo.output_scanline < cinfo.output_height) {(void)jpeg_read_scanlines(&cinfo, &buffer, 1);FBShowLine(0, cinfo.output_width, cinfo.output_scanline, buffer);}/* 7.循环结束后,调用jpeg_finish_decompress(...) */jpeg_finish_decompress(&cinfo);/* 8.释放decompression结构体 */jpeg_destroy_decompress(&cinfo);free(buffer);return 0;
}

程序编译成功后,在开发板运行:./jpeg2rgb_lcd 1.jpg ,然后输入 1/2 的缩放因子,显示结果如下图所示:

输入 1/4 的缩放因子,显示结果如下图所示:

数码相框(十六、LCD显示JPG格式图片)相关推荐

  1. 【数字图像处理】一.MFC详解显示BMP格式图片

    本文主要是讲述<数字图像处理>系列栏目中的第一篇文章.主要详细介绍了BMP图片格式,同时使用C++和MFC显示BMP格式,主要结合自己的<数字图像处理>课程和以前的项目叙述讲解 ...

  2. MFC详解显示BMP格式图片

    本文主要是讲述<数字图像处理>系列栏目中的第一篇文章.主要详细介绍了BMP图片格式,同时使用C++和MFC显示BMP格式,主要结合自己的<数字图像处理>课程和以前的项目叙述讲解 ...

  3. Qt显示wmf格式图片

    Qt显示wmf格式图片         夸平台的Qt不并不支持Auto CAD的输出图wmf.那么怎么才能在Qt下显示wmf格式图片呢?智能用win32 api了.具体过程下面一一介绍.        ...

  4. 占20列用c语言怎么表示,十六万的数字格式怎么写

    1.数字十六进制怎么写 一.常用数制及其相互转换 在我们的日常生活中计数采用了多种记数制,比如:十进制,六十进制(六十秒为一分,六十分为一小时,即基数为60,运算规则是逢六十进一),--. 在计算机中 ...

  5. OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移、缩放和旋转操作

    OpenCasCade学习笔记(三):加载显示STEP格式图片,并实现平移.缩放和旋转操作 C3DWidget.h #pragma once#include <QtWidgets/QApplic ...

  6. 数码相框(三、LCD显示文字)

    注:本人已购买韦东山第三期项目视频,内容来源<数码相框项目视频>,只用于学习记录,如有侵权,请联系删除.     文字在LCD上的显示其实就是LCD上的一些点的显示与不显示,这些显示的点就 ...

  7. osd 显示 png格式图片水印

    最近做音视频项目需要做水印,且提供的水印为png格式图片,通过学习和尝试,终于解决.osd需要的是显示内容的数据,其核心就是将png图片解码成一系列数据. 解码库版本:libpng-1.6.35 1. ...

  8. webp图片在html上显示,WebP 格式图片在实际项目中的使用方式

    一.前言 关于 WebP 的支持情况,以及适用场景此处不做详细说明,具体见官方文档. 先说结论,目前 WebP 支持情况占比较大(数据如下),在适合的场景下可以使用 WebP 格式图片来提高页面加载速 ...

  9. 学习QT之显示SVG格式图片

    SVG的英文全称是Scalable Vector Graphics,即可缩放的矢量图形.它是有万维网联盟在2000年8月制定的一种新的二维矢量图形格式,也是规范中的网格矢量图形标准,是一个开发的图形标 ...

  10. Qt5开发从入门到精通——第六篇四节( 图像与图片——显示SVG格式图片 )

    欢迎小伙伴的点评✨✨,相互学习.互关必回.全天在线

最新文章

  1. seal report mysql_Seal Report开放数据库报表工具(.Net)
  2. Linux之cp和mv命令选项
  3. OOP设计模式[JAVA]——03职责链模式
  4. resiprocate之message
  5. 进阶10 补充知识点
  6. java处理日期时间代码
  7. Android Studio - 安装插件GsonFormat
  8. Point to Raster 工作原理
  9. 软件开发全生命周期安全管理规范--模板
  10. DOS攻击之Synflood攻击
  11. 1.Spring注解01、组件注册-@Configuration@Bean给容器中注册组件
  12. 依图科技暑期实习生面试经验
  13. 数据分析师,如何向亲友解释自己的工作
  14. LNMP架构部署详细步骤
  15. 【C语言】函数详解(入门到进阶)
  16. 手机python怎么画图_无所不能的python编程是怎么快速画图的呢?5分钟学会!
  17. 将王者荣耀头像设置成和微信头像不一样
  18. Linux 高并发服务器实战 - 2 Linux多进程开发
  19. 基于ANFIS的有色噪声抵消技术
  20. MATLAB超宽带通信技术,基于ADS和Matlab的超宽带低噪声放大器的频带选择性设计

热门文章

  1. FaShop-开源拖拽式小程序搭建平台
  2. 条件期望,重期望,相关知识点
  3. win10误删的注册表能还原吗_win10恢复系统注册表,win10删除注册表怎么还原
  4. 太可怕了!有些码农为啥写代码,写到监狱里去了?
  5. 通俗易懂的Spatial Transformer Networks(STN)(二)
  6. U盘启动盘cmd制作
  7. ice php 5.6.32,PHP通过ice调用python程序
  8. qt超级马里奥_探索《超级马里奥》 35周年选集
  9. 微软Win8Server2012各版本安装密匙序列号
  10. 外键的约束(Mysql、PostgreSQL)