之前使用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; }