`

使用libpng,libjpeg从文件读取和从内存读取2中方式的实现

 
阅读更多

近来在工作中用到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;
}

如果大家发现有什么不完善的地方,欢迎大家交流。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics