之前使用opencv在内存中解析图片,发现当解析错误的时候,程序直接崩溃。于是乎就重新把libjpeg封装一下,把容错性给做好。具体代码如下:

Image.h

#ifndef  __IMAGE_H
#define  __IMAGE_H
#include <iostream>
#include <vector>
using namespace std;

//加载libjpeg
#include "libjpeg/jpeglib.h"
#pragma  comment(lib,"libjpeg.lib")


#define  EXECUOK       0
//ERROR
#define  ANALYZERROR  -1
#define  SAVEERROR          -2
#define  OPENFILEERROR  -3
#define  CHANNELERROR -4
#define  PARAERROR  -5

#define	MAX(a, b) (((a) > (b)) ? (a) : (b))
#define	MIN(a, b) (((a) < (b)) ? (a) : (b))
//定义二维数组
typedef vector<vector<unsigned char> > Matrix;

//裁剪区域的结构体
struct  ImageRect
{
	int x;//起始点X
	int y;//起始点Y
	int width;//宽
	int height;//高
};

//图像结构体
struct ImageData
{
	Matrix data;//图像数据 bgr  左上角开始
	int width;//宽
	int height;//高
	int channel;//通道
};
//bgr图像值
struct BGR
{
	unsigned char b;
	unsigned char g;
	unsigned char r;
};
//获取图像在固定点的颜色值
//获取bgr的值
int GetPixel(const ImageData _img,const int x, const int y, BGR &_bgr);
//获取灰度的值
int GetPixel(const ImageData _img, const int x, const int y, unsigned char &_uchar);

//设置图像在固定点的颜色值
//设置bgr的值
int SetPixel(ImageData &_img,const int x,const int y,const BGR _bgr);
//设置灰度的值
int SetPixel(ImageData &_img,const int x,const int y,const unsigned char _uchar);

//文件数据解析成bgr数据
int  File2Matrix(const char *_buff, const int _length, ImageData &_dst);

//保存图像
int SaveImage(const ImageData _img, const  char *_filename);

//剪切图像
int GetRIO(const ImageData _img, const ImageRect _rect, ImageData &_dst);

//BGR转灰度
int BGR2GRAY(const ImageData _img,ImageData &_gray);

#endif

Image.cpp

#include "Image.h"

jmp_buf   setjmp_buffer;//用于跳转
//跳转函数
static void  my_error_exit(j_common_ptr cinfo)
{
	longjmp(setjmp_buffer, 1);
}

int SetPixel(ImageData &_img, const int x, const int y, const BGR _bgr)
{
	if (_img.height < 0 || _img.width < 0 || _img.channel != 3 || x < 0 || x >= _img.width || y < 0 || y >= _img.height)
	{
		return PARAERROR;
	}
	_img.data[y][x*_img.channel + 0] = _bgr.b;
	_img.data[y][x*_img.channel + 1] = _bgr.g;
	_img.data[y][x*_img.channel + 2] = _bgr.r;
	return EXECUOK;
}

int SetPixel(ImageData &_img, const int x, const int y, const unsigned char _uchar)
{
	if (_img.height < 0 || _img.width < 0 || _img.channel != 1 || x < 0 || x >= _img.width || y < 0 || y >= _img.height)
	{
		return PARAERROR;
	}
	_img.data[y][x] = _uchar;
	return EXECUOK;
}

int GetPixel(const ImageData _img, const int x, const int y, BGR &_bgr)
{
	if (_img.height < 0||_img.width<0||_img.channel!=3||x<0||x>=_img.width||y<0||y>=_img.height)
	{
		return PARAERROR;
	}
	_bgr.b = _img.data[y][x*_img.channel + 0];
	_bgr.g = _img.data[y][x*_img.channel + 1];
	_bgr.r = _img.data[y][x*_img.channel + 2];
	return EXECUOK;
}

int GetPixel(const ImageData _img, const int x, const int y, unsigned char &_uchar)
{
	if (_img.height < 0 || _img.width < 0 || _img.channel != 1 || x<0 || x >= _img.width || y<0 || y >= _img.height)
	{
		return PARAERROR;
	}
	_uchar = _img.data[y][x];
	return EXECUOK;
}

//剪切图像
int GetRIO(const ImageData _img, const ImageRect _rect, ImageData &_dst)
{
	if (_img.height <= 0||_img.width <= 0 || _rect.x<0 || _rect.y<0 || (_rect.x + _rect.width - 1) >= _img.width || (_rect.y + _rect.height - 1) >= _img.height)
	{
		return PARAERROR;
	}
	_dst.width = _rect.width;
	_dst.height = _rect.height;
	_dst.channel = _img.channel;
	_dst.data.resize(_dst.height);
	for (int i = 0; i < _dst.height;i++)
	{
		_dst.data[i].resize(_dst.width*_dst.channel);
	}
	for (int i =0; i < _rect.height;i++)
	{
		for (int j = 0; j < _rect.width;j++)
		{
			for (int m = 0; m < _img.channel;m++)
			{
				_dst.data[i][j*_dst.channel + m] = _img.data[i+_rect.y][(j+_rect.x)*_img.channel+m];
			}
		}
	}
	return EXECUOK;
}

//BGR转灰度
int BGR2GRAY(const ImageData _img, ImageData &_gray)
{
	if (_img.channel==1)//如果本来就是灰度图像,直接等于返回
	{
		_gray = _img;
		return EXECUOK;
	}
	else  if (_img.channel!=3)//不是rgb的,则直接返回错误
	{
		return CHANNELERROR;
	}
	ImageData temp;
	temp.width = _img.width;
	temp.height = _img.height;
	temp.channel = 1;
	temp.data.resize(_img.height);
	for (int i = 0; i < _img.height;i++)
	{
		temp.data[i].resize(_img.width);
	}
	int Rw = 299;
	int Gw = 587;
	int Bw = 114;
	for (int  i = 0; i < _img.height; i++)
	{
		for (int j = 0; j < _img.width; j++)
		{
			int B = _img.data[i][j*_img.channel+0]; 
			int G = _img.data[i][j*_img.channel + 1];
			int R = _img.data[i][j*_img.channel + 2];
			temp.data[i][j] = (R*Rw + G*Gw + B*Bw + 500) / 1000;
		}
	}
	_gray = temp;
	return EXECUOK;
}

int SaveImage(const ImageData _img, const  char *_filename)
{
	cout << _img.width << " " << _img.height << " " << _img.channel << endl;
	unsigned char *data = NULL;
	char *outdata = new char[_img.width*_img.height*_img.channel * 2];
	int nSize;	// 用于存放压缩完后图像数据的大小
	// 以下代码用于压缩,从本行开始
	struct jpeg_error_mgr jerr;
	struct jpeg_compress_struct jcs;

	jcs.err = jpeg_std_error(&jerr);
	jerr.error_exit = my_error_exit;

	jpeg_create_compress(&jcs);

	int flag = false;
	int  ret = setjmp(setjmp_buffer);
	if (ret)         //解析失败
	{
		if (flag)
		{
			jpeg_finish_compress(&jcs);
		}
		jpeg_destroy_compress(&jcs);
		delete[] data;
		delete[]outdata;
		return SAVEERROR;
	}

	jpeg_stdio_dest(&jcs, outdata, &nSize);
	jcs.p_w_picpath_width = _img.width; 			// 为图的宽和高,单位为像素 
	jcs.p_w_picpath_height = _img.height;
	jcs.input_components = _img.channel;			// 1,表示灰度图, 如果是彩色位图,则为3 
	if (_img.channel == 1)
		jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图,JCS_RGB表示彩***像 
	else
		jcs.in_color_space = JCS_RGB;

	jpeg_set_defaults(&jcs);
	jpeg_set_quality(&jcs, 100, true);
	jpeg_start_compress(&jcs, TRUE);
	flag = true;
	JSAMPROW row_pointer[1];			// 一行位图
	int row_stride;						// 每一行的字节数 
	row_stride = jcs.p_w_picpath_width*_img.channel;		// 如果不是索引图,此处需要乘以3

	int nAdjust = _img.width * 3 % 4;
	if (nAdjust)
		nAdjust = 4 - nAdjust;
	data = new unsigned char[(_img.width*_img.channel + nAdjust)*_img.height];
	for (int i = 0; i < _img.height; i++)
	{
		for (int j = 0; j < _img.width; j++)
		{
			for (int n = 0; n < _img.channel; n++)
			{
				data[(_img.width*_img.channel + nAdjust)*(_img.height - 1 - i) + j*_img.channel + n] = _img.data[i][j*_img.channel + (_img.channel - 1 - n)];
			}
		}
	}
	// 对每一行进行压缩
	while (jcs.next_scanline < jcs.p_w_picpath_height) {
		row_pointer[0] = &data[(jcs.p_w_picpath_height - jcs.next_scanline - 1) * (row_stride + nAdjust)];
		jpeg_write_scanlines(&jcs, row_pointer, 1);
	}

	jpeg_finish_compress(&jcs);
	jpeg_destroy_compress(&jcs);
	//上面的代码用于实际的图像压缩,到本行结束
	// 下面代码将压缩后的图像数据存入文件,也可以根据实际进行应用,如传输,outdata存储了图像数据,nSize为图像数据的实际大小

	FILE *f = fopen(_filename, "wb");
	if (f == NULL)
	{
		delete[] data;
		delete[]outdata;
		return OPENFILEERROR;
	}
	fwrite(outdata, nSize, 1, f);
	fclose(f);
	delete[] data;
	delete[]outdata;
	return EXECUOK;
}

