提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
文章目錄
目錄
文章目錄
前言
一、為什么要解碼?
二、bmp圖片
1.bmp圖片信息
2.獲取圖片信息
三、jpg圖片?
總結(jié)
前言
????????在學習C語言、文件IO、數(shù)據(jù)結(jié)構(gòu)之后做了一個6818的開發(fā)板項目,自覺想要記錄一下,本該將整個項目整理好發(fā)布的,由于當時著急提交查驗,代碼并未優(yōu)化,繼而現(xiàn)在將在做項目的時候遇到的自認為較關鍵的圖片格式解碼整理一下。
一、為什么要解碼?
????????想要將圖片寫入或者映射到開發(fā)板設備上,就必須知道圖片的像素信息,但圖片的信息是一整個合集,各種信息都集中在里面,包括圖片的文件類型、圖片大小、像素等等信息,而我們只需要像素信息,將之寫入/映射到設備,這就需要解碼。
二、bmp圖片
1.bmp圖片信息
??bmp圖片信息前面14個字節(jié)是文件信息
?Bitmap File Header,包含文件類型、文件大小等信息,接下來40個字節(jié)是位圖信息
Bitmap Information Header,這部分包含位圖的寬高、位圖數(shù)據(jù)大小等很多信息,接下來才是像素信息,而我們讀取的就是這部分,想要讀取這部分信息就要:
????????????????????????????????????????Bitmap File Header | |||
????????????????位置 | ?????大小(byte) | ????????????????描述 | |
00 | 0 | 2 | 頭文件字段 |
02 | 2 | 4 | 整個.bmp文件大小 |
06 | 6 | 2 | 預留字段,通常為0 |
08 | 8 | 2 | |
0A | 10 | 4 | 圖片信息的開始位置 |
????????????????????????????????Bitmap Information Header | |||
? ? ? ? ? ? ? ? ?位置 | 尺寸 | 描述 | |
0E | 14 | 4 | DIB? header的大小通常為40byte即0x28 |
12 | 18 | 4 | 圖像寬度 |
16 | 22 | 4 | 圖像高度 |
1A | 26 | 2 | 色彩平面的數(shù)量必須為1 |
1C | 28 | 2 | 每像素用多少bit來表示 |
1E | 30 | 4 | 采用何種壓縮方式,通常不壓縮,即BI_RGB,對應值為0 |
22 | 34 | 4 | 圖片大?。ㄔ嘉粓D數(shù)據(jù)的大?。?/p> 對于不壓縮的圖片,通常表示為0 |
26 | 38 | 4 | 橫向分辨率(像素/米) |
2A | 42 | 4 | 縱向分辨率(像素/米) |
2E | 46 | 4 | 調(diào)色板中顏色數(shù)量 通常為0(不表示沒有顏色) |
32 | 50 | 4 | 重要顏色的數(shù)量(通常被忽略) 通常為0(表示每種顏色都重要) |
2.獲取圖片信息
(1)獲取圖片的寬度和高度
? ?以下是圖片文件信息結(jié)構(gòu)體
// 前14個字節(jié)
struct bitmap_header
{
int16_t type;
int32_t size; // 圖像文件大小
int16_t reserved1;
int16_t reserved2;
int32_t offbits; // bmp圖像數(shù)據(jù)偏移量
}__attribute__((packed));
// 14-54個字節(jié)
struct bitmap_info
{
int32_t size; // 本結(jié)構(gòu)大小
int32_t width; // 圖像寬
int32_t height; // 圖像高
int16_t planes;
int16_t bit_count; // 色深
int32_t compression;
int32_t size_img; // bmp數(shù)據(jù)大小,必須是4的整數(shù)倍
int32_t X_pel;
int32_t Y_pel;
int32_t clrused;
int32_t clrImportant;
}__attribute__((packed));
故而要獲取圖片大小為:
int fd = open("dd.bmp", O_RDONLY);
// 讀取BMP格式頭,獲取圖片信息
struct bitmap_header header;
struct bitmap_info info;
// 讀取文件信息到結(jié)構(gòu)體
read(fd, &header, sizeof(header));
read(fd, &info, sizeof(info));
// 輸出圖片相關信息
printf("圖片大小: %d\n", header.size);
printf("圖片尺寸: %d×%d\n", info.width, info.height);
(2)獲取圖片的像素信息
// 打開bmp圖片
int fd_pic = open(addr_bmp, O_RDONLY);
if (fd_pic < 0)
{
perror("open bmp faile");
return -1;
}
// 圖片偏移54位
lseek(fd_pic, 54, SEEK_SET);
// 獲取圖片像素信息
char rgb[480 * 800 * 3] = {0};
read(fd_pic, rgb, sizeof(rgb));
三、jpg圖片?
關于jpg(jpeg)圖片的解碼是使用第三方庫來實現(xiàn)的,因此編譯時要帶上庫
jpeg第三方庫下載Directory Listing of /files (ijg.org)
解碼過程如下:
#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>
#include <string.h>
struct my_error_mgr
{
struct jpeg_error_mgr pub; /* "public" fields */
jmp_buf setjmp_buffer; /* for return to caller */
};
typedef struct my_error_mgr *my_error_ptr;
METHODDEF(void)
my_error_exit(j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr)cinfo->err;
(*cinfo->err->output_message)(cinfo);
longjmp(myerr->setjmp_buffer, 1);
}
//解碼jpge
int read_JPEG_file(void *lcd_addr, char *filename)
{
// 定義一個jpeg解碼對象
struct jpeg_decompress_struct cinfo;
// 定義一個jpeg錯誤對象
struct my_error_mgr jerr;
FILE *infile; /* 源文件 */
JSAMPARRAY buffer; /* 輸出行緩存 */
int row_stride; /* 輸出行大小 */
// 打開需要解碼的jpeg文件
if ((infile = fopen(filename, "rb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return 0;
}
/* Step 1: 初始化解碼對象*/
/* 設置jpeg出錯處理函數(shù)*/
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer))
{
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
/*初始化解碼對象函數(shù)*/
jpeg_create_decompress(&cinfo);
/* Step 2: 關聯(lián)文件與解碼對象 */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: 讀取jpeg文件頭*/
(void)jpeg_read_header(&cinfo, TRUE);
/* Step 5: 開始解碼 */
(void)jpeg_start_decompress(&cinfo);
// 保存圖像的寬度與高度
int width = cinfo.output_width;
int height = cinfo.output_height;
row_stride = cinfo.output_width * cinfo.output_components;
/* 分配一行的RGB數(shù)據(jù)空間 */
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
// buffer 輸出行緩存,是一個二維數(shù)組
// 把解碼后的數(shù)據(jù)輸出到argb數(shù)組中
char argb[width * height * 4];
int y = 0;
// cinfo.output_scanline 解碼的當前行 cinfo.output_height 圖像的總行數(shù)
while (cinfo.output_scanline < cinfo.output_height)
{
(void)jpeg_read_scanlines(&cinfo, buffer, 1);
char *p = buffer[0]; // 指向解碼后的RGB 數(shù)據(jù)
for (int x = 0; x < width; x++)
{
argb[y * width * 4 + 2 + x * 4] = buffer[0][0 + x * 3]; // R
argb[y * width * 4 + 1 + x * 4] = buffer[0][1 + x * 3]; // G
argb[y * width * 4 + 0 + x * 4] = buffer[0][2 + x * 3]; // B
argb[y * width * 4 + 3 + x * 4] = 0;
}
y++;
}
// 把LCD 轉(zhuǎn)換為二維數(shù)組
int(*lcd)[800] = lcd_addr;
// 把argb 轉(zhuǎn)換為二維數(shù)組
int(*color)[width] = (void *)argb;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
if (y < 480 && x < 800) // 限制顯示范圍
{
lcd[y][x] = color[y][x]; // 把小圖的對應像素點放入屏幕的對應位置
}
}
}
/* Step 7: 結(jié)束解碼 */
(void)jpeg_finish_decompress(&cinfo);
// 銷毀解碼對象
jpeg_destroy_decompress(&cinfo);
// 關閉文件
fclose(infile);
return 1;
}
void *inin_lcd()
{
// 1.打開LCD 設備
int lcd = open("/dev/fb0", O_RDWR);
if (lcd == -1)
{
perror("打開 /dev/fb0 失敗");
exit(0);
}
// 定義LCD 設備信息結(jié)構(gòu)體
struct fb_var_screeninfo varinfo;
// FBIOGET_VSCREENINFO 獲取屏幕參數(shù)命令,成功后會把屏幕的所有信息放入varinfo結(jié)構(gòu)體中
if (ioctl(lcd, FBIOGET_VSCREENINFO, &varinfo) != 0)
{
perror("獲取LCD設備可變屬性信息失敗");
return 0;
}
// 根據(jù)獲取的參數(shù)映射 映射的length 多少個字節(jié)?? varinfo.xres*varinfo.yres*varinfo.bits_per_pixel/4
// 32/8 = 4
void *lcd_p = mmap(NULL, varinfo.xres * varinfo.yres * varinfo.bits_per_pixel / 8, PROT_READ | PROT_WRITE,
MAP_SHARED, lcd, 0);
close(lcd);
// 返回映射地址
return lcd_p;
}
int main()
{
//初始化lcd設備
void *lcd = inin_lcd();
read_JPEG_file(lcd, adr_jpg);
return;
}
編譯時注意,以下僅供參考文章來源:http://www.zghlxwxcb.cn/news/detail-734688.html
arm-linux-gcc main.c -o main -I /home/gec/jpeglib/include -L /home/gec/jpeglib/lib -ljpeg
參數(shù)解析:
-I/home/gec/jpeglib/include #指定頭文件所在路徑
-L/home/gec/jpeglib/lib #指定庫文件所在路徑
-ljpeg #指定庫的名稱
總結(jié)
以上就是關于這兩種圖片格式的解壓總結(jié),如有不足請指教,本人初學嵌入式,寫文章一是為了總結(jié)回顧,二是為了方便日后翻閱查看。文章來源地址http://www.zghlxwxcb.cn/news/detail-734688.html
到了這里,關于關于bmp、jpg格式圖片的解碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!