16.render/fomat和operation文件夹分析

1.render/format文件夹

这个文件夹主要是用来识别图片文件、从图片文件中提取数据像素,所用到两个结构体如下

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

/* 用来描述一个图片解析器(解析BMP还是JPG) */
typedef struct PicFileParser {
	char *name;                     			/* 图片文件解析模块的名字 */
	int (*isSupport)(PT_FileMap ptFileMap);  	/* 是否支持某文件 */
	int (*GetPixelDatas)(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas); /* 从文件中解析出图像的象素数据 */
	int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);  					/* 释放图像的象素数据所占内存 */
    struct PicFileParser *ptNext;  				/* 链表 */
}T_PicFileParser, *PT_PicFileParser;

1.picfmt_manager.c中的函数
这个文件里主要是图片解析器的框架,如之前的一样,包含

  • 注册一个解释器
  • 解释器的初始化
  • 打印注册过的解释器
  • 根据名字寻找对应解释器的结构体
  • 输入一个图片文件寻找合适的解释器
int RegisterPicFileParser(PT_PicFileParser ptPicFileParser);
void ShowPicFmts(void);
int PicFmtsInit(void);
PT_PicFileParser Parser(char *pcName);				/* 根据名字寻找解析器*/
PT_PicFileParser GetParser(PT_FileMap ptFileMap);	/* 输入一个图片文件,找到可以解析的一个解析器 */

2.jpg.c中的函数
libjpeg库的使用这里不做赘述,最简单的使用方法在bmp和jpg图片显示中有讲,这里不对libjpeg库的使用做详细介绍。

完成jpg解析器的底层,只需要完成typedef struct PicFileParser这个结构体即可

static T_PicFileParser g_tJPGParser = {
	.name           = "jpg",
	.isSupport      = isJPGFormat,
	.GetPixelDatas  = GetPixelDatasFrmJPG,
	.FreePixelDatas = FreePixelDatasForJPG,	
};
  • GetPixelDatasFrmJPG函数
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;

	/* 16bpp与32bpp 的指针,这样就可以自加自减了,指向的是目标地址,就是PT_PixelDatas结构体里的aucPixelDatas*/
	unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
	unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

	int i;
	int pos = 0;

	if (iSrcBpp != 24)
	{
		return -1;
	}

	if (iDstBpp == 24)			/* 源肯定是24bpp,如果目标bpp是24,那么直接memcpy*/
	{
		memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
	}
	else
	{
		for (i = 0; i < iWidth; i++)
		{
			/* 一个像素一个像素来,一共来一行有多少个像素次 */
			/* 这是一个像素的三个字节的rgb信息 */
			dwRed   = pudSrcDatas[pos++];	
			dwGreen = pudSrcDatas[pos++];
			dwBlue  = pudSrcDatas[pos++];
			if (iDstBpp == 32)				
			{
				/* 转成32bpp的 */
				dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
				*pwDstDatas32bpp = dwColor;
				pwDstDatas32bpp++;
			}
			else if (iDstBpp == 16)
			{
				/* 转成565 */
				dwRed   = dwRed >> 3;
				dwGreen = dwGreen >> 2;
				dwBlue  = dwBlue >> 3;
				dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
				*pwDstDatas16bpp = dwColor;
				pwDstDatas16bpp++;
			}
		}
	}
	return 0;
}

