11.bmp和jpg图片显示

1.libjpeg库的基本使用

int main(int argc , char **argv)
{
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	FILE * infile;
	int row_stride;
	unsigned char *buffer;
	/*分配和初始化一个decompression结构体*/
	cinfo.err = jpeg_std_error(&jerr);	
	jpeg_create_decompress(&cinfo);
	
	// 指定源文件
	if ((infile = fopen(argv[1], "rb")) == NULL) {
		fprintf(stderr, "can't open %s\n", argv[1]);
		return -1;
	}
	jpeg_stdio_src(&cinfo, infile);

	// 用jpeg_read_header获得jpg信息
	jpeg_read_header(&cinfo, TRUE);
	/* 源信息 */
	printf("image_width = %d\n", cinfo.image_width);
	printf("image_height = %d\n", cinfo.image_height);
	printf("num_components = %d\n", cinfo.num_components);	//一个像素由几种元素组成,一般是3,RGB
	
	// 设置解压参数,比如放大、缩小
	printf("enter scale M/N:\n");
	scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);	// 1/4 
	printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);

	// 启动解压:jpeg_start_decompress	
	jpeg_start_decompress(&cinfo);

	/* 启动解压后,就可以看到一些图像的信息,这里输出的图象的信息 */
	printf("output_width = %d\n", cinfo.output_width);		//输出的图像的宽高
	printf("output_height = %d\n", cinfo.output_height);	//因为可能缩放了,所以可能和上面的源的信息不一样
	printf("output_components = %d\n", cinfo.output_components);
	
	// 一行的数据长度
	row_stride = cinfo.output_width * cinfo.output_components;	//一个components一字节
	buffer = malloc(row_stride);
	
	while (cinfo.output_scanline < cinfo.output_height) 	//一行一行的来
	{
		(void) jpeg_read_scanlines(&cinfo, &buffer, 1);

		// 写到LCD去		 每行多少个像素点	  这是第几行			 这是数据
		FBShowLine(0, cinfo.output_width, cinfo.output_scanline, buffer);
	}
	
	free(buffer);
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

	return 0;
}

2.bmp图片显示

1.bmp图片,头有54字节,包含了一些信息

#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1)    /* 必须在结构体定义之前使用,这是为了让结构体中各成员按1字节对齐 */
//接下来定义的这些,都是以1字节对齐的
//如果不写这个,很可能就是以4字节对其
//比如unsigned short虽然是2字节,但是在内存中很可能是分配了4字节,然后有两个字节不用
typedef struct tagBITMAPFILEHEADER { /* bmfh */
	unsigned short bfType; 			//必须是0x424d
	unsigned long  bfSize;			//整个bmp文件大小
	unsigned short bfReserved1;		//保留
	unsigned short bfReserved2;		//保留
	unsigned long  bfOffBits;		//文件起始位置 到 图片像素数据 的偏移量
} BITMAPFILEHEADER;
#pragma pack(pop) /* 恢复先前的pack设置 */

typedef struct tagBITMAPINFOHEADER { /* bmih */
	unsigned long  biSize;			//这个INFOHEADER结构体的大小
	unsigned long  biWidth;			//图像的宽(像素)
	unsigned long  biHeight;		//高
	unsigned short biPlanes;		//图像数据平面,BMP存储RGB数据,因此总为1
	unsigned short biBitCount;		//图像一个像素的位数
	unsigned long  biCompression;	//是否压缩 0:不压缩  1:RLE8  2:RLE4
	unsigned long  biSizeImage;		//4字节对齐的图像数据大小
	unsigned long  biXPelsPerMeter;	
	unsigned long  biYPelsPerMeter;
	unsigned long  biClrUsed;
	unsigned long  biClrImportant;
} BITMAPINFOHEADER;

2.bmp数据是从一个面板的左下角开始的,相当于原点在左下角( 笛卡尔坐标的第一象限 ),而我们用的LCD一般是将左上角作为原点( 类似笛卡尔坐标第四象限 )。

