在LCD上任意位置顯示一張任意大小並且寬高變為原來1/n大小的色深為 24bit的bmp圖片
標頭檔案
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <strings.h>
從此處開始以1位元組對齊
#pragma pack(1) // 結構體以1位元組對齊
自定義BMP檔案頭部結構,方便後續獲取或建立bmp圖片使用
typedef struct
{
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
} BITMAPFILEHEADER;
typedef struct
{
unsigned int biSize;
int biWidth; // 寬
int biHeight; // 高
unsigned short biPlanes;
unsigned short biBitCount; // 色深
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} BITMAPINFOHEADER;
在此處取消位元組對齊
#pragma pack()
呼叫此函式,可以將bmp圖片正常縮放2及4的倍數倍(未進行位元組對齊操作,後續補齊)
傳入的引數分別透過命令列及執行時的標準輸入傳入,
/*******************************************************************
*
* 函式名稱: Scalinbmp
* 函式功能: 在LCD上任意位置顯示一張任意大小並且寬高變為原來1/n大小的色深為 24bit的bmp圖片
* 函式引數:
* @name bmp影像檔名
* @x 影像顯示的起點x軸座標
* @y 影像顯示的起點y軸左邊
* @n 想要縮放的倍數
* 返回結果:
* 注意事項: None
* 函式作者: mailLinL@163.com
* 建立日期: 2024/05/14
* 修改歷史:
* 函式版本: V1.0
* *****************************************************************/
int Scalinbmp(char *name, int x, int y, int n)
{
// 1.開啟bmp檔案,獲取檔案頭資訊,影像大小,影像寬,高,位深度等可用資訊
FILE *bmp_src = fopen(name, "rb");
if (NULL == bmp_src)
{
printf("open SRCFILE is error!\n");
return -1;
}
BITMAPFILEHEADER src_head;
BITMAPINFOHEADER src_vinfo;
fread(&src_head, 1, 14, bmp_src); // 讀取bmp影像的檔案頭段 獲取檔案大小 以位元組為單位
fread(&src_vinfo, 1, 40, bmp_src); // 讀取bmp影像的資訊頭段 獲取檔案寬,高 以畫素點為單位 位深度以bits為單位
int width = src_vinfo.biWidth;
int height = src_vinfo.biHeight;
// 3.以wb許可權開啟新建bmp圖片,並向新的bmp影像的檔案頭中錄入資料
FILE *bmp_new = fopen("new.bmp", "wb");
src_head.bfSize = src_vinfo.biWidth / n * src_vinfo.biHeight / n * src_vinfo.biBitCount / 8 + 54;
// 新bmp檔案的總大小 = 源bmp畫素點寬的一半 * 源畫素點高的一半 * bmp影像位深度 / 位元 + 新檔案頭54位元組
src_vinfo.biWidth = src_vinfo.biWidth / n;
// 新bmp檔案的畫素點寬 = 源bmp畫素點寬的一半
src_vinfo.biHeight = src_vinfo.biHeight / n;
// 新bmp檔案的影像區大小 = 源bmp影像區大小的一半
// src_vinfo.biSizeImage = src_vinfo.biSizeImage / 4;
fwrite(&src_head, 1, 14, bmp_new);
fwrite(&src_vinfo, 1, 40, bmp_new);
// 建立緩衝區,每次讀取一行存入緩衝區
char *line_size = (char *)calloc(1, width * 3);
// 迴圈將源bmp圖片的顏色分量輸入到新bmp檔案中
for (int i = 0; i < height * 3; i += n)
{ // 外層迴圈,隔行讀取
fread(line_size, 1, width * 3, bmp_src); // 每次讀取一行,存入緩衝區
for (int j = 0; j < width * 3; j += 3 * n)
{
fwrite(&line_size[j], 3, 1, bmp_new);
}
bzero(line_size, width * 3);
fseek(bmp_src, width * 3 * (n - 1), SEEK_CUR);
}
/* // 5.開啟lcd並建立lcd對映記憶體
int lcd_fd = open("/dev/fb0", O_RDWR);
if (lcd_fd == -1)
{
printf("mmap for lcd is error\n");
return -1;
}
// 呼叫LCD屏的畫素 獲取螢幕的寬高資訊
struct fb_var_screeninfo lcd_vinfo;
ioctl(lcd_fd, FBIOGET_VSCREENINFO, &lcd_vinfo);
int *lcd_mp = (int *)mmap(NULL, // 申請記憶體對映的地址,填NULL讓MMU自行分配
lcd_vinfo.xres * lcd_vinfo.yres * 4, // 申請的空間大小,以lcd屏實際畫素大小*每個畫素點的位元組數
PROT_READ | PROT_WRITE, // 對映空間的操作許可權,讀 |寫
MAP_SHARED, // 對映空間對其他成員的許可權 共享
lcd_fd, // lcd檔案指示符
0); // 對映空間起始偏移量
// 5.將新的bmp影像位置指示器設定在顏色分量資料起始地址
fseek(bmp_new, 54, SEEK_SET);
// 6.定義緩衝區,獲取新bmp影像的顏色分量,行列都縮放為原來的一半,畫素寬/2*畫素高/2乘以位深度/8
char new_buff[src_vinfo.biHeight * src_vinfo.biWidth * src_vinfo.biBitCount / 8];
// 初始化緩衝區
bzero(new_buff, src_vinfo.biWidth * src_vinfo.biHeight * src_vinfo.biBitCount / 8);
// 畫素點寬 畫素點高的 位深度
// 7.將新的bmp影像中的顏色分量寫入lcd對映記憶體中
int data = 0;
int cnt = 0;
for (int i = (y + src_vinfo.biHeight - 1); i >= y; i--)
{ // bmp影像寫入lcd的資料錄入方式是自底向上,外層迴圈以指定位置到向上偏移bmp影像高度單位為終點
for (int j = y; j < (src_vinfo.biWidth + y); j++)
{ // 內層迴圈寫入lcd的資料錄入方式是自左向右,以指定位置到向後偏移bmp影像寬度單位為止
data |= new_buff[cnt];
data |= new_buff[cnt + 1] << 8;
data |= new_buff[cnt + 2] << 16;
lcd_mp[i * (lcd_vinfo.xres) + j] = data;
cnt += 3;
data = 0;
}
}
*/
// 8.關閉源bmp圖片,新bmp圖片,lcd屏,釋放對映記憶體
fclose(bmp_src);
fclose(bmp_new);
// close(lcd_fd);
// munmap(new_buff, lcd_vinfo.xres * lcd_vinfo.yres * 4);
return 0;
}
主函式中測試
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("argument is error!\n");
return -1;
}
if (NULL == argv[1])
{
printf("argument 2 is error!\n");
return -1;
}
int x, y, n;
scanf("%d%d%d", &x, &y, &n);
Scalinbmp(argv[1], x, y, n);
return 0;
}
源bmp圖片
檔案屬性
執行程式後生成的新bmp圖片
檔案屬性
注:此程式碼仍需最佳化,考慮位元組對齊,最佳化後將及時更改