现在的位置: 首页 > 综合 > 正文

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

2012年09月11日 ⁄ 综合 ⁄ 共 7519字 ⁄ 字号 评论关闭

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

 

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

抱歉!评论已关闭.