最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

PNG图片数据解析

来源:动视网 责编:小OO 时间:2025-10-05 23:52:29
文档

PNG图片数据解析

PNG图⽚数据解析PNG是⼀种⾮常流⾏的图⽚格式,它不仅⽀持透明效果,⽽且图⽚数据经过了压缩处理,所以⼴泛⽤于web等应⽤。PNG的⽂件格式:PNG⽂件中的数据,总是以⼀个固定的8个字节开头:除此之外,PNG的其他数据都是以数据块的⽅式组织,它们被分为标准数据块和辅助数据块,其中的辅助数据块是可选的。关键数据块包含我们必须的图⽚信息,我们之后要重点解析的也是关键数据块。每种数据块的结构:Length:该数据块的中ChunkData的长度;ChunkTypeCode:数据类型,就是指上⾯提到的I
推荐度:
导读PNG图⽚数据解析PNG是⼀种⾮常流⾏的图⽚格式,它不仅⽀持透明效果,⽽且图⽚数据经过了压缩处理,所以⼴泛⽤于web等应⽤。PNG的⽂件格式:PNG⽂件中的数据,总是以⼀个固定的8个字节开头:除此之外,PNG的其他数据都是以数据块的⽅式组织,它们被分为标准数据块和辅助数据块,其中的辅助数据块是可选的。关键数据块包含我们必须的图⽚信息,我们之后要重点解析的也是关键数据块。每种数据块的结构:Length:该数据块的中ChunkData的长度;ChunkTypeCode:数据类型,就是指上⾯提到的I
PNG图⽚数据解析

PNG是⼀种⾮常流⾏的图⽚格式,它不仅⽀持透明效果,⽽且图⽚数据经过了压缩处理,所以⼴泛⽤于web等应⽤。

PNG的⽂件格式:

  PNG⽂件中的数据,总是以⼀个固定的8个字节开头:

  除此之外,PNG的其他数据都是以数据块的⽅式组织,它们被分为标准数据块和辅助数据块,其中的辅助数据块是可选的。关键数据块包含我们必须的图⽚信息,我们之后要重点解析的也是关键数据块。

  

每种数据块的结构:

  

  Length:该数据块的中Chunk Data的长度;

  Chunk Type Code:数据类型,就是指上⾯提到的IHDR,IEND等;

  Chunk Data:数据区域,如果是IDAT,就表⽰存储的还未解压的图⽚数据;

  CRC:循环冗余效验码;

具体实现:(实现中没有处理png数据中变形的情况,部分头中的宏定义来⾃libpng,实例不具备实⽤性,仅作参考)

头⽂件:

1 #ifndef __PNG__

2#define __PNG__

3

4 #include

5 #include

6 #include

7 #include "zlib/zlib.h"

8

9/**

10 * 类型标志

11*/

12#define PNG_FLAG_HEX "504E470D0A1A0A"

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];

} 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*/

83class PNG

84 {

85public:

86 PNG();

87 PNG(const char* filePath);

88

~PNG();

90

91int getWindth();

92int getHeight();

93

94/**

95 * 获取图⽚宽度

96*/

97 unsigned char* getImageData();

98

99private:

100int m_width;

101int 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*/

115bool loadImageDataFromFile(const char* filePath);

116

117/**

118 * 解析数值

119*/

120int parseNumber(const unsigned char* data, int len);

121

122/**

123 * 解压数据

124*/

125int decompressData(z_stream* zStream, unsigned char* data, int dataLen, int leftLen, FILE *pFile); 126

127/**

128 * ⽣成图⽚数据

129*/

130void generateImageData(unsigned char* data, unsigned long dataLen);

131

132/**133 * 默认的过滤⽅式

134*/

135void defaultFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes);

136

137/**

138 * 当前⾏相加的过滤⽅式

139*/

140void addCurrentRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 141

142/**

143 * 前⼀⾏相加的过滤⽅式

144*/

145void addUpRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes); 146

147/**

148 * 平均的过滤⽅式

149*/

150void avergeFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes);

151

152/**

153 * paeth的过滤⽅式

154*/

155void paethFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes);

156

157/**

158 * 解析IHDR数据

159*/

160void parseIHDRData(DataChunkHeader& dataChunkHeader, FILE* pFile);

161

162/**

163 * 解析IDAT数据

1*/

165void parseIDATData(DataChunkHeader& dataChunkHeader, FILE* pFile);

