jpg图片解码

1. bmp 图片格式

bmp :位图像素文件

  • 文件头部
/* 位图文件的文件头 */
struct BitMapPicHeader{
    unsigned short bfType;  /* 类型,必须是 0x4d42 */
    unsigned long  bfSize;  /* 该文件的大小 */
    unsigned short bfReserved1; /* 保留,不使用 */
    unsigned short bfReserved2;
    unsigned long  bfOffBytes;  /* 像素数据的偏移地址 */
};

/* 位图文件的信息头 */
struct BitMapPicInfoHeader{
    unsigned long  biSize;          /* 信息头的大小,就是该结构体的大小 */
    unsigned long  biWidth;         /* 图片的宽高 */
    unsigned long  biHeight;
    unsigned short biPlanes;        /*  */
    unsigned short biBitCount;      /* 像素位宽 */
    unsigned long  biCompression;
    unsigned long  biSizeImage;     /* 像素总大小,也就是图片大小 */
    unsigned long  biXPelsPerMeter; /* X 分辨率 */
    unsigned long  biYPelsPerMeter; /* Y 分辨率 */
    unsigned long  biClrUsed;
    unsigned long  biClrImportant;
};
  • 剩下的就是像素数据,这些数据是未经过压缩的数据。
  • BMP 24位像素的组织方式是 BGR 格式,而不是普通的 RGB
  • 它的最后一行像素数据是实际上图片的第一行像素数据,依次往上分别是对应的图片从上到下的像素数据
  • 它的像素数据是 4 字节对齐的,也就是一行像素数据如果不够 4 字节的倍数会自动补齐 4 个字节,那几个是空值,我们在读取的时候不需要,这个是跟 windows 系统有关系的
static void ConvertOneLine(int iSrcBpp, int iDesBpp, unsigned char *pucSrcPiexl, unsigned char *pucDesPiexl, int iConvLen)
{
    int iPixelNum = 0;
    int iRed;
    int iGreen;
    int iBlue;

    unsigned short *pwDes16Bpp = (unsigned short *)pucDesPiexl;
    unsigned int *pdwDes32Bpp  = (unsigned int *)pucDesPiexl;

    switch(iDesBpp){
        case 16: {
            for(iPixelNum = 0; iPixelNum < iConvLen; iPixelNum ++){
                iBlue  = pucSrcPiexl[3*iPixelNum];
                iGreen = pucSrcPiexl[3*iPixelNum + 1];
                iRed   = pucSrcPiexl[3*iPixelNum + 2];

                iRed   = iRed >> 3;
                iGreen = iGreen >> 2;
                iBlue  = iBlue>> 3;

                pwDes16Bpp[iPixelNum] = ((iRed << 11) | (iGreen << 5) | (iBlue << 0));  
            }
            break;
        }
        case 32: {
            for(iPixelNum = 0; iPixelNum < iConvLen; iPixelNum ++){
                iBlue  = pucSrcPiexl[3*iPixelNum];
                iGreen = pucSrcPiexl[3*iPixelNum + 1];
                iRed   = pucSrcPiexl[3*iPixelNum + 2];

                pdwDes32Bpp[iPixelNum] = (iRed << 16) | (iGreen << 8) | (iBlue << 0);
            }
            break;
        }

        default : break;
    }
}


/* ptPiexlDatasDesc->iBpp        = iBpp;
 * 要从外部输入
 */