static int GetPixelDatasFrmJPG(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{
	struct jpeg_decompress_struct tDInfo;
	//struct jpeg_error_mgr tJErr;
    int iRet;
    int iRowStride;
    unsigned char *aucLineBuffer = NULL;
    unsigned char *pucDest;
	T_MyErrorMgr tJerr;

    fseek(ptFileMap->tFp, 0, SEEK_SET);

	//tDInfo.err = jpeg_std_error(&tJErr);
	tDInfo.err               = jpeg_std_error(&tJerr.pub);
	tJerr.pub.error_exit     = MyErrorExit;

	if(setjmp(tJerr.setjmp_buffer))
	{
		/* 如果程序能运行到这里, 表示JPEG解码出错 */
        jpeg_destroy_decompress(&tDInfo);
        if (aucLineBuffer)
        {
            free(aucLineBuffer);
        }
        if (ptPixelDatas->aucPixelDatas)
        {
            free(ptPixelDatas->aucPixelDatas);
        }
		return -1;
	}
	// 分配和初始化一个decompression结构体
	jpeg_create_decompress(&tDInfo);
	/* 指定源文件 */
	jpeg_stdio_src(&tDInfo, ptFileMap->tFp);
	
	// 用jpeg_read_header获得jpg信息
    iRet = jpeg_read_header(&tDInfo, TRUE);

	// 设置解压参数,比如放大、缩小
	/* 这里就按原来的大小来整,因为后面有放大和缩小的函数来处理 */
    tDInfo.scale_num = tDInfo.scale_denom = 1;
    
	//启动解压:jpeg_start_decompress	
	jpeg_start_decompress(&tDInfo);

	//一行数据的长度,单位Bytes,一个output_components一字节
	iRowStride = tDInfo.output_width * tDInfo.output_components;	
	//这个相当于一个缓存,先解押出数据放到这里面,然后再转换成需要的数据,放到别处
	aucLineBuffer = malloc(iRowStride);								

    if (NULL == aucLineBuffer)
    {
        return -1;
    }
	
	ptPixelDatas->iWidth  = tDInfo.output_width;
	ptPixelDatas->iHeight = tDInfo.output_height;
	//ptPixelDatas->iBpp    = iBpp;						/* 这个是目标bpp,由显示设备决定,所以由上层函数传进来*/
	ptPixelDatas->iLineBytes    = ptPixelDatas->iWidth * ptPixelDatas->iBpp / 8;
    ptPixelDatas->iTotalBytes   = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes;
	/* 这里申请了一块内存,用于存放从jpg图片中读到的数据,在FreePixelDatasForJPG函数里面释放 */
	ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes);
	if (NULL == ptPixelDatas->aucPixelDatas)
	{
		return -1;
	}
	/* 这里之所以还声明了一个变量,是因为这里的aucPixelDatas不能变,一直指向一个地方
	 * 而后续写数据是需要移动指针的,所以这里又声明了一个指针
	 */
    pucDest = ptPixelDatas->aucPixelDatas;	

	/* 循环调用jpeg_read_scanlines来一行一行地获得解压的数据 */
	while (tDInfo.output_scanline < tDInfo.output_height) 
	{
        /* 得到一行数据,里面的颜色格式为0xRR, 0xGG, 0xBB,bpp是24的 */
		(void) jpeg_read_scanlines(&tDInfo, &aucLineBuffer, 1);	

		/* 一行一行转到pucDest,也就是ptPixelDatas->aucPixelDatas里*/
		CovertOneLine(ptPixelDatas->iWidth, 24, ptPixelDatas->iBpp, aucLineBuffer, pucDest);
		/* 一行完了,开始下一行 */
		pucDest += ptPixelDatas->iLineBytes;				
	}
	/* 程序至此,就已经从ptFileMap文件中拿出了所有的数据,放到了ptPixelDatas结构体里 */
	
	/* 释放掉刚刚申请的一块内存 */
	free(aucLineBuffer);
	jpeg_finish_decompress(&tDInfo);
	jpeg_destroy_decompress(&tDInfo);

    return 0;
}
  • FreePixelDatasForJPGhanshu
static int FreePixelDatasForJPG(PT_PixelDatas ptPixelDatas)
{
	/* 在GetPixelDatasFrmJPG函数中申请的数据,用于存放jpg数据的 */
	free(ptPixelDatas->aucPixelDatas);
	return 0;
}

3.bmp.c
从bmp文件获取并转换成我们需要的像素数据,在之前的博客中已经详细写明:bmp和jpg图片显示

2.render/operation文件夹

这个文件夹包括两个:

  • 一个是zoom.c,是用来将一块图片信息(已经转成我们需要的图片信息了)放大或者缩小。
  • 另一个是merge.c,用来把小图片合并到大图片上去(小图片整个合并到大图片上某个位置,入参xy决定这个位置)

这两个功能,在bmp和jpg图片显示也已经讲清楚。

merge.c中的PicMergeRegion函数

这个函数的功能是,从一张图片上扣下来一块儿,按在另外一张图片的某个地方,一比一的移动

 /* 把ptNewPic图片上从(iStartXofNewPic,iStartYofNewPic)开始
  * iWidth,iHeight这么大的一块区域扣下来
  * 合并到ptOldPic这个图片的(iStartXofOldPic,iStartYofOldPic)这个位置去
  */
int PicMergeRegion(int iStartXofNewPic, int iStartYofNewPic, int iStartXofOldPic, int iStartYofOldPic, int iWidth, int iHeight, PT_PixelDatas ptNewPic, PT_PixelDatas ptOldPic)
{
	int i;
	unsigned char *pucSrc;
	unsigned char *pucDst;
    int iLineBytesCpy = iWidth * ptNewPic->iBpp / 8;

	/* 判断,如果xy的坐标超过了原图片的范围,就是输入参数有问题 */
    if ((iStartXofNewPic < 0 || iStartXofNewPic >= ptNewPic->iWidth) || \
        (iStartYofNewPic < 0 || iStartYofNewPic >= ptNewPic->iHeight) || \
        (iStartXofOldPic < 0 || iStartXofOldPic >= ptOldPic->iWidth) || \
        (iStartYofOldPic < 0 || iStartYofOldPic >= ptOldPic->iHeight))
    {
        return -1;
    }

	/* 计算源和目的两个的基地址
	 * 计算方式是:图片数据的源地址 + 坐标*LineByets + x*bpp/8 
	 */
	pucSrc = ptNewPic->aucPixelDatas + iStartYofNewPic * ptNewPic->iLineBytes + iStartXofNewPic * ptNewPic->iBpp / 8;
	pucDst = ptOldPic->aucPixelDatas + iStartYofOldPic * ptOldPic->iLineBytes + iStartXofOldPic * ptOldPic->iBpp / 8;
	/* 一行一行的直接memcpy */
	for (i = 0; i < iHeight; i++)
	{
		memcpy(pucDst, pucSrc, iLineBytesCpy);
		/* 每次都加自己那张图片的一行的数据量就行 */
		pucSrc += ptNewPic->iLineBytes;
		pucDst += ptOldPic->iLineBytes;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值