准备
1.开发板(支持帧缓冲'fb'的linux系统)
2.开发板需要的显示器
3.libjpeg源代码
4.jpeg.c源代码
我的环境
开发板:这里我使用的是安装了官方镜像的树莓派3b+
显示器:之前和树莓派一起买的HDMI支持触屏的小型显示器
libjpeg:我使用的版本为老师提供的jpegsrc.v9d.tar.gz libjpeg下载地址
jpeg.c:搜索下载或直接点击jpeg.c下载地址蓝奏云不支持c格式,故文件名改为jpeg.c.txt,使用前请自行修改文件名。
文件路径:将'jpegsrc.v9d.tar.gz'和'jpeg.c'统一放在'/home/c_project/img/',路径请保持一致或者自行修改Makefile。
如图所示:
显示器:之前和树莓派一起买的HDMI支持触屏的小型显示器
libjpeg:我使用的版本为老师提供的jpegsrc.v9d.tar.gz libjpeg下载地址
jpeg.c:搜索下载或直接点击jpeg.c下载地址蓝奏云不支持c格式,故文件名改为jpeg.c.txt,使用前请自行修改文件名。
文件路径:将'jpegsrc.v9d.tar.gz'和'jpeg.c'统一放在'/home/c_project/img/',路径请保持一致或者自行修改Makefile。
如图所示:

