jpg图片解码

来源:互联网 发布:系统检测安全数据 编辑:程序博客网 时间:2024/05/29 21:36

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 库的安装

  • 下载
    https://sourceforge.net/projects/libjpeg-turbo/

  • 安装

mkdir tmpCC= arm-linux-gcc./configure --host=arm-linux --prefix=/work/testfile/digital_prj/libjpeg/libjpeg-turbo-1.5.0/tmpmakemake install
  • 拷贝库文件到交叉编译工具链
sudo cp ./lib/*.so* /work/tools/opt/FriendlyARM/toolschain/4.4.3/lib -drfsudo 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;}
0 0
原创粉丝点击