centos7 C++ 使用libjpeg-turbo (让jpg 转bmp以及bmp转jpg)

    libjpeg-turbo这个库比libjpeg强大一些,libjpeg解析完bmp以后,数据格式是RGB,如果再保存为BGR就比较麻烦,而libjpeg-turbo保存为BGR格式的时候有JCS_EXT_BGR这个参数,所以保存bmp图片就方便很多了。

    解析为bmp时,bmp需要4字节对齐,这里我的做法是,假如一个jpg的tup宽度是157,我这边是将图片扩展为160个像素。这里支持从本地文件加载jpg后解析为bmp,也可以从内存解析为bmp,同时支持将bmp压缩为jpg

  

   封装头文件:

   

#ifndef __PARSE_JPEG__
#define __PARSE_JPEG__

#include <stdio.h>
#include <string.h>
#include<sys/types.h>

extern "C" {
    #include "include/jpeglib.h"
}

class ParseJpeg
{//不使用单例是为了支持多线程操作
public:
    ParseJpeg();
    ~ParseJpeg();

public:
    unsigned char* Parse(const char* pstrImageName, bool bHasHeader/*是否只要bmp数据区*/, long& nLen/*返回bmp图像的长度*/, long& nWidth, long& nHeight);
    unsigned char* Parse(const char* pstrImageData, long nImageSize, bool bHasHeader/*是否只要bmp数据区*/, long& nLen/*返回bmp图像的长度*/, long& nWidth, long& nHeight);
    bool CompressBMPToJPG(const char *pstrFilename, unsigned char *bits, int nWidth, int nHeight, int nDepth, int nQuality);

private:
    void analyse_jpeg(const char* pstrImageName, long& nWidth, long& nHeight);//从本地文件夹加载JPG并解析为BMP
    void analyse_jpeg(const char* pstrImageData, long nImageSize, long& nWidth, long& nHeight);//从内存直接解析JPG文件
    void write_bmp_header(long nWidth, long nHeight, long nDepth);
    void write_bmp_data(j_decompress_ptr cinfo, unsigned char *src_buff);

private:
    bool m_bHasHeader;//是否输出bmp图片文件头
    long m_nLenHeader;
    unsigned char* m_pJpgBuffer;
    unsigned char* m_pLineBuffer;
    unsigned char* m_pImageBuffer;
};


#endif
#include "ParseJpeg.h"
#define MAX_IMAGE_SIZE  20 * 1024 * 1024 //针对1920*1080的图像

#pragma pack(2)
typedef struct BITMAPFILEHEADER {
    u_int16_t bfType;
    u_int32_t bfSize;
    u_int16_t bfReserved1;
    u_int16_t bfReserved2;
    u_int32_t bfOffBits;
} BITMAPFILEHEADER;

typedef struct BITMAPINFOHEADER {
    u_int32_t biSize;
    u_int32_t biWidth;
    u_int32_t biHeight;
    u_int16_t biPlanes;
    u_int16_t biBitCount;
    u_int32_t biCompression;
    u_int32_t biSizeImage;
    u_int32_t biXPelsPerMeter;
    u_int32_t biYPelsPerMeter;
    u_int32_t biClrUsed;
    u_int32_t biClrImportant;
} BITMAPINFODEADER;


ParseJpeg::ParseJpeg()
{//主要是为了防止频繁分配内存
    m_bHasHeader = false;
    m_nLenHeader = 0;

    m_pJpgBuffer = NULL;
    while(!m_pJpgBuffer){
        try{
            m_pJpgBuffer = new unsigned char[MAX_IMAGE_SIZE];
        }
        catch(...){}
    }

    m_pLineBuffer = NULL;
    while(!m_pLineBuffer){
        try{
            m_pLineBuffer = new unsigned char[MAX_IMAGE_SIZE];
        }
        catch(...){}
    }

    m_pImageBuffer = NULL;
    while(!m_pImageBuffer){
        try{
            m_pImageBuffer = new unsigned char[MAX_IMAGE_SIZE];
        }
        catch(...){}
    }
}
ParseJpeg::~ParseJpeg()
{
    if(m_pJpgBuffer){
        delete[] m_pJpgBuffer;
        m_pJpgBuffer = NULL;
    }
    if(m_pLineBuffer){
        delete[] m_pLineBuffer;
        m_pLineBuffer = NULL;
    }
    if(m_pImageBuffer){
        delete[] m_pImageBuffer;
        m_pImageBuffer = NULL;
    }
}