安装libjpeg
# 切换为root
sudo -i
# 下载jpegsrc.v9d.tar.gz到'/home/c_project/img/'
# 解压
tar -xvf jpegsrc.v9d.tar.gz
# 进入解压文件夹
cd jpeg-9d
# 设置为交叉编译器(根据自己的系统环境选择,同时修改Makefile)
./configure --host=arm-linux-gnueabihf
# 编译
make
# 安装
make install
编写代码
设计思路:
1.屏幕显示像素点
2.屏幕显示图片
3.图片全屏缩放
4.设计图片显示风格
5.设置循环播放
6.设置随机风格
过程省略,代码如下:
// 请命名为fb.c,或自行修改Makefile。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
unsigned char *decode_jpeg(char *filename, short *w, short *h);
int PicZoom(unsigned char *ptOriginPic_aucPixelDatas, unsigned int ptOriginPic_iWidth, unsigned int ptOriginPic_iHeight, unsigned char *ptZoomPic_aucPixelDatas, unsigned int ptZoomPic_iWidth, unsigned int ptZoomPic_iHeight);
int w, h, k;
int *fb_mem;
int style_id = 1;
int rand_len = 6;
// 注意:这里设置了6张图片1-6.jpg
// 同时对应使用6种显示风格(见main函数)
int rand_id[6] = {2, 5, 3, 6, 4, 1};
int init_fb()
{
struct fb_var_screeninfo fb_var;
int fd = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
printf("open fb0 error\n");
return -1;
}
ioctl(fd, FBIOGET_VSCREENINFO, &fb_var);
w = fb_var.xres;
h = fb_var.yres;
k = fb_var.bits_per_pixel;
//printf("framebuffer: %d * %d | %d\n", w, h ,k);
fb_mem = mmap(0, w * h * k / 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return 0;
}
void fb_point(int x, int y, int color)
{
fb_mem[y * w + x] = color;
}
/**
* 全屏缩放图片数据流
*/
unsigned char *full_jpeg_buf(char *filename, short *img_w, short *img_h)
{
// ! new 1
unsigned char *buf24 = decode_jpeg(filename, img_w, img_h);
// ! new 2
unsigned char *new_buf = malloc(w * h * 3);
if (new_buf == NULL)
{
printf("malloc申请空间失败!\n");
return NULL;
}
// 缩放图片
if (PicZoom(buf24, *img_w, *img_h, new_buf, w, h))
{
printf("图片缩放失败!\n");
return NULL;
}
// ! free 1
free(buf24);
buf24 = NULL;
return new_buf;
}
/**
* 图片全屏显示风格
*/
void full_show_style(unsigned char *ptr)
{
unsigned char *tmp = ptr;
int x, y, color;
int i;
if (style_id == 1)
{ // 纵向交叉
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
if (x < w / 8 ||
(x >= w * 2 / 8 && x < w * 3 / 8) ||
(x >= w * 4 / 8 && x < w * 5 / 8) ||
(x >= w * 6 / 8 && x < w * 7 / 8))
{
tmp = ptr + 3 * (y * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, y, color);
}
else
{
tmp = ptr + 3 * ((h - y - 1) * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, h - y - 1, color);
}
}
usleep(3000);
}
}
else if (style_id == 2)
{ // 横向交叉
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
if (y < h / 8 ||
(y >= h * 2 / 8 && y < h * 3 / 8) ||
(y >= h * 4 / 8 && y < h * 5 / 8) ||
(y >= h * 6 / 8 && y < h * 7 / 8))
{
tmp = ptr + 3 * (y * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, y, color);
}
else
{
tmp = ptr + 3 * (y * w + w - x - 1);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(w - x - 1, y, color);
}
}
usleep(3000);
}
}
else if (style_id == 3)
{ // 纵向百叶 y < h/8
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{
for (i = 0; i < 8; i++)
{
if (y + i * h / 8 < h)
{
tmp = ptr + 3 * ((y + i * h / 8) * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, y + i * h / 8, color);
}
else
{
return;
}
}
}
usleep(8 * 3000);
}
}
else if (style_id == 4)
{ // 横向百叶 x < w/8
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
for (i = 0; i < 8; i++)
{
if (x + i * w / 8 < w)
{
tmp = ptr + 3 * (y * w + x + i * w / 8);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x + i * w / 8, y, color);
}
else
{
return;
}
}
}
usleep(8 * 3000);
}
}
else if (style_id == 5)
{ // 纵向过渡交叉
for (y = 0; y < h; y++)
{
for (x = 0; x < w; x++)
{ //2y
if (2 * y < h)
{
tmp = ptr + 3 * (2 * y * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, 2 * y, color);
}
//2y+1
if (2 * y + 1 < h)
{
tmp = ptr + 3 * ((h - 2 * y - 1) * w + x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(x, h - 2 * y - 1, color);
}
}
usleep(2 * 3000);
}
}
else if (style_id == 6)
{ // 横向过渡交叉
for (x = 0; x < w; x++)
{
for (y = 0; y < h; y++)
{
//2x
if (2 * x < w)
{
tmp = ptr + 3 * (y * w + 2 * x);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(2 * x, y, color);
}
//2x+1
if (2 * x + 1 < w)
{
tmp = ptr + 3 * (y * w + w - 2 * x - 1);
color = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2];
fb_point(w - 2 * x - 1, y, color);
}
}
usleep(2 * 3000);
}
}
}
/**
* 全屏输出图片
*/
void display_jpeg_full(char *filename)
{
short img_w, img_h;
unsigned char *buf24 = full_jpeg_buf(filename, &img_w, &img_h);
full_show_style(buf24);
// ! free 2
free(buf24);
buf24 = NULL;
}
/**
* 内存拷贝函数
*/
void *my_memcpy(void *v_dst, const void *v_src, unsigned char c)
{
const char *src = v_src;
char *dst = v_dst;
while (c--)
*dst++ = *src++;
return v_dst;
}
/**********************************************************************
* 函数名称:PicZoom(参考:https://blog.csdn.net/xiaolong1126626497/article/details/107944138)
* 功能描述:近邻取样插值算法缩放图片
* !注意:分配内存存放缩放图片,用完后要用free释放
* 输入参数:ptOriginPic - 原始图片数据
* ptZoomPic - 缩放后的图片数据
***********************************************************************/
int PicZoom(unsigned char *ptOriginPic_aucPixelDatas, unsigned int ptOriginPic_iWidth, unsigned int ptOriginPic_iHeight, unsigned char *ptZoomPic_aucPixelDatas, unsigned int ptZoomPic_iWidth, unsigned int ptZoomPic_iHeight)
{
unsigned int ptOriginPic_iLineBytes = ptOriginPic_iWidth * 3; //一行的字节数
unsigned int ptZoomPic_iLineBytes = ptZoomPic_iWidth * 3; //一行的字节数
unsigned long dwDstWidth = ptZoomPic_iWidth;
unsigned long *pdwSrcXTable;
unsigned long x;
unsigned long y;
unsigned long dwSrcY;
unsigned char *pucDest;
unsigned char *pucSrc;
unsigned long dwPixelBytes = 3; //像素字节
pdwSrcXTable = malloc(sizeof(unsigned long) * dwDstWidth);
if (NULL == pdwSrcXTable)
{
return -1;
}
for (x = 0; x < dwDstWidth; x++) //生成表 pdwSrcXTable
{
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++)
{
my_memcpy(pucDest + x * dwPixelBytes, pucSrc + pdwSrcXTable[x] * dwPixelBytes, dwPixelBytes);
}
}
free(pdwSrcXTable);
return 0;
}
/**
* Int2String ( 10进制正整数 )
* 参考:https://blog.csdn.net/nanfeibuyi/article/details/80811498
*/
char *Int2String(int num, char *str)
{
int i = 0;
do
{
str[i++] = num % 10 + 48;
num /= 10;
} while (num);
str[i] = '\0';
int j = 0;
for (; j < i / 2; j++)
{
str[j] = str[j] + str[i - j - 1];
str[i - j - 1] = str[j] - str[i - j - 1];
str[j] = str[j] - str[i - j - 1];
}
return str;
}
/**
* 交换数组元素模拟随机数
*/
void swap(int *arr, int l_id, int r_id)
{
int max = rand_len - 1;
if (l_id == r_id)
{
r_id = r_id == max ? 1 : r_id + 1;
}
int temp = arr[l_id];
arr[l_id] = arr[r_id];
arr[r_id] = temp;
temp = arr[max - l_id];
arr[max - l_id] = arr[max - r_id];
arr[max - r_id] = temp;
}
int main(int argc, char *argv[])
{
init_fb();
int img_id = 1;
while (1)
{
srand((unsigned)time(NULL));
char filename[20] = {0};
//img_id = rand() % 7 + 1; // 1.jpg - 7.jpg
Int2String(img_id, filename);
char *str2 = ".jpg";
int len1 = strlen(filename);
int len2;
for (len2 = 0; len2 < 4; ++len2)
{
filename[len1 + len2] = str2[len2];
}
// 设置style 1-6
// style_id = rand() % 6 + 1;
style_id = rand_id[img_id-1];
// printf("style_id:%d\n",style_id);
display_jpeg_full(filename);
if (++img_id == 7){
img_id = 1;
swap(rand_id, rand() % rand_len, rand() % rand_len);
}
sleep(3);
}
return 0;
}
编写Makefile编译脚本
注意:缩进必须使用tab,设置CC为系统对应的交叉编译器
CC=arm-linux-gnueabihf-gcc
CFLAGS=-I /home/c_project/img/jpeg-9d
LDFLAGS=-L /home/c_project/img/jpeg-9d/.libs
all:fb
fb:fb.o jpeg.o
$(CC) -o fb fb.o jpeg.o $(LDFLAGS) -ljpeg -static
clean:
rm fb *.o -rf
运行fb
# 编译全部生成fb
make fb
# 运行fb(运行前请确认目录含有1-6.jpg)
./fb
# 清除生成文件
make clean