准备
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)
# 比如使用交叉编译器 arm-none-linux-gnueabi-gcc
./configure --host=arm-linux-gnueabihf
# 编译
make
# 安装
make install
编写代码
设计思路:
1.屏幕显示像素点
2.屏幕显示图片
3.图片全屏缩放
4.设计图片显示风格
5.设置循环播放
6.设置随机风格
7.添加汉字摘要(更新补充,需要HZK16文件)
过程省略,代码如下:
// 请命名为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; //进程空间中帧缓冲的起始地址
unsigned char *hzk_mem; //进程空间中汉字字符集的起始地址
//需要输出的汉字的GBK编码,仅作示范1234321
unsigned char str1[7][2] = {{0xD2, 0xBC}, {0xB7, 0xA1}, {0xC8, 0xFE}, {0xCB, 0xC1}, {0xC8, 0xFE}, {0xB7, 0xA1}, {0xD2, 0xBC}};
int style_id = 1;
int rand_len = 6;
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", w, h ,k);
fb_mem = mmap(0, w * h * k / 8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return 0;
}
int init_hzk()
{
struct stat hzk_stat;
int fd_hzk;
fd_hzk = open("HZK16", O_RDONLY);
if (fd_hzk < 0)
{
printf("open hzk error\n");
return -1;
}
if (fstat(fd_hzk, &hzk_stat))
{
printf("cannot get hzkstat");
return -1;
}
hzk_mem = mmap(0, hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk, 0); //申请汉字的映射空间
return 0;
}
void fb_point(int x, int y, int color)
{
fb_mem[y * w + x] = color;
}
void alpha_point(int x, int y, int color, double a) //实现颜色的层叠,a (0,1) 表示背景的颜色深度 0为无背景
{
int bcolor;
int fr, fg, fb;
int br, bg, bb;
int ar, ag, ab;
//get bcolor
bcolor = fb_mem[y * w + x]; //获取(y,x)该点的背景颜色
/*获取背景颜色的RGB分量*/
br = (bcolor >> 16) & 0xff;
bg = (bcolor >> 8) & 0xff;
bb = (bcolor)&0xff;
/*获取需要叠加颜色的RGB分量*/
fr = (color >> 16) & 0xff;
fg = (color >> 8) & 0xff;
fb = (color)&0xff;
ar = (int)(br * a + fr * (1 - a));
ag = (int)(bg * a + fg * (1 - a));
ab = (int)(bb * a + fb * (1 - a));
fb_point(x, y, ab | (ag << 8) | (ar << 16)); //从新绘制该点
}
//在起始坐标(x,y)绘制粗体汉字(字符串),d为加粗的倍数(默认为2),w为放大的倍数(默认为2), a 为汉字的透明程度
void show_chineseDouble(int x, int y, unsigned char my_str[][2], int color, int d, int w, double a)
{
int i;
int X = x;
int Y = y;
for (i = 0; i < 7; i++)
{
unsigned int area = my_str[i][0] - 0xa1; //区号
unsigned int where = my_str[i][1] - 0xa1; //位号
unsigned char *dots = hzk_mem + (area * 94 + where) * 32; //基地址+偏移量
unsigned char byte; //一个汉字点阵占32个字节(16×16)的点阵
int i, j, b, m, n;
for (i = 0; i < 16; i++)
{ //点阵行
for (j = 0; j < 2; j++)
{ //点阵列
byte = dots[i * 2 + j];
for (b = 7; b >= 0; b--)
{
if (byte & (1 << b))
{
/* show 加粗显示*/
for (m = 0; m < d; m++)
{
for (n = 0; n < d; n++)
{
alpha_point((X + (7 - b + j * 8) * w) + m, (Y + i * w) + n, color, a); //以半透明的方式打印汉字
}
}
}
}
}
}
X += 16 * w + 20; //按照行来显示,中间空20个pixs
Y += 0;
}
}
/**
* 全屏缩放图片数据流
*/
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;
unsigned char r, g, b;
int x, y, color;
int i, j;
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
* 功能描述:近邻取样插值方法算法缩放图片
* ! 注意:分配内存存放缩放图片,用完后要用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进制正整数 )
*/
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();
init_hzk(); //加载汉字库
int img_id = 1;
int i;
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);
for (i = 0; i < 4; ++i)
{
filename[len1 + i] = str2[i];
}
// 设置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);
//显示汉字摘要
//show_chineseDouble(100, 100, str1, 0xff0000, 2, 2, 0.5);
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