近来在工作中用到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; }
如果大家发现有什么不完善的地方,欢迎大家交流。
|