Linux应用程--BMP与JPG格式图片解码
文章摘要: 本文主要描述了BMP/JPG解码及显示的示例。
操作系统: Debian
BMP数据结构:
// BMP文件头(54字节),其中文件头14字节,图像信息40字节
#pragma pack(1) //设置内存按照1个字节对齐
typedef struct
{
char bfType[2]; // 00 文件类型: 固定为BM
uint32_t bfSize; // 02 文件大小:单位字节
uint16_t bfReserved1; // 06 保留字段
uint16_t bfReserved2; // 08 保留字段
uint32_t bfOffBits; // 10 数据偏移
uint32_t biSize; // 14 信息结构长度
uint32_t biWidth; // 18 图像宽度
uint32_t biHeight; // 22 图像高度
uint16_t biPlanes; // 26 颜色面板数(总是为1)
uint16_t biBitCount; // 28 像素位数
uint32_t biCompression; // 30 压缩格式
uint32_t biSizeImage; // 34 图像内容大小
uint32_t biXPelsPerMeter; // 38 水平分辨率 像素/米
uint32_t biYPelsPerMeter; // 42 竖直分辨率 像素/米
uint32_t biClrUsed; // 46 调色板数量
uint32_t biClrImportant; // 50 关键色彩数
} BITMAPINFOHEADER, bmp_info_t;
#pragma pack()
BMP文件解析:
bmp_info_t* bmp_info = (void*)&buff[0];
// 正常情况是读出54个字节
fread(buff, 54, 1, fp);
dump_data(buff, 54);
printf("文件类型: %c%c\r\n", bmp_info->bfType[0], bmp_info->bfType[1]);
printf("文件大小: %d 字节\r\n", bmp_info->bfSize);
printf("数据偏移: %d\r\n", bmp_info->bfOffBits);
printf("信息长度: %d\r\n", bmp_info->biSize);
printf("图像尺寸: %dx%d\r\n", bmp_info->biWidth, bmp_info->biHeight);
printf("像素位数: %d bits\r\n", bmp_info->biBitCount);
printf("压缩格式: %d\r\n", bmp_info->biCompression);
printf("图像内容: %d 字节\r\n", bmp_info->biSizeImage);
printf("分 辨 率: %d,%d\r\n", bmp_info->biXPelsPerMeter, bmp_info->biXPelsPerMeter);
printf("调色板数: %d\r\n\r\n", bmp_info->biClrUsed);
// 如果文件头大于54个字节,需要读出其他数据
if(bmp_info->bfOffBits > 54)
{
fread(buff, bmp_info->bfOffBits - 54, 1, fp);
}
// 申请读取一行数据需要的内存
int line_size = bmp_info->biWidth * bmp_info->biBitCount / 8;
// BMP文件和每行长度必须以4字节对齐,不足部分填充0,所以必须全部读出来
// 否则显示会错位
line_size = (line_size + 3 )/ 4 * 4;
char *pline = malloc(line_size);
if (pline == NULL)
{
perror("内存分配失败");
exit(-2);
}
//----------------------------
int xcnt;
int ycnt;
int offset; // 偏移
char *p2;
char *p3;
// 屏幕和图像尺寸取最小值
xcnt = (bmp_info->biWidth < vinfo.xres)?bmp_info->biWidth :vinfo.xres;
ycnt = (bmp_info->biHeight < vinfo.yres)?bmp_info->biHeight:vinfo.yres;
while (ycnt--)
{
// 从文件中读一行数据出来
fread((char *)pline, 1, line_size, fp);
// 计算偏移值
offset = (ycnt) * finfo.line_length;
p2 = (char *)(pfb + offset);
p3 = pline;
for (j = 0; j < xcnt; j++)
{
*p2++ = *p3++; // 先按24bit显示
*p2++ = *p3++;
*p2++ = *p3++;
*p2++ = 0;
}
}
JPG图像解码:
需要添加libjpeg-dev支持;
编译选项:-ljpeg
// 指定图片的路径就可以调用这个jpg的解析
// output_width: 图像的输出宽度
// output_height: 图像的输出高度
// output_component: 每个像素的分量数,也即字节数(3或4字节)
int jpg_display(char *path)
{
// 1. 分配并初始化一个jpeg解压对象
struct jpeg_decompress_struct dinfo;
struct jpeg_error_mgr jerr; // 错误变量
dinfo.err = jpeg_std_error(&jerr); //
jpeg_create_decompress(&dinfo); // 初始化
// 2. 打开JPG图像文件
FILE *infile;
infile = fopen(path, "r");
if (infile == NULL)
{
perror("fopen error");
return -1;
}
jpeg_stdio_src(&dinfo, infile); //为解压对象dinfo指定要解压的文件
// 3. 获取图像信息
jpeg_read_header(&dinfo, TRUE);
//-------------------------------------------------
// 4. 设置jpeg解压缩对象dinfo的一些参数,可采用默认参数
//-------------------------------------------------
// 5. 解码文件头
jpeg_start_decompress(&dinfo);
printf("图像信息: %dx%d %d\r\n", dinfo.output_width, dinfo.output_height, dinfo.output_components);
//-----------------------------------------------------
// 6. 读取一行或者多行扫描线数据并处理
// 分配内存以便读入数据
unsigned char *line_buff = malloc(dinfo.output_width * dinfo.output_components);
if(line_buff == NULL)
{
perror("malloc failed");
exit(1);
}
while (dinfo.output_scanline < dinfo.output_height)
{
// 读取一行数据并解码(output_scanlinee表示当前行数,会自动增加)
jpeg_read_scanlines(&dinfo, &line_buff, 1);
// 此处加入数据后续处理
// BMP的顺序为BGR, 显示器顺序为BGRA, JPG的顺序为RGB
// 如果直接输出为图片,则显示为上下翻转且颜色也不对(BMP本身的问题)
}
// 完成解压过程
jpeg_finish_decompress(&dinfo);
// 释放内容
jpeg_destroy_decompress(&dinfo);
return 0;
}
调整图像(输出BMP格式文件):
int sp;
int offset;
unsigned char *file_buff = malloc(line_size * dinfo.output_height);
unsigned char *line_buff = malloc(line_size);
if((file_buff == NULL) || (line_buff == NULL))
{
exit(1);
}
while (dinfo.output_scanline < dinfo.output_height)
{
offset = (dinfo.output_height - dinfo.output_scanline - 1) * line_size;
unsigned char *p = file_buff + offset;
jpeg_read_scanlines(&dinfo, &line_buff, 1);
sp = 0;
for (int i = 0; i < dinfo.output_width; i++)
{
*p++ = line_buff[sp+2];
*p++ = line_buff[sp+1];
*p++ = line_buff[sp];
sp += dinfo.output_components;
}
}
FILE* bmp_fp = bmp_file_init(&dinfo);
fwrite(file_buff,1,dinfo.output_width*dinfo.output_components*dinfo.output_height,bmp_fp);
fclose(bmp_fp);
BMP文件头处理:
FILE* bmp_file_init(struct jpeg_decompress_struct* j)
{
FILE *fp;
bmp_info_t bmp_info;
long int img_size = j->output_width * j->output_height * j->output_components;
bmp_info.bfType[0] = 'B';
bmp_info.bfType[1] = 'M';
bmp_info.bfSize = img_size + 54; // 文件大小
bmp_info.bfReserved1 = 0; // 06 保留
bmp_info.bfReserved2 = 0; // 08 保留
bmp_info.bfOffBits = 54; // 10 数据偏移(一般都为54)
bmp_info.biSize = 40; // 14 信息结构长度
bmp_info.biWidth = j->output_width; // 18 图像宽度
bmp_info.biHeight = j->output_height; // 22 图像高度
bmp_info.biPlanes = 1; // 26 颜色面板数(总是为1)
bmp_info.biBitCount = 24; // 28 像素位数
bmp_info.biCompression = 0; // 30 压缩格式
bmp_info.biSizeImage = img_size; // 34 图像内容大小
bmp_info.biXPelsPerMeter = 1024; // 38 水平分辨率 像素/米
bmp_info.biYPelsPerMeter = 1024; // 42 竖直分辨率 像素/米
bmp_info.biClrUsed = 0; // 46 调色板数量
bmp_info.biClrImportant = 0; // 50 关键色彩数
fp = fopen("output.bmp", "wb");
if(fp == NULL)
{
perror("Open Bmp File Failed");
exit(-1);
}
fwrite(&bmp_info,1,54,fp);
return fp;
}
Linux应用程序--FrameBuffer帧缓冲应用
文章说明: Linux显示基于FrameBuffer帧缓冲
硬件平台: 树莓派4B
测试说明: 由于桌面系统会一直刷新屏幕,需要关闭桌面,进入单用户模式测试(init 3);
打开设备文件:
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
int fb;
fb = open("/dev/fb0", O_RDWR);
if (fd < 0)
{
perror("can not open device");
exit(1);
}
// 获取显示器可变参数
if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo))
{
perror("get screen var info");
exit(2);
}
printf("屏幕分辨率: %dx%d %dbit\r\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
// 获取显示器固定参数
if (ioctl(fb, FBIOGET_FSCREENINFO, &finfo))
{
perror("get screen fix info");
exit(3);
}
// 每行字节数 = 行像素数*每个像素的字节数
printf("每行字节数: %d\r\n", finfo.line_length);
将FrameBuff映射至内存区:
int mem_size = vinfo.xres*vinfo.yres*vinfo.bits_per_pixel/8;
// 内存映射
pfb = (char*)mmap(0, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
if(pfb == NULL)
{
perror("mmap error");
}
int x, y;
int offset;
// 画一个300*200的蓝色矩形
for (y = 0; y < 200; y++)
{
offset = y * finfo.line_length;
for (x = 0; x < 300; x++)
{
// 计算内存位置(bpp=32bit)
*(pfb + offset) = 255; // B
*(pfb + offset + 1) = 0; // G
*(pfb + offset + 2) = 0; // R
*(pfb + offset + 3) = 0; // 透明度(没发现啥用)
offset += 4; // 下一个位置(vinfo.bits_per_pixel / 8)
}
}
从文件读取24位图BMP文件并显示:
由于24位图文件仅存了RGB信息,与fb的32bit的不匹配,所以不能直接用cat命令显示,设置第4个字节的信息。
int fd;
int ret;
char buff[100];
char* p = pfb;
fd = open("./Tulips.bmp", O_RDONLY);
if(fd < 1)
{
perror("can not open file");
}
// 跳过54字节的BMP文件头
ret= read(fd, buff, 54);
while(cnt)
{
ret = read(fd, buff, 3);
*p++ = buff[0]; // 将前3个字节的RGB信息原样输出
*p++ = buff[1];
*p++ = buff[2];
*p++ = 0; // 设置第4字节的信息
}
close(fd);
显示的图倒立的,原因是BMP格式本身的问题,需要进行显示调整:
int *p = (int *)(pfb + mem_size) - 1;
while (read(fd, (char *)p--, 3))
{
if (p < pfb)
{
break;
}
}
Linux系统应用--路由表配置
文章摘要: 本文主要描述了Linux系统下路由表的配置详细说明
命令格式:
# route [add|del] [-net|-host] target [netmask Nm] [gw Gw] [[dev] If]
add : 添加一条路由规则
del : 删除一条路由规则
-net : 目的地址是一个网络(后边跟网段/掩码)
-host : 目的地址是一个主机(后边跟单个主机地址)
target : 目的网络或主机
netmask : 目的地址的网络掩码
gw : 路由数据包通过的网关
dev : 为路由指定的网络接口
查看当前路由表:
# route
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.10.1 0.0.0.0 UG 1024 0 0 eth0
192.168.10.0 * 255.255.254.0 U 0 0 0 eth0
Destination: 目标地址,default表示未明确定义的所有地址;
Gateway: 网关地址,*表示与本机相同的网段不需要指定网关;
Genmask:子网掩码
Iface: 网络接口
添加默认网关:
# route add default gw 192.168.10.1
执行完成后路由表如下:
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.10.1 0.0.0.0 UG 1024 0 0 eth0
添加一条路由: 该网段的数据从指定网关通过
# route add -net 6.6.6.0/24 gw 192.168.10.1
删除默认路由:
# route del default
删除指定路由:
# route del –net 6.6.6.0/24
Mysql数据库应用脚本
创建数据库用户
#!/bin/sh
mysql -u root -p <<END
USE mysql;
CREATE USER 'user';
SET PASSWORD FOR 'user'=PASSWORD('123456');
\q
END
创建数据库并授权用户:
#!/bin/sh
mysql -u root -p <<END
CREATE DATABASE $1;
GRANT ALL PRIVILEGES ON $1.* to $2@localhost;
FLUSH PRIVILEGES
\q
END