static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
	unsigned int dwRed;
	unsigned int dwGreen;
	unsigned int dwBlue;
	unsigned int dwColor;

	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;			//用来标志源文件的位置

	if (iSrcBpp != 24)		//如果bmp文件不是像素为24位的,就报错
	{
		return -1;
	}

	if (iDstBpp == 24)		//如果LCD也需要24Bpp的话,就直接memcpy从头拷到尾就可以
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			dwBlue  = pudSrcDatas[pos++];	//每次自加1,一次循环加3次,刚好一个像素的24位
			dwGreen = pudSrcDatas[pos++];
			dwRed   = pudSrcDatas[pos++];
			if (iDstBpp == 32)				//如果LCD需要32位的iBPP的
			{	
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;	//组合成32位的
				*pwDstDatas32bpp = dwColor;	//直接放到那个缓存里
				pwDstDatas32bpp++;			//这个本来就是unsigned int型,自加就加4
			}
			else if (iDstBpp == 16)			//如果LCD需要16位的
			{
				/* 565 */
				dwRed   = dwRed >> 3;		//分别舍掉后3位、2位、3位
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);	//组合
				*pwDstDatas16bpp = dwColor;	//放到缓存里
				pwDstDatas16bpp++;		
			}
		}
	}
	return 0;
}

从bmp数据,转成我们需要的数据
static int GetPixelDatasFrmBMP(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{
	BITMAPFILEHEADER *ptBITMAPFILEHEADER;
	BITMAPINFOHEADER *ptBITMAPINFOHEADER;

    unsigned char *aFileHead; //存放bmp数据的头

	int iWidth;
	int iHeight;
	int iBMPBpp;		//存放的是数据的Bpp,就是一个像素占用多少位
	int y;

	unsigned char *pucSrc;	//源数据地址
	unsigned char *pucDest;	//目的数据地址
	int iLineWidthAlign;
	int iLineWidthReal;

    aFileHead = ptFileMap->pucFileMapMem;	//pucFileMapMem是经过mmap映射后的地址

	ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
	ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));	//拿到这两个结构体的地址

	iWidth = ptBITMAPINFOHEADER->biWidth;		//bmp数据的宽
	iHeight = ptBITMAPINFOHEADER->biHeight;		//bmp数据的高
	iBMPBpp = ptBITMAPINFOHEADER->biBitCount;	//bmp数据的位数

	if (iBMPBpp != 24)				//如果bmp图片的像素不是24位的,就返回错误
	{
		DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp);
		DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER));
		return -1;
	}

	ptPixelDatas->iWidth  = iWidth;	//设置这个图片宽、高
	ptPixelDatas->iHeight = iHeight;
	//这里屏蔽掉,是不使用bmp文件的Bpp,iBpp作为入参,将从bmp文件中读出的数据,转换成输入进来的Bpp
	//ptPixelDatas->iBpp    = iBpp;	
	ptPixelDatas->iLineBytes    = iWidth * ptPixelDatas->iBpp / 8;	//一行数据有多大,单位Bytes,根据入参Bpp和图片的宽来决定
    ptPixelDatas->iTotalBytes   = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes;	//高 * 一行大小
	ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);	//给这个分配一块空间,用来放适用于LCD的数据
	if (NULL == ptPixelDatas->aucPixelDatas)	//分配失败
	{
		return -1;
	}

	iLineWidthReal = iWidth * iBMPBpp / 8;			//这是bmp图片一行有多少个有效Bytes。
													//因为Bpp要4字节对齐,一行的数据未完,需要填其他数据以凑够4的倍数
													//所以有效数据不一定等于一行的所有数据量
	iLineWidthAlign = (iLineWidthReal + 3) & ~0x3;   //实际上一行有多少个数据,4字节对齐
		
	pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits;	//数据头的地址,文件头 + INFO->bfOffBits,从这里开始,就是真正bmp数据的地方
	pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign;	//把这个当作开头,是因为我们想把bmp图片从第一象限的表示方式,
														//转换成第四象限(LCD使用的)表示方式。

	pucDest = ptPixelDatas->aucPixelDatas;				//要把数据存入的地方
	
	for (y = 0; y < iHeight; y++)
	{		
		//memcpy(pucDest, pucSrc, iLineWidthReal);
		//不直接用memcpy是因为可能我们需要的iBpp不是24,所以若不是要转换成我们需要的,单独写了一个
		CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);	//转换一行的数据
		pucSrc  -= iLineWidthAlign;					//每次源数据都是减,因为是从后往前的
		pucDest += ptPixelDatas->iLineBytes;		//这个要加ptPixelDatas->iLineBytes,是因为它要根据它自己的iBpp算一行的数据量
	}
	return 0;	
}

3.bmp图片的缩放

