第三階段應用層——1.9 數碼相冊—在LCD上顯示BMP圖片

數碼相冊——在LCD上顯示BMP圖片

  • 硬件平臺:韋東山嵌入式Linxu開發板(S3C2440.v3)
  • 軟件平臺:運行於VMware Workstation 12 Player下UbuntuLTS16.04_x64 系統
  • 參考資料:《嵌入式Linux應用開發手冊》、《嵌入式Linux應用開發手冊第2版》、【bitmap格式分析】
  • 開發環境:Linux 3.4.2內核、arm-linux-gcc 4.3.2工具鏈


一、數碼相冊

1、軟件框架

對於數碼相冊的軟件框架,在電子書框架的基礎上修改進而實現數碼相冊功能,並在此基礎上實現文件瀏覽器的功能,具體的框架如下:

在這裏插入圖片描述

對於上述完成主要功能的7個部分:encoding編碼部分、fonts獲取字體點陣部分、display顯示部分、input輸入部分、debug調試部分、page頁面管理部分、render渲染部分

  1. encoding編碼部分去文件中獲得編碼信息,對於每個文件,保存的時候,系統對自動或手動的根據編碼規範,對文件的信息進行編碼:如保存爲ASCII、GBK、UTF-8、UTF16LE、UTF16BE
  2. fonts獲取字體點陣部分根據獲得的編碼信息得到字體數據(LCD上表示爲點陣)
  3. display顯示部分把字體數據(點陣)顯示在LCD上
  4. input輸入部分管理不同的輸入方式,定製不同的輸入方式所實現的控制,滿足多種控制場合;
  5. debug調試部分設置打印等級和打印通道,通過打印等級控制程序打印的調試信息錯誤信息警告信息等,通過打印通道設置來控制程序打印的輸出的流向標準輸出還是網絡打印輸出
  6. page頁面管理部分:負責對多種頁面進行管理,通過觸控進行不同頁面的切換與功能實現
  7. render渲染部分:負責對bmp文件進行讀取、解析、提取有效的像素信息、顯示到LCD上

至多個部分的協調,通過在main.c文件中實現。

2、頁面管理

爲了滿足多種需求,設計瞭如下頁面:
當程序一運行時,進入的是主頁面,通過觸控不同的區域進入以下到不同的頁面

  1. 點擊瀏覽模式進入文件瀏覽模式,在這裏可以對根文件系統中的文件進行圖片與文字瀏覽、上下頁切換、選擇文件、返回上一級操作。在瀏覽圖片信息時,可以實現縮放、移動、上下張切換,點擊返回區域即可回到文件瀏覽模式
  2. 點擊連播模式,可以對指定的目錄的圖片進行連續播放,每張圖片播放時間間隔可以進行設置;
  3. 點擊設置,可對連播模式的目錄與時間間隔進行設置
    在這裏插入圖片描述

3、Makefile框架

這個Makefile針對的是實現顯示bmp文件程序,對於完整的會在後面進行完善。
在這裏插入圖片描述

二、bmp文件

bmp圖片是無損的,同時這種圖片格式幾乎沒有對數據進行壓縮,所以通常具有較大的文件大小,同時支持索引色和直接色。

1、組成

bmp位圖信息主要由以下3部分組成:

塊名稱 塊名稱 大小(Byte)
文件信息頭 BITMAPFILEHEADER 14
位圖信息頭 BITMAPINFOHEADER 40
RGB顏色陣列 RGB顏色陣列 RGB顏色陣列

1.1 文件信息頭BITMAPFILEHEADER

  • 結構體定義如下:
/* WINDOW系統下 */
typedef struct tagBITMAPFILEHEADER { /* bmfh */
	UINT bfType; 
	DWORD bfSize;
	UINT bfReserved1;
	UINT bfReserved2;
	DWORD bfOffBits;
} BITMAPFILEHEADER;

/* Linux系統下 */
typedef struct tagBITMAPFILEHEADER {
	unsigned short bfType; 			//文件類型
	unsigned long  bfSize;			//文件大小
	unsigned short bfReserved1;		//保留位,必須爲0
	unsigned short bfReserved2;		//保留位,必須爲0
	unsigned long  bfOffBits;		//文件頭開始到實際的圖象數據之間的字節的偏移量
} BITMAPFILEHEADER;
  • 參數介紹:
