一、解压缩:
(1)、解压jpg文件数据示例:
/*
功能:解码jpg文件的数据到内存中
参数:1、input:strFileName 要解码的jpg文件全路径
2、input:pData 存放解码后数据的内存首地址
3、input and ouput:nSize 输入“存放解码后数据的内存空间”大小,如果失败,返回真正需要的大小
4、output:nByteAdjust 调整字节数,当一行的字节数不是4的整数倍时此值不为0
5、output:nComponents 图像深度
6、output:nImageWidth 图像宽度
7、output:nImageHeight 图像高度
*/
bool DecodeJPG(char * strFileName, unsigned char * pData, int &nSize, int &nByteAdjust, int &nComponents, int &nImageWidth, int &nImageHeight)
{
FILE* fp = NULL;
long nAdjust(0), nBmpSize(0);
try
{
if (0 != fopen_s(&fp, strFileName, "rb")) { return FALSE; }
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
jpeg_read_header(&cinfo, TRUE);
nAdjust = cinfo.image_width * cinfo.num_components % 4;
if (nAdjust) { nAdjust = 4 - nAdjust; }
nByteAdjust = nAdjust;
nComponents = cinfo.num_components;
nImageWidth = cinfo.image_width;
nImageHeight = cinfo.image_height;
nBmpSize = (cinfo.image_width * cinfo.num_components + nAdjust) * cinfo.image_height;
if (nSize < nBmpSize)
{
nSize = nBmpSize;
if (fp) { fclose(fp), fp = NULL; }
return false;
}
if (!jpeg_start_decompress(&cinfo))
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
return false;
}
//...此处可以设置解压缩的一些参数:如解压缩后图像大小、颜色空间等,不需要可以不设置。
JSAMPROW row_pointer[1];
while (cinfo.output_scanline < cinfo.output_height)
{
row_pointer[0] = (unsigned char *)&pData[cinfo.output_scanline * (cinfo.image_width * cinfo.num_components + nAdjust)];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
if (fp) { fclose(fp), fp = NULL; }
}
catch (...)
{
if (fp) { fclose(fp), fp = NULL; }
return false;
}
return true;
}
(2)、解压内存中的数据:
/*
功能:解码内存中的jpg数据到申请的内存中
原理:模拟测试,先把数据从jpg文件中读取到内存中,再解压到申请好的内存中
参数:1、input:strFileName 要解码的jpg文件全路径
2、input:pData 存放解码后数据的内存首地址
3、input and ouput:nSize 输入“存放解码后数据的内存空间”大小,如果失败,返回真正需要的大小
4、output:nByteAdjust 调整字节数,当一行的字节数不是4的整数倍时此值不为0
5、output:nComponents 图像深度
6、output:nImageWidth 图像宽度
7、output:nImageHeight 图像高度
*/
bool DecodeJpgFromMemoty(char * strFileName, unsigned char * pData, int &nSize, int &nByteAdjust, int &nComponents, int &nImageWidth, int &nImageHeight)
{
FILE* fp = NULL;
BYTE* pJpgData = NULL;
long nAdjust(0), nBmpSize(0); DWORD dwFileSize(0);
HANDLE hFind = NULL; WIN32_FIND_DATAA fInfo;
try
{
if (0 != fopen_s(&fp, strFileName, "rb")) { return false; }
//计算文件大小,文件大小不超过4G
if ((hFind = FindFirstFileA(strFileName, &fInfo)) != INVALID_HANDLE_VALUE)
{
dwFileSize = fInfo.nFileSizeLow;
FindClose(hFind);
}
else
{
fclose(fp);
return false;
}
//根据文件大小申请临时缓存
if (dwFileSize <= 0) { fclose(fp); return false; }
if (NULL == (pJpgData = new BYTE[dwFileSize])) { fclose(fp); return false; }
//将文件内容读入到临时缓存中
const unsigned int unMaxSize = 1024 * 1024;
DWORD dwFileLeft = dwFileSize, dwReadAll = 0, dwRead = 0;
do
{
if ((dwRead = fread(pJpgData + dwReadAll, 1, dwFileLeft > unMaxSize ? unMaxSize : dwFileLeft, fp)) <= 0) { break; }
if((dwReadAll += dwRead) == dwFileSize) break;
else dwFileLeft -= dwRead;
} while (true);
//对于小文件一次读取就可以
//fread(pJpgData, dwFileSize, 1, fp);
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, pJpgData, dwFileSize);
jpeg_read_header(&cinfo, TRUE);
nAdjust = cinfo.image_width * cinfo.num_components % 4;
if (nAdjust) { nAdjust = 4 - nAdjust; }
nByteAdjust = nAdjust;
nComponents = cinfo.num_components;
nImageWidth = cinfo.image_width;
nImageHeight = cinfo.image_height;
//判断存放解压后数据的内存大小是否够用
nBmpSize = (cinfo.image_width * cinfo.num_components + nAdjust) * cinfo.image_height;
if (nSize < nBmpSize)
{
nSize = nBmpSize;
if (fp) { fclose(fp), fp = NULL; }
if (pJpgData) { delete[]pJpgData, pJpgData = NULL; }
return false;
}
if (!jpeg_start_decompress(&cinfo))
{
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
if (fp) { fclose(fp), fp = NULL; }
if (pJpgData) { delete[]pJpgData, pJpgData = NULL; }
return false;
}
//...此处可以设置解压缩的一些参数:如解压缩后图像大小、颜色空间等,不需要可以不设置。
JSAMPROW row_pointer[1];
while (cinfo.output_scanline < cinfo.output_height)
{
row_pointer[0] = (unsigned char *)&pData[cinfo.output_scanline * (cinfo.image_width * cinfo.num_components + nAdjust)];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
if (fp) { fclose(fp), fp = NULL; }
if (pJpgData) { delete[]pJpgData, pJpgData = NULL; }
}
catch (...)
{
if (fp) { fclose(fp), fp = NULL; }
if (pJpgData) { delete[]pJpgData, pJpgData = NULL; }
return false;
}
return true;
}
二、压缩:
(1)、将原始数据压缩到文件中
/*
功能:将原始数据(可能来自内存/也可能来自文件)压缩到文件中,此处来自内存
参数:1、input:strFileName 压缩后的jpg数据存放到的文件名称
2、input:pData 存放“原始数据”的内存首地址
3、input:nByteAdjust 调整字节数,保持图像宽度4字节对齐,根据图像宽度计算
4、input:nComponents 生成的图像深度
5、input:nImageWidth 生成的图像宽度
6、input:nImageHeight 生成的图像高度
*/
bool EncodeJPG(char * strFileName, unsigned char * pData, int nByteAdjust, int nComponents, int nImageWidth, int nImageHeight)
{
FILE* fp = NULL;
try
{
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
if (0 == fopen_s(&fp, strFileName, "wb"))
{
jpeg_stdio_dest(&jcs, fp);
//设置压缩参数
jcs.image_width = nImageWidth;
jcs.image_height = nImageHeight;
jcs.input_components = nComponents;
if (nComponents == 1) { jcs.in_color_space = JCS_GRAYSCALE; }
else { jcs.in_color_space = JCS_RGB; }
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, 90, true);
//开始压缩
jpeg_start_compress(&jcs, TRUE);
//压缩内存中的原始数据,考虑了4字节对齐
JSAMPROW row_pointer[1];
long row_stride = jcs.image_width * nComponents;
while (jcs.next_scanline < jcs.image_height)
{
row_pointer[0] = (BYTE *)&pData[jcs.next_scanline * (row_stride + nByteAdjust)];
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
if (fp) { fclose(fp), fp = NULL; }
}
else
return false;
}
catch (...)
{
if (fp) { fclose(fp), fp = NULL; }
return false;
}
return true;
}
(2)、将原始数据压缩到内存中:
/*
功能:将原始数据(可能来自内存/也可能来自文件)压缩到内存中,此处来自内存
参数:1、input:pDstData 压缩后的jpg数据的内存首地址,此内存由libjpeg库内部申请,需要由“调用者”释放
2、input:pSrcData 存放“原始数据”的内存首地址
3、output:pulDstDataSize 压缩后数据的字节数
4、input:nByteAdjust 调整字节数,保持图像宽度4字节对齐,根据图像宽度计算
5、input:nComponents 生成的图像深度
6、input:nImageWidth 生成的图像宽度
7、input:nImageHeight 生成的图像高度
*/
bool EncodeJPGToMemory(unsigned char ** pDstData, unsigned char * pSrcData, unsigned long* pulDstDataSize, int nByteAdjust, int nComponents, int nImageWidth, int nImageHeight)
{
try
{
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
//设置压缩的数据到内存中,并输出压缩后的字节数
*pulDstDataSize= nImageWidth * nImageHeight;
jpeg_mem_dest(&jcs, pDstData,pulDstDataSize);
//设置压缩参数
jcs.image_width = nImageWidth;
jcs.image_height = nImageHeight;
jcs.input_components = nComponents;
if (nComponents == 1) { jcs.in_color_space = JCS_GRAYSCALE; }
else { jcs.in_color_space = JCS_RGB; }
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, 90, true);
//开始压缩
jpeg_start_compress(&jcs, TRUE);
//压缩原始内存中的原始数据,考虑了4字节对齐
JSAMPROW row_pointer[1];
long row_stride = jcs.image_width * nComponents;
while (jcs.next_scanline < jcs.image_height)
{
row_pointer[0] = &pSrcData[jcs.next_scanline * (row_stride + nByteAdjust)];
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
}
catch (...)
{
return false;
}
return true;
}