libpng比较另类,解码方式比较奇特,这里记录下
以下代码为使用虚拟IOReader的方式,稍做修改就基于FILE使用
代码很详细,不需额外解释
PNGImage::PNGImage(const std::string& filename):
ReferenceCountedImage(filename),
data_(0)
{
IOReader* reader = FileSystem::instance()->readFile(filename);
if(reader == 0)
return;
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if(png_ptr == 0)
{
reader->close();
reader->deleteLater();
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == 0)
{
png_destroy_read_struct(&png_ptr, png_infopp(0), png_infopp(0));
reader->close();
reader->deleteLater();
}
if(setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr,png_infopp(0),png_infopp(0));
reader->close();
reader->deleteLater();
}
png_set_read_fn( png_ptr,reader,(png_rw_ptr)user_read_data);
png_set_sig_bytes(png_ptr,0);
png_read_png(png_ptr,info_ptr,PNG_TRANSFORM_IDENTITY,0);
const unsigned int width = png_get_image_width(png_ptr,info_ptr);
const unsigned int height = png_get_image_height(png_ptr,info_ptr);
const unsigned int bit_depth = png_get_bit_depth(png_ptr,info_ptr);
if(bit_depth != 8)
{
reader->close();
reader->deleteLater();
png_destroy_info_struct(png_ptr,png_infopp(&info_ptr));
png_destroy_read_struct(&png_ptr,png_infopp(0), png_infopp(0));
}
const png_byte colorType = png_get_color_type(png_ptr, info_ptr);
if((colorType != PNG_COLOR_TYPE_RGB) && (colorType != PNG_COLOR_TYPE_RGB_ALPHA))
{
reader->close();
reader->deleteLater();
png_destroy_info_struct(png_ptr, png_infopp(&info_ptr));
png_destroy_read_struct(&png_ptr, png_infopp(0), png_infopp(0));
}
const int bytesPerPixel = (colorType == PNG_COLOR_TYPE_RGB) ? 3 : 4;
const int stride = bytesPerPixel * width;
unsigned char* data = new unsigned char[stride * height];
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
for(unsigned int i = 0; i < height; ++i)
{
const unsigned int row = height - i - 1;
memcpy(data + (row * stride), row_pointers[i], stride);
}
size_.x_ = width;
size_.y_ = height;
numberOfBitsPerPixel_ = bytesPerPixel * 8;
data_ = data;
reader->close();
reader->deleteLater();
png_destroy_info_struct(png_ptr, png_infopp(&info_ptr));
png_destroy_read_struct(&png_ptr, png_infopp(0), png_infopp(0));
}