166

167/**

168 * 解析IEND数据

169*/

170void parseIENDData(DataChunkHeader& dataChunkHeader, FILE *pFile);

171

172/**

173 * 解析其他数据

174*/

175void parseCommonData(DataChunkHeader& dataChunkHeader, FILE *pFile);

176 };

177

178#endif

cpp⽂件:

1 #include "png.h"

2 #include "utils/cUtil.h"

3 #include

4

5 #include

6

7/**

8 * 默认构造函数

9*/

10 PNG::PNG()

11 {

12this->m_width = 0;

13this->m_height = 0;

14

15this->m_imageData = 0;

16 }

17

18/**

19 * 构造函数

20 * @param filePath 图⽚路径

21*/

22 PNG::PNG(const char *filePath)

23 {

24this->m_width = 0;

25this->m_height = 0;

26

27this->loadImageDataFromFile(filePath);

28 }

29

30/**

31 * 析构函数

32*/

33 PNG::~PNG()

34 {

3537

38/**

39 * 从⽂件加载图⽚数据

40*/

41bool PNG::loadImageDataFromFile(const char* filePath)

42 {

43 FILE* pFile = fopen(filePath, "rb");

44if (!pFile)

45return false;

46

47// 解析PNG标志

48char flag[8];

49char hexFlag[17];

50 fread(flag, 1, 8, pFile);

51 toHexStr(flag, 8, hexFlag);

52if (strcmp(hexFlag, PNG_FLAG_HEX) != 0)

53return false;

54

55// 解析图⽚数据

56 DataChunkHeader dataChunkHeader;

57char dataChunkHeaderType[5];

58do {

59 fread(&dataChunkHeader, 1, sizeof(DataChunkHeader), pFile);

60

61 memcpy(dataChunkHeaderType, dataChunkHeader.type, 4);

62 dataChunkHeaderType[4] = '\\0';

63

// IHDR

65if ( strcmp(dataChunkHeaderType, DATA_CHUNK_TYPE_IHDR) == 0 ) {

66this->parseIHDRData(dataChunkHeader, pFile);

67 }

68// IDAT

69else if ( strcmp(dataChunkHeaderType, DATA_CHUNK_TYPE_IDAT) == 0 ) { 70this->parseIDATData(dataChunkHeader, pFile);

71 }

72// IEND

73else if ( strcmp(dataChunkHeaderType, DATA_CHUNK_TYPE_IEND) == 0 ) { 74this->parseIENDData(dataChunkHeader, pFile);

75 }

76// 其他数据

77else {

78this->parseCommonData(dataChunkHeader, pFile);

79 }

80 } while( strcmp(dataChunkHeaderType, DATA_CHUNK_TYPE_IEND) != 0 );

81

82int i = 1;

83

84return true;

85 }

86

87/**

88 * 解析数值

*/

90int PNG::parseNumber(const unsigned char* data, int len)

91 {

92char localNum[4];

93

94bool isLittleEndian = checkEndian();

95for (int i = 0; i<4; i++) {

96char ch;

97

98if (isLittleEndian) {

99if (i <= len-1)

100 ch = data[len - 1 - i];

101else

102 ch = '\\0';

103 }

104else {

105if (i <= len-1)

106 ch = data[i];

107else

108 ch = '\\0';

109 }

110 localNum[i] = ch;

111 }

112

113int num;

114 memcpy(&num, localNum, 4);

115return num;

116 }

117

118/**

119 * 解析IHDR数据121void PNG::parseIHDRData(DataChunkHeader& dataChunkHeader, FILE* pFile)

122 {

123int dataLen = this->parseNumber(dataChunkHeader.length, 4);

124

125 IDHRData idhrData;

126char crc[4];

127

128 fread(&idhrData, 1, sizeof(IDHRData), pFile);

129 fread(crc, 1, 4, pFile);

130

131this->m_width = this->parseNumber(idhrData.width, 4);

132this->m_height = this->parseNumber(idhrData.height, 4);

133this->m_bitDepth = this->parseNumber(idhrData.bitDepth, 1);

134this->m_colorType = this->parseNumber(idhrData.colorType, 1);

135this->m_compressionMethod = this->parseNumber(idhrData.compressionMethod, 1);

136this->m_filterMethod = this->parseNumber(idhrData.filterMethod, 1);

137this->m_interlaceMethod = this->parseNumber(idhrData.interlaceMethod, 1);

138this->m_chanels = 0;

139

140switch (this->m_colorType) {

141case PNG_COLOR_TYPE_GRAY:

142case PNG_COLOR_TYPE_PALETTE:

143this->m_chanels = 1;

144break;

145case PNG_COLOR_TYPE_RGB:

146this->m_chanels = 3;

147break;

148case PNG_COLOR_TYPE_GRAY_ALPHA:

149this->m_chanels = 2;

150break;

151case PNG_COLOR_TYPE_RGB_ALPHA:

152this->m_chanels = 4;

153break;

154default:

155this->m_chanels = 0;

156break;

157 }

158 }

159

160/**

161 * 解压数据

162*/

163int PNG::decompressData(z_stream* zStream, unsigned char* data, int dataLen, int leftLen, FILE *pFile) 1 {

165int result = 0;

166

167int leftBytesCount = leftLen;

168int avail_out = -1;

169do {

170if (zStream->avail_in == 0) {

171if (avail_out == 0)

172break;

173else {

174if (leftBytesCount == 0) {

175 DataChunkHeader dataChunkHeader;

176 fread(&dataChunkHeader, 1, sizeof(DataChunkHeader), pFile);

177

178int newDataLen = this->parseNumber(dataChunkHeader.length, 4);

179 unsigned char* newData = new unsigned char[dataLen + newDataLen];

180char crc[4];

181

182 fread(newData + dataLen, 1, newDataLen, pFile);

183 fread(crc, 1, 4, pFile);

184 memcpy(newData, data, dataLen);

185

186 delete data;

187 data = newData;

188

1 zStream->next_in = newData + dataLen;

190 zStream->avail_in = newDataLen;

191

192 dataLen = dataLen + newDataLen;

193

194return this->decompressData(zStream, data, dataLen, 0, pFile);

195 }

196 }

197

198// 导出数据是否超过

199if (leftBytesCount > DECOMPRESSION_MAX_BYTES)

200 zStream->avail_in = DECOMPRESSION_MAX_BYTES;

201else

202 zStream->avail_in = leftBytesCount;

203204 leftBytesCount -= zStream->avail_in;

205 }

206

207if (avail_out > 0)

208 zStream->avail_out = avail_out;

209else

210 zStream->avail_out = m_width * 4 + 1;

211

212 result = inflate(zStream, Z_NO_FLUSH);

213if (result != Z_OK)

214break;

215

216 avail_out = zStream->avail_out;

217 } while (zStream->avail_in >= 0);

218

219return result;

220 }

221

222/**

223 * ⽣成图⽚数据

224*/

225void PNG::generateImageData(unsigned char* data, unsigned long dataLen) 226 {

227// ⾏字节数

228int rowBytes = this->m_chanels * this->m_width;

229

230// 初始化图⽚数据

231this->m_imageData = new unsigned char[rowBytes * this->m_height];

232

233 unsigned char* pImageData = this->m_imageData;

234 unsigned char* pRowData = data;

235

236for (int rowIndex = 0; rowIndex < this->m_height; rowIndex++) {

237// 过滤类型

238 unsigned char filterType = pRowData[0];

239

240 pRowData += 1;

241

242switch (filterType) {

243// 不需要过滤处理

244case DATA_FILTER_TYPE_DEFAULT:

245this->defaultFilterType(pImageData, pRowData, rowBytes);

246break;

247// 当前⾏相加

248case DATA_FILTER_TYPE_ADD_ROW:

249this->addCurrentRowFilterType(pImageData, pRowData, rowBytes); 250break;

251// 和前⼀⾏相加

252case DATA_FILTER_TYPE_ADD_UP:

253this->addUpRowFilterType(pImageData, pRowData, rowBytes); 254break;

255// 求平均

256case DATA_FILTER_TYPE_AVERGE:

257this->avergeFilterType(pImageData, pRowData, rowBytes);

258break;

259// Paeth

260case DATA_FILTER_TYPE_PAETH:

261this->paethFilterType(pImageData, pRowData, rowBytes);

262break;

263// 类型错误

2default:

265break;

266 }

267

268 pImageData += rowBytes;

269 pRowData += rowBytes;

270

271char text[100];

272 sprintf(text, "filter type:%d, rowIndex:%d \\n

273 OutputDebugString(text);

274 }

275

276int channel = rowBytes / this->m_width;

277if (channel == 4) {

278 unsigned int *tmp = (unsigned int *)this->m_imageData;

279

280for (unsigned short i = 0; i < this->m_height; i++) {

281for (unsigned int j = 0; j < rowBytes; j+=4) {

282 unsigned int offset = i * rowBytes + j;

283

284 *tmp++ = RGB_USE_ALPHA(

285this->m_imageData[offset],

286this->m_imageData[offset+1],

287this->m_imageData[offset+2],

288this->m_imageData[offset+3]

2 );

290 }

291 }

292 }

293 }

294

295/**

296 * 默认的过滤⽅式

297*/

298void PNG::defaultFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes)

299 {

300for (int i = 0; i < rowBytes; i++) {

301 *pImageData++ = *pRowData++;

302 }

303 }

304

305/**

306 * 当前⾏相加的过滤⽅式

307*/

308void PNG::addCurrentRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes) 309 {

310for (int i = 0; i < rowBytes; i++) {

311if (i == 0) {

312 memcpy(pImageData, pRowData, 4);

313 i += 3;

314 pImageData += 4;

315 pRowData += 4;

316 }

317else {

318 *pImageData++ = (unsigned char)(((int)*(pRowData++) + (int)*(pImageData-4)) & 0xFF);

319 }

320 }

321 }

322

323/**

324 * 前⼀⾏相加的过滤⽅式

325*/

326void PNG::addUpRowFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes) 327 {

328for (int i = 0; i < rowBytes; i++) {

329 *pImageData++ = (unsigned char)(((int)*(pRowData++) + (int)*(pImageData-rowBytes)) & 0xFF);

330 }

331 }

332

333/**

334 * 平均的过滤⽅式

335*/

336void PNG::avergeFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes)

337 {

338for (int i = 0; i < rowBytes; i++) {

339int averge = 0;

340

341if (i <= 3) {

342 averge = ((int)*(pImageData-rowBytes)) / 2;

343

344 *pImageData++ = (unsigned char)((averge + (int)*(pRowData++)) & 0xFF);

345 }

346else {

347 averge = (((int)*(pImageData-4)) + ((int)*(pImageData-rowBytes))) / 2;

348

349 *pImageData++ = (unsigned char)((averge + (int)*(pRowData++)) & 0xFF);

350 }

351 }

352 }

353

354/**

355 * paeth的过滤⽅式

356*/

357int Paeth(int a, int b, int c)

358 {

359int p = a + b - c;

360int pa = abs(p - a);

361int pb = abs(p - b);

362int pc = abs(p - c);

363

3int Paeth;

365if(pa <= pb && pa <= pc)

366 Paeth = a;

367else if (pb <= pc)

368 Paeth = b;

369else

370 Paeth = c;

371return Paeth ;372 }