bfType 說明文件的類型,該值必需是0x4D42,也就是字符’BM’。
bfSize 說明該位圖文件的大小,用字節爲單位
bfReserved1 保留,必須設置爲0
bfReserved2 保留,必須設置爲0
bfOffBits 說明從文件頭開始到實際的圖象數據之間的字節的偏移量。這個參數是非常有用的,因爲位圖信息頭和調色板的長度會根據不同情況而變化,所以你可以用這個偏移值迅速的從文件中讀取到位數據。
  • 舉例說明:
    通過用二進制文件打開一個.bmp格式文件,注意其二進制數據存儲爲低位在前,高位在後
    在這裏插入圖片描述

1.2 位圖信息頭BITMAPINFOHEADER

  • 結構體定義如下:
/* WINDOW系統下 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
	DWORD biSize;
	LONG biWidth;
	LONG biHeight;
	WORD biPlanes;
	WORD biBitCount;
	DWORD biCompression;
	DWORD biSizeImage;
	LONG biXPelsPerMeter;
	LONG biYPelsPerMeter;
	DWORD biClrUsed;
	DWORD biClrImportant;
} BITMAPINFOHEADER;

/* Linux系統下 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;			//文件信息頭結構體需要的自身
	unsigned long  biWidth;			//圖像寬度
	unsigned long  biHeight;		//圖像高度
	unsigned short biPlanes;		//位面數,總被設爲1
	unsigned short biBitCount;		//bpp
	unsigned long  biCompression;	//數據壓縮的類型
	unsigned long  biSizeImage;		//圖象的大小
	unsigned long  biXPelsPerMeter;//水平分辨率
	unsigned long  biYPelsPerMeter;//垂直分辨率
	unsigned long  biClrUsed;		//使用的彩色表中的顏色索引,0-使用所有調色板項
	unsigned long  biClrImportant;	//對圖象顯示有重要影響的顏色索引的數目,0-都重要
} BITMAPINFOHEADER;
  • 參數介紹:
biSize 說明BITMAPINFOHEADER結構所需要的字數
biWidth 說明圖象的寬度,以象素爲單位
biHeight 說明圖象的高度,以象素爲單位。注:這個值除了用於描述圖像的高度之外,它還有另一個用處,就是指明該圖像是倒向的位圖,還是正向的位圖。如果該值是一個正數,說明圖像是倒向的,如果該值是一個負數,則說明圖像是正向的。大多數的BMP文件都是倒向的位圖,也就是時,高度值是一個正數
biPlanes 爲目標設備說明位面數,其值將總是被設爲1。
biBitCount 說明比特數/象素,其值爲1、4、8、16、24、或32。但是由於我們平時用到的圖像絕大部分是24位和32位的,所以我們討論這兩類圖像
biCompression 說明圖象數據壓縮的類型,同樣我們只討論沒有壓縮的類型:BI_RGB
biSizeImage 說明圖象的大小,以字節爲單位。當用BI_RGB格式時,可設置爲0
biXPelsPerMeter 說明水平分辨率,用象素/米表示
biYPelsPerMeter 說明垂直分辨率,用象素/米表示
biClrUsed 說明位圖實際使用的彩色表中的顏色索引數(設爲0的話,則說明使用所有調色板項)
biClrImportant 說明對圖象顯示有重要影響的顏色索引的數目,如果是0,表示都重要
  • 舉例說明:
    在這裏插入圖片描述

1.3 RGB顏色陣列

在Windows下,RGB顏色陣列存儲的格式其實BGR。也就是說,對於24位的RGB位圖像素數據格式是:

藍色B值 綠色G值 紅色R值

對於32位的RGB位圖像素數據格式是:

藍色B值 綠色G值 紅色R值 透明通道A值
  • 舉例說明
    注意:bmp二進制文件格式存儲的像素是從圖片的左下角開始,從左往右一行一行的上去
    在這裏插入圖片描述

三、代碼編寫

代碼以實現顯示bmp文件爲主,對於其他部分後面的博客會慢慢完善。

1、pic_operation.hbmp描述頭文件

  • 定義兩個結構體變量,用來存儲bmp文件信息與bmp文件像素信息,拓展文件可以根據自己的情況:分配結構體、設置結構體

#ifndef _PIC_OPERATION_H
#define _PIC_OPERATION_H

typedef struct PixelDatas{
	int bpp;
	int width;
	int height;
	int linebytes;
	unsigned char *PixelDatas;
}T_PixelDatas, *PT_PixelDatas;

typedef struct PicFileParser {
	char *name;
	int (*isSupport)(unsigned char *pFileHead);
	int (*GetPixelDatas)(unsigned char *pFileHead, PT_PixelDatas ptPixelID);
	int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);
}T_PicFileParser, *PT_PicFileParser;

#endif /* _PIC_OPERATION_H */

