之前使用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.image_width = _img.width; // 为图的宽和高,单位为像素
jcs.image_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.image_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.image_height) {
row_pointer[0] = &data[(jcs.image_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=\‘#\‘" // 上面代码用于解压缩,到本行为止解压缩完成
_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.image_width*cinfo.num_components + nAdjust) + j*_dst.channel + n];
}
}
}
delete[]data;
return EXECUOK;
}本文出自 “叶子” 博客,请务必保留此出处http://luoqiu.blog.51cto.com/2198651/1650709
原文:http://luoqiu.blog.51cto.com/2198651/1650709