使用libpng,libjpeg从文件读取和从内存读取2中方式的实现
2010-06-03 12:01
429 查看
近来在工作中用到libpng和libjpeg对图片做解析,要求解析出RGB数据,并能提供8位和24位2中借口,并要求能对图片进行缩放,结合网上各个朋友的文章,写出了我自己的代码,现在贴出来给大家参考。
1.从文件读取:
bool PngImage::loadFromFile(const char* Path, IMAGE_TYPE type)
{
// 重新初始化,防止load多个图片。
m_good = false;
m_width = 0;
m_height = 0;
if (m_bgra)
{
delete m_bgra;m_bgra = 0;//类成员变量,存储24位RGB数据。
}
if(m_8bit)
{
delete m_8bit;m_8bit=0;//类成员变量,存储8位数据。
}
if(type == IMAGE_PNG)
{
//对PNG文件的解析
// try to open file
FILE* file = fopen(Path, "rb");
// unable to open
if (file == 0) return false;
// create read struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
// check pointer
if (png_ptr == 0)
{
fclose(file);
return false;
}
// create info struct
png_infop info_ptr = png_create_info_struct(png_ptr);
// check pointer
if (info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, 0, 0);
fclose(file);
return false;
}
// set error handling
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(file);
return false;
}
// I/O initialization using standard C streams
png_init_io(png_ptr, file);
// read entire image , ignore alpha channel,如果你要使用alpha通道,请把PNG_TRANSFORM_STRIP_ALPHA去掉
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);
/*
PNG_TRANSFORM_EXPAND有下边几个处理:
1.Expand paletted colors into true RGB triplets
2.Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
3.Expand paletted or RGB images with transparency to full alpha channels so the data will be available
as RGBA quartets。
PNG_TRANSFORM_STRIP_ALPHA:Strip alpha bytes from the input data without combining withthe background
*/
int width = m_width = info_ptr->width;
int height = m_height = info_ptr->height;
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->pixel_depth;
png_bytep* row_pointers = png_get_rows(png_ptr,info_ptr);
int pos=0;
if(color_type == PNG_COLOR_TYPE_GRAY)
{//对灰度图的处理
m_8bit = new unsigned char[width*height];
memset(m_8bit,0,width*height);
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j+=1)
{
m_8bit[pos++] = row_pointers[i][j];
}
}
}
else
{//对非灰度图的处理
m_bgra = new unsigned char[width*height*3];
memset(m_bgra,0,width*height*3);
for(int i=0;i<height;i++)
{
for(int j=0;j<3*width;j+=3)
{
m_bgra[pos++] = row_pointers[i][j+2];//BLUE
m_bgra[pos++] = row_pointers[i][j+1];//GREEN
m_bgra[pos++] = row_pointers[i][j];//RED
}
}
}
// free memory
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
// close file
fclose(file);
}
else if(type == IMAGE_JPEG)
{//对JPEG图片的解析
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
FILE* infile;
if((infile=fopen(Path,"rb")) == NULL )
{
printf("Open file error!/n");
return false;
}
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
m_height = cinfo.image_height;
m_width = cinfo.image_width;
m_bgra = new unsigned char[cinfo.image_width*cinfo.image_height*cinfo.num_components];
jpeg_start_decompress(&cinfo);
JSAMPROW row_pointer[1];
while(cinfo.output_scanline < cinfo.output_height)
{
/*row_pointer[0] = &m_bgr[(cinfo.output_height-cinfo.output_scanline-1)
*cinfo.image_width*cinfo.num_components];*/
row_pointer[0]=&m_bgra[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
}
return TRUE;
}
2.从内存读取:
对于PNG格式,从内存读取要重设读取回调函数,然后用png_set_read_fn()函数指明读函数。
对于JPEG格式,只需用jpeg_mem_src()函数替代原来从文件读取的 jpeg_stdio_src(&cinfo, infile)即可。
typedef struct
{
unsigned char* data;
int size;
int offset;
}ImageSource;
//从内存读取PNG图片的回调函数
static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
{
ImageSource* isource = (ImageSource*)png_get_io_ptr(png_ptr);
if(isource->offset + length <= isource->size)
{
memcpy(data, isource->data+isource->offset, length);
isource->offset += length;
}
else
png_error(png_ptr, "pngReaderCallback failed");
}
//从内存读取
bool PngImage::loadFromStream(unsigned char* data, const unsigned int dataSize, IMAGE_TYPE type)
{
m_good = false;
m_width = 0;
m_height = 0;
if(m_bgra)
{
delete m_bgra; m_bgra=0;
}
if(m_8bit)
{
delete m_8bit; m_8bit=0;
}
if(type == IMAGE_PNG)
{
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(png_ptr == 0)
return false;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, 0, 0);
return false;
}
if(setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr,0);
}
ImageSource imgsource;
imgsource.data = data;
imgsource.size = dataSize;
imgsource.offset = 0;
png_set_read_fn(png_ptr, &imgsource,pngReadCallback);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);
int width = m_width = info_ptr->width;
int height = m_height = info_ptr->height;
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->pixel_depth;
png_bytep* row_pointers = png_get_rows(png_ptr,info_ptr);
int pos=0;
if(color_type == PNG_COLOR_TYPE_GRAY)
{
m_8bit = new unsigned char[width*height];
memset(m_8bit,0,width*height);
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j+=1)
{
m_8bit[pos++] = row_pointers[i][j];
}
}
}
else
{
m_bgra = new unsigned char[width*height*3];
memset(m_bgra,0,width*height*3);
for(int i=0;i<height;i++)
{
for(int j=0;j<3*width;j+=3)
{
m_bgra[pos++] = row_pointers[i][j+2];//BLUE
m_bgra[pos++] = row_pointers[i][j+1];//GREEN
m_bgra[pos++] = row_pointers[i][j];//RED
}
}
}
// free memory
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
}
else if(type == IMAGE_JPEG)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
//从内存读取
jpeg_mem_src(&cinfo, data, dataSize);
jpeg_read_header(&cinfo, TRUE);
m_height = cinfo.image_height;
m_width = cinfo.image_width;
m_bgra = new unsigned char[cinfo.image_width*cinfo.image_height*cinfo.num_components];
jpeg_start_decompress(&cinfo);
JSAMPROW row_pointer[1];
while(cinfo.output_scanline < cinfo.output_height)
{
/*row_pointer[0] = &m_bgr[(cinfo.output_height-cinfo.output_scanline-1)
*cinfo.image_width*cinfo.num_components];*/
row_pointer[0]=&m_bgra[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
}
return /*(m_good = true)*/TRUE;
}
3. 对图片的缩放,是用的网上广为流传的插值算法。
传入的参数为:返回图片的宽度(w_Dest),返回图片的高度(h_Dest),返回图片的位深(bit_depth),源图片的RGB数据(src),源图片的宽度(w_Src),源图片的高度(h_Src).
unsigned char* PngImage::do_Stretch_Linear(int w_Dest,int h_Dest,int bit_depth,unsigned char *src,int w_Src,int h_Src)
{
int sw = w_Src-1, sh = h_Src-1, dw = w_Dest-1, dh = h_Dest-1;
int B, N, x, y;
int nPixelSize = bit_depth/8;
unsigned char *pLinePrev,*pLineNext;
unsigned char *pDest = new unsigned char[w_Dest*h_Dest*bit_depth/8];
unsigned char *tmp;
unsigned char *pA,*pB,*pC,*pD;
for(int i=0;i<=dh;++i)
{
tmp =pDest + i*w_Dest*nPixelSize;
y = i*sh/dh;
N = dh - i*sh%dh;
pLinePrev = src + (y++)*w_Src*nPixelSize;
//pLinePrev =(unsigned char *)aSrc->m_bitBuf+((y++)*aSrc->m_width*nPixelSize);
pLineNext = (N==dh) ? pLinePrev : src+y*w_Src*nPixelSize;
//pLineNext = ( N == dh ) ? pLinePrev : (unsigned char *)aSrc->m_bitBuf+(y*aSrc->m_width*nPixelSize);
for(int j=0;j<=dw;++j)
{
x = j*sw/dw*nPixelSize;
B = dw-j*sw%dw;
pA = pLinePrev+x;
pB = pA+nPixelSize;
pC = pLineNext + x;
pD = pC + nPixelSize;
if(B == dw)
{
pB=pA;
pD=pC;
}
for(int k=0;k<nPixelSize;++k)
{
*tmp++ = ( unsigned char )( int )(
( B * N * ( *pA++ - *pB - *pC + *pD ) + dw * N * *pB++
+ dh * B * *pC++ + ( dw * dh - dh * B - dw * N ) * *pD++
+ dw * dh / 2 ) / ( dw * dh ) );
}
}
}
return pDest;
}
如果大家发现有什么不完善的地方,欢迎大家交流。
1.从文件读取:
bool PngImage::loadFromFile(const char* Path, IMAGE_TYPE type)
{
// 重新初始化,防止load多个图片。
m_good = false;
m_width = 0;
m_height = 0;
if (m_bgra)
{
delete m_bgra;m_bgra = 0;//类成员变量,存储24位RGB数据。
}
if(m_8bit)
{
delete m_8bit;m_8bit=0;//类成员变量,存储8位数据。
}
if(type == IMAGE_PNG)
{
//对PNG文件的解析
// try to open file
FILE* file = fopen(Path, "rb");
// unable to open
if (file == 0) return false;
// create read struct
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
// check pointer
if (png_ptr == 0)
{
fclose(file);
return false;
}
// create info struct
png_infop info_ptr = png_create_info_struct(png_ptr);
// check pointer
if (info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, 0, 0);
fclose(file);
return false;
}
// set error handling
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
fclose(file);
return false;
}
// I/O initialization using standard C streams
png_init_io(png_ptr, file);
// read entire image , ignore alpha channel,如果你要使用alpha通道,请把PNG_TRANSFORM_STRIP_ALPHA去掉
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);
/*
PNG_TRANSFORM_EXPAND有下边几个处理:
1.Expand paletted colors into true RGB triplets
2.Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
3.Expand paletted or RGB images with transparency to full alpha channels so the data will be available
as RGBA quartets。
PNG_TRANSFORM_STRIP_ALPHA:Strip alpha bytes from the input data without combining withthe background
*/
int width = m_width = info_ptr->width;
int height = m_height = info_ptr->height;
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->pixel_depth;
png_bytep* row_pointers = png_get_rows(png_ptr,info_ptr);
int pos=0;
if(color_type == PNG_COLOR_TYPE_GRAY)
{//对灰度图的处理
m_8bit = new unsigned char[width*height];
memset(m_8bit,0,width*height);
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j+=1)
{
m_8bit[pos++] = row_pointers[i][j];
}
}
}
else
{//对非灰度图的处理
m_bgra = new unsigned char[width*height*3];
memset(m_bgra,0,width*height*3);
for(int i=0;i<height;i++)
{
for(int j=0;j<3*width;j+=3)
{
m_bgra[pos++] = row_pointers[i][j+2];//BLUE
m_bgra[pos++] = row_pointers[i][j+1];//GREEN
m_bgra[pos++] = row_pointers[i][j];//RED
}
}
}
// free memory
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
// close file
fclose(file);
}
else if(type == IMAGE_JPEG)
{//对JPEG图片的解析
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
FILE* infile;
if((infile=fopen(Path,"rb")) == NULL )
{
printf("Open file error!/n");
return false;
}
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
m_height = cinfo.image_height;
m_width = cinfo.image_width;
m_bgra = new unsigned char[cinfo.image_width*cinfo.image_height*cinfo.num_components];
jpeg_start_decompress(&cinfo);
JSAMPROW row_pointer[1];
while(cinfo.output_scanline < cinfo.output_height)
{
/*row_pointer[0] = &m_bgr[(cinfo.output_height-cinfo.output_scanline-1)
*cinfo.image_width*cinfo.num_components];*/
row_pointer[0]=&m_bgra[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
}
return TRUE;
}
2.从内存读取:
对于PNG格式,从内存读取要重设读取回调函数,然后用png_set_read_fn()函数指明读函数。
对于JPEG格式,只需用jpeg_mem_src()函数替代原来从文件读取的 jpeg_stdio_src(&cinfo, infile)即可。
typedef struct
{
unsigned char* data;
int size;
int offset;
}ImageSource;
//从内存读取PNG图片的回调函数
static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
{
ImageSource* isource = (ImageSource*)png_get_io_ptr(png_ptr);
if(isource->offset + length <= isource->size)
{
memcpy(data, isource->data+isource->offset, length);
isource->offset += length;
}
else
png_error(png_ptr, "pngReaderCallback failed");
}
//从内存读取
bool PngImage::loadFromStream(unsigned char* data, const unsigned int dataSize, IMAGE_TYPE type)
{
m_good = false;
m_width = 0;
m_height = 0;
if(m_bgra)
{
delete m_bgra; m_bgra=0;
}
if(m_8bit)
{
delete m_8bit; m_8bit=0;
}
if(type == IMAGE_PNG)
{
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(png_ptr == 0)
return false;
png_infop info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, 0, 0);
return false;
}
if(setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr,0);
}
ImageSource imgsource;
imgsource.data = data;
imgsource.size = dataSize;
imgsource.offset = 0;
png_set_read_fn(png_ptr, &imgsource,pngReadCallback);
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_ALPHA, 0);
int width = m_width = info_ptr->width;
int height = m_height = info_ptr->height;
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->pixel_depth;
png_bytep* row_pointers = png_get_rows(png_ptr,info_ptr);
int pos=0;
if(color_type == PNG_COLOR_TYPE_GRAY)
{
m_8bit = new unsigned char[width*height];
memset(m_8bit,0,width*height);
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j+=1)
{
m_8bit[pos++] = row_pointers[i][j];
}
}
}
else
{
m_bgra = new unsigned char[width*height*3];
memset(m_bgra,0,width*height*3);
for(int i=0;i<height;i++)
{
for(int j=0;j<3*width;j+=3)
{
m_bgra[pos++] = row_pointers[i][j+2];//BLUE
m_bgra[pos++] = row_pointers[i][j+1];//GREEN
m_bgra[pos++] = row_pointers[i][j];//RED
}
}
}
// free memory
png_destroy_read_struct(&png_ptr, &info_ptr, 0);
}
else if(type == IMAGE_JPEG)
{
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
//从内存读取
jpeg_mem_src(&cinfo, data, dataSize);
jpeg_read_header(&cinfo, TRUE);
m_height = cinfo.image_height;
m_width = cinfo.image_width;
m_bgra = new unsigned char[cinfo.image_width*cinfo.image_height*cinfo.num_components];
jpeg_start_decompress(&cinfo);
JSAMPROW row_pointer[1];
while(cinfo.output_scanline < cinfo.output_height)
{
/*row_pointer[0] = &m_bgr[(cinfo.output_height-cinfo.output_scanline-1)
*cinfo.image_width*cinfo.num_components];*/
row_pointer[0]=&m_bgra[cinfo.output_scanline*cinfo.image_width*cinfo.num_components];
jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
}
return /*(m_good = true)*/TRUE;
}
3. 对图片的缩放,是用的网上广为流传的插值算法。
传入的参数为:返回图片的宽度(w_Dest),返回图片的高度(h_Dest),返回图片的位深(bit_depth),源图片的RGB数据(src),源图片的宽度(w_Src),源图片的高度(h_Src).
unsigned char* PngImage::do_Stretch_Linear(int w_Dest,int h_Dest,int bit_depth,unsigned char *src,int w_Src,int h_Src)
{
int sw = w_Src-1, sh = h_Src-1, dw = w_Dest-1, dh = h_Dest-1;
int B, N, x, y;
int nPixelSize = bit_depth/8;
unsigned char *pLinePrev,*pLineNext;
unsigned char *pDest = new unsigned char[w_Dest*h_Dest*bit_depth/8];
unsigned char *tmp;
unsigned char *pA,*pB,*pC,*pD;
for(int i=0;i<=dh;++i)
{
tmp =pDest + i*w_Dest*nPixelSize;
y = i*sh/dh;
N = dh - i*sh%dh;
pLinePrev = src + (y++)*w_Src*nPixelSize;
//pLinePrev =(unsigned char *)aSrc->m_bitBuf+((y++)*aSrc->m_width*nPixelSize);
pLineNext = (N==dh) ? pLinePrev : src+y*w_Src*nPixelSize;
//pLineNext = ( N == dh ) ? pLinePrev : (unsigned char *)aSrc->m_bitBuf+(y*aSrc->m_width*nPixelSize);
for(int j=0;j<=dw;++j)
{
x = j*sw/dw*nPixelSize;
B = dw-j*sw%dw;
pA = pLinePrev+x;
pB = pA+nPixelSize;
pC = pLineNext + x;
pD = pC + nPixelSize;
if(B == dw)
{
pB=pA;
pD=pC;
}
for(int k=0;k<nPixelSize;++k)
{
*tmp++ = ( unsigned char )( int )(
( B * N * ( *pA++ - *pB - *pC + *pD ) + dw * N * *pB++
+ dh * B * *pC++ + ( dw * dh - dh * B - dw * N ) * *pD++
+ dw * dh / 2 ) / ( dw * dh ) );
}
}
}
return pDest;
}
如果大家发现有什么不完善的地方,欢迎大家交流。
相关文章推荐
- 使用libpng,libjpeg从文件读取和从内存读取2中方式的实现
- java 读取文件——按照行取出(使用BufferedReader和一次将数据保存到内存两种实现方式)
- 读取配置文件[方式二]之使用Awk实现
- JavaScript下用IE的方式实现文件读取
- 使用libjpeg 压缩yuv420到jpg (内存方式)
- 内存映射方式读取文件
- 使用WebView实现文件下载的两种方式
- 使用C#实现读取系统配置文件的代码实例讲解
- 09_通过读取配置文件的方式来使用反射完成对实例对象方法调用
- 使用内存映射文件加快读取大文件的速度 .
- 使用openoffice实现文件的预览 使用流的方式实现
- 几种读取属性文件的JAVA实现方式
- java读取资源文件--使用文件流的方式读取
- 使用文件操作函数实现简单的CP、cat、size功能及读取文件内容初始化结构体
- Jmeter使用嵌套循环实现读取2个文件的参数来进行组合参数化
- java 实现poi方式读取word文件内容
- 使用cmd命令方式登录ftp实现上传下载文件数据
- 关于 Delphi 中流的使用(3) 通过内存流读取文件
- PHP使用header方式实现文件下载
- 使用Anthem.NET 1.5中的FileUpload控件实现Ajax方式的文件上传