373void PNG::paethFilterType(unsigned char* pImageData, unsigned char* pRowData, int rowBytes)

374 {

375for (int i = 0; i < rowBytes; i++) {

376if (i <= 3) {

377 *pImageData++ = (unsigned char)(((int)*(pRowData++) + (int)*(pImageData-rowBytes)) & 0xFF); 378 }

379else {

380 unsigned char left = *(pImageData - 4);

381 unsigned char up = *(pImageData - rowBytes);

382 unsigned char leftUp = *(pImageData - rowBytes - 4);

383

384int value = Paeth((int)left, (int)up, (int)leftUp);

385

386 *pImageData++ = (unsigned char)(((int)*(pRowData++) + value) & 0xFF);

387 }

388 }

3 }

390

391/**

392 * 解析IDAT数据

393*/

394void PNG::parseIDATData(DataChunkHeader& dataChunkHeader, FILE* pFile)

395 {

396// 解压后的图⽚数据

397 unsigned char* imageData = new unsigned char[m_width * m_height * 4];

398

399int dataLen = this->parseNumber(dataChunkHeader.length, 4);

400// 解压前的图⽚数据

401 unsigned char* data = new unsigned char[dataLen];

402char crc[4];

403// 提取数据

404 fread(data, 1, dataLen, pFile);

405 fread(crc, 1, 4, pFile);

406

407// 存放临时的解压数据

408 unsigned long decompressDataLen = m_width * m_height * 4 + m_height;

409 unsigned char* decompressData = new unsigned char[decompressDataLen];

410

411 z_stream* zStream = new z_stream();

412 zStream->next_in = data;

413 zStream->next_out = decompressData;

414

415 inflateInit(zStream);

416

417// 解压数据

418this->decompressData(zStream, data, dataLen, dataLen, pFile);

419// ⽣成图⽚数据

420this->generateImageData(decompressData, decompressDataLen);

421

422/*

423 int result = 0;

424 // 开始解压数据

425 int leftBytesCount = dataLen;

426 int avail_out = -1;

427 do {

428 if (zStream->avail_in == 0) {

429 if (avail_out == 0)

430 break;

431 else {

432 if (leftBytesCount == 0) {

433

434 }

435 }

436

437 // 导出数据是否超过

438 if (leftBytesCount > DECOMPRESSION_MAX_BYTES)

439 zStream->avail_in = DECOMPRESSION_MAX_BYTES;

440 else

441 zStream->avail_in = leftBytesCount;

442

443 leftBytesCount = dataLen - zStream->avail_in;

444 }

445

446 if (avail_out > 0)

447 zStream->avail_out = avail_out;

448 else

449 zStream->avail_out = m_width * 4 + 1;

450

451 result = inflate(zStream, Z_NO_FLUSH);

452 if (result != Z_OK)

453 break;

454

455 avail_out = zStream->avail_out;456 } while (zStream->avail_in >= 0);

457 // 数据解压是否成功

458 if (result == Z_STREAM_END) {

459 int i = 1;

460 }

461*/

462 }