int  File2Matrix(const char *_buff, const int _length, ImageData &_dst)
{
	unsigned char *data = NULL;
	// 声明解压缩对象及错误信息管理器
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;

	cinfo.err = jpeg_std_error(&jerr);
	jerr.error_exit = my_error_exit;
	jpeg_create_decompress(&cinfo);

	int flag = false;
	int  ret = setjmp(setjmp_buffer);
	if (ret)         //解析失败
	{
		if (flag)
		{
			jpeg_finish_decompress(&cinfo);
		}
		jpeg_destroy_decompress(&cinfo);
		delete[]data;
		return ANALYZERROR;
	}
	jpeg_stdio_src(&cinfo, (char*)_buff, _length);
	jpeg_read_header(&cinfo, true);

	_dst.width = cinfo.p_w_picpath_width;
	_dst.height = cinfo.p_w_picpath_height;
	_dst.channel = cinfo.num_components;

	int nAdjust = cinfo.p_w_picpath_width*cinfo.num_components % 4;
	if (nAdjust)
		nAdjust = 4 - nAdjust;
	data = new unsigned char[(cinfo.p_w_picpath_width*cinfo.num_components + nAdjust)*cinfo.p_w_picpath_height];

	jpeg_start_decompress(&cinfo);
	flag = true;
	JSAMPROW row_pointer[1];
	while (cinfo.output_scanline < cinfo.output_height)
	{
		row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline - 1)*(cinfo.p_w_picpath_width*cinfo.num_components + nAdjust)];
		jpeg_read_scanlines(&cinfo, row_pointer, 1);
	}
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	// 上面代码用于解压缩,到本行为止解压缩完成
	_dst.data.resize(_dst.height);
	for (int i = 0; i < _dst.height; i++)
	{
		_dst.data[i].resize(_dst.width * _dst.channel);
	}

	//修改成bgr 和从上往下
	for (int i = 0; i < _dst.height; i++)
	{
		for (int j = 0; j < _dst.width; j++)
		{
			for (int n = 0; n < _dst.channel; n++)
			{
				_dst.data[_dst.height-1-i][j*_dst.channel + (_dst.channel - 1 - n)] = data[i*(cinfo.p_w_picpath_width*cinfo.num_components + nAdjust) + j*_dst.channel + n];
			}
		}
	}
	delete[]data;
	return EXECUOK;
}