static int BMPGetPiexlDatas(struct FileDesc *ptFileDesc, struct PiexlDatasDesc *ptPiexlDatasDesc)
{
    unsigned char *BMPFileMem;
    struct BitMapPicHeader     *ptBMPHeader;
    struct BitMapPicInfoHeader *ptBMPInfoHeader;

    int iWidth;
    int iHeight;
    int iBMPLineWidth;
    int iBpp;

    int iLineNum = 0;
    unsigned char *pucPiexlSrc;
    unsigned char *pucPiexlDes;

    ptBMPHeader     = (struct BitMapPicHeader*)ptFileDesc->pucFileMem;
    ptBMPInfoHeader = (struct BitMapPicInfoHeader*)(ptFileDesc->pucFileMem + sizeof(struct BitMapPicHeader));
    BMPFileMem = ptFileDesc->pucFileMem;

    iWidth     = ptBMPInfoHeader->biWidth;
    iHeight    = ptBMPInfoHeader->biHeight;
    iBpp       = ptBMPInfoHeader->biBitCount;

    if(iBpp != 24){
        DebugPrint(DEBUG_ERR"BMP bpp = %d\n", iBpp);
        return -1;
    }

    ptPiexlDatasDesc->iWidth      = iWidth;
    ptPiexlDatasDesc->iHeight     = iHeight;
    ptPiexlDatasDesc->iLineLength = iWidth * ptPiexlDatasDesc->iBpp / 8;
    ptPiexlDatasDesc->iTotalLength= iHeight * ptPiexlDatasDesc->iLineLength;

//  DebugPrint("iLineLength = %d\n", ptPiexlDatasDesc->iLineLength);

    ptPiexlDatasDesc->pucPiexlDatasMem = malloc(ptPiexlDatasDesc->iTotalLength);
    if(NULL == ptPiexlDatasDesc->pucPiexlDatasMem){
        DebugPrint(DEBUG_ERR"Has no space for PiexlDatasMem\n");
        return -1;
    }

    /* BMP 位图的像素数据 4 字节对齐,但是 LCD 屏的像素数据不需要对齐 */
    iBMPLineWidth  = (iWidth * iBpp / 8 + 3) & ~0x03;

    pucPiexlSrc = (unsigned char *)(BMPFileMem + ptBMPHeader->bfOffBytes);
    pucPiexlSrc += (iHeight - 1) * iBMPLineWidth;
    pucPiexlDes = ptPiexlDatasDesc->pucPiexlDatasMem;

    for(iLineNum = 0; iLineNum < iHeight; iLineNum ++){
        ConvertOneLine(iBpp, ptPiexlDatasDesc->iBpp, pucPiexlSrc, pucPiexlDes, iWidth);
        pucPiexlSrc -= iBMPLineWidth;
        pucPiexlDes += ptPiexlDatasDesc->iLineLength;
    }

    return 0;       
}

2. jpeg 图片

没有去关注过 jpeg 文件的文件格式,只是用 libjpeg-turbo 进行文件的读取,解压缩

2.1 libjpeg 库的安装

mkdir tmp
CC= arm-linux-gcc
./configure --host=arm-linux --prefix=/work/testfile/digital_prj/libjpeg/libjpeg-turbo-1.5.0/tmp
make
make install
  • 拷贝库文件到交叉编译工具链
