概述
APNG是PNG一个小分支,但还没有正式加入libpng这个库,而是以一个patch的形式存在。
libpng 这里下载:https://sourceforge.net/projects/libpng/files/
APNG的patch则在这儿: https://sourceforge.net/projects/libpng-apng/
而libpng还依赖zlib,还需要这个:http://zlib.net/
APNG格式定义:
see https://wiki.mozilla.org/APNG_Specification#mw-head
环境
解码:libpng + libpng-apng.patch + zlib
显示:GDI+ + Win32
开发环境: VS2015
搭建工程
libpng
- Clone libpng, apng.patch最新版,所有源文件放到同一个目录,如: e:\apng\libpng\
- 打patch需要用到patch命令,我用的是: git for windows 的 git bash:
patch -p0 < libpng-1.6.37-apng.patch
用vs新建一个lib工程,名为 libpng.vcxproj,加入libpng*.c, libpng*.h
zlib
- Clone zlib最新版,所有源文件放在 e:\apng\zlib\
- 用vs新建一个lib工程,名为 zlib.vcxproj,加入zlib*.c, zlib*.h
可以用cmake搭建工程,但可能有error,且小工程还没我手动来得快~
解码
解码目标是使用libpng把所有APNG帧解析成BGRA流,用来构建后续用来显示的GDI+ Bitmap,部分代码:
//APNG解码
#include "stdafx.h"
#include "ApngLoader.h"
BOOL CApngLoader::LoadAPNG(const wstring& strImg)
{
FILE* f1 = NULL;
_wfopen_s(&f1, strImg.c_str(), L"rb");
if (f1 == NULL)
{
OutputDebugString(L"Cannot open file!\r\n");
return FALSE;
}
UINT32 i, j;
png_bytepp rows_image;
png_bytepp rows_frame;
BYTE* p_image;
BYTE* p_frame;
BYTE* p_temp;
BYTE sig[8];
fread(sig, 1, 8, f1);
if (png_sig_cmp(sig, 0, 8) != 0)
{
OutputDebugString(L"Not a png image!\r\n");
fclose(f1);
return FALSE;
}
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
png_infop info_ptr = png_create_info_struct(png_ptr);
if (png_ptr && info_ptr)
{
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f1);
return FALSE;
}
png_init_io(png_ptr, f1);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL))
{
OutputDebugString(L"Not a apng image!\r\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f1);
return FALSE;
}
UINT32 nFrameCount = 1;
m_nPlays = 0;
png_get_acTL(png_ptr, info_ptr, &nFrameCount, &m_nPlays);
if (nFrameCount <= 1)
{
OutputDebugString(L"Not a apng Image!\r\n");
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(f1);
return FALSE;
}
//设置解码的格式,统统转成BGRA格式
png_set_expand(png_ptr);
png_set_strip_16(png_ptr);
png_set_gray_to_rgb(png_ptr);
png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
png_set_bgr(png_ptr);
png_set_interlace_handling(png_ptr)