2、render.h渲染頭文件

定義如下函數

#ifndef _RENDER_H
#define _RENDER_H

int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic);	//圖片壓縮
int PicMerge(int x, int y, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic);	//圖片LCD顯示

#endif /* _RENDER_H */

3、bmp.cbmp文件解析

在這個文件中,進行分配結構體、設置結構體

  • 結構體對齊:在定義如下結構體時,需要添加如下語句,使得結構體呈現1字節對齊否則系統默認4字節對齊,最終定位不到bmp文件中有效信息
#pragma pack(push) /* 將當前pack設置壓棧保存 */
#pragma pack(1)    /* 必須在結構體定義之前使用 */
#pragma pack(pop) /* 恢復先前的pack設置 */
#pragma pack(push) /* 將當前pack設置壓棧保存 */
#pragma pack(1)    /* 必須在結構體定義之前使用 */

/* bmp文件信息頭 */
typedef struct tagBITMAPFILEHEADER {
	unsigned short bfType; 			//文件類型
	unsigned long  bfSize;			//文件大小
	unsigned short bfReserved1;		//保留位,必須爲0
	unsigned short bfReserved2;		//保留位,必須爲0
	unsigned long  bfOffBits;		//文件頭開始到實際的圖象數據之間的字節的偏移量
} BITMAPFILEHEADER;

/* 位圖信息頭 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;			//文件信息頭結構體需要的自身
	unsigned long  biWidth;			//圖像寬度
	unsigned long  biHeight;		//圖像高度
	unsigned short biPlanes;		//位面數,總被設爲1
	unsigned short biBitCount;		//bpp
	unsigned long  biCompression;	//數據壓縮的類型
	unsigned long  biSizeImage;		//圖象的大小
	unsigned long  biXPelsPerMeter;//水平分辨率
	unsigned long  biYPelsPerMeter;//垂直分辨率
	unsigned long  biClrUsed;		//使用的彩色表中的顏色索引,0-使用所有調色板項
	unsigned long  biClrImportant;	//對圖象顯示有重要影響的顏色索引的數目,0-都重要
} BITMAPINFOHEADER;

#pragma pack(pop) /* 恢復先前的pack設置 */
  • 解析bmp文件信息,提取像素數據
    注意:1、在bmp二進制文件中,像素數據存在向四取整的情況,在代碼中需要進行處理
    2、由於bmp文件中一開始存儲的是圖片左下角的像素數據LCD從圖片的左上角開始像素描畫,所以需要如下的轉換
    在這裏插入圖片描述
