PNG是一种非常流行的图片格式,它不仅支持透明效果,而且图片数据经过了压缩处理,所以广泛用于web等应用。
PNG的文件格式:
PNG文件中的数据,总是以一个固定的8个字节开头:
(图片来自http://blog.csdn.net/bisword/article/details/2777121)
除此之外,PNG的其他数据都是以数据块的方式组织,它们被分为标准数据块和辅助数据块,其中的辅助数据块是可选的。关键数据块包含我们必须的图片信息,我们之后要重点解析的也是关键数据块。
(图片来自http://blog.csdn.net/bisword/article/details/2777121)
每种数据块的结构:
(图片来自http://blog.csdn.net/bisword/article/details/2777121)
Length:该数据块的中Chunk Data的长度;
Chunk Type Code:数据类型,就是指上面提到的IHDR,IEND等;
Chunk Data:数据区域,如果是IDAT,就表示存储的还未解压的图片数据;
CRC:循环冗余效验码;
具体实现:(实现中没有处理png数据中变形的情况,部分头中的宏定义来自libpng,实例不具备实用性,仅作参考)
头文件:
1 #ifndef __PNG__ 2 #define __PNG__ 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <math.h> 7 #include "zlib/zlib.h" 8 9 /** 10 * 类型标志 11 */ 12 #define PNG_FLAG_HEX "89504E470D0A1A0A" 13 14 /** 15 * 数据块类型 16 */ 17 #define DATA_CHUNK_TYPE_IHDR "IHDR" 18 #define DATA_CHUNK_TYPE_IDAT "IDAT" 19 #define DATA_CHUNK_TYPE_IEND "IEND" 20 #define DATA_CHUNK_TYPE_tEXt "tEXt" 21 #define DATA_CHUNK_TYPE_iTXt "iTXt" 22 23 /** 24 * 过滤方式 25 */ 26 #define DATA_FILTER_TYPE_DEFAULT 0 27 #define DATA_FILTER_TYPE_ADD_ROW 1 28 #define DATA_FILTER_TYPE_ADD_UP 2 29 #define DATA_FILTER_TYPE_AVERGE 3 30 #define DATA_FILTER_TYPE_PAETH 4 31 32 /* color type masks */ 33 #define PNG_COLOR_MASK_PALETTE 1 34 #define PNG_COLOR_MASK_COLOR 2 35 #define PNG_COLOR_MASK_ALPHA 4 36 37 /* color types. Note that not all combinations are legal */ 38 #define PNG_COLOR_TYPE_GRAY 0 39 #define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) 40 #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) 41 #define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) 42 #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) 43 44 #define RGB_USE_ALPHA(vr, vg, vb, va) 45 (unsigned)(((unsigned)((unsigned char)(vr) * ((unsigned char)(va) + 1)) >> 8) | 46 ((unsigned)((unsigned char)(vg) * ((unsigned char)(va) + 1) >> 8) << 8) | 47 ((unsigned)((unsigned char)(vb) * ((unsigned char)(va) + 1) >> 8) << 16) | 48 ((unsigned)(unsigned char)(va) << 24)) 49 50 /** 51 * 一次解压图片数据的限制 52 */ 53 #define DECOMPRESSION_MAX_BYTES 8192 54 55 /** 56 * 数据块信息 57 */ 58 typedef struct _DataChunkHeader 59 { 60 // 数据长度 61 unsigned char length[4]; 62 // 数据类型 63 unsigned char type[4]; 64 } DataChunkHeader; 65 66 /** 67 * IHDR数据 68 */ 69 typedef struct _IDHRData 70 { 71 unsigned char width[4]; 72 unsigned char height[4]; 73 unsigned char bitDepth[1]; 74 unsigned char colorType[1]; 75 unsigned char compressionMethod[1]; 76 unsigned char filterMethod[1]; 77 unsigned char interlaceMethod[1]; 78 } IDHRData; 79 80 /** 81 * PNG图片类 82 */ 83 class PNG 84 { 85 public: 86 PNG(); 87 PNG(const char* filePath); 88 89 ~PNG(); 90 91 int getWindth(); 92 int getHeight(); 93 94 /** 95 * 获取图片宽度 96 */ 97 unsigned char* getImageData(); 98 99 private: 100 int m_width; 101 int m_height; 102 103 unsigned char m_bitDepth; 104 unsigned char m_colorType; 105 unsigned char m_compressionMethod; 106 unsigned char m_filterMethod; 107 unsigned char m_interlaceMethod; 108 unsigned char m_chanels; 109 110 unsigned char* m_imageData; 111 112 /** 113 * 从文件加载图片数据 114 */ 115 bool loadImageDataFromFile(const char* filePath); 116 117 /** 118 * 解析数值 119 */ 120 int parseNumber(const unsigned char* data, int len); 121 122 /** 123 * 解压数据 124 */ 125 int decompressData(z_stream* zStream, unsigned char* data, int dataLen, int leftLen, FILE *pFile); 126 127 /** 128 * 生成图片数据 129 */ 130 void generateImageData(unsigned char* data, unsigned long dataLen); 131 132 /** 133 * 默认的过滤方式 134 */ 135 void defaultFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 136 137 /** 138 * 当前行相加的过滤方式 139 */ 140 void addCurrentRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 141 142 /** 143 * 前一行相加的过滤方式 144 */ 145 void addUpRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 146 147 /** 148 * 平均的过滤方式 149 */ 150 void avergeFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 151 152 /** 153 * paeth的过滤方式 154 */ 155 void paethFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 156 157 /** 158 * 解析IHDR数据 159 */ 160 void parseIHDRData(DataChunkHeader& dataChunkHeader, FILE* pFile); 161 162 /** 163 * 解析IDAT数据 164 */ 165 void parseIDATData(DataChunkHeader& dataChunkHeader, FILE* pFile); 166 167 /** 168 * 解析IEND数据 169 */ 170 void parseIENDData(DataChunkHeader& dataChunkHeader, FILE *pFile); 171 172 /** 173 * 解析其他数据 174 */ 175 void parseCommonData(DataChunkHeader& dataChunkHeader, FILE *pFile); 176 }; 177 178 #endif
cpp文件:
1 #include "png.h" 2 #include "utils/cUtil.h" 3 #include <stdlib.h> 4 5 #include <windows.h> 6 7 /** 8 * 默认构造函数 9 */ 10 PNG::PNG() 11 { 12 this->m_width = 0; 13 this->m_height = 0; 14 15 this->m_imageData = 0; 16 } 17 18 /** 19 * 构造函数 20 * @param filePath 图片路径 21 */ 22 PNG::PNG(const char *filePath) 23 { 24 this->m_width = 0; 25 this->m_height = 0; 26 27 this->loadImageDataFromFile(filePath); 28 } 29 30 /** 31 * 析构函数 32 */ 33 PNG::~PNG() 34 { 35 36 } 37 38 /** 39 * 从文件加载图片数据 40 */ 41 bool PNG::loadImageDataFromFile(const char* filePath) 42 { 43 FILE* pFile = fopen(filePath, "rb"); 44 if (!pFile) 45 return false; 46 47 // 解析PNG标志 48 char flag[8]; 49 char hexFlag[17]; 50 fread(flag, 1, 8, pFile); 51 toHexStr(flag, 8, hexFlag); 52 if (strcmp(hexFlag, PNG_FLAG_HEX) != 0) 53 return false; 54 55 // 解析图片数据 56 DataChunkHeader dataChunkHeader; 57 char dataChunkHeaderType[5]; 58 do { 59 fread(&dataChunkHeader, 1, sizeof(DataChunkHeader), pFile); 60 61 memcpy(dataChunkHeaderType, dataChunkHeader.type, 4); 62 dataChunkHeaderType[4] = '