void ParseJpeg::analyse_jpeg(const char* pstrImageName, long& nWidth, long& nHeight)
{
    FILE* pFile = fopen(pstrImageName, "rb+");
    if(pFile){
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr jerr;

        cinfo.err = jpeg_std_error(&jerr);    //一下为libjpeg函数,具体参看相关文档
        jpeg_create_decompress(&cinfo);
        jpeg_stdio_src(&cinfo, pFile);
        jpeg_read_header(&cinfo, TRUE);
        jpeg_start_decompress(&cinfo);

        unsigned long width = cinfo.output_width;
        unsigned long height = cinfo.output_height;
        unsigned short depth = cinfo.output_components;
        if(width % 4 != 0){
            nWidth = width + 4 - width % 4;
        }
        else{
            nWidth = width;
        }
        nHeight = height;
        JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, width * depth, 1);

        unsigned char *point = m_pJpgBuffer;
        while (cinfo.output_scanline < height) {
            jpeg_read_scanlines(&cinfo, buffer, 1);//读取一行jpg图像数据到buffer
            memcpy(point, *buffer, width * depth);//将buffer中的数据逐行给src_buff
            point += width*depth;//一次改变一行
        }

        if(m_bHasHeader){
            write_bmp_header(nWidth, nHeight, depth);//写bmp文件头
        }
        write_bmp_data(&cinfo, m_pJpgBuffer);//写bmp像素数据

        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);

        fclose(pFile);
    }
}
void ParseJpeg::analyse_jpeg(const char* pstrImageData, long nImageSize, long& nWidth, long& nHeight)
{//从内存直接解析JPG文件
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);    //一下为libjpeg函数,具体参看相关文档
    jpeg_create_decompress(&cinfo);
    jpeg_mem_src(&cinfo, (unsigned char*)pstrImageData, nImageSize);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);

    unsigned long width = cinfo.output_width;
    unsigned long height = cinfo.output_height;
    unsigned short depth = cinfo.output_components;

    if(width % 4 != 0){
        nWidth = width + 4 - width % 4;
    }
    else{
        nWidth = width;
    }
    
    nHeight = height;
    JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, width * depth, 1);

    unsigned char *point = m_pJpgBuffer;
    while (cinfo.output_scanline < height) {
        jpeg_read_scanlines(&cinfo, buffer, 1);//读取一行jpg图像数据到buffer
        memcpy(point, *buffer, width * depth);//将buffer中的数据逐行给src_buff
        point += width*depth;//一次改变一行
    }

    if(m_bHasHeader){
        write_bmp_header(nWidth, nHeight, depth);//写bmp文件头
    }
    write_bmp_data(&cinfo, m_pJpgBuffer);//写bmp像素数据

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
}
void ParseJpeg::write_bmp_header(long nWidth, long nHeight, long nDepth)
{
    struct BITMAPFILEHEADER bfh;
    struct BITMAPINFOHEADER bih;

    unsigned long headersize = 0;
    unsigned long filesize = 0;

    if (nDepth == 1) {
        headersize = 14 + 40 + 256 * 4;
        filesize = headersize + nWidth * nHeight;
    }

    if (nDepth == 3) {
        headersize = 14 + 40;
        filesize = headersize + nWidth * nHeight * nDepth;
    }

    memset(&bfh, 0, sizeof(struct BITMAPFILEHEADER));
    memset(&bih, 0, sizeof(struct BITMAPINFOHEADER));

    //写入比较关键的几个bmp头参数
    bfh.bfType = 0x4D42;
    bfh.bfSize = filesize;
    bfh.bfOffBits = headersize;

    bih.biSize = 40;
    bih.biWidth = nWidth;
    bih.biHeight = nHeight;
    bih.biPlanes = 1;
    bih.biBitCount = (unsigned short)nDepth * 8;
    bih.biSizeImage = nWidth * nHeight * nDepth;

    memcpy(m_pImageBuffer, &bfh, sizeof(struct BITMAPFILEHEADER));
    memcpy(m_pImageBuffer + sizeof(struct BITMAPFILEHEADER), &bih, sizeof(struct BITMAPINFOHEADER));
    if (nDepth == 1) {//灰度图像要添加调色板
        unsigned char *platte = NULL;
        while(!platte){
            try{
                platte = new unsigned char[256*4];
            }
            catch(...){}
        }

        unsigned char j = 0;
        for (int i = 0; i < 1024; i += 4) {
            platte[i] = j;
            platte[i+1] = j;
            platte[i+2] = j;
            platte[i+3] = 0;
            j++;
        }
        memcpy(m_pImageBuffer + sizeof(struct BITMAPFILEHEADER) + sizeof(struct BITMAPINFOHEADER), platte, sizeof(unsigned char) * 1024);
        m_nLenHeader = sizeof(struct BITMAPFILEHEADER) + sizeof(struct BITMAPINFOHEADER) + sizeof(unsigned char) * 1024;
        delete[] platte;
    }
    else{
        m_nLenHeader = sizeof(struct BITMAPFILEHEADER) + sizeof(struct BITMAPINFOHEADER);
    }
}