/**
 * @Description: 從bmp文件中獲取像素數據,並分配緩衝區存放像素信息,供外部文件調用
 * @param pFileHead - 文件頭,ptPixelDatas - 位圖信息,存儲像素信息,其bpp用戶設定
 * @return 0 - 成功,-1 - 失敗 
 */
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)
{
	int y;
	int width;
	int height;
	int BMPbpp;
	int LineWidthReal;
	int LineWidthAlign;
	unsigned char *pSrc;
	unsigned char *pDest;
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;

	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)pFileHead;
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(pFileHead + sizeof(BITMAPFILEHEADER));

	/* 獲取bmp文件信息 */
	width  = ptBITMAPINFOHEADER->biWidth;
	height = ptBITMAPINFOHEADER->biHeight;
	BMPbpp = ptBITMAPINFOHEADER->biBitCount;
	if (BMPbpp != 24) {
		DebugPrint(APP_ERR"can not support %d bpp\n", BMPbpp);
		return -1;
	}

	/* 設置結構體 */
	ptPixelDatas->height      = height;
	ptPixelDatas->width       = width;
	ptPixelDatas->linebytes   = width * ptPixelDatas->bpp / 8;
	
	/* 分配緩衝區 */
	ptPixelDatas->PixelDatas = (unsigned char *)malloc(width * height * ptPixelDatas->bpp / 8);
	if (ptPixelDatas->PixelDatas == NULL) {
		DebugPrint(APP_ERR"malloc ptPixelDatas->PixelDatas err\n");
		return -1;
	}

	/* 獲取bmp像素信息:存儲像素的起始是圖片左下角 */
	LineWidthReal  = width * BMPbpp / 8;	//每行像素所佔的字節
	LineWidthAlign = (LineWidthReal + 3) & ~0x3;		//向4取整後的每行像素所佔的字節

	pSrc = pFileHead + ptBITMAPFILEHEADER->bfOffBits;	//像素信息的源地址
	pSrc = pSrc + LineWidthAlign * (height- 1);			//移動到存儲圖片左上角的數據地址

	pDest = ptPixelDatas->PixelDatas;	//數據最終的去向
	
	for (y = 0; y < height; y++) {
		//memcpy(pDest, pSrc, LineWidthReal);
		CoverOneLine(width, BMPbpp, ptPixelDatas->bpp, pSrc, pDest);
		pSrc  -= LineWidthAlign;	//bmp二進制數據
		pDest += ptPixelDatas->linebytes;		//LCD顯示數據
	}

	return 0;
}
  • 完整的文件:
/**
 * @file  bmp.c
 * @brief 處理bmp文件,對其進行解析
 * @version 1.0 (版本聲明)
 * @author Dk
 * @date  July 7,2020
 */
#include <stdlib.h>
#include <string.h>

#include "pic_operation.h"
#include "debug_manager.h"

#pragma pack(push) /* 將當前pack設置壓棧保存 */
#pragma pack(1)    /* 必須在結構體定義之前使用 */

/* bmp文件信息頭 */
typedef struct tagBITMAPFILEHEADER {
	unsigned short bfType; 			//文件類型
	unsigned long  bfSize;			//文件大小
	unsigned short bfReserved1;		//保留位,必須爲0
	unsigned short bfReserved2;		//保留位,必須爲0
	unsigned long  bfOffBits;		//文件頭開始到實際的圖象數據之間的字節的偏移量
} BITMAPFILEHEADER;

/* 位圖信息頭 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;			//文件信息頭結構體需要的自身
	unsigned long  biWidth;			//圖像寬度
	unsigned long  biHeight;		//圖像高度
	unsigned short biPlanes;		//位面數,總被設爲1
	unsigned short biBitCount;		//bpp
	unsigned long  biCompression;	//數據壓縮的類型
	unsigned long  biSizeImage;		//圖象的大小
	unsigned long  biXPelsPerMeter;//水平分辨率
	unsigned long  biYPelsPerMeter;//垂直分辨率
	unsigned long  biClrUsed;		//使用的彩色表中的顏色索引,0-使用所有調色板項
	unsigned long  biClrImportant;	//對圖象顯示有重要影響的顏色索引的數目,0-都重要
} BITMAPINFOHEADER;

#pragma pack(pop) /* 恢復先前的pack設置 */

/**
 * @Description: 判斷是否爲bmp文件
 * @param pFileHead - 文件頭
 * @return 1 - bmp文件, 0 - 非bmp文件
 */
static int isBMPFormat(unsigned char *pFileHead)
{
	/* bmp文件最開始的兩字節數據爲0x4D42 */
	if ((pFileHead[0] != 0x42) || (pFileHead[1] != 0x4d))
		return 0;
	else
		return 1;
}

/**
 * @Description: 從源數據中按照DstBpp的值,轉換到目的數據
 * @param width - bmp位圖的寬度,SrcBpp - bmp位圖的bpp
 *		  DstBpp - LCD上顯示位圖的bpp,SrcDatas - bmp位圖的一行像素起始地址
 *		  DstDatas - LCD上顯示位圖的一行像素起始地址
 * @return 0 - 支持轉換,-1 - 不支持轉換 
 */
static int CoverOneLine(int width, int SrcBpp, int DstBpp, unsigned char *SrcDatas, unsigned char *DstDatas)
{
	int i;
	int pos;
	unsigned int red;
	unsigned int green;
	unsigned int blue;
	unsigned int color;
	unsigned short *DstData16Bpp;
	unsigned int   *DstData32Bpp;

	pos = 0;
	DstData16Bpp = (unsigned short *)DstDatas;
	DstData32Bpp = (unsigned int   *)DstDatas;
	
	if (SrcBpp != 24) {
		DebugPrint(APP_NOTICE"can not support %bpp\n", SrcBpp);
		return -1;
	}

	if (DstBpp == 24)
		memcpy(DstDatas, SrcDatas, width * 3);
	else {
		/* 提取有效的數據 */
		for (i = 0; i < width; i++) {
			blue   = SrcDatas[pos++];
			green  = SrcDatas[pos++];
			red    = SrcDatas[pos++];
			
			if (DstBpp == 32) {
				color = (red << 16) | (green << 8) | blue;
				*DstData32Bpp = color;
				DstData32Bpp++;
			} else if (DstBpp == 16) {
				/* RGB:565 */
				red   = red   >> 3;
				green = green >> 2;
				blue  = blue  >> 3;
				color = (red << 11) | (green << 5) | blue;
				*DstData16Bpp= color;
				DstData16Bpp++;
			}
		}
	}

	return 0;
}

/**
 * @Description: 從bmp文件中獲取像素數據,並分配緩衝區存放像素信息,供外部文件調用
 * @param pFileHead - 文件頭,ptPixelDatas - 位圖信息,存儲像素信息,其bpp用戶設定
 * @return 0 - 成功,-1 - 失敗 
 */
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)
{
	int y;
	int width;
	int height;
	int BMPbpp;
	int LineWidthReal;
	int LineWidthAlign;
	unsigned char *pSrc;
	unsigned char *pDest;
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;

	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)pFileHead;
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(pFileHead + sizeof(BITMAPFILEHEADER));

	/* 獲取bmp文件信息 */
	width  = ptBITMAPINFOHEADER->biWidth;
	height = ptBITMAPINFOHEADER->biHeight;
	BMPbpp = ptBITMAPINFOHEADER->biBitCount;
	if (BMPbpp != 24) {
		DebugPrint(APP_ERR"can not support %d bpp\n", BMPbpp);
		return -1;
	}

	/* 設置結構體 */
	ptPixelDatas->height      = height;
	ptPixelDatas->width       = width;
	ptPixelDatas->linebytes   = width * ptPixelDatas->bpp / 8;
	
	/* 分配緩衝區 */
	ptPixelDatas->PixelDatas = (unsigned char *)malloc(width * height * ptPixelDatas->bpp / 8);
	if (ptPixelDatas->PixelDatas == NULL) {
		DebugPrint(APP_ERR"malloc ptPixelDatas->PixelDatas err\n");
		return -1;
	}

	/* 獲取bmp像素信息:存儲像素的起始是圖片左下角 */
	LineWidthReal  = width * BMPbpp / 8;	//每行像素所佔的字節
	LineWidthAlign = (LineWidthReal + 3) & ~0x3;		//向4取整後的每行像素所佔的字節

	pSrc = pFileHead + ptBITMAPFILEHEADER->bfOffBits;	//像素信息的源地址
	pSrc = pSrc + LineWidthAlign * (height- 1);			//移動到存儲圖片左上角的數據地址

	pDest = ptPixelDatas->PixelDatas;	//數據最終的去向
	
	for (y = 0; y < height; y++) {
		//memcpy(pDest, pSrc, LineWidthReal);
		CoverOneLine(width, BMPbpp, ptPixelDatas->bpp, pSrc, pDest);
		pSrc  -= LineWidthAlign;	//bmp二進制數據
		pDest += ptPixelDatas->linebytes;		//LCD顯示數據
	}

	return 0;
}

/**
 * @Description: 釋放存儲bmp文件中的像素信息的內存
 * @param ptPixelDatas - 位圖信息,存儲像素信息
 * @return 0 - 釋放成功
 */
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
	free(ptPixelDatas->PixelDatas);
	return 0;
}

T_PicFileParser s_tBMPParser = {
	.name 			= "bmp",
	.isSupport 		= isBMPFormat,
	.GetPixelDatas 	= GetPixelDatasFrmBMP,
	.FreePixelDatas = FreePixelDatasForBMP,
};

4、zoom.c處理圖片縮放

設計思路:

  1. 外部函數調用時,源圖片信息存儲在ptOriginPic結構體縮放信息存儲在ptZoomPic結構體,在調用前用戶已經設置好縮放圖片的height、width等信息
  2. 通過以下公式計算得到縮放圖片中每個像素在源圖片的對應位置
    在這裏插入圖片描述
  3. 根據縮放圖片每一行起始像素對應在源圖片的像素的位置以源圖片的像素的位置爲起始點複製長度爲縮放圖片一行寬度的像素數量到縮放圖片對應的內存中。
/**
 * @file  bmp.c
 * @brief 處理bmp文件的座標信息,計算實現縮放
 * @version 1.0 (版本聲明)
 * @author Dk
 * @date  July 7,2020
 */

#include <stdlib.h>
#include <string.h>

#include "pic_operation.h"
#include "debug_manager.h"

/**
 * @Description: 對圖片數據處理進行實現縮放,採用近鄰取樣插值
 * @param ptOriginPic - 縮放前圖片信息, ptZoomPic - 縮放後圖片信息
 * @return 0 - 成功縮放,-1 - 不支持縮放
 */
int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic)
{
	unsigned long x, y;
	unsigned long PixelBytes;
	unsigned long SrcY;
    unsigned long DstWidth;
    unsigned long *pSrcXTable;
	unsigned char *pDest;
	unsigned char *pSrc;

	if (ptOriginPic->bpp != ptZoomPic->bpp) {
		DebugPrint(APP_NOTICE"can not support bpp where the source %d and destination %d are different\n"
					, ptOriginPic->bpp, ptZoomPic->bpp);
		return -1;
	}
	
	DstWidth = ptZoomPic->width;
	PixelBytes = ptOriginPic->bpp / 8;

	/* 分配空間 */
	pSrcXTable = (unsigned long *)malloc(sizeof(unsigned long) * DstWidth);
	if (pSrcXTable == NULL) {
		DebugPrint(APP_ERR"pSrcXTable malloc err\n");
		return -1;
	}

	/* 獲取源圖片一行中像素點的x座標 */
    for (x = 0; x < DstWidth; x++)
        pSrcXTable[x]=(x * ptOriginPic->width / ptZoomPic->width);

	/* 計算縮放後的座標信息 */
    for (y = 0; y < ptZoomPic->height; y++) {
		SrcY = (y * ptOriginPic->height / ptZoomPic->height);		//獲取源圖片一列中像素點的y座標

		pSrc  = ptOriginPic->PixelDatas + SrcY * ptOriginPic->linebytes;	//原圖每行起始像素在內存的地址
		pDest = ptZoomPic->PixelDatas    + y * ptZoomPic->linebytes;	//縮放圖每行起始像素在內存的地址

		/* 原圖座標:(pSrcXTable[x], SrcY)
		 * 縮放座標:(x, y)
		 */
        for (x = 0; x < DstWidth; x++){
			memcpy(pDest + x * PixelBytes, pSrc + pSrcXTable[x] * PixelBytes, PixelBytes); 
        }
    }

	/* 釋放空間 */
    free(pSrcXTable);

	return 0;
}

5、merge.c處理縮放後的數據到Frambufer中

/**
 * @file  merge.c
 * @brief 把zoom.c縮放後處理的像素信息存放到Framebuffer中
 * @version 1.0 (版本聲明)
 * @author Dk
 * @date  July 7,2020
 */
#include <stdlib.h>
#include <string.h>
	
#include "pic_operation.h"
#include "debug_manager.h"

int PicMerge(int x, int y, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic)
{
	int i;
	unsigned char *pDst;
	unsigned char *pSrc;
	
	if ((ptSmallPic->width > ptBigPic->width) ||
		(ptSmallPic->height > ptBigPic->height) ||
		(ptSmallPic->bpp != ptBigPic->bpp)) {
		DebugPrint(APP_ERR"SmallPic > BigPic || SmallPic.bpp != BigPic.bpp\n");
		return -1;
	}

	pSrc = ptSmallPic->PixelDatas;
	pDst = ptBigPic->PixelDatas + y * ptBigPic->width + x * ptBigPic->bpp / 8;
	for (i = 0; i < ptSmallPic->height; i++) {
		memcpy(pDst, pSrc, ptSmallPic->linebytes);
		pSrc += ptSmallPic->linebytes;
		pDst += ptBigPic->linebytes;
	}
	
	return 0;
}

6、main.c協調

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include "config.h"
#include "page_manager.h"
#include "encoding_manager.h"
#include "fonts_manager.h"
#include "disp_manager.h"
#include "input_manager.h"
#include "debug_manager.h"
#include "pic_operation.h"
#include "render.h"

/* digitpic <bmp_file> */
int main(int argc, char **argv)
{
	PT_DispOpr ptDispOpr;
	int error;
	int FDbmp;
	int ret;
	unsigned char *BMPmem;
	struct stat BMPstat;
	extern T_PicFileParser s_tBMPParser;
	T_PixelDatas BMPPixelDatas;
	T_PixelDatas BMPSamllPic;
	T_PixelDatas PixelDataFB;

	if (argc != 2) {
		DebugPrint(APP_NOTICE" %s <bmp_file>\n", argv[0]);
		return -1;
	}
	
	/* 初始化調試系統 */
	error = DebugInit();
	if (error) {
		DBG_PRINTF("DebugInit error!\n");
		return -1;
	}
	
	error = InitDebugChanel();
	if (error) {
		printf("InitDebugChanel error!\n");
		return -1;
	}

	error = DisplayInit();
	if (error) {
		DBG_PRINTF("DisplayInit error!\n");
		return -1;
	}

	/* 獲得負責顯示的結構體 */
	ptDispOpr = GetDispOpr("fb");

	/* 初始化顯示設備 */
	ptDispOpr->DeviceInit();

	/* 清屏 */
	ptDispOpr->CleanScreen(0);
	
	/* 打開bmp文件 */
	FDbmp = open(argv[1], O_RDWR);
	if (FDbmp < 0) {
		DebugPrint(APP_ERR"can not open %s\n", argv[1]);
		return -1;
	}

	/* 獲得文件的大小 */
	fstat(FDbmp, &BMPstat);
	
	/* 直接映射到內存 */
	BMPmem = (unsigned char *)mmap(NULL, BMPstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, FDbmp, 0);
	if (BMPmem == (unsigned char *)-1) {
		DebugPrint(APP_ERR"mmap err\n");
		return -1;
	}

	/* 打開bmp文件 */
	ret = s_tBMPParser.isSupport(BMPmem);
	if (ret == 0) {
		DebugPrint(APP_ERR"can not support bmp_file: %s\n", argv[1]);
		return -1;
	}
	
	BMPPixelDatas.bpp = ptDispOpr->Bpp;
	
	/* 獲得圖片數據 */
	ret = s_tBMPParser.GetPixelDatas(BMPmem, &BMPPixelDatas);
	if (ret != 0) {
		DebugPrint(APP_ERR"GetPixelDatas err\n");
		return -1;
	}

	/* 設置LCD上顯示圖片的信息 */
	PixelDataFB.height     = ptDispOpr->Yres;
	PixelDataFB.width      = ptDispOpr->Xres;
	PixelDataFB.bpp        = ptDispOpr->Bpp;
	PixelDataFB.linebytes  = ptDispOpr->Xres * ptDispOpr->Bpp / 8;
	PixelDataFB.PixelDatas = ptDispOpr->pDispMem;
	
	/* 顯示原始圖片 */
	PicMerge(0, 0, &BMPPixelDatas, &PixelDataFB);

	/* 設置LCD上顯示縮小圖片的信息 */
	BMPSamllPic.height     = BMPPixelDatas.height / 4;
	BMPSamllPic.width      = BMPPixelDatas.width / 4;
	BMPSamllPic.bpp        = BMPPixelDatas.bpp;
	BMPSamllPic.linebytes  = BMPSamllPic.width * BMPSamllPic.bpp / 8;
	BMPSamllPic.PixelDatas = (unsigned char *)malloc(BMPSamllPic.linebytes * BMPSamllPic.height);
	if (BMPSamllPic.PixelDatas == NULL) {
		DebugPrint(APP_ERR"malloc BMPSamllPic.PixelDatas err\n");
		return -1;
	}
	
	/* 縮放圖片,原來的1/4 */
	PicZoom(&BMPPixelDatas, &BMPSamllPic);

	/* 顯示縮小的圖片 */
	PicMerge(128, 128, &BMPSamllPic, &PixelDataFB);

	/* 釋放 */
	free(BMPSamllPic.PixelDatas);
	
	/* 縮放 */
	return 0;
}

