/** * @brief :實現bmp格式圖片的2倍縮小功能,並輸出新的目標bmp格式文件。最後利用800*480的開發板,展示縮放後的bmp文件 因為只是進行函數練習,未採用函數封裝的做法 * @author [email protected] * @date 2024/05/12 * Cop ...
/**
* @brief :實現bmp格式圖片的2倍縮小功能,並輸出新的目標bmp格式文件。最後利用800*480的開發板,展示縮放後的bmp文件
因為只是進行函數練習,未採用函數封裝的做法
* @author [email protected]
* @date 2024/05/12
* CopyRight (c) 2023-2024 [email protected] All Right Reseverd
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <stdlib.h>
#define MUL 2 // 規定縮放倍數,多重倍數需後續筆者繼續優化
#pragma pack(1) // 取消預設位元組對齊
typedef struct tagBITMAPFILEHEADER // bmp格式圖片的文件信息頭1
{
unsigned short type; // 文件標識,字母編碼“BM”
unsigned int size; // 點陣圖文件大小,以位元組為單位
unsigned short reserved1; // 點陣圖文件保留字,為0
unsigned short reserved2; // 點陣圖文件保留字,為0
unsigned int offBits; // 文件開始到點陣圖數據開始自建的偏移量,單位位元組
} BMF_HEADER;
typedef struct tagBITMAPINFOHEADER // bmp格式圖片的文件信息頭2
{
unsigned int biSize; // 圖像描述信息塊大小,常為28H
int width; // 圖像寬度
int height; // 圖像高度
unsigned short biPlanes; // 圖像plane總數(恆為1)
unsigned short biBit_depth; // 記錄顏色的位數取值1
unsigned int biCompression; // 數據壓縮方式
unsigned int biSizeImage; // 圖像區數據的大小,必須是4的倍數
int biXPelsPerMeter; // 水平每米像素
int biYPelsPerMeter; // 垂直每米像素
unsigned int biClrUsed; // 圖像所用顏色素,不用,固定為0
unsigned int biClrImportant; // 重要顏色數,不用,固定為0
} BMFI_HEADER;
#pragma pack() // 恢復預設位元組對齊
int main(int argc, char *argv[])
{
// 1.打開源圖片文件,併進行信息提取
BMF_HEADER S1;
BMFI_HEADER S2; // 用於頭文件信息提取
FILE *bmp_fp = fopen(argv[1], "rb+"); // 打開源圖片文件
if (argc != 3) // 錯誤判斷
{
printf("Usage:%s <srcfile><dstfile>\n", argv[0]);
exit(1);
}
if (!bmp_fp) // 錯誤判斷
{
perror("fopen()");
exit(1);
}
fread(&S1, 1, 14, bmp_fp); // 進行源圖片的頭文件信息提取
fread(&S2, 1, 40, bmp_fp);
int bmp_size = S2.width * S2.height * S2.biBit_depth / 8;
char bmp_buf[bmp_size]; // 申請空間,存放源圖片信息
fread(bmp_buf, 1, bmp_size, bmp_fp); // 讀取圖片文件信息
fclose(bmp_fp); // 關掉源圖片文件
// 2.進行源圖片的數據處理
/*
此處的思路,是先將圖片信息進行縮放,即用一個新的數組進行採樣,每MUL個原數組拼成一個新的數組
然後再利用採樣好的數據進行輸出到文件或者LCD
因此此處僅考慮按順序採樣即可,保證數據不丟失
*/
char newbuf[bmp_size / MUL / MUL]; // 申請數組,存放重新採樣後的圖片信息
int cnt = 0;
for (int y = 0; y < S2.height; y += MUL) // 存放按倍數縮放採樣後的圖片信息,每次前進MUL個像素點
{
for (int x = 0; x < S2.width; x += MUL)
{
newbuf[cnt++] = bmp_buf[(y * S2.width + x) * 3]; // B
newbuf[cnt++] = bmp_buf[(y * S2.width + x) * 3 + 1]; // G
newbuf[cnt++] = bmp_buf[(y * S2.width + x) * 3 + 2]; // R
}
}
// 3.創建新的圖片文件,並存入相關信息
FILE *new_fp = fopen(argv[2], "wb+"); // 創建新的圖片文件
if (!new_fp) // 錯誤判斷
{
perror("fopen()");
exit(1);
}
S2.width = S2.width / MUL;
S2.height = S2.height / MUL;
fwrite(&S1, 1, 14, new_fp); // 往新的圖片文件寫進內容;先寫頭1
fwrite(&S2, 1, 40, new_fp); // 往新的圖片文件寫進內容;寫頭2
fwrite(&newbuf, 1, bmp_size / MUL / MUL, new_fp);
fclose(new_fp);
// 4.打開LCD設備操作,並申請映射空間
int lcd_fd = open("/dev/fb0", O_RDWR); // 打開LCD設備
int *lcd_map = (int *)mmap(NULL,
800 * 480 * 4, // 申請映射空間,此處一定要是設備的尺寸
PROT_READ | PROT_WRITE,
MAP_SHARED,
lcd_fd,
0);
// 5.設置圖片位置偏移量,並將圖片信息寫入映射記憶體
int X, Y;
printf("Please enter the location(X Y):\n"); // X和Y是相對於左上角點的位置,讓用戶輸入
scanf("%d %d", &X, &Y);
int i = 0;
int data = 0;
for (int y = S2.height / MUL - 1; y >= 0; y--) // 此處要寫新圖片的尺寸,以完整的輸入整張圖片信息
{
for (int x = 0; x < S2.width / MUL; ++x)
{
// 把BMP圖片的一個像素點的顏色分量轉換為LCD屏幕的一個像素點的顏色分量格式 ARGB <--- BGR
data |= newbuf[i]; // B
data |= newbuf[i + 1] << 8; // G
data |= newbuf[i + 2] << 16; // R
lcd_map[800 * (y + Y) + x + X] = data; // 此處要寫LCD屏幕的高度
i += 3;
data = 0;
}
}
close(lcd_fd);
munmap(lcd_map, 800 * 480 * 4); // 此處要寫LCD屏幕的尺寸
return 0;
}