#ifndef __PNGWRITE_INCLUDED__ #define __PNGWRITE_INCLUDED__ #include #include #include "zlib.h" #include "typedef.h" #include "macro.h" class PNGWRITE { public: bool Write( const char* fname, INT nWidth, INT nHeight, RGBQUAD* pRGB, LPBYTE lpBitmap, DWORD dwScan ) { FILE* fp = NULL; LPBYTE pBits = NULL; LPBYTE pZbuf = NULL; unsigned long zlibbuffersize; INT i; if( !(fp = ::fopen( fname, "wb" )) ) goto error_exit; if( !WriteSignature( fp ) ) goto error_exit; if( !(pBits = (LPBYTE)::malloc( (nWidth+1)*nHeight*sizeof(BYTE) )) ) goto error_exit; LPBYTE pSrc, pDst; pSrc = lpBitmap; pDst = pBits; // No Filter for( i = 0; i < nHeight; i++ ) { *(pDst++) = 0; ::memcpy( pDst, pSrc, nWidth ); pSrc += dwScan; pDst += nWidth; } zlibbuffersize = ((nWidth+1)*nHeight)*1.1+12; if( !(pZbuf = (LPBYTE)::malloc( zlibbuffersize )) ) goto error_exit; if( compress( pZbuf, &zlibbuffersize, pBits, ((nWidth+1)*nHeight) ) != Z_OK ) goto error_exit; // write IHDR { BYTE temp[13]; // Write Length ConvertNetworkOrder( nWidth, temp ); ConvertNetworkOrder( nHeight, temp+4 ); *(temp+ 8) = 8; // 8bpp *(temp+ 9) = 3; // Indexed color *(temp+10) = 0; // Compression method *(temp+11) = 0; // Filter method *(temp+12) = 0; // Interace method if( !WriteChunk( fp, PNG_CHUNK_IHDR, temp, 13 ) ) goto error_exit; } // write PLTE { BYTE pal[256*3]; for( INT i = 0; i < 256; i++ ) { pal[i*3+0] = pRGB[i].rgbRed; pal[i*3+1] = pRGB[i].rgbGreen; pal[i*3+2] = pRGB[i].rgbBlue; } if( !WriteChunk( fp, PNG_CHUNK_PLTE, pal, 256*3 ) ) goto error_exit; } // write IDAT if( !WriteChunk( fp, PNG_CHUNK_IDAT, pZbuf, zlibbuffersize ) ) goto error_exit; // write IEND if( !WriteChunk( fp, PNG_CHUNK_IEND, NULL, 0 ) ) goto error_exit; FREE( pBits ); FREE( pZbuf ); FCLOSE( fp ); return true; error_exit: FREE( pBits ); FREE( pZbuf ); FCLOSE( fp ); return false; } protected: void ConvertNetworkOrder( UINT uData, BYTE* pBuf ) { pBuf[0] = (BYTE)(uData>>24); pBuf[1] = (BYTE)(uData>>16); pBuf[2] = (BYTE)(uData>>8); pBuf[3] = (BYTE)(uData); } bool WriteSignature( FILE* fp ) { const char PNG_SIGNATURE[] = { "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A" }; if( ::fwrite( PNG_SIGNATURE, 8, 1, fp ) != 1 ) return false; return true; } bool WriteChunk( FILE* fp, UINT uType, BYTE* pData, UINT uLength ) { BYTE temp[4]; // Write Length ConvertNetworkOrder( uLength, temp ); if( ::fwrite( temp, sizeof(temp), 1, fp ) != 1 ) return false; // Write Chunk Type ConvertNetworkOrder( uType, temp ); if( ::fwrite( temp, sizeof(temp), 1, fp ) != 1 ) return false; UINT crc = crc32( 0, temp, sizeof(temp) ); if( uLength ) { if( ::fwrite( pData, uLength, 1, fp ) != 1 ) return false; crc = crc32( crc, pData, uLength ); } // Write CRC32 ConvertNetworkOrder( crc, temp ); if( ::fwrite( temp, sizeof(temp), 1, fp ) != 1 ) return false; return true; } private: enum { PNG_CHUNK_IHDR = 0x49484452, PNG_CHUNK_PLTE = 0x504C5445, PNG_CHUNK_IDAT = 0x49444154, PNG_CHUNK_IEND = 0x49454E44, }; }; #endif // !__PNGWRITE_INCLUDED__