四、Makefile修改

1、/render目錄下Makefile

# render子目錄Makefile

obj-y += render.o
obj-y += operation/
obj-y += format/

1.1 /render/format目錄下Makefile

# /render/format子目錄Makefile

obj-y += bmp.o

1.2 /render/operation目錄下Makefile

# /render/operation子目錄Makefile

obj-y += merge.o
obj-y += zoom.o

1.3 頂層目錄Makefile

  • 添加render目錄:
obj-y += render/
  • 完整文件:
# 頂層目錄Makefile
#
# 目的:
#	1、每個子目錄都會建立一個Makefile,包含當前目錄下.c文件.h文件
# 	2、頂層目錄下


# 交叉編譯工具鏈
CROSS_COMPILE = arm-linux-

# 定義一些變量 $(CROSS_COMPILE):取出該變量的值 $(CROSS_COMPILE)gcc->arm-linux-gcc
AS		= $(CROSS_COMPILE)as		
LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc
CPP		= $(CC) -E
AR		= $(CROSS_COMPILE)ar
NM		= $(CROSS_COMPILE)nm

STRIP		= $(CROSS_COMPILE)strip
OBJCOPY		= $(CROSS_COMPILE)objcopy
OBJDUMP		= $(CROSS_COMPILE)objdump

# 取出變量的值
export 	AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP

# := 		簡單擴展型變量的值是一次掃描永遠使用
# CFLAGS	方便您利用隱含規則指定編譯C語言源程序的旗標
# -Wall 	幫助列出所有警告信息
# -02		多優化一些,除了涉及空間和速度交換的優化選項,執行幾乎所有的優化工作
# -g		可以認爲它是缺省推薦的選項	
CFLAGS := -Wall -O2 -g

# 把當前目錄下的include目錄下指定爲系統目錄
# +=		爲已經定以過的變量的值追加更多的文本
# -I		指定搜尋包含makefile文件的路徑
# $(shell pwd)  執行shell命令的pwd命令,獲取執行命令的結果
CFLAGS += -I $(shell pwd)/include

# LDFLAGS	用於調用linker(‘ld’)的編譯器的額外標誌
# -l		連接庫的搜尋目錄 -lm調用math庫 -lfreetype調用freetype庫
LDFLAGS := -lm -lfreetype -lts -lpthread

# 取出變量的值
export 	CFLAGS LDFLAGS

TOPDIR := $(shell pwd)
export TOPDIR

# TARGET	目標變量
# := 		簡單擴展型變量的值是一次掃描永遠使使用
TARGET := digitpic

obj-y += main.o
obj-y += display/
obj-y += encoding/
obj-y += fonts/
obj-y += input/
obj-y += debug/
obj-y += render/

# 規則		arm-linux-gcc -lm -lfreetype -o show_file built-in.o
all : 
	make -C ./ -f $(TOPDIR)/Makefile.build
	$(CC) $(LDFLAGS) -o $(TARGET) built-in.o
	
# clean 	刪除所有make正常創建的文件
# 規則		找到所有make創建出來.o文件進行刪除
#			刪除show_file
clean :
	rm -f $(shell find -name "*.o")
	rm -f $(TARGET)
	
# distclean 刪除所有正常創建的文件
#			配置文件或爲編譯正常創建的準備文件,甚至makefile文件自身不能創建的文件
# 規則		找到所有mkae創建出來的.o文件進行刪除
#			刪除show_file
distclean:
	rm -f $(shell find -name "*.o")
	rm -f $(shell find -name "*.d")
	rm -f $(TARGET)

五、編譯與運行

  1. 執行make,獲得digitpic可執行文件
    在這裏插入圖片描述
  2. 把可執行文件與顯示的圖片文件上傳到開發板的根文件系統
  3. 執行./digitpic time.bmp
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章