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;