这章就是为了读取png格式图像到32位位图(ARGB)中,逆之则然,废话少说开始正题。
1. 使用pnglib读写文件
以下操作就能实现加载png图像到32位图像中:
Image*img_bg=Image::Create(L"data/img/bg.png");
以下操作就能实现导出png图像:
img_bg->Save_To_PNG(L"bin/bg.png");
Image类用一个DWORD一维数组储存每个点,每个点由ARGB组成,例如0x66ff0000是半透明红色。假设要访问点(x,y),应该使用下标索引[y *w + x]。Image类还有图像的大小信息。
首先需要配置pnglib,其中还包括zlib。下载相应源码后,生成静态链接库链接到
项目。在代码中解析图片的cpp包含png.h。下面是解析png图片的具体实现,可结合注释理解。
Image* Image::Create(constString&path)
{
//定义空图像
Image* img =newImage;
System_imp* sys =System_imp::Get_Instance();
//String 转 char字符数组
char temp[512] ={NULL };
path.Get_Multi_Byte_Str(temp, 512);
///从文件加载/
//打开png文件
FILE* fp = NULL;
fopen_s(&fp,temp,"rb");
if (!fp)
{
Debug::Instance()->Write_Line(String(L"文件打开失败:")+path);
assert(0 &&L"Image加载时文件打开失败!");
return NULL;
}
//判断是否为 png文件(用fread读取8字节,然后调用png_sig_cmp判断)
size_t number = 8;
png_bytep header = new png_byte[number];
fread(header, 1,number,fp);
bool is_png = !png_sig_cmp(header, 0,number);
if (!is_png)
{
fclose(fp);
Debug::Instance()->Write_Line(String(L"只支持png格式的图像读取:")+path);
assert(0 &&L"Image加载时为非png格式图像!");
return NULL;
}
//初始化pnglib
static png_structppng_ptr =NULL;
if (!png_ptr)
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (!png_ptr)
{
fclose(fp);
assert(0 &&L"Image加载时初始化pnglib失败!");
return NULL;
}
//创建图像信息 info
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
fclose(fp);
assert(0 &&L"Image加载时创建png_info失败!");
return NULL;
}
//错误处理
if (setjmp(png_jmpbuf(png_ptr)))
{
fclose(fp);
png_destroy_read_struct(&png_ptr, &info_ptr,png_infopp_NULL);
assert(0 &&L"Image加载时 pnglib出现错误!");
return NULL;
}
//设置数据源
png_init_io(png_ptr,fp);
//表明文件头已处理
png_set_sig_bytes(png_ptr, 8);
//读png
png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);
//从info查询数据
unsigned w = png_get_image_width(png_ptr, info_ptr); //获得图片宽度
unsigned h = png_get_image_height(png_ptr, info_ptr); //获得图片高度
int color_type = png_get_color_type(png_ptr,info_ptr); //获得图片颜色
//赋值给image
img->m_size.w =w;
img->m_size.h =h;
img->m_buffer =newDWORD[w*h];
//从info复制到 image
png_bytep *row_point =NULL;
row_point = png_get_rows(png_ptr,info_ptr);
//带透明通道一个点是4字节,否则为3字节
int block_size = (color_type == 6 ? 4 : 3);
//(A)RGB
unsigned pos = 0;
for (unsignedx = 0;x < h; ++x)
for (unsignedy = 0;y < w*block_size;y +=block_size)
{
((unsigned char*)img->m_buffer)[pos + 0] =row_point[x][y + 2];//b;
((unsigned char*)img->m_buffer)[pos + 1] =row_point[x][y + 1];//g
((unsigned char*)img->m_buffer)[pos + 2] =row_point[x][y + 0];//r
if(color_type == 6)//不带透明通道就填充 0xff表示不透明
((unsigned char*)img->m_buffer)[pos + 3] =row_point[x][y + 3];//a
else
((unsigned char*)img->m_buffer)[pos + 3] = 0xff; pos += 4;
}
//关闭文件
fclose(fp);
//释放png内存
png_destroy_read_struct(&png_ptr, &info_ptr,png_infopp_NULL);
return img;
}
保存到png图像,如下调用:
canvas->Get_Image()->Save_To_PNG(L"bin/layer_image.png");
上面的语句将画布(一个DrawCall)的图像导出到指定文件中。画布Canvas会拼接Sprite使用的Image成大图,从下面的图片可以看到拼接并导出后的效果(这是导出的layer_image.png的一部分,不是程序截图哈!):
保存图像数据到PNG的实现如下:
void Image::Save_To_PNG(constString&path)
{
FILE* fp;
png_infop info_ptr;
char cpath[MAX_PATH] = {NULL };
path.Get_Multi_Byte_Str(cpath,MAX_PATH);
//创建或覆盖文件
fopen_s(&fp,cpath,"wb");
if (fp ==NULL)
{
assert(0 && L"Save_To_PNG 创建文件失败!");
return;
}
//初始化pnglib(注意相关的函数名read都变成了write)
static png_structppng_ptr =NULL;
if (!png_ptr)
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL,NULL);
if (!png_ptr)
{
assert(0 && L"Save_To_PNG 创建文件时初始化pnglib失败!");
return;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr ==NULL)
{
fclose(fp);
assert(0 && L"Save_To_PNG:png_create_info_struct失败!");
return;
}
//错误处理
if (setjmp(png_jmpbuf(png_ptr)))
{
fclose(fp);
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
assert(0 && L"Save_To_PNG:pnglib出现错误!");
return;
}
//颜色深度8,像素大小(ARGB 4字节),行字节宽度
unsigned bit_depth = 8;
unsigned pixel_byte = 4;
unsigned row_byte =m_size.w *pixel_byte;
//设置输出文件
png_init_io(png_ptr,fp);
//设置图像属性
png_set_IHDR(png_ptr, info_ptr, m_size.w,m_size.h,bit_depth,
PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,//交错无
PNG_COMPRESSION_TYPE_BASE,PNG_FILTER_TYPE_BASE);
//写头部
png_write_info(png_ptr, info_ptr);
//行指针
png_bytepp row_pointers = (png_bytep*)malloc(m_size.h*sizeof(png_bytep));
//填充数据
for (unsignedx = 0;x < m_size.h; ++x)
{//分配一行
row_pointers[x] = (png_bytep)malloc(row_byte);
for (unsignedy = 0;y < row_byte; y += pixel_byte)
{
row_pointers[x][y + 2] = ((unsignedchar*)m_buffer)[x *row_byte + y + 0];
row_pointers[x][y + 1] = ((unsignedchar*)m_buffer)[x *row_byte + y + 1];
row_pointers[x][y + 0] = ((unsignedchar*)m_buffer)[x *row_byte + y + 2];
row_pointers[x][y + 3] = ((unsignedchar*)m_buffer)[x *row_byte + y + 3];
}
}
//写入全部行
png_write_image(png_ptr, row_pointers);
//写尾部
png_write_end(png_ptr, info_ptr);
//释放png内存
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
for (unsignedx = 0;x < m_size.h; ++x)
{//释放每行
free(row_pointers[x]);
}
free(row_pointers);
fclose(fp);
}
作者:略游
日期:17-06-20
QQ:1339484752