libjpeg库解压缩和压缩示例封装

一、解压缩:

(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;
}

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是一个使用libjpeg将YUV420p压缩JPEG格式的C++代码示例: ```cpp #include <stdio.h> #include <jpeglib.h> void compress_yuv_to_jpeg(unsigned char* yuv, int width, int height, int quality, const char* filename) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE* outfile = fopen(filename, "wb"); if (!outfile) { fprintf(stderr, "Failed to open output file.\n"); return; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // YUV420p是3个颜色分量 cinfo.in_color_space = JCS_YCbCr; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); JSAMPROW row_pointer[1]; int row_stride; jpeg_start_compress(&cinfo, TRUE); row_stride = width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &yuv[cinfo.next_scanline * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); } int main() { // 假设你已经将YUV420p数据存储在unsigned char* yuv中 unsigned char* yuv; int width, height; int quality = 80; // JPEG质量设置为80 const char* filename = "output.jpg"; // 假设你已经设置了yuv的宽度和高度 compress_yuv_to_jpeg(yuv, width, height, quality, filename); return 0; } ``` 这段代码使用libjpeg中的函数和结构体来进行压缩。它将YUV420p数据写入到一个JPEG文件中,你可以通过调整quality参数来控制JPEG压缩质量。请确保你已经安装了libjpeg并在编译时链接到对应的文件。 注意:这只是一个简单的示例代码,实际使用中可能需要更多的错误处理和输入验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小米的修行之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值