int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic)
{
    unsigned long dwDstWidth = ptZoomPic->iWidth;	//目标的宽
    unsigned long* pdwSrcXTable;					//用来存 目标的X需要从源文件什么地方的X取数据,把这一行全部都一次行算出来,存下,省的每次都要算,有乘除费时间
	unsigned long x;
	unsigned long y;
	unsigned long dwSrcY;
	unsigned char *pucDest;
	unsigned char *pucSrc;
	unsigned long dwPixelBytes = ptOriginPic->iBpp/8;	//源文件一个像素的字节数,和目标文件的字节数是一样的

	if (ptOriginPic->iBpp != ptZoomPic->iBpp) 			//如果缩放的两个文件iBpp不一样,就不搞了
	{
		return -1;
	}

    pdwSrcXTable = malloc(sizeof(unsigned long) * dwDstWidth);		//那个位置用unsigned long来保存
    if (NULL == pdwSrcXTable)
    {
        DBG_PRINTF("malloc error!\n");
        return -1;
    }

    for (x = 0; x < dwDstWidth; x++)					//生成表 pdwSrcXTable	
    {
        pdwSrcXTable[x]=(x*ptOriginPic->iWidth/ptZoomPic->iWidth);	//存放着目标宽对应的源文件的宽位置,计算公式: x * srcwidth / dstwidth
    }

    for (y = 0; y < ptZoomPic->iHeight; y++)			//一行一行的转
    {			
        dwSrcY = (y * ptOriginPic->iHeight / ptZoomPic->iHeight);	//目标Y需要从原来文件的哪个Y取数据

		pucDest = ptZoomPic->aucPixelDatas + y*ptZoomPic->iLineBytes; 			//目的地址:本次写入的数据是从哪开始的:内存头+第几行*一行多少字节
		pucSrc  = ptOriginPic->aucPixelDatas + dwSrcY*ptOriginPic->iLineBytes;	//源地址: 本次需要从第几行数据里抄
		
        for (x = 0; x <dwDstWidth; x++)
        {
            /* 原图座标: pdwSrcXTable[x],srcy
             * 缩放座标: x, y
			 */
			 memcpy(pucDest+x*dwPixelBytes, pucSrc+pdwSrcXTable[x]*dwPixelBytes, dwPixelBytes);	//一个位置一个位置的抄,可能是32位,也可能是24位
        }
    }

    free(pdwSrcXTable);
	return 0;
}

4.小图片拼接到大图片上

int PicMerge(int iX, int iY, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic)	//小图片拼入大图片的位置
{
	int i;
	unsigned char *pucSrc;		//源文件目的地址
	unsigned char *pucDst;		//目标文件的地址
	
	if ((ptSmallPic->iWidth > ptBigPic->iWidth)  ||	//如果小图片大于大图片、两个bpp不一样,就返错
		(ptSmallPic->iHeight > ptBigPic->iHeight) ||
		(ptSmallPic->iBpp != ptBigPic->iBpp))
	{
		return -1;
	}

	pucSrc = ptSmallPic->aucPixelDatas;			//就是小文件存放数据的位置
	pucDst = ptBigPic->aucPixelDatas + iY * ptBigPic->iLineBytes + iX * ptBigPic->iBpp / 8;	//计算存放到大文件的地方
	for (i = 0; i < ptSmallPic->iHeight; i++)
	{
		memcpy(pucDst, pucSrc, ptSmallPic->iLineBytes);	//开始拷贝
		pucSrc += ptSmallPic->iLineBytes;	//这两个都是一次加一行
		pucDst += ptBigPic->iLineBytes;
	}
	return 0;
}

以上用到的结构体

/* 图片的象素数据 */
typedef struct PixelDatas {
	int iWidth;   /* 宽度: 一行有多少个象素 */
	int iHeight;  /* 高度: 一列有多少个象素 */
	int iBpp;     /* 一个象素用多少位来表示 */
	int iLineBytes;  /* 一行数据有多少字节 */
	int iTotalBytes; /* 所有字节数 */ 
	unsigned char *aucPixelDatas;  /* 象素数据存储的地方 */
}T_PixelDatas, *PT_PixelDatas;

typedef struct FileMap {
	char strFileName[256];   /* 文件名 */
	// int iFd; 
	FILE * tFp;              /* 文件句柄 */
	int iFileSize;           /* 文件大小 */
	unsigned char *pucFileMapMem;  /* 使用mmap函数映射文件得到的内存 */
}T_FileMap, *PT_FileMap;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值