sudo cp ./lib/*.so* /work/tools/opt/FriendlyARM/toolschain/4.4.3/lib -drf
sudo cp ./include/* /work/tools/opt/FriendlyARM/toolschain/4.4.3/include/ -drf
  • 拷贝库文件到 arm 开发板上面
cp ../libjpeg-turbo-1.5.0/tmp/lib/*so* /lib/

2.2 libjpeg 的使用

  • 解压缩:
     
    1. 分配并且初始化一个 JPEG 解压缩结构体对象
    2. 指定要解压的压缩文件,jpg 格式的
    3. 调用 jpeg_read_header() 来获得图像信息
    4. 设置结构体成员
    5. jpeg_start_decompress(…); 开始解压缩
    6. while (scan lines remain to be read)
      jpeg_read_scanlines(…);
      开始不断的扫描读取点数据
    7. jpeg_finish_decompress(…); 结束解压过程
    8. 释放 JPEG 解压缩结构体

实例:

#include <stdio.h>
#include <stdlib.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

static struct fb_var_screeninfo g_tFBVar;   
static struct fb_fix_screeninfo g_tFBFix;
static unsigned int g_dwFBScreenSize = 0;
static unsigned char *g_pucFBMem = NULL;

static int g_FBfd;
static unsigned int g_dwScreenWidth;
static unsigned int g_dwScreenHight;
static unsigned int g_dwPixelWidth;

static int FBDisDeviceInit(void)
{
    int iError;

    g_FBfd = open("/dev/fb0", O_RDWR);
    if (g_FBfd < 0){
        printf("Can't open /dev/fb0\n");
        return -1;
    }

    iError = ioctl(g_FBfd, FBIOGET_VSCREENINFO, &g_tFBVar);
    if (iError){
        printf("Can't get the framebuffer screen info\n");
        return -1;
    }

    iError = ioctl(g_FBfd, FBIOGET_FSCREENINFO, &g_tFBFix);
    if (iError){
        printf("Can't get the fix info\n");
        return -1;
    }

    g_dwFBScreenSize = g_tFBVar.xres * g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;

    g_pucFBMem = (unsigned char *)mmap(NULL, g_dwFBScreenSize, 
                                    PROT_READ | PROT_WRITE, MAP_SHARED, g_FBfd, 0);
    if(g_pucFBMem == (unsigned char *)-1){
        printf("mmap g_pucFBMem failed\n");
        return -1;
    }

    g_dwScreenWidth = g_tFBVar.xres * g_tFBVar.bits_per_pixel / 8;
    g_dwScreenHight = g_tFBVar.yres * g_tFBVar.bits_per_pixel / 8;
    g_dwPixelWidth  = g_tFBVar.bits_per_pixel / 8;

    return 0;
}
static int FBShowPiexl(int iPenX, int iPeny, unsigned int dwColor)
{
    int iRed, iGreen, iBlue;
    unsigned char *pucPen8bpp;
    unsigned short *pwPen16bpp;
    unsigned int *pdwPen32bpp;

    if(iPenX > g_dwScreenWidth || iPeny > g_dwScreenHight){
        printf("Out of screen\n");
        return -1;
    }

    pucPen8bpp  = (unsigned char *)
        g_pucFBMem + (iPeny * g_tFBVar.xres + iPenX) * g_tFBVar.bits_per_pixel / 8;
    pwPen16bpp  = (unsigned short *)
        g_pucFBMem + (iPeny * g_tFBVar.xres + iPenX) * g_tFBVar.bits_per_pixel / 16;
    pdwPen32bpp = (unsigned int *)
        g_pucFBMem + (iPeny * g_tFBVar.xres + iPenX) * g_tFBVar.bits_per_pixel / 32;

    switch(g_tFBVar.bits_per_pixel){
        case 8: {
            *pucPen8bpp = dwColor;
            break;
        }
        case 16: {
            iRed   = (dwColor >> 16) & 0xff;
            iGreen = (dwColor >> 8) & 0xff;
            iBlue  = (dwColor >> 0) & 0xff;

            dwColor = ((iRed >> 3) << 11) | ((iGreen >> 2) << 5) | ((iBlue >> 3));
            *pwPen16bpp = dwColor;
            break;
        }
        case 32: {
            *pdwPen32bpp = dwColor;
            break;
        }
        default:{
            printf("Can't support bpp %d\n", g_tFBVar.bits_per_pixel);
            break;
        }
    }

    return 0;
}
static int FBCleanScreen(unsigned int dwBackColor)
{
    int iRed, iGreen, iBlue;
    unsigned char *pucPen8bpp;
    unsigned short *pwPen16bpp;
    unsigned int *pdwPen32bpp;

    unsigned int i = 0;

    pucPen8bpp  = (unsigned char *) g_pucFBMem;
    pwPen16bpp  = (unsigned short *) g_pucFBMem;
    pdwPen32bpp = (unsigned int *) g_pucFBMem;

    switch(g_tFBVar.bits_per_pixel){
        case 8: {
            memset(pucPen8bpp, dwBackColor, g_dwFBScreenSize);
            break;
        }
        case 16: {
            iRed   = (dwBackColor >> 16) & 0xff;
            iGreen = (dwBackColor >> 8) & 0xff;
            iBlue  = (dwBackColor >> 0) & 0xff;

            dwBackColor = ((iRed >> 3) << 11) | ((iGreen >> 2) << 5) | ((iBlue >> 3));

            for(i = 0; i < g_dwFBScreenSize; i += 2){
                pwPen16bpp[i/2] = dwBackColor;
            }   
            break;
        }
        case 32: {
            for(i = 0; i < g_dwFBScreenSize; i += 4){
                pdwPen32bpp[i/4] = dwBackColor;
            }
            break;
        }
        default:{
            printf("Can't support bpp %d\n", g_tFBVar.bits_per_pixel);
            break;
        }
    }

    return 0;
}

int FbDrawLines(int iXStart, int iXEnd, int iYStart, unsigned char *pucLineBuff, int iPiexlLength)
{
    int iNPiexlNum;
    unsigned int dwRed;
    unsigned int dwGreen;
    unsigned int dwBlue;
    unsigned int dwColor;

    if(iYStart >= g_tFBVar.yres){
            return -1;
    }

    for(iNPiexlNum = iXStart * iPiexlLength; iNPiexlNum < iXEnd * iPiexlLength; iNPiexlNum += iPiexlLength){
        if(iNPiexlNum / iPiexlLength >= g_tFBVar.xres){
            return -1;
        }

        dwRed   = pucLineBuff[iNPiexlNum];
        dwGreen = pucLineBuff[iNPiexlNum + 1];
        dwBlue  = pucLineBuff[iNPiexlNum + 2];

        dwColor = (dwRed << 16) | (dwGreen << 8) | (dwBlue << 0);
        FBShowPiexl(iNPiexlNum / iPiexlLength, iYStart, dwColor);
    }

    return 0;
}

static void JPGErrorExit(j_common_ptr ptCInfo)
{
    static char errStr[JMSG_LENGTH_MAX];

    struct JPGErrorMgr *ptJPGError;

    ptJPGError = (struct JPGErrorMgr *)ptCInfo->err;

    /* 创建信息 */
    (*ptCInfo->err->format_message)(ptCInfo, errStr);
    DebugPrint("%s\n", errStr);

    longjmp(ptJPGError->setjmp_buffer, 1);
}

