JPEG图片
JPEG文件:经压缩,不仅空间能缩小挺多,而且图片质量损失不太明显,被广泛应用。
jpeglib库
配置编译:
- ./configure --host=arm-linux
- make
- make DESTDIR=$PWD/tmp install
- 将指定的库文件和头文件拷贝到交叉编译工具对应目录下
把编译出来的头文件应该放入:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include
把编译出来的动态库文件应该放入:/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib 以及 arm根文件系统的lib目录下
关键实现思路
打开jpeg,获取其文件描述符的对应信息cinfo,根据其成员可得到该Jpeg一行数据的大小row_stride = cinfo.output_width * cinfo.output_components,申请一段空间,将该行数据解压后存放于该空间中,解压后的数据用以描述一个像素点的字节数由num_components可知,一般为3字节,分别表示RGB,每次解压都将一行的RGB数据存放于对应空间中,并将3字节大小的RGB数据通过错位相加888格式存储于unsigned int color变量中,通过该color值,写入FB对应位置中,显示出来。
即读一行,显示一行,循环一直往下读,到底部。
使用
- 分配和初始化一个decompression结构体
struct jpeg_decompress_struct cinfo;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
- 打开LCD Fb对应的设备结点,并将其空间共享到用户空间中,即可在内存中进行操作
g_fd = open(FB_DEVICE_NAME, O_RDWR);
ret = ioctl(g_fd, FBIOGET_VSCREENINFO, &g_tFBVar);
ret = ioctl(g_fd, FBIOGET_FSCREENINFO, &g_tFBFix);
g_dwScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;
g_pucFBMem = (unsigned char *)mmap(NULL , g_dwScreenSize, PROT_READ | PROT_WRITE,MAP_SHARED, g_fd, 0);
- 指定jpeg源文件
FILE *infile = fopen(argv[1], "rb");
jpeg_stdio_src(&cinfo, infile);
- 用jpeg_read_header获得jpg信息,num_components一般为3,表示分别表示RGB值
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);
- 设置解压参数,比如放大、缩小; 注意:该步骤可能不成功,需要对比解压前后的参数确定。
printf("enter scale M/N:\n");
scanf("%d/%d", &cinfo.scale_num, &cinfo.scale_denom);
printf("scale to : %d/%d\n", cinfo.scale_num, cinfo.scale_denom);
- 启动解压:
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;
buffer = malloc(row_stride);
- 循环调用,一行一行获取并显示到LCD
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
-
释放decompression结构体:jpeg_destroy_decompress(&cinfo);
FBshowline
static int FBShowLine(int iXStart, int iXEnd, int iY, unsigned char *pucRGBArray)
{
int i = iXStart * 3;
int iX;
unsigned int dwColor;
if (iY >= g_tFBVar.yres)
return -1;
if (iXStart >= g_tFBVar.xres)
return -1;
if (iXEnd >= g_tFBVar.xres)
{
iXEnd = g_tFBVar.xres;
}
for (iX = iXStart; iX < iXEnd; iX++)
{
/* 0xRRGGBB */
dwColor = (pucRGBArray[i]<<16) + (pucRGBArray[i+1]<<8) + (pucRGBArray[i+2]<<0);
i += 3;
FBShowPixel(iX, iY, dwColor);
}
return 0;
}
FBShowPixel
static int FBShowPixel(int iX, int iY, unsigned int dwColor)
{
unsigned char *pucFB;
unsigned short *pwFB16bpp;
unsigned int *pdwFB32bpp;
unsigned short wColor16bpp; /* 565 */
int iRed;
int iGreen;
int iBlue;
if ((iX >= g_tFBVar.xres) || (iY >= g_tFBVar.yres))
{
DBG_PRINTF("out of region\n");
return -1;
}
pucFB = g_pucFBMem + g_dwLineWidth * iY + g_dwPixelWidth * iX;
pwFB16bpp = (unsigned short *)pucFB;
pdwFB32bpp = (unsigned int *)pucFB;
switch (g_tFBVar.bits_per_pixel)
{
case 8:
{
*pucFB = (unsigned char)dwColor;
break;
}
case 16:
{
iRed = (dwColor >> (16+3)) & 0x1f;
iGreen = (dwColor >> (8+2)) & 0x3f;
iBlue = (dwColor >> 3) & 0x1f;
wColor16bpp = (iRed << 11) | (iGreen << 5) | iBlue;
*pwFB16bpp = wColor16bpp;
break;
}
case 32:
{
*pdwFB32bpp = dwColor;
break;
}
default :
{
DBG_PRINTF("can't support %d bpp\n", g_tFBVar.bits_per_pixel);
return -1;
}
}
return 0;
}