463

4/**

465 * 解析IEND数据

466*/

467void PNG::parseIENDData(DataChunkHeader& dataChunkHeader, FILE *pFile)

468 {

469char crc[4];

470 fread(crc, 1, 4, pFile);

471 }

472

473/**

474 * 解析其他数据

475*/

476void PNG::parseCommonData(DataChunkHeader& dataChunkHeader, FILE *pFile)

477 {

478int dataLen = this->parseNumber(dataChunkHeader.length, 4);

479 fseek(pFile, dataLen + 4, SEEK_CUR);

480 }

481

482/**

483 * 获取图⽚宽度

484*/

485 unsigned char* PNG::getImageData()

486 {

487return this->m_imageData;

488 }

4

490/**

491 * 获取图⽚宽度

492*/

493int PNG::getWindth()

494 {

495return this->m_width;

496 }

497

498/**

499 * 获取图⽚⾼度

500*/

501int PNG::getHeight()

502 {

503return this->m_height;

504 }

如果需要绘制图⽚,可以使⽤opengl库

参考代码:

1 glViewport(0, 0, winWidth, winHeight);

2

3 glMatrixMode(GL_PROJECTION);

4 glLoadIdentity();

5 glOrtho(0.0f, winWidth - 1.0, 0.0, winHeight - 1.0, -10.0, 10.0);

6

7 glMatrixMode(GL_MODELVIEW);

8 glLoadIdentity();

9

10 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

11

12 glEnable(GL_TEXTURE_2D);

13

14int width = png->getWindth();

15int height = png->getHeight();

16 unsigned char* data = png->getImageData();

17

18 GLuint name1;

19 glGenTextures(1, &name1);

20 glBindTexture(GL_TEXTURE_2D, name1);

21 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

22 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

23 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

24 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

25 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,GL_RGBA, GL_UNSIGNED_BYTE, data);

26 glBegin(GL_POLYGON);

27 glTexCoord2f(1, 1);

28 glVertex3d(800, 800, 2);

29 glTexCoord2f(0, 1);30 glVertex3d(0, 800, 2);

31 glTexCoord2f(0, 0);

32 glVertex3d(0, 0, 2);

33 glTexCoord2f(1, 0);

34 glVertex3d(800, 0, 2);

35 glEnd();

文档

PNG图片数据解析

PNG图⽚数据解析PNG是⼀种⾮常流⾏的图⽚格式,它不仅⽀持透明效果,⽽且图⽚数据经过了压缩处理,所以⼴泛⽤于web等应⽤。PNG的⽂件格式:PNG⽂件中的数据,总是以⼀个固定的8个字节开头:除此之外,PNG的其他数据都是以数据块的⽅式组织,它们被分为标准数据块和辅助数据块,其中的辅助数据块是可选的。关键数据块包含我们必须的图⽚信息,我们之后要重点解析的也是关键数据块。每种数据块的结构:Length:该数据块的中ChunkData的长度;ChunkTypeCode:数据类型,就是指上⾯提到的I
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top