void ParseJpeg::write_bmp_data(j_decompress_ptr cinfo, unsigned char *src_buff)
{
    unsigned long width = cinfo->output_width;
    unsigned long height = cinfo->output_height;
    unsigned short depth = cinfo->output_components;

    unsigned char *point = src_buff + width * depth * (height - 1);    //倒着写数据,bmp格式是倒的,jpg是正的
    for (unsigned long i = 0; i < height; i++) {
        for (unsigned long j = 0; j < width * depth; j += depth) {
            if (depth == 1) {//处理灰度图
                m_pLineBuffer[j] = point[j];
            }

            if (depth == 3) {//处理彩色图
                m_pLineBuffer[j + 2] = point[j + 0];
                m_pLineBuffer[j + 1] = point[j + 1];
                m_pLineBuffer[j + 0] = point[j + 2];
            }
        }
        point -= width * depth;


        memcpy(m_pImageBuffer + m_nLenHeader, m_pLineBuffer, sizeof(unsigned char) * width * depth);
        m_nLenHeader += sizeof(unsigned char) * width * depth;
        if(width % 4 != 0){
            long nOffset = 4 - width % 4;//本人添加,当bmp图片宽度不以4字节对齐的时候,会出现图像倾斜、模糊等状况
            for(int i = 0; i < nOffset * depth; i++){
                m_pImageBuffer[m_nLenHeader++] = 0x00;
            }
        }
    }
}


unsigned char* ParseJpeg::Parse(const char* pstrImageName, bool bHasHeader, long& nLen, long& nWidth, long& nHeight)
{
    m_bHasHeader = bHasHeader;
    m_nLenHeader = 0;
    memset(m_pJpgBuffer, 0, MAX_IMAGE_SIZE);
    memset(m_pLineBuffer, 0, MAX_IMAGE_SIZE);
    memset(m_pImageBuffer, 0, MAX_IMAGE_SIZE);
    analyse_jpeg(pstrImageName, nWidth, nHeight);
    nLen = m_nLenHeader;
    return m_pImageBuffer;
}

