libjpeg內存解析圖片

之前使用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(&cinfo, (char*)_buff, _length);
	jpeg_read_header(&cinfo, true);

	_dst.width = cinfo.image_width;
	_dst.height = cinfo.image_height;
	_dst.channel = cinfo.num_components;

	int nAdjust = cinfo.image_width*cinfo.num_components % 4;
	if (nAdjust)
		nAdjust = 4 - nAdjust;
	data = new unsigned char[(cinfo.image_width*cinfo.num_components + nAdjust)*cinfo.image_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.image_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.image_width*cinfo.num_components + nAdjust) + j*_dst.channel + n];
			}
		}
	}
	delete[]data;
	return EXECUOK;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章