int main(int argc, char *argv[])
{   
    struct jpeg_decompress_struct tJpegInfo;
    struct jpeg_error_mgr tJpegPub;
    char cScale[10];
    int iSacnlines;
    unsigned char *pucScanBuffer;
    int iLineBufferLength;
    int iError = 0;

    FILE *ptJpegFile;

    if(argc != 2){
        printf("exe <file.jpg>\n");
        return -1;
    }

    iError = FBDisDeviceInit();
    if(iError){
        printf("No such device\n");
        return -1;
    }

    FBCleanScreen(0);

    ptJpegFile = fopen(argv[1], "rb");  /* 只读,二进制 */
    if(ptJpegFile == NULL){
        printf("Open jpeg file failed\n");
        return -1;
    }

    tJpegInfo.err = jpeg_std_error(&tJpegPub);
    tJpegPub.error_exit     = JPGErrorExit;  /* 不使用 libjpeg 库提供的退出函数,那个会导致整个进程直接退出 */

    /* 分配一个解压缩结构体 */
    jpeg_create_decompress(&tJpegInfo);

    /* 指定数据文件 */
    jpeg_stdio_src(&tJpegInfo, ptJpegFile);

    printf("Where did this program exit\n");

    /* 读取文件头部 */
    jpeg_read_header(&tJpegInfo, TRUE);
    printf("input weight = %d\n", tJpegInfo.image_width);
    printf("input height = %d\n", tJpegInfo.image_height);
    printf("input color components = %d\n", tJpegInfo.num_components);

    scanf("%d/%d", &tJpegInfo.scale_num, &tJpegInfo.scale_denom);
    printf("scale %d/%d\n", tJpegInfo.scale_num, tJpegInfo.scale_denom);

    /* 开始解压缩 */
    jpeg_start_decompress(&tJpegInfo);

    printf("out weight = %d\n", tJpegInfo.output_width);
    printf("out height = %d\n", tJpegInfo.output_height);
    printf("out color components = %d\n", tJpegInfo.output_components);

    iLineBufferLength = tJpegInfo.output_width * tJpegInfo.output_components;
    pucScanBuffer = malloc(iLineBufferLength);
    if(NULL == pucScanBuffer){
        printf("No space for line-buff\n");
        goto exit;
    }

    /* 不断地逐行读取数据 */
    for (iSacnlines = 0; iSacnlines < tJpegInfo.output_height; iSacnlines ++){
        /* 每次读取一行的数据 */
        jpeg_read_scanlines(&tJpegInfo, &pucScanBuffer, 1);
        FbDrawLines(0, tJpegInfo.output_width,iSacnlines, pucScanBuffer, tJpegInfo.output_components);
    }

    /* 结束解压缩 */
    jpeg_finish_decompress(&tJpegInfo);

    /* 释放结构体 */
    jpeg_destroy_decompress(&tJpegInfo);

    free(pucScanBuffer);
exit:
    /* 关闭文件 */
    fclose(ptJpegFile);

    return 0;
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页