unsigned char* ParseJpeg::Parse(const char* pstrImageData, long nImageSize, bool bHasHeader, long& nLen/*返回bmp图像的长度*/, long& nWidth, long& nHeight)
{
    m_bHasHeader = bHasHeader;
    m_nLenHeader = 0;
    memset(m_pJpgBuffer, 0, MAX_IMAGE_SIZE);
    memset(m_pLineBuffer, 0, MAX_IMAGE_SIZE);
    memset(m_pImageBuffer, 0, MAX_IMAGE_SIZE);
    analyse_jpeg(pstrImageData, nImageSize, nWidth, nHeight);
    nLen = m_nLenHeader;
    return m_pImageBuffer;
}

bool ParseJpeg::CompressBMPToJPG(const char *pstrFilename, unsigned char *bits, int nWidth, int nHeight, int nDepth, int nQuality)
{
    FILE * pFile = fopen(pstrFilename, "wb+");
    if (pFile){
        struct jpeg_compress_struct cinfo;
        struct jpeg_error_mgr jerr;
        JSAMPROW row_pointer[1];        //pointer to JSAMPLE row[s]

        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_compress(&cinfo);
        jpeg_stdio_dest(&cinfo, pFile);
        cinfo.image_width = nWidth;      //image width and height, in pixels
        cinfo.image_height = nHeight;
        cinfo.input_components = 3;         //# of color components per pixel
        cinfo.in_color_space = JCS_EXT_BGR;         //colorspace of input image
        jpeg_set_defaults(&cinfo);
        jpeg_set_quality(&cinfo, nQuality, TRUE);//limit to baseline-JPEG values
        jpeg_start_compress(&cinfo, TRUE);

        int row_stride = nWidth * nDepth; // JSAMPLEs per row in image_buffer
        while (cinfo.next_scanline < cinfo.image_height)
        {
            //这里我做过修改,由于jpg文件的图像是倒的,所以改了一下读的顺序
            row_pointer[0] = &bits[(cinfo.image_height - cinfo.next_scanline - 1) * row_stride];
            (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
        }
        jpeg_finish_compress(&cinfo);
        fclose(pFile);
        jpeg_destroy_compress(&cinfo);
        return true;
    }

    return false;
}

 

makefile:

INCLUDE_Jpeg=./include
LIBRARY_Jpeg=./lib/libjpeg.a

libChlFaceSdk.so:test.o ParseJpeg.o
	g++ -fPIC -lz -lm -lc -pthread test.o ParseJpeg.o -I$(INCLUDE_Jpeg) $(LIBRARY_Jpeg)   -o ./test 

ParseJpeg.o:ParseJpeg.h ParseJpeg.cpp
	g++ -c ParseJpeg.cpp -fPIC -o ParseJpeg.o

test.o:test.cpp
	g++ -c test.cpp -fPIC -o test.o

clean:
	rm test.o ParseJpeg.o

下载地址:https://download.csdn.net/download/sz76211822/10800690

用于将jpeg文件换成为bmp文件, MICROSOFT FOUNDATION CLASS LIBRARY : JpgVSbmp ======================================================================== AppWizard has created this JpgVSbmp DLL for you. This DLL not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your DLL. This file contains a summary of what you will find in each of the files that make up your JpgVSbmp DLL. JpgVSbmp.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. JpgVSbmp.h This is the main header file for the DLL. It declares the CJpgVSbmpApp class. JpgVSbmp.cpp This is the main DLL source file. It contains the class CJpgVSbmpApp. JpgVSbmp.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. JpgVSbmp.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. res\JpgVSbmp.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file. JpgVSbmp.def This file contains information about the DLL that must be provided to run with Microsoft Windows. It defines parameters such as the name and description of the DLL. It also exports functions from the DLL. ///////////////////////////////////////////////////////////////////////////// Other standard files: StdAfx.h, StdAfx.cpp These files are used to build a precompiled header (PCH) file named JpgVSbmp.pch and a precompiled types file named StdAfx.obj. Resource.h This is the standard header file, which defines new resource IDs. Microsoft Visual C++ reads and updates this file. ///////////////////////////////////////////////////////////////////////////// Other notes: AppWizard uses "TODO:" to indicate parts of the source code you should add to or customize.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值