Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2083 lines
50 KiB

  1. #include "stdafx.h"
  2. #include "pngfilt.h"
  3. #include "resource.h"
  4. #include "cpngfilt.h"
  5. #include "scanline.h"
  6. #include <math.h>
  7. #include "pngcrc.cpp"
  8. #undef DEFINE_GUID
  9. #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  10. EXTERN_C const GUID name \
  11. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  12. DEFINE_GUID( IID_IDirectDrawSurface, 0x6C14DB81,0xA733,0x11CE,0xA5,0x21,0x00,
  13. 0x20,0xAF,0x0B,0xE5,0x60 );
  14. #ifdef _DEBUG
  15. static ULONG g_nPNGTraceLevel = 1;
  16. static void _cdecl FakeTrace( LPCTSTR pszFormat, ... )
  17. {
  18. (void)pszFormat;
  19. }
  20. #define PNGTRACE1(PARAMS) ((g_nPNGTraceLevel >= 1) ? AtlTrace##PARAMS : FakeTrace##PARAMS)
  21. #define PNGTRACE(PARAMS) ATLTRACE##PARAMS
  22. #else
  23. #define PNGTRACE1(PARAMS) ATLTRACE##PARAMS
  24. #define PNGTRACE(PARAMS) ATLTRACE##PARAMS
  25. #endif
  26. // Gamma correction table for sRGB, assuming a file gamma of 1.0
  27. #define VIEWING_GAMMA 1.125
  28. #define DISPLAY_GAMMA 2.2
  29. #define MAXFBVAL 255
  30. BYTE gamma10[256] = {
  31. 0, 15, 21, 26, 30, 34, 37, 41, 43, 46, 49, 51, 53, 56, 58, 60,
  32. 62, 64, 66, 68, 69, 71, 73, 75, 76, 78, 79, 81, 82, 84, 85, 87,
  33. 88, 90, 91, 92, 94, 95, 96, 98, 99,100,101,103,104,105,106,107,
  34. 109,110,111,112,113,114,115,116,117,119,120,121,122,123,124,125,
  35. 126,127,128,129,130,131,132,133,134,135,135,136,137,138,139,140,
  36. 141,142,143,144,145,145,146,147,148,149,150,151,151,152,153,154,
  37. 155,156,156,157,158,159,160,160,161,162,163,164,164,165,166,167,
  38. 167,168,169,170,170,171,172,173,173,174,175,176,176,177,178,179,
  39. 179,180,181,181,182,183,184,184,185,186,186,187,188,188,189,190,
  40. 190,191,192,192,193,194,194,195,196,196,197,198,198,199,200,200,
  41. 201,202,202,203,203,204,205,205,206,207,207,208,208,209,210,210,
  42. 211,212,212,213,213,214,215,215,216,216,217,218,218,219,219,220,
  43. 221,221,222,222,223,223,224,225,225,226,226,227,228,228,229,229,
  44. 230,230,231,231,232,233,233,234,234,235,235,236,236,237,238,238,
  45. 239,239,240,240,241,241,242,242,243,244,244,245,245,246,246,247,
  46. 247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,
  47. };
  48. #ifdef BIG_ENDIAN
  49. #define my_ntohl(x) (x)
  50. inline DWORD endianConverter( DWORD dwSrc )
  51. {
  52. return( ((dwSrc&0xff)<<24)+((dwSrc&0xff00)<<8)+((dwSrc&0xff0000)>>8)+
  53. ((dwSrc&0xff000000)>>24) );
  54. }
  55. #else
  56. inline DWORD my_ntohl( DWORD dwSrc )
  57. {
  58. return( ((dwSrc&0xff)<<24)+((dwSrc&0xff00)<<8)+((dwSrc&0xff0000)>>8)+
  59. ((dwSrc&0xff000000)>>24) );
  60. }
  61. #endif
  62. void FixByteOrder( PNGCHUNKHEADER* pChunkHeader )
  63. {
  64. pChunkHeader->nDataLength = my_ntohl( pChunkHeader->nDataLength );
  65. }
  66. void FixByteOrder( PNGIHDRDATA* pIHDR )
  67. {
  68. pIHDR->nWidth = my_ntohl( pIHDR->nWidth );
  69. pIHDR->nHeight = my_ntohl( pIHDR->nHeight );
  70. }
  71. void CopyPaletteEntriesFromColors(PALETTEENTRY *ppe, const RGBQUAD *prgb,
  72. UINT uCount)
  73. {
  74. while (uCount--)
  75. {
  76. ppe->peRed = prgb->rgbRed;
  77. ppe->peGreen = prgb->rgbGreen;
  78. ppe->peBlue = prgb->rgbBlue;
  79. ppe->peFlags = 0;
  80. prgb++;
  81. ppe++;
  82. }
  83. }
  84. /////////////////////////////////////////////////////////////////////////////
  85. //
  86. CPNGFilter::CPNGFilter() :
  87. m_eInternalState( ISTATE_READFILEHEADER ),
  88. m_nBytesLeftInCurrentTask( 0 ),
  89. m_nDataBytesRead( 0 ),
  90. m_iAppend( 0 ),
  91. m_pStream( NULL ),
  92. m_bFinishedIDAT( FALSE ),
  93. m_nBytesInScanLine( 0 ),
  94. m_iScanLine( 0 ),
  95. m_iFirstStaleScanLine( 0 ),
  96. m_bExpandPixels( FALSE ),
  97. m_pbScanLine( NULL ),
  98. m_pbPrevScanLine( NULL ),
  99. m_pfnCopyScanLine( NULL ),
  100. m_dwChunksEncountered( 0 ),
  101. m_iBackgroundIndex( 0 ),
  102. m_bSurfaceUsesAlpha( FALSE ),
  103. m_bConvertAlpha( FALSE ),
  104. m_nFormats( 0 ),
  105. m_pFormats( NULL ),
  106. m_nTransparentColors( 0 )
  107. {
  108. m_rgbBackground.rgbRed = 0;
  109. m_rgbBackground.rgbGreen = 0;
  110. m_rgbBackground.rgbBlue = 0;
  111. m_rgbBackground.rgbReserved = 0;
  112. for (int i = 0; i < 256; ++i)
  113. m_abTrans[i] = (BYTE)i;
  114. memcpy(m_abGamma, m_abTrans, sizeof(m_abTrans));
  115. }
  116. CPNGFilter::~CPNGFilter()
  117. {
  118. if( m_pFormats != NULL )
  119. {
  120. CoTaskMemFree( m_pFormats );
  121. }
  122. delete m_pbPrevScanLine;
  123. delete m_pbScanLine;
  124. }
  125. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGray1[1] =
  126. {
  127. CopyScanLineGray1ToBGR24
  128. };
  129. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGray2[1] =
  130. {
  131. CopyScanLineGray2ToBGR24
  132. };
  133. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGray4[1] =
  134. {
  135. CopyScanLineGray4ToBGR24
  136. };
  137. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGray8[1] =
  138. {
  139. CopyScanLineGray8ToBGR24
  140. };
  141. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGray16[1] =
  142. {
  143. CopyScanLineGray16ToBGR24
  144. };
  145. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineRGB24[1] =
  146. {
  147. CopyScanLineRGB24ToBGR24
  148. };
  149. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineRGB48[1] =
  150. {
  151. CopyScanLineRGB48ToBGR24
  152. };
  153. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineIndex1[1] =
  154. {
  155. CopyScanLineIndex1ToIndex8
  156. };
  157. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineIndex2[1] =
  158. {
  159. CopyScanLineIndex2ToIndex8
  160. };
  161. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineIndex4[1] =
  162. {
  163. CopyScanLineIndex4ToIndex8
  164. };
  165. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineIndex8[1] =
  166. {
  167. CopyScanLineIndex8ToIndex8
  168. };
  169. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGrayA16[2] =
  170. {
  171. CopyScanLineGrayA16ToBGRA32,
  172. CopyScanLineGrayA16ToBGR24
  173. };
  174. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineGrayA32[2] =
  175. {
  176. CopyScanLineGrayA32ToBGRA32,
  177. CopyScanLineGrayA32ToBGR24
  178. };
  179. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineRGBA32[2] =
  180. {
  181. CopyScanLineRGBA32ToBGRA32,
  182. CopyScanLineRGBA32ToBGR24
  183. };
  184. const PNGCOPYSCANLINEPROC g_apfnCopyScanLineRGBA64[2] =
  185. {
  186. CopyScanLineRGBA64ToBGRA32,
  187. CopyScanLineRGBA64ToBGR24
  188. };
  189. const PNGDUPLICATESCANLINEPROC g_apfnDuplicateScanLineBGR24[1] =
  190. {
  191. DuplicateScanLineBGR24
  192. };
  193. const PNGDUPLICATESCANLINEPROC g_apfnDuplicateScanLineIndex8[1] =
  194. {
  195. DuplicateScanLineIndex8
  196. };
  197. const PNGDUPLICATESCANLINEPROC g_apfnDuplicateScanLineAlphaSrc[2] =
  198. {
  199. DuplicateScanLineARGB32,
  200. DuplicateScanLineBGR24
  201. };
  202. const GUID g_TargetGuidsForAlphaSrcs[2] =
  203. {
  204. // BFID_RGBA_32
  205. { 0x773c9ac0, 0x3274, 0x11d0, { 0xb7, 0x24, 0x00, 0xaa, 0x00, 0x6c, 0x1a, 0x1 } },
  206. // BFID_RGB_24
  207. { 0xe436eb7d, 0x524f, 0x11ce, { 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 } }
  208. };
  209. const PNG_FORMAT_INFO CPNGFilter::s_aFormatInfo[15] =
  210. {
  211. { 1, &BFID_RGB_24, g_apfnCopyScanLineGray1, g_apfnDuplicateScanLineBGR24 },
  212. { 1, &BFID_RGB_24, g_apfnCopyScanLineGray2, g_apfnDuplicateScanLineBGR24 },
  213. { 1, &BFID_RGB_24, g_apfnCopyScanLineGray4, g_apfnDuplicateScanLineBGR24 },
  214. { 1, &BFID_RGB_24, g_apfnCopyScanLineGray8, g_apfnDuplicateScanLineBGR24 },
  215. { 1, &BFID_RGB_24, g_apfnCopyScanLineGray16, g_apfnDuplicateScanLineBGR24 },
  216. { 1, &BFID_RGB_24, g_apfnCopyScanLineRGB24, g_apfnDuplicateScanLineBGR24 },
  217. { 1, &BFID_RGB_24, g_apfnCopyScanLineRGB48, g_apfnDuplicateScanLineBGR24 },
  218. { 1, &BFID_INDEXED_RGB_8, g_apfnCopyScanLineIndex1, g_apfnDuplicateScanLineIndex8 },
  219. { 1, &BFID_INDEXED_RGB_8, g_apfnCopyScanLineIndex2, g_apfnDuplicateScanLineIndex8 },
  220. { 1, &BFID_INDEXED_RGB_8, g_apfnCopyScanLineIndex4, g_apfnDuplicateScanLineIndex8 },
  221. { 1, &BFID_INDEXED_RGB_8, g_apfnCopyScanLineIndex8, g_apfnDuplicateScanLineIndex8 },
  222. { 2, g_TargetGuidsForAlphaSrcs, g_apfnCopyScanLineGrayA16, g_apfnDuplicateScanLineAlphaSrc },
  223. { 2, g_TargetGuidsForAlphaSrcs, g_apfnCopyScanLineGrayA32, g_apfnDuplicateScanLineAlphaSrc },
  224. { 2, g_TargetGuidsForAlphaSrcs, g_apfnCopyScanLineRGBA32, g_apfnDuplicateScanLineAlphaSrc },
  225. { 2, g_TargetGuidsForAlphaSrcs, g_apfnCopyScanLineRGBA64, g_apfnDuplicateScanLineAlphaSrc }
  226. };
  227. HRESULT CPNGFilter::ChooseDestinationFormat( GUID* pBFID )
  228. {
  229. ULONG iPossibleFormat;
  230. ULONG iAcceptableFormat;
  231. const PNG_FORMAT_INFO* pFormatInfo;
  232. BOOL bFound;
  233. ULONG iChosenFormat;
  234. _ASSERTE( pBFID != NULL );
  235. *pBFID = GUID_NULL;
  236. pFormatInfo = &s_aFormatInfo[m_eSrcFormat];
  237. bFound = FALSE;
  238. iChosenFormat = 0;
  239. for( iAcceptableFormat = 0; (iAcceptableFormat < m_nFormats) && !bFound;
  240. iAcceptableFormat++ )
  241. {
  242. for( iPossibleFormat = 0; iPossibleFormat <
  243. pFormatInfo->nPossibleFormats; iPossibleFormat++ )
  244. {
  245. if( IsEqualGUID(m_pFormats[iAcceptableFormat],
  246. pFormatInfo->pPossibleFormats[iPossibleFormat] ) )
  247. {
  248. iChosenFormat = iPossibleFormat;
  249. bFound = TRUE;
  250. }
  251. }
  252. }
  253. if( !bFound )
  254. {
  255. return( E_FAIL );
  256. }
  257. m_pfnCopyScanLine = pFormatInfo->ppfnCopyScanLineProcs[iChosenFormat];
  258. m_pfnDuplicateScanLine = pFormatInfo->ppfnDuplicateScanLineProcs[iChosenFormat];
  259. *pBFID = pFormatInfo->pPossibleFormats[iChosenFormat];
  260. return( S_OK );
  261. }
  262. HRESULT CPNGFilter::LockBits(RECT *prcBounds, DWORD dwLockFlags, void **ppBits, long *pPitch)
  263. {
  264. HRESULT hResult;
  265. DDSURFACEDESC ddsd;
  266. (dwLockFlags);
  267. ddsd.dwSize = sizeof(ddsd);
  268. hResult = m_pDDrawSurface->Lock(prcBounds, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL);
  269. if (FAILED(hResult))
  270. return hResult;
  271. *ppBits = ddsd.lpSurface;
  272. *pPitch = ddsd.lPitch;
  273. return S_OK;
  274. }
  275. HRESULT CPNGFilter::UnlockBits(RECT *prcBounds, void *pBits)
  276. {
  277. (prcBounds);
  278. return m_pDDrawSurface->Unlock(pBits);
  279. }
  280. HRESULT CPNGFilter::FireGetSurfaceEvent()
  281. {
  282. HRESULT hResult;
  283. GUID bfid;
  284. CComPtr < IUnknown > pSurface;
  285. _ASSERTE( m_pEventSink != NULL );
  286. _ASSERTE( m_pDDrawSurface == NULL );
  287. m_bConvertAlpha = FALSE;
  288. m_bSurfaceUsesAlpha = FALSE;
  289. hResult = ChooseDestinationFormat(&bfid);
  290. if (FAILED(hResult))
  291. {
  292. return(hResult);
  293. }
  294. hResult = m_pEventSink->GetSurface(m_pngIHDR.nWidth, m_pngIHDR.nHeight,
  295. bfid, m_nPasses, IMGDECODE_HINT_TOPDOWN|IMGDECODE_HINT_FULLWIDTH,
  296. &pSurface);
  297. if (FAILED(hResult))
  298. {
  299. return( hResult);
  300. }
  301. hResult = pSurface->QueryInterface(IID_IDirectDrawSurface, (void **)&m_pDDrawSurface);
  302. if (FAILED(hResult))
  303. return(hResult);
  304. return (S_OK);
  305. }
  306. // Send an OnProgress event to the event sink (if it has requested progress
  307. // notifications).
  308. HRESULT CPNGFilter::FireOnProgressEvent()
  309. {
  310. HRESULT hResult;
  311. RECT rect;
  312. if( !(m_dwEvents & IMGDECODE_EVENT_PROGRESS) )
  313. {
  314. return( S_OK );
  315. }
  316. PNGTRACE1((_T("Pass: %d\n"), m_iPass ));
  317. rect.left = 0;
  318. rect.top = m_iFirstStaleScanLine;
  319. rect.right = m_pngIHDR.nWidth;
  320. rect.bottom = min( m_iScanLine, m_pngIHDR.nHeight );
  321. hResult = m_pEventSink->OnProgress( &rect, TRUE );
  322. if( FAILED( hResult ) )
  323. {
  324. return( hResult );
  325. }
  326. m_iFirstStaleScanLine = m_iScanLine;
  327. return( S_OK );
  328. }
  329. ///////////////////////////////////////////////////////////////////////////////
  330. // PNG scan line filtering routines
  331. void CPNGFilter::NoneFilterScanLine()
  332. {
  333. }
  334. void CPNGFilter::SubFilterScanLine()
  335. {
  336. BYTE* pbByte;
  337. ULONG iByte;
  338. ULONG nSrcByte;
  339. pbByte = m_pbScanLine+1+m_nBPP;
  340. for( iByte = m_nBPP; iByte < m_nBytesInScanLine; iByte++ )
  341. {
  342. nSrcByte = *pbByte;
  343. nSrcByte += *(pbByte-m_nBPP);
  344. *pbByte = BYTE( nSrcByte );
  345. pbByte++;
  346. }
  347. }
  348. void CPNGFilter::UpFilterScanLine()
  349. {
  350. ULONG iByte;
  351. if( m_iScanLineInPass == 0 )
  352. {
  353. // Unfiltering the top scan line is a NOP
  354. return;
  355. }
  356. for( iByte = 1; iByte <= m_nBytesInScanLine; iByte++ )
  357. {
  358. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+
  359. m_pbPrevScanLine[iByte] );
  360. }
  361. }
  362. void CPNGFilter::AverageFilterScanLine()
  363. {
  364. ULONG iByte;
  365. ULONG nSum;
  366. if( m_iScanLineInPass == 0 )
  367. {
  368. // No prior scan line. Skip the first m_nBPP bytes, since they are not
  369. // affected by the filter
  370. for( iByte = m_nBPP+1; iByte <= m_nBytesInScanLine; iByte++ )
  371. {
  372. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+
  373. (m_pbScanLine[iByte-m_nBPP]/2) );
  374. }
  375. }
  376. else
  377. {
  378. for( iByte = 1; iByte <= m_nBPP; iByte++ )
  379. {
  380. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+
  381. (m_pbPrevScanLine[iByte]/2) );
  382. }
  383. for( ; iByte <= m_nBytesInScanLine; iByte++ )
  384. {
  385. nSum = m_pbScanLine[iByte-m_nBPP]+m_pbPrevScanLine[iByte];
  386. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+(nSum/2) );
  387. }
  388. }
  389. }
  390. static inline int Abs( int n )
  391. {
  392. if( n > 0 )
  393. {
  394. return( n );
  395. }
  396. else
  397. {
  398. return( -n );
  399. }
  400. }
  401. BYTE PaethPredictor( BYTE a, BYTE b, BYTE c )
  402. {
  403. int p;
  404. int pa;
  405. int pb;
  406. int pc;
  407. p = int( a )+int( b )-int( c );
  408. pa = Abs( p-a );
  409. pb = Abs( p-b );
  410. pc = Abs( p-c );
  411. if( (pa <= pb) && (pa <= pc) )
  412. {
  413. return( a );
  414. }
  415. if( pb <= pc )
  416. {
  417. return( b );
  418. }
  419. return( c );
  420. }
  421. void CPNGFilter::PaethFilterScanLine()
  422. {
  423. ULONG iByte;
  424. if( m_iScanLineInPass == 0 )
  425. {
  426. for( iByte = 1; iByte <= m_nBPP; iByte++ )
  427. {
  428. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+PaethPredictor( 0, 0,
  429. 0 ) );
  430. }
  431. for( ; iByte <= m_nBytesInScanLine; iByte++ )
  432. {
  433. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+PaethPredictor(
  434. m_pbScanLine[iByte-m_nBPP], 0, 0 ) );
  435. }
  436. }
  437. else
  438. {
  439. for( iByte = 1; iByte <= m_nBPP; iByte++ )
  440. {
  441. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+PaethPredictor( 0,
  442. m_pbPrevScanLine[iByte], 0 ) );
  443. }
  444. for( ; iByte <= m_nBytesInScanLine; iByte++ )
  445. {
  446. m_pbScanLine[iByte] = BYTE( m_pbScanLine[iByte]+PaethPredictor(
  447. m_pbScanLine[iByte-m_nBPP], m_pbPrevScanLine[iByte],
  448. m_pbPrevScanLine[iByte-m_nBPP] ) );
  449. }
  450. }
  451. }
  452. // Update a CRC accumulator with new data bytes
  453. DWORD UpdateCRC( DWORD dwInitialCRC, const BYTE* pbData, ULONG nCount )
  454. {
  455. DWORD dwCRC;
  456. ULONG iByte;
  457. dwCRC = dwInitialCRC;
  458. for( iByte = 0; iByte < nCount; iByte++ )
  459. {
  460. dwCRC = g_adwCRCTable[(dwCRC^pbData[iByte])&0xff]^(dwCRC>>8);
  461. }
  462. return( dwCRC );
  463. }
  464. HRESULT CPNGFilter::NextState()
  465. {
  466. switch( m_eInternalState )
  467. {
  468. case ISTATE_READFILEHEADER:
  469. m_eInternalState = ISTATE_READCHUNKHEADER;
  470. break;
  471. case ISTATE_READCHUNKHEADER:
  472. if( m_pngChunkHeader.dwChunkType == PNG_CHUNK_IDAT )
  473. {
  474. if (!(m_dwChunksEncountered & CHUNK_BKGD))
  475. m_eInternalState = ISTATE_CHOOSEBKGD;
  476. else
  477. m_eInternalState = ISTATE_READIDATDATA;
  478. }
  479. else
  480. {
  481. m_eInternalState = ISTATE_READCHUNKDATA;
  482. }
  483. break;
  484. case ISTATE_CHOOSEBKGD:
  485. m_eInternalState = ISTATE_READIDATDATA;
  486. break;
  487. case ISTATE_READCHUNKDATA:
  488. if (m_bSkipData)
  489. {
  490. m_eInternalState = ISTATE_EATDATA;
  491. }
  492. else switch( m_pngChunkHeader.dwChunkType )
  493. {
  494. case PNG_CHUNK_BKGD:
  495. m_eInternalState = ISTATE_PROCESSBKGD;
  496. break;
  497. case PNG_CHUNK_IHDR:
  498. m_eInternalState = ISTATE_PROCESSIHDR;
  499. break;
  500. case PNG_CHUNK_TRNS:
  501. m_eInternalState = ISTATE_PROCESSTRNS;
  502. break;
  503. case PNG_CHUNK_GAMA:
  504. m_eInternalState = ISTATE_PROCESSGAMA;
  505. break;
  506. case PNG_CHUNK_PLTE:
  507. m_eInternalState = ISTATE_PROCESSPLTE;
  508. break;
  509. case PNG_CHUNK_IEND:
  510. m_eInternalState = ISTATE_PROCESSIEND;
  511. break;
  512. case PNG_CHUNK_IDAT:
  513. _ASSERT( FALSE );
  514. // fallthrough
  515. default:
  516. m_eInternalState = ISTATE_EATDATA;
  517. break;
  518. }
  519. break;
  520. case ISTATE_PROCESSBKGD:
  521. m_eInternalState = ISTATE_READCHUNKCRC;
  522. break;
  523. case ISTATE_PROCESSIHDR:
  524. m_eInternalState = ISTATE_READCHUNKCRC;
  525. break;
  526. case ISTATE_PROCESSIEND:
  527. m_eInternalState = ISTATE_READCHUNKCRC;
  528. break;
  529. case ISTATE_EATDATA:
  530. if( m_nDataBytesRead != m_pngChunkHeader.nDataLength )
  531. {
  532. m_eInternalState = ISTATE_READCHUNKDATA;
  533. }
  534. else
  535. {
  536. m_eInternalState = ISTATE_READCHUNKCRC;
  537. }
  538. break;
  539. case ISTATE_READCHUNKCRC:
  540. if( m_dwChunksEncountered & CHUNK_IEND )
  541. {
  542. m_eInternalState = ISTATE_DONE;
  543. }
  544. else
  545. {
  546. m_eInternalState = ISTATE_READCHUNKHEADER;
  547. }
  548. break;
  549. case ISTATE_READIDATDATA:
  550. if( m_nDataBytesRead < m_pngChunkHeader.nDataLength )
  551. {
  552. m_eInternalState = ISTATE_READIDATDATA;
  553. }
  554. else
  555. {
  556. _ASSERTE( m_nDataBytesRead == m_pngChunkHeader.nDataLength );
  557. m_eInternalState = ISTATE_READCHUNKCRC;
  558. }
  559. break;
  560. case ISTATE_PROCESSPLTE:
  561. m_eInternalState = ISTATE_READCHUNKCRC;
  562. break;
  563. case ISTATE_PROCESSTRNS:
  564. m_eInternalState = ISTATE_READCHUNKCRC;
  565. break;
  566. case ISTATE_PROCESSGAMA:
  567. m_eInternalState = ISTATE_READCHUNKCRC;
  568. break;
  569. case ISTATE_DONE:
  570. m_eInternalState = ISTATE_DONE;
  571. break;
  572. default:
  573. PNGTRACE((_T("Unknown state\n")));
  574. _ASSERT( FALSE );
  575. break;
  576. }
  577. m_nBytesLeftInCurrentTask = 0;
  578. return( S_OK );
  579. }
  580. // Process a PNG background color chunk.
  581. HRESULT CPNGFilter::ProcessBKGD()
  582. {
  583. if( !(m_dwChunksEncountered & CHUNK_IHDR) )
  584. {
  585. PNGTRACE((_T("Missing IHDR\n")));
  586. return( E_FAIL );
  587. }
  588. if( m_dwChunksEncountered & CHUNK_BKGD )
  589. {
  590. PNGTRACE((_T("Multiple bKGD chunks\n")));
  591. return( E_FAIL );
  592. }
  593. if( m_dwChunksEncountered & (CHUNK_IDAT|CHUNK_IEND) )
  594. {
  595. PNGTRACE((_T("Invalid bKGD placement\n")));
  596. return( E_FAIL );
  597. }
  598. if( m_bPalette && !(m_dwChunksEncountered & CHUNK_PLTE) )
  599. {
  600. PNGTRACE((_T("bKGD before PLTE in indexed-color image\n")));
  601. return( E_FAIL );
  602. }
  603. m_dwChunksEncountered |= (CHUNK_BKGD|CHUNK_POSTPLTE);
  604. switch( m_pngIHDR.bColorType )
  605. {
  606. case PNG_COLORTYPE_INDEXED:
  607. if( m_pngChunkHeader.nDataLength != 1 )
  608. {
  609. PNGTRACE((_T("Invalid bKGD size\n")));
  610. return( E_FAIL );
  611. }
  612. m_iBackgroundIndex = m_abData[0];
  613. if( m_iBackgroundIndex >= m_nColors )
  614. {
  615. PNGTRACE((_T("Invalid palette index in bKGD\n")));
  616. return( E_FAIL );
  617. }
  618. break;
  619. case PNG_COLORTYPE_RGB:
  620. case PNG_COLORTYPE_RGBA:
  621. if( m_pngChunkHeader.nDataLength != 6 )
  622. {
  623. PNGTRACE((_T("Invalid bKGD size\n")));
  624. return( E_FAIL );
  625. }
  626. if( m_pngIHDR.nBitDepth == 8 )
  627. {
  628. m_frgbBackground.fRed = float( m_abData[1]/255.0 );
  629. m_frgbBackground.fGreen = float( m_abData[3]/255.0 );
  630. m_frgbBackground.fBlue = float( m_abData[5]/255.0 );
  631. }
  632. else
  633. {
  634. m_frgbBackground.fRed = float( ((m_abData[0]<<8)+m_abData[1] )/
  635. 65535.0 );
  636. m_frgbBackground.fGreen = float( ((m_abData[2]<<8)+m_abData[3] )/
  637. 65535.0 );
  638. m_frgbBackground.fBlue = float( ((m_abData[4]<<8)+m_abData[5] )/
  639. 65535.0 );
  640. }
  641. break;
  642. case PNG_COLORTYPE_GRAY:
  643. case PNG_COLORTYPE_GRAYA:
  644. if( m_pngChunkHeader.nDataLength != 2 )
  645. {
  646. PNGTRACE((_T("Invalid bKGD size\n")));
  647. return( E_FAIL );
  648. }
  649. m_frgbBackground.fRed = float( ((m_abData[0]<<8)+m_abData[1])&
  650. ((0x01<<m_pngIHDR.nBitDepth)-1) );
  651. m_frgbBackground.fRed /= float( (0x01<<m_pngIHDR.nBitDepth)-1 );
  652. m_frgbBackground.fGreen = m_frgbBackground.fRed;
  653. m_frgbBackground.fBlue = m_frgbBackground.fRed;
  654. break;
  655. default:
  656. _ASSERT( FALSE );
  657. break;
  658. }
  659. m_rgbBackground.rgbRed = BYTE( m_frgbBackground.fRed*255.0 );
  660. m_rgbBackground.rgbGreen = BYTE( m_frgbBackground.fGreen*255.0 );
  661. m_rgbBackground.rgbBlue = BYTE( m_frgbBackground.fBlue*255.0 );
  662. m_rgbBackground.rgbReserved = 0;
  663. return( S_OK );
  664. }
  665. HRESULT CPNGFilter::ChooseBKGD()
  666. {
  667. if( !(m_dwChunksEncountered & CHUNK_IHDR) )
  668. {
  669. PNGTRACE((_T("Missing IHDR\n")));
  670. return( E_FAIL );
  671. }
  672. if( m_dwChunksEncountered & CHUNK_BKGD )
  673. {
  674. PNGTRACE((_T("Multiple bKGD chunks\n")));
  675. return( E_FAIL );
  676. }
  677. m_dwChunksEncountered |= (CHUNK_BKGD|CHUNK_POSTPLTE);
  678. // Since the image doesn't specify a background color we have to
  679. // choose one. Since the image target isn't known we'll use the
  680. // button face color for lack of anything better...
  681. *((DWORD *)&m_rgbBackground) = (GetSysColor(COLOR_BTNFACE) & 0x00FFFFFF);
  682. m_frgbBackground.fRed = float( m_rgbBackground.rgbRed/255.0 );
  683. m_frgbBackground.fGreen = float( m_rgbBackground.rgbGreen/255.0 );
  684. m_frgbBackground.fBlue = float( m_rgbBackground.rgbBlue/255.0 );
  685. return S_OK;
  686. }
  687. // Get ready to read the image data
  688. HRESULT CPNGFilter::BeginImage()
  689. {
  690. LPDIRECTDRAWPALETTE pDDPalette;
  691. PALETTEENTRY ape[256];
  692. HRESULT hResult;
  693. BYTE *pby;
  694. int i;
  695. // Nothing to do if there's no palette
  696. if (!m_bPalette)
  697. return S_OK;
  698. if (!(m_dwChunksEncountered & CHUNK_PLTE))
  699. {
  700. PNGTRACE((_T("No PLTE chunk found for indexed color image\n")));
  701. return (E_FAIL);
  702. }
  703. // TRICK: This applies gamma to the rgbReserved field as well
  704. // but this field is always 0, and gamma correction of
  705. // 0 is always 0, so this safe.
  706. pby = (BYTE *)m_argbColors;
  707. for (i = m_nColors * 4; i ; --i, ++pby)
  708. *pby = m_abGamma[*pby];
  709. hResult = m_pDDrawSurface->GetPalette(&pDDPalette);
  710. if (SUCCEEDED(hResult))
  711. {
  712. CopyPaletteEntriesFromColors(ape, m_argbColors, m_nColors);
  713. pDDPalette->SetEntries(0, 0, m_nColors, ape);
  714. pDDPalette->Release();
  715. }
  716. if (m_dwEvents & IMGDECODE_EVENT_PALETTE)
  717. {
  718. hResult = m_pEventSink->OnPalette();
  719. if (FAILED(hResult))
  720. {
  721. return (hResult);
  722. }
  723. }
  724. return (S_OK);
  725. }
  726. // Process the PNG end-of-stream chunk
  727. HRESULT CPNGFilter::ProcessIEND()
  728. {
  729. if( !(m_dwChunksEncountered & CHUNK_LASTIDAT) )
  730. {
  731. PNGTRACE((_T("Invalid IEND placement\n")));
  732. return( E_FAIL );
  733. }
  734. m_dwChunksEncountered |= CHUNK_IEND;
  735. if( m_pngChunkHeader.nDataLength > 0 )
  736. {
  737. PNGTRACE((_T("Invalid IEND chunk length\n")));
  738. return( E_FAIL );
  739. }
  740. return( S_OK );
  741. }
  742. HRESULT CPNGFilter::DetermineSourceFormat()
  743. {
  744. switch( m_pngIHDR.bColorType )
  745. {
  746. case PNG_COLORTYPE_RGB:
  747. switch( m_pngIHDR.nBitDepth )
  748. {
  749. case 8:
  750. m_eSrcFormat = SRC_RGB_24;
  751. break;
  752. case 16:
  753. m_eSrcFormat = SRC_RGB_48;
  754. break;
  755. default:
  756. PNGTRACE((_T("Invalid bit depth %d for RGB image\n"),
  757. m_pngIHDR.nBitDepth ));
  758. return( E_FAIL );
  759. break;
  760. }
  761. m_nBitsPerPixel = m_pngIHDR.nBitDepth*3;
  762. break;
  763. case PNG_COLORTYPE_RGBA:
  764. switch( m_pngIHDR.nBitDepth )
  765. {
  766. case 8:
  767. m_eSrcFormat = SRC_RGBA_32;
  768. break;
  769. case 16:
  770. m_eSrcFormat = SRC_RGBA_64;
  771. break;
  772. default:
  773. PNGTRACE((_T("Invalid bit depth %d for RGBA image\n"),
  774. m_pngIHDR.nBitDepth ));
  775. return( E_FAIL );
  776. break;
  777. }
  778. m_nBitsPerPixel = m_pngIHDR.nBitDepth*4;
  779. break;
  780. case PNG_COLORTYPE_INDEXED:
  781. switch( m_pngIHDR.nBitDepth )
  782. {
  783. case 1:
  784. m_eSrcFormat = SRC_INDEXED_RGB_1;
  785. break;
  786. case 2:
  787. m_eSrcFormat = SRC_INDEXED_RGB_2;
  788. break;
  789. case 4:
  790. m_eSrcFormat = SRC_INDEXED_RGB_4;
  791. break;
  792. case 8:
  793. m_eSrcFormat = SRC_INDEXED_RGB_8;
  794. break;
  795. default:
  796. PNGTRACE((_T("Invalid bit depth %d for indexed-color image\n"),
  797. m_pngIHDR.nBitDepth ));
  798. return( E_FAIL );
  799. break;
  800. }
  801. m_nBitsPerPixel = m_pngIHDR.nBitDepth;
  802. break;
  803. case PNG_COLORTYPE_GRAY:
  804. switch( m_pngIHDR.nBitDepth )
  805. {
  806. case 1:
  807. m_eSrcFormat = SRC_GRAY_1;
  808. break;
  809. case 2:
  810. m_eSrcFormat = SRC_GRAY_2;
  811. break;
  812. case 4:
  813. m_eSrcFormat = SRC_GRAY_4;
  814. break;
  815. case 8:
  816. m_eSrcFormat = SRC_GRAY_8;
  817. break;
  818. case 16:
  819. m_eSrcFormat = SRC_GRAY_16;
  820. break;
  821. default:
  822. PNGTRACE((_T("Invalid bit depth %d for grayscale image\n"),
  823. m_pngIHDR.nBitDepth ));
  824. return( E_FAIL );
  825. break;
  826. }
  827. m_nBitsPerPixel = m_pngIHDR.nBitDepth;
  828. break;
  829. case PNG_COLORTYPE_GRAYA:
  830. switch( m_pngIHDR.nBitDepth )
  831. {
  832. case 8:
  833. m_eSrcFormat = SRC_GRAYA_16;
  834. break;
  835. case 16:
  836. m_eSrcFormat = SRC_GRAYA_32;
  837. break;
  838. default:
  839. PNGTRACE((_T("Invalid bit depth %d for grayscale/alpha image\n"),
  840. m_pngIHDR.nBitDepth ));
  841. return( E_FAIL );
  842. break;
  843. }
  844. m_nBitsPerPixel = m_pngIHDR.nBitDepth*2;
  845. break;
  846. default:
  847. PNGTRACE((_T("Invalid color type %d\n"), m_pngIHDR.bColorType ));
  848. return( E_FAIL );
  849. break;
  850. }
  851. return( S_OK );
  852. }
  853. // Process the PNG image header chunk
  854. HRESULT CPNGFilter::ProcessIHDR()
  855. {
  856. PNGIHDRDATA* pIHDR;
  857. HRESULT hResult;
  858. int nError;
  859. if( m_dwChunksEncountered != 0 )
  860. {
  861. PNGTRACE((_T("Multiple IHDR chunks\n")));
  862. return( E_FAIL );
  863. }
  864. m_dwChunksEncountered |= CHUNK_IHDR;
  865. pIHDR = (PNGIHDRDATA*)m_abData;
  866. FixByteOrder( pIHDR );
  867. memcpy( &m_pngIHDR, pIHDR, sizeof( m_pngIHDR ) );
  868. PNGTRACE1((_T("%dx%dx%d\n"), m_pngIHDR.nWidth, m_pngIHDR.nHeight,
  869. m_pngIHDR.nBitDepth ));
  870. if( (m_pngIHDR.nWidth == 0) || (m_pngIHDR.nHeight == 0) )
  871. {
  872. PNGTRACE((_T("Invalid image size\n")));
  873. return( E_FAIL );
  874. }
  875. m_bPalette = m_pngIHDR.bColorType & PNG_COLORTYPE_PALETTE_MASK;
  876. m_bColor = m_pngIHDR.bColorType & PNG_COLORTYPE_COLOR_MASK;
  877. m_bAlpha = m_pngIHDR.bColorType & PNG_COLORTYPE_ALPHA_MASK;
  878. hResult = DetermineSourceFormat();
  879. if( FAILED( hResult ) )
  880. {
  881. return( hResult );
  882. }
  883. m_nBytesInScanLine = ((m_pngIHDR.nWidth*m_nBitsPerPixel)+7)/8;
  884. m_nBPP = max( 1, m_nBytesInScanLine/m_pngIHDR.nWidth );
  885. m_pbPrevScanLine = new BYTE[m_nBytesInScanLine+1];
  886. if( m_pbPrevScanLine == NULL )
  887. {
  888. return( E_OUTOFMEMORY );
  889. }
  890. m_pbScanLine = new BYTE[m_nBytesInScanLine+1];
  891. if( m_pbScanLine == NULL )
  892. {
  893. return( E_OUTOFMEMORY );
  894. }
  895. switch( m_pngIHDR.bCompressionMethod )
  896. {
  897. case PNG_COMPRESSION_DEFLATE32K:
  898. m_zlibStream.zalloc = NULL;
  899. m_zlibStream.zfree = NULL;
  900. m_zlibStream.opaque = NULL;
  901. nError = inflateInit( &m_zlibStream );
  902. if( nError != Z_OK )
  903. {
  904. return( E_OUTOFMEMORY );
  905. }
  906. break;
  907. default:
  908. PNGTRACE((_T("Unknown compression method %x\n"),
  909. m_pngIHDR.bCompressionMethod ));
  910. return( E_FAIL );
  911. break;
  912. }
  913. if( m_pngIHDR.bFilterMethod != PNG_FILTER_ADAPTIVE )
  914. {
  915. PNGTRACE((_T("Unknown filter method %x\n"), m_pngIHDR.bFilterMethod ));
  916. return( E_FAIL );
  917. }
  918. switch( m_pngIHDR.bInterlaceMethod )
  919. {
  920. case PNG_INTERLACE_NONE:
  921. PNGTRACE1((_T("Image is not interlaced\n")));
  922. m_nPasses = 1;
  923. m_pInterlaceInfo = s_aInterlaceInfoNone;
  924. m_bExpandPixels = FALSE;
  925. break;
  926. case PNG_INTERLACE_ADAM7:
  927. PNGTRACE1((_T("Image is Adam7 interlaced\n")));
  928. m_nPasses = 7;
  929. m_pInterlaceInfo = s_aInterlaceInfoAdam7;
  930. if( m_dwEvents & IMGDECODE_EVENT_PROGRESS )
  931. {
  932. m_bExpandPixels = TRUE;
  933. }
  934. else
  935. {
  936. // Don't bother expanding the pixels if the event sink doesn't care
  937. // about progress messages.
  938. m_bExpandPixels = FALSE;
  939. }
  940. break;
  941. default:
  942. PNGTRACE((_T("Unknown interlace method %d\n"), m_pngIHDR.bInterlaceMethod ));
  943. return( E_FAIL );
  944. break;
  945. }
  946. m_iPass = 0;
  947. BeginPass( m_iPass );
  948. if( m_bPalette )
  949. {
  950. PNGTRACE1((_T("Palette used\n")));
  951. }
  952. if( m_bColor )
  953. {
  954. PNGTRACE1((_T("Color used\n")));
  955. }
  956. if( m_bAlpha )
  957. {
  958. PNGTRACE1((_T("Alpha channel used\n")));
  959. }
  960. hResult = FireGetSurfaceEvent();
  961. if( FAILED( hResult ) )
  962. {
  963. return( hResult );
  964. }
  965. m_iAppend = 0;
  966. return( S_OK );
  967. }
  968. HRESULT CPNGFilter::ProcessPLTE()
  969. {
  970. ULONG iColor;
  971. ULONG iByte;
  972. if( !(m_dwChunksEncountered & CHUNK_IHDR) )
  973. {
  974. PNGTRACE((_T("Missing IHDR\n")));
  975. return( E_FAIL );
  976. }
  977. if( m_dwChunksEncountered & CHUNK_PLTE )
  978. {
  979. PNGTRACE((_T("Multiple PLTE chunks\n")));
  980. return( E_FAIL );
  981. }
  982. if( m_dwChunksEncountered & (CHUNK_POSTPLTE|CHUNK_IDAT|CHUNK_IEND) )
  983. {
  984. PNGTRACE((_T("Invalid PLTE placement\n")));
  985. return( E_FAIL );
  986. }
  987. if( !m_bColor )
  988. {
  989. PNGTRACE(( _T("Palettes not allowed for grayscale images - ignoring\n" )));
  990. return( S_OK );
  991. }
  992. m_dwChunksEncountered |= CHUNK_PLTE;
  993. if( m_pngChunkHeader.nDataLength == 0 )
  994. {
  995. return( E_FAIL );
  996. }
  997. if( m_bPalette )
  998. {
  999. // Image requires a palette
  1000. if( m_pngChunkHeader.nDataLength > (1U<<m_pngIHDR.nBitDepth)*3 )
  1001. {
  1002. return( E_FAIL );
  1003. }
  1004. }
  1005. else
  1006. {
  1007. if( m_pngChunkHeader.nDataLength > 256*3 )
  1008. {
  1009. return( E_FAIL );
  1010. }
  1011. }
  1012. if( m_pngChunkHeader.nDataLength%3 != 0 )
  1013. {
  1014. return( E_FAIL );
  1015. }
  1016. m_nColors = m_pngChunkHeader.nDataLength/3;
  1017. iByte = 0;
  1018. for( iColor = 0; iColor < m_nColors; iColor++ )
  1019. {
  1020. m_argbColors[iColor].rgbRed = m_abData[iByte];
  1021. m_argbColors[iColor].rgbGreen = m_abData[iByte+1];
  1022. m_argbColors[iColor].rgbBlue = m_abData[iByte+2];
  1023. // ATLTRACE( "Palette[%x] = (%x, %x, %x)\n", iColor, m_abData[iByte],
  1024. // m_abData[iByte+1], m_abData[iByte+2] );
  1025. iByte += 3;
  1026. }
  1027. m_iAppend = 0;
  1028. return( S_OK );
  1029. }
  1030. HRESULT CPNGFilter::ProcessTRNS()
  1031. {
  1032. WORD *pw = (WORD *)m_abData;
  1033. RGBQUAD trans;
  1034. int byShiftCnt;
  1035. ULONG i;
  1036. HRESULT hResult;
  1037. DDCOLORKEY ddKey;
  1038. // TRNS chunk must precede first IDAT chunk and must follow the
  1039. // PLTE chunk (if any).
  1040. if ((m_dwChunksEncountered & CHUNK_IDAT)
  1041. || (m_bPalette && (~m_dwChunksEncountered & CHUNK_PLTE)))
  1042. {
  1043. PNGTRACE((_T("Invalid TRNS placement\n")));
  1044. return (E_FAIL);
  1045. }
  1046. m_dwChunksEncountered |= CHUNK_TRNS;
  1047. switch (m_pngIHDR.bColorType)
  1048. {
  1049. case PNG_COLORTYPE_RGB:
  1050. case PNG_COLORTYPE_GRAY:
  1051. // ISSUE: we really should preserve the full 16-bit values
  1052. // for proper transparent calculation but our main client,
  1053. // MSHTML, doesn't preserve the RGB values at 16-bit resolution
  1054. // either so it doesn't matter.
  1055. byShiftCnt = (m_eSrcFormat == SRC_RGB_48) ? 8 : 0;
  1056. trans.rgbRed = (BYTE)(my_ntohl(pw[0]) >> byShiftCnt);
  1057. trans.rgbReserved = 0;
  1058. if (m_pngIHDR.bColorType == PNG_COLORTYPE_GRAY)
  1059. {
  1060. trans.rgbGreen = trans.rgbBlue = trans.rgbRed;
  1061. }
  1062. else
  1063. {
  1064. trans.rgbGreen = (BYTE)(my_ntohl(pw[1]) >> byShiftCnt);
  1065. trans.rgbBlue = (BYTE)(my_ntohl(pw[2]) >> byShiftCnt);
  1066. }
  1067. m_nTransparentColors = 1;
  1068. m_dwTransKey = *((DWORD *)&trans);
  1069. break;
  1070. case PNG_COLORTYPE_INDEXED:
  1071. // Fill in m_abTrans. Remember this is filled with
  1072. // the identity map in the constructor...
  1073. for (i = 0; i < m_pngChunkHeader.nDataLength; ++i)
  1074. {
  1075. if (m_abData[i] != 0xff)
  1076. {
  1077. if (m_nTransparentColors++)
  1078. {
  1079. // collapse transparent index to first level seen
  1080. m_abTrans[i] = (BYTE)m_dwTransKey;
  1081. }
  1082. else
  1083. {
  1084. // first transparent index seen
  1085. m_dwTransKey = i;
  1086. m_abTrans[i] = (BYTE)i;
  1087. }
  1088. }
  1089. }
  1090. break;
  1091. default:
  1092. PNGTRACE(( _T("Color type %d doesn't allow tRNS chunk\n"), m_pngIHDR.bColorType ));
  1093. return E_FAIL;
  1094. }
  1095. // Tell the surface what the transparent index is
  1096. ddKey.dwColorSpaceLowValue = m_dwTransKey;
  1097. ddKey.dwColorSpaceHighValue = m_dwTransKey;
  1098. hResult = m_pDDrawSurface->SetColorKey(DDCKEY_SRCBLT, &ddKey);
  1099. return (S_OK);
  1100. }
  1101. HRESULT CPNGFilter::ProcessGAMA()
  1102. {
  1103. double gbright, gcvideo, file_gamma, max_sample, final_gamma;
  1104. ULONG ulGamma;
  1105. int i, iGamma;
  1106. // GAMA chunk must precede first IDAT chunk
  1107. if (m_dwChunksEncountered & CHUNK_IDAT)
  1108. {
  1109. PNGTRACE((_T("Invalid GAMA placement\n")));
  1110. return (E_FAIL);
  1111. }
  1112. m_dwChunksEncountered |= CHUNK_GAMA;
  1113. // Get the file gamma and compute table if it's not 1.0
  1114. ulGamma = my_ntohl(*((ULONG *)m_abData));
  1115. max_sample = 255;
  1116. // use our precomputed table if possible
  1117. if (ulGamma == 100000)
  1118. {
  1119. memcpy(m_abGamma, gamma10, sizeof(gamma10));
  1120. }
  1121. else
  1122. {
  1123. file_gamma = ulGamma / 100000.0;
  1124. final_gamma = (VIEWING_GAMMA / (file_gamma * DISPLAY_GAMMA));
  1125. for (i = 0; i < 256; ++i)
  1126. {
  1127. gbright = (double)i / max_sample;
  1128. gcvideo = pow(gbright, final_gamma);
  1129. iGamma = (int)(gcvideo * MAXFBVAL + 0.5);
  1130. m_abGamma[i] = (iGamma > 255) ? (BYTE)255 : (BYTE)iGamma;
  1131. }
  1132. }
  1133. return (S_OK);
  1134. }
  1135. HRESULT CPNGFilter::ReadChunkCRC()
  1136. {
  1137. HRESULT hResult;
  1138. ULONG nBytesRead;
  1139. BYTE* pBuffer;
  1140. if( m_nBytesLeftInCurrentTask == 0 )
  1141. {
  1142. m_nBytesLeftInCurrentTask = 4;
  1143. }
  1144. pBuffer = LPBYTE( &m_dwChunkCRC )+4-m_nBytesLeftInCurrentTask;
  1145. hResult = m_pStream->Read( pBuffer, m_nBytesLeftInCurrentTask,
  1146. &nBytesRead );
  1147. m_nBytesLeftInCurrentTask -= nBytesRead;
  1148. switch( hResult )
  1149. {
  1150. case S_OK:
  1151. break;
  1152. case S_FALSE:
  1153. return( E_FAIL );
  1154. break;
  1155. default:
  1156. return( hResult );
  1157. break;
  1158. }
  1159. m_dwChunkCRC = my_ntohl( m_dwChunkCRC );
  1160. if( m_dwChunkCRC != ~m_dwCRC )
  1161. {
  1162. PNGTRACE((_T("Bad CRC\n")));
  1163. return( E_FAIL );
  1164. }
  1165. if( m_pngChunkHeader.dwChunkType == PNG_CHUNK_IEND )
  1166. {
  1167. PNGTRACE1((_T("Finished IEND chunk\n")));
  1168. }
  1169. return( S_OK );
  1170. }
  1171. HRESULT CPNGFilter::ReadChunkData()
  1172. {
  1173. HRESULT hResult = S_OK;
  1174. ULONG nBytesToRead;
  1175. ULONG nBytesRead;
  1176. BYTE* pBuffer;
  1177. if( m_nBytesLeftInCurrentTask == 0 )
  1178. {
  1179. if( m_pngChunkHeader.nDataLength == 0 )
  1180. {
  1181. return( S_OK );
  1182. }
  1183. m_iAppend = 0;
  1184. m_nDataBytesRead = 0;
  1185. m_nBytesLeftInCurrentTask = m_pngChunkHeader.nDataLength;
  1186. }
  1187. if (m_nBytesLeftInCurrentTask > PNG_BUFFER_SIZE - m_iAppend)
  1188. {
  1189. // We should have already previously decided to skip too-long data
  1190. _ASSERTE(m_bSkipData);
  1191. m_bSkipData = TRUE;
  1192. }
  1193. while (m_nBytesLeftInCurrentTask && hResult == S_OK)
  1194. {
  1195. pBuffer = &m_abData[m_iAppend];
  1196. _ASSERTE(!m_nBytesLeftInCurrentTask || m_iAppend < PNG_BUFFER_SIZE);
  1197. nBytesToRead = min(PNG_BUFFER_SIZE - m_iAppend, m_nBytesLeftInCurrentTask);
  1198. hResult = m_pStream->Read( pBuffer, nBytesToRead,
  1199. &nBytesRead );
  1200. m_nBytesLeftInCurrentTask -= nBytesRead;
  1201. m_nDataBytesRead += nBytesRead;
  1202. m_iAppend += nBytesRead;
  1203. m_dwCRC = UpdateCRC( m_dwCRC, pBuffer, nBytesRead );
  1204. // If we're just skipping data, reset starting point
  1205. if (m_bSkipData)
  1206. m_iAppend = 0;
  1207. }
  1208. switch( hResult )
  1209. {
  1210. case S_OK:
  1211. break;
  1212. case S_FALSE:
  1213. return( E_FAIL );
  1214. break;
  1215. default:
  1216. return( hResult );
  1217. break;
  1218. }
  1219. return( S_OK );
  1220. }
  1221. const PNG_INTERLACE_INFO CPNGFilter::s_aInterlaceInfoNone[1] =
  1222. {
  1223. {
  1224. 1, 1, 1, 1, 0, 0,
  1225. { 0, 1, 2, 3, 4, 5, 6, 7 },
  1226. { 0, 1, 2, 3, 4, 5, 6, 7 }
  1227. }
  1228. };
  1229. const PNG_INTERLACE_INFO CPNGFilter::s_aInterlaceInfoAdam7[7] =
  1230. {
  1231. {
  1232. 8, 8, 8, 8, 0, 0,
  1233. { 0, 1, 1, 1, 1, 1, 1, 1 },
  1234. { 0, 1, 1, 1, 1, 1, 1, 1 }
  1235. },
  1236. {
  1237. 8, 8, 4, 8, 4, 0,
  1238. { 0, 0, 0, 0, 0, 1, 1, 1 },
  1239. { 0, 1, 1, 1, 1, 1, 1, 1 }
  1240. },
  1241. {
  1242. 4, 8, 4, 4, 0, 4,
  1243. { 0, 1, 1, 1, 1, 2, 2, 2 },
  1244. { 0, 0, 0, 0, 0, 1, 1, 1 }
  1245. },
  1246. {
  1247. 4, 4, 2, 4, 2, 0,
  1248. { 0, 0, 0, 1, 1, 1, 1, 2 },
  1249. { 0, 1, 1, 1, 1, 2, 2, 2 }
  1250. },
  1251. {
  1252. 2, 4, 2, 2, 0, 2,
  1253. { 0, 1, 1, 2, 2, 3, 3, 4 },
  1254. { 0, 0, 0, 1, 1, 1, 1, 2 }
  1255. },
  1256. {
  1257. 2, 2, 1, 2, 1, 0,
  1258. { 0, 0, 1, 1, 2, 2, 3, 3 },
  1259. { 0, 1, 1, 2, 2, 3, 3, 4 }
  1260. },
  1261. {
  1262. 1, 2, 1, 1, 0, 1,
  1263. { 0, 1, 2, 3, 4, 5, 6, 7 },
  1264. { 0, 0, 1, 1, 2, 2, 3, 3 }
  1265. }
  1266. };
  1267. BOOL CPNGFilter::BeginPass( ULONG iPass )
  1268. {
  1269. const PNG_INTERLACE_INFO* pInfo;
  1270. ULONG iRightEdgeOfLastPixel;
  1271. _ASSERTE( iPass < m_nPasses );
  1272. pInfo = &m_pInterlaceInfo[iPass];
  1273. m_nDeltaX = pInfo->nDeltaX;
  1274. m_nDeltaY = pInfo->nDeltaY;
  1275. m_iFirstX = pInfo->iFirstX;
  1276. m_iScanLine = pInfo->iFirstY;
  1277. m_nPixelsInScanLine = ((m_pngIHDR.nWidth/8)*(8/m_nDeltaX))+
  1278. pInfo->anPixelsInPartialBlock[m_pngIHDR.nWidth%8];
  1279. m_nBytesInScanLine = (m_nBitsPerPixel*m_nPixelsInScanLine+7)/8;
  1280. m_nScanLinesInPass = ((m_pngIHDR.nHeight/8)*(8/m_nDeltaY))+
  1281. pInfo->anScanLinesInPartialBlock[m_pngIHDR.nHeight%8];
  1282. m_iScanLineInPass = 0;
  1283. m_iFirstStaleScanLine = 0;
  1284. if( m_bExpandPixels )
  1285. {
  1286. m_nPixelWidth = pInfo->nPixelWidth;
  1287. m_nPixelHeight = pInfo->nPixelHeight;
  1288. iRightEdgeOfLastPixel = m_iFirstX+((m_nPixelsInScanLine-1)*m_nDeltaX)+
  1289. m_nPixelWidth;
  1290. if( iRightEdgeOfLastPixel > m_pngIHDR.nWidth )
  1291. {
  1292. // The last pixel in the scan line is a partial pixel
  1293. m_nPartialPixelWidth = m_nPixelWidth-(iRightEdgeOfLastPixel-
  1294. m_pngIHDR.nWidth);
  1295. m_nFullPixelsInScanLine = m_nPixelsInScanLine-1;
  1296. }
  1297. else
  1298. {
  1299. m_nPartialPixelWidth = 0;
  1300. m_nFullPixelsInScanLine = m_nPixelsInScanLine;
  1301. }
  1302. }
  1303. else
  1304. {
  1305. m_nPixelWidth = 1;
  1306. m_nPixelHeight = 1;
  1307. m_nPartialPixelWidth = 0;
  1308. }
  1309. PNGTRACE1((_T("Pass %d. %d pixels in scan line\n"), iPass,
  1310. m_nPixelsInScanLine ));
  1311. m_zlibStream.next_out = m_pbScanLine;
  1312. m_zlibStream.avail_out = m_nBytesInScanLine+1;
  1313. if( (m_nPixelsInScanLine == 0) || (m_nScanLinesInPass == 0) )
  1314. {
  1315. return( TRUE );
  1316. }
  1317. return( FALSE );
  1318. }
  1319. HRESULT CPNGFilter::NextPass()
  1320. {
  1321. BOOL bEmpty;
  1322. bEmpty = FALSE;
  1323. do
  1324. {
  1325. m_iPass++;
  1326. if( m_iPass < m_nPasses )
  1327. {
  1328. bEmpty = BeginPass( m_iPass );
  1329. }
  1330. } while( (m_iPass < m_nPasses) && bEmpty );
  1331. if( m_iPass >= m_nPasses )
  1332. {
  1333. return( S_FALSE );
  1334. }
  1335. return( S_OK );
  1336. }
  1337. HRESULT CPNGFilter::NextScanLine()
  1338. {
  1339. HRESULT hResult;
  1340. BYTE* pbTemp;
  1341. _ASSERTE( m_zlibStream.avail_out == 0 );
  1342. m_iScanLine += m_nDeltaY;
  1343. m_iScanLineInPass++;
  1344. if( m_iScanLineInPass >= m_nScanLinesInPass )
  1345. {
  1346. // We're done with this pass
  1347. hResult = FireOnProgressEvent();
  1348. if( FAILED( hResult ) )
  1349. {
  1350. return( hResult );
  1351. }
  1352. hResult = NextPass();
  1353. return( hResult );
  1354. }
  1355. else if( ((m_iScanLine-m_iFirstStaleScanLine)/m_nDeltaY) >= 16 )
  1356. {
  1357. hResult = FireOnProgressEvent();
  1358. if( FAILED( hResult ) )
  1359. {
  1360. return( hResult );
  1361. }
  1362. }
  1363. pbTemp = m_pbScanLine;
  1364. m_pbScanLine = m_pbPrevScanLine;
  1365. m_pbPrevScanLine = pbTemp;
  1366. m_zlibStream.avail_out = m_nBytesInScanLine+1;
  1367. m_zlibStream.next_out = m_pbScanLine;
  1368. return( S_OK );
  1369. }
  1370. HRESULT CPNGFilter::ReadIDATData()
  1371. {
  1372. HRESULT hResult;
  1373. ULONG nBytesToRead;
  1374. ULONG nBytesRead;
  1375. int nError;
  1376. if( !(m_dwChunksEncountered & CHUNK_IHDR) )
  1377. {
  1378. PNGTRACE((_T("Missing IHDR\n")));
  1379. return( E_FAIL );
  1380. }
  1381. if( m_dwChunksEncountered & CHUNK_LASTIDAT )
  1382. {
  1383. PNGTRACE((_T("Extra IDAT chunk\n")));
  1384. return( E_FAIL );
  1385. }
  1386. if( !(m_dwChunksEncountered & CHUNK_IDAT) )
  1387. {
  1388. // This is the first IDAT chunk. Initialize the surface.
  1389. hResult = BeginImage();
  1390. if( FAILED( hResult ) )
  1391. {
  1392. return( hResult );
  1393. }
  1394. }
  1395. m_dwChunksEncountered |= CHUNK_IDAT;
  1396. nBytesToRead = min( m_pngChunkHeader.nDataLength-m_nDataBytesRead,
  1397. PNG_BUFFER_SIZE );
  1398. hResult = m_pStream->Read( m_abData, nBytesToRead, &nBytesRead );
  1399. m_nDataBytesRead += nBytesRead;
  1400. m_dwCRC = UpdateCRC( m_dwCRC, m_abData, nBytesRead );
  1401. switch( hResult )
  1402. {
  1403. case S_OK:
  1404. break;
  1405. case S_FALSE:
  1406. return( E_FAIL );
  1407. break;
  1408. case E_PENDING:
  1409. if( nBytesRead == 0 )
  1410. {
  1411. return( E_PENDING );
  1412. }
  1413. break;
  1414. default:
  1415. return( hResult );
  1416. break;
  1417. }
  1418. m_zlibStream.next_in = m_abData;
  1419. m_zlibStream.avail_in = nBytesRead;
  1420. do
  1421. {
  1422. nError = inflate( &m_zlibStream, Z_PARTIAL_FLUSH );
  1423. if( (nError == Z_OK) || (nError == Z_STREAM_END) )
  1424. {
  1425. if( m_zlibStream.avail_out == 0 )
  1426. {
  1427. switch( m_pbScanLine[0] )
  1428. {
  1429. case 0:
  1430. NoneFilterScanLine();
  1431. break;
  1432. case 1:
  1433. SubFilterScanLine();
  1434. break;
  1435. case 2:
  1436. UpFilterScanLine();
  1437. break;
  1438. case 3:
  1439. AverageFilterScanLine();
  1440. break;
  1441. case 4:
  1442. PaethFilterScanLine();
  1443. break;
  1444. default:
  1445. _ASSERT( FALSE );
  1446. break;
  1447. }
  1448. hResult = WriteScanLine();
  1449. if( FAILED( hResult ) )
  1450. {
  1451. return( hResult );
  1452. }
  1453. hResult = NextScanLine();
  1454. if( FAILED( hResult ) )
  1455. {
  1456. return( hResult );
  1457. }
  1458. }
  1459. else
  1460. {
  1461. _ASSERTE( m_zlibStream.avail_in == 0 );
  1462. }
  1463. }
  1464. else
  1465. {
  1466. return( E_FAIL );
  1467. }
  1468. if( nError == Z_STREAM_END )
  1469. {
  1470. if( m_nDataBytesRead < m_pngChunkHeader.nDataLength )
  1471. {
  1472. PNGTRACE((_T("Extra IDAT data\n")));
  1473. return( E_FAIL );
  1474. }
  1475. m_dwChunksEncountered |= CHUNK_LASTIDAT;
  1476. m_bFinishedIDAT = TRUE;
  1477. inflateEnd( &m_zlibStream );
  1478. if( m_dwEvents & IMGDECODE_EVENT_BITSCOMPLETE )
  1479. {
  1480. hResult = m_pEventSink->OnBitsComplete();
  1481. if( FAILED( hResult ) )
  1482. {
  1483. return( hResult );
  1484. }
  1485. }
  1486. }
  1487. } while( (nError == Z_OK) && (m_zlibStream.avail_in > 0) );
  1488. return( S_OK );
  1489. }
  1490. HRESULT CPNGFilter::ReadChunkHeader()
  1491. {
  1492. HRESULT hResult;
  1493. ULONG nBytesRead;
  1494. BYTE* pBuffer;
  1495. if( m_nBytesLeftInCurrentTask == 0 )
  1496. {
  1497. m_nBytesLeftInCurrentTask = sizeof( m_pngChunkHeader );
  1498. }
  1499. pBuffer = LPBYTE( &m_pngChunkHeader )+sizeof( m_pngChunkHeader )-
  1500. m_nBytesLeftInCurrentTask;
  1501. hResult = m_pStream->Read( pBuffer, m_nBytesLeftInCurrentTask,
  1502. &nBytesRead );
  1503. m_nBytesLeftInCurrentTask -= nBytesRead;
  1504. switch( hResult )
  1505. {
  1506. case S_OK:
  1507. break;
  1508. case S_FALSE:
  1509. return( E_FAIL );
  1510. break;
  1511. default:
  1512. return( hResult );
  1513. break;
  1514. }
  1515. FixByteOrder( &m_pngChunkHeader );
  1516. m_dwCRC = UpdateCRC( 0xffffffff, LPBYTE( &m_pngChunkHeader.dwChunkType ),
  1517. sizeof( m_pngChunkHeader.dwChunkType ) );
  1518. #ifdef BIG_ENDIAN
  1519. m_pngChunkHeader.dwChunkType = endianConverter(m_pngChunkHeader.dwChunkType);
  1520. #endif
  1521. m_nDataBytesRead = 0;
  1522. m_bSkipData = FALSE;
  1523. PNGTRACE1((_T("Chunk type: %c%c%c%c\n"), m_pngChunkHeader.dwChunkType&0xff,
  1524. (m_pngChunkHeader.dwChunkType>>8)&0xff,
  1525. (m_pngChunkHeader.dwChunkType>>16)&0xff,
  1526. (m_pngChunkHeader.dwChunkType>>24)&0xff ));
  1527. PNGTRACE1((_T("Data length: %d\n"), m_pngChunkHeader.nDataLength ));
  1528. if( !(m_pngChunkHeader.dwChunkType & PNG_CHUNK_ANCILLARY) )
  1529. {
  1530. switch( m_pngChunkHeader.dwChunkType )
  1531. {
  1532. case PNG_CHUNK_IHDR:
  1533. case PNG_CHUNK_PLTE:
  1534. case PNG_CHUNK_IEND:
  1535. // If m_pngChunkHeader.nDataLength > 4096 on an critical non-IDAT chunk,
  1536. // we can't decode it, so fail.
  1537. if (m_pngChunkHeader.nDataLength > PNG_BUFFER_SIZE)
  1538. {
  1539. PNGTRACE((_T("Critical chunk too long\n")));
  1540. return( E_FAIL );
  1541. }
  1542. break;
  1543. case PNG_CHUNK_IDAT:
  1544. break;
  1545. default:
  1546. PNGTRACE((_T("Unknown critical chunk\n")));
  1547. return( E_FAIL );
  1548. break;
  1549. }
  1550. }
  1551. else
  1552. {
  1553. // If m_pngChunkHeader.nDataLength > 4096 on an ancillary chunk,
  1554. // set a flag so we discard the data
  1555. if (m_pngChunkHeader.nDataLength > PNG_BUFFER_SIZE)
  1556. {
  1557. PNGTRACE((_T("Discarding ancillary chunk that is too long\n")));
  1558. m_bSkipData = TRUE;
  1559. }
  1560. }
  1561. return( S_OK );
  1562. }
  1563. static const BYTE g_abPNGHeader[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
  1564. HRESULT CPNGFilter::ReadFileHeader()
  1565. {
  1566. HRESULT hResult;
  1567. ULONG nBytesRead;
  1568. BYTE* pBuffer;
  1569. if( m_nBytesLeftInCurrentTask == 0 )
  1570. {
  1571. m_nBytesLeftInCurrentTask = 8;
  1572. }
  1573. pBuffer = &m_abData[m_iAppend];
  1574. hResult = m_pStream->Read( pBuffer, m_nBytesLeftInCurrentTask,
  1575. &nBytesRead );
  1576. m_nBytesLeftInCurrentTask -= nBytesRead;
  1577. switch( hResult )
  1578. {
  1579. case S_OK:
  1580. break;
  1581. case S_FALSE:
  1582. return( E_FAIL );
  1583. break;
  1584. default:
  1585. return( hResult );
  1586. break;
  1587. }
  1588. if( memcmp( m_abData, g_abPNGHeader, 8 ) == 0 )
  1589. {
  1590. PNGTRACE1((_T("File is a PNG image\n")));
  1591. }
  1592. else
  1593. {
  1594. PNGTRACE((_T("File is not a PNG image\n")));
  1595. return( E_FAIL );
  1596. }
  1597. m_iAppend = 0;
  1598. return( S_OK );
  1599. }
  1600. HRESULT CPNGFilter::EatData()
  1601. {
  1602. m_iAppend = 0;
  1603. return( S_OK );
  1604. }
  1605. ///////////////////////////////////////////////////////////////////////////////
  1606. // IImageDecodeFilter methods
  1607. ///////////////////////////////////////////////////////////////////////////////
  1608. STDMETHODIMP CPNGFilter::Initialize( IImageDecodeEventSink* pEventSink )
  1609. {
  1610. HRESULT hResult;
  1611. if( pEventSink == NULL )
  1612. {
  1613. return( E_INVALIDARG );
  1614. }
  1615. m_pEventSink = pEventSink;
  1616. hResult = m_pEventSink->OnBeginDecode( &m_dwEvents, &m_nFormats,
  1617. &m_pFormats );
  1618. if( FAILED( hResult ) )
  1619. {
  1620. return( hResult );
  1621. }
  1622. return( S_OK );
  1623. }
  1624. STDMETHODIMP CPNGFilter::Process( IStream* pStream )
  1625. {
  1626. HRESULT hResult;
  1627. BYTE bData;
  1628. ULONG nBytesRead;
  1629. // We have to do this every time. We don't AddRef, since we don't hold onto
  1630. // the stream.
  1631. m_pStream = pStream;
  1632. do
  1633. {
  1634. switch( m_eInternalState )
  1635. {
  1636. case ISTATE_READFILEHEADER:
  1637. hResult = ReadFileHeader();
  1638. break;
  1639. case ISTATE_READCHUNKHEADER:
  1640. hResult = ReadChunkHeader();
  1641. break;
  1642. case ISTATE_READCHUNKDATA:
  1643. hResult = ReadChunkData();
  1644. break;
  1645. case ISTATE_READIDATDATA:
  1646. hResult = ReadIDATData();
  1647. break;
  1648. case ISTATE_READCHUNKCRC:
  1649. hResult = ReadChunkCRC();
  1650. break;
  1651. case ISTATE_EATDATA:
  1652. hResult = EatData();
  1653. break;
  1654. case ISTATE_PROCESSBKGD:
  1655. hResult = ProcessBKGD();
  1656. break;
  1657. case ISTATE_CHOOSEBKGD:
  1658. hResult = ChooseBKGD();
  1659. break;
  1660. case ISTATE_PROCESSTRNS:
  1661. hResult = ProcessTRNS();
  1662. break;
  1663. case ISTATE_PROCESSGAMA:
  1664. hResult = ProcessGAMA();
  1665. break;
  1666. case ISTATE_PROCESSIEND:
  1667. hResult = ProcessIEND();
  1668. break;
  1669. case ISTATE_PROCESSIHDR:
  1670. hResult = ProcessIHDR();
  1671. break;
  1672. case ISTATE_PROCESSPLTE:
  1673. hResult = ProcessPLTE();
  1674. break;
  1675. case ISTATE_DONE:
  1676. hResult = m_pStream->Read( &bData, 1, &nBytesRead );
  1677. if (hResult == S_OK && nBytesRead == 0)
  1678. hResult = S_FALSE;
  1679. break;
  1680. default:
  1681. PNGTRACE((_T("Unknown state\n")));
  1682. _ASSERT( FALSE );
  1683. hResult = E_UNEXPECTED;
  1684. break;
  1685. }
  1686. if( hResult == S_OK )
  1687. {
  1688. NextState();
  1689. }
  1690. } while( hResult == S_OK );
  1691. m_pStream = NULL;
  1692. return( hResult );
  1693. }
  1694. STDMETHODIMP CPNGFilter::Terminate( HRESULT hrStatus )
  1695. {
  1696. PNGTRACE1((_T("Image decode terminated. Status: %x\n"), hrStatus ));
  1697. if (m_pDDrawSurface != NULL)
  1698. {
  1699. m_pDDrawSurface.Release();
  1700. }
  1701. if( m_pEventSink != NULL )
  1702. {
  1703. m_pEventSink->OnDecodeComplete( hrStatus );
  1704. m_pEventSink.Release();
  1705. }
  1706. return( S_OK );
  1707. }
  1708. HRESULT CPNGFilter::WriteScanLine()
  1709. {
  1710. ULONG nPixelHeight;
  1711. ULONG iScanLine;
  1712. RECT rect;
  1713. HRESULT hResult;
  1714. void* pBits = NULL;
  1715. LONG nPitch;
  1716. nPixelHeight = min( m_nPixelHeight, m_pngIHDR.nHeight-m_iScanLine );
  1717. if (nPixelHeight < 1)
  1718. return S_OK;
  1719. rect.left = m_iFirstX;
  1720. rect.top = m_iScanLine;
  1721. rect.right = m_pngIHDR.nWidth;
  1722. rect.bottom = m_iScanLine+nPixelHeight;
  1723. hResult = LockBits( &rect, SURFACE_LOCK_EXCLUSIVE, &pBits,
  1724. &nPitch );
  1725. if( FAILED( hResult ) )
  1726. {
  1727. return( hResult );
  1728. }
  1729. m_pfnCopyScanLine( pBits, &m_pbScanLine[1], m_nPixelsInScanLine, m_nDeltaX,
  1730. &m_frgbBackground, m_bPalette ? m_abTrans : m_abGamma);
  1731. if( m_bExpandPixels )
  1732. {
  1733. for( iScanLine = 0; iScanLine < nPixelHeight; iScanLine++ )
  1734. {
  1735. m_pfnDuplicateScanLine( pBits, m_nDeltaX, m_nFullPixelsInScanLine,
  1736. m_nPixelWidth, m_nPartialPixelWidth );
  1737. }
  1738. }
  1739. UnlockBits( &rect, pBits );
  1740. return( S_OK );
  1741. }