mng.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. //---------------------------------------------------------------------------------------------
  2. //---------------------------------------------------------------------------------------------
  3. //
  4. // MNGView Sample Application for VC6:
  5. // Loads all MNG/JNG/PNG Files LibMNG can do
  6. // Can save a single Frame to PNG Format.
  7. //
  8. // This code is public domain.
  9. // Created by Nikolaus Brennig, November 14th, 2000.
  10. // [email protected]
  11. // http://cust.nol.at/ppee
  12. //
  13. // Tab: 4
  14. //
  15. //---------------------------------------------------------------------------------------------
  16. //---------------------------------------------------------------------------------------------
  17. #define WIN32_LEAN_AND_MEAN
  18. #include "Main.h"
  19. #include <libmng.h>
  20. //---------------------------------------------------------------------------------------------
  21. // VARS:
  22. //---------------------------------------------------------------------------------------------
  23. typedef struct
  24. {
  25. FILE *file;
  26. LPSTR filename;
  27. mng_uint32 delay;
  28. } mngstuff;
  29. int lineWidth;
  30. BYTE *mngdestbuffer;
  31. mngstuff *mymngstuff;
  32. mng_handle Curmng;
  33. ///////////////////////////////////////////////////////////////////////////////////////////////
  34. ///////////////////////////////////////////////////////////////////////////////////////////////
  35. //---------------------------------------------------------------------------------------------
  36. // callbacks for the mng decoder:
  37. //---------------------------------------------------------------------------------------------
  38. ///////////////////////////////////////////////////////////////////////////////////////////////
  39. ///////////////////////////////////////////////////////////////////////////////////////////////
  40. //---------------------------------------------------------------------------------------------
  41. // memory allocation; data must be zeroed
  42. //---------------------------------------------------------------------------------------------
  43. mng_ptr mymngalloc( mng_uint32 size )
  44. {
  45. return (mng_ptr)calloc(1, size);
  46. }
  47. //---------------------------------------------------------------------------------------------
  48. // memory deallocation
  49. //---------------------------------------------------------------------------------------------
  50. void mymngfree(mng_ptr p, mng_uint32 size)
  51. {
  52. free(p);
  53. }
  54. //---------------------------------------------------------------------------------------------
  55. // Stream open:
  56. //---------------------------------------------------------------------------------------------
  57. mng_bool mymngopenstream(mng_handle mng)
  58. {
  59. mngstuff *mymng;
  60. // look up our stream struct
  61. mymng = (mngstuff*)mng_get_userdata(mng);
  62. // open the file
  63. mymng->file = fopen( mymng->filename, "rb" );
  64. if( mymng->file == NULL )
  65. {
  66. char temp[100];
  67. sprintf( temp, "Unable to open File: %s", mymng->filename );
  68. Warning( temp );
  69. return MNG_FALSE;
  70. }
  71. return MNG_TRUE;
  72. }
  73. //---------------------------------------------------------------------------------------------
  74. // Stream open for Writing:
  75. //---------------------------------------------------------------------------------------------
  76. mng_bool mymngopenstreamwrite(mng_handle mng)
  77. {
  78. mngstuff *mymng;
  79. // look up our stream struct
  80. mymng = (mngstuff*)mng_get_userdata(mng);
  81. // open the file
  82. mymng->file = fopen( mymng->filename, "wb" );
  83. if( mymng->file == NULL )
  84. {
  85. Warning( "unable to open file!" );
  86. return MNG_FALSE;
  87. }
  88. return MNG_TRUE;
  89. }
  90. //---------------------------------------------------------------------------------------------
  91. // Stream close:
  92. //---------------------------------------------------------------------------------------------
  93. mng_bool mymngclosestream(mng_handle mng)
  94. {
  95. return MNG_TRUE; // We close the file ourself, mng_cleanup doesnt seem to do it...
  96. }
  97. //---------------------------------------------------------------------------------------------
  98. // feed data to the decoder
  99. //---------------------------------------------------------------------------------------------
  100. mng_bool mymngreadstream( mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread )
  101. {
  102. mngstuff *mymng;
  103. // look up our stream struct
  104. mymng = (mngstuff*)mng_get_userdata(mng);
  105. // read the requested amount of data from the file
  106. *bytesread = fread( buffer, sizeof(BYTE), size, mymng->file );
  107. return MNG_TRUE;
  108. }
  109. //---------------------------------------------------------------------------------------------
  110. // the header's been read. set up the display stuff
  111. //---------------------------------------------------------------------------------------------
  112. mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height )
  113. {
  114. // Store values:
  115. W = width; H = height;
  116. Bits = 24;
  117. lineWidth = ((((W * Bits) + 31) >> 5) << 2);
  118. // Create decoderbuffer:
  119. mngdestbuffer = new BYTE[lineWidth*H];
  120. if( mngdestbuffer == 0 ) Warning( "Out of Memory!" );
  121. // Create the MemoryBitmap now, we store there the image...
  122. if( DefaultMemImage ) SelectObject( MemDC, DefaultMemImage );
  123. if( MemDC ) DeleteDC( MemDC );
  124. if( MemImage ) DeleteObject( MemImage );
  125. hdc = GetDC( hPicWin );
  126. MemDC = CreateCompatibleDC( 0 );
  127. MemImage = CreateCompatibleBitmap( hdc, W, H );
  128. DefaultMemImage = (HBITMAP)SelectObject( MemDC, MemImage );
  129. ReleaseDC( hPicWin, hdc );
  130. // Set output style:
  131. mng_set_canvasstyle( mng, MNG_CANVAS_BGR8 );
  132. return MNG_TRUE;
  133. }
  134. //---------------------------------------------------------------------------------------------
  135. // return a row pointer for the decoder to fill
  136. //---------------------------------------------------------------------------------------------
  137. mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line )
  138. {
  139. return (mng_ptr)(mngdestbuffer + (lineWidth*(H-1-line)));
  140. }
  141. //---------------------------------------------------------------------------------------------
  142. // timer
  143. //---------------------------------------------------------------------------------------------
  144. mng_uint32 mymnggetticks(mng_handle mng)
  145. {
  146. return (mng_uint32)GetTickCount();
  147. }
  148. //---------------------------------------------------------------------------------------------
  149. // Refresh:
  150. //---------------------------------------------------------------------------------------------
  151. mng_bool mymngrefresh( mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h )
  152. {
  153. PBITMAPINFO bmpi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
  154. bmpi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  155. bmpi->bmiHeader.biWidth = W;
  156. bmpi->bmiHeader.biHeight = H;
  157. bmpi->bmiHeader.biPlanes = 1;
  158. bmpi->bmiHeader.biCompression = BI_RGB;
  159. bmpi->bmiHeader.biBitCount = Bits;
  160. bmpi->bmiHeader.biSizeImage = 0;
  161. bmpi->bmiHeader.biClrUsed = 0;
  162. bmpi->bmiHeader.biClrImportant = 0;
  163. // Now blt the Image onto our MemDC...
  164. StretchDIBits( MemDC, 0, 0, W, H, 0, 0, W, H, mngdestbuffer, bmpi, 0, SRCCOPY );
  165. LocalFree((PBITMAPINFO)bmpi);
  166. return MNG_TRUE;
  167. }
  168. //---------------------------------------------------------------------------------------------
  169. // interframe delay callback
  170. //---------------------------------------------------------------------------------------------
  171. mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs)
  172. {
  173. mngstuff *mymng;
  174. // look up our stream struct
  175. mymng = (mngstuff*)mng_get_userdata(mng);
  176. // set the timer for when the decoder wants to be woken
  177. mymng->delay = msecs;
  178. return MNG_TRUE;
  179. }
  180. //---------------------------------------------------------------------------------------------
  181. // Error Callback;
  182. //---------------------------------------------------------------------------------------------
  183. mng_bool mymngerror(
  184. mng_handle mng, mng_int32 code, mng_int8 severity,
  185. mng_chunkid chunktype, mng_uint32 chunkseq,
  186. mng_int32 extra1, mng_int32 extra2, mng_pchar text
  187. )
  188. {
  189. char chunk[5];
  190. // pull out the chuck type as a string
  191. // FIXME: does this assume unsigned char?
  192. chunk[0] = (char)((chunktype >> 24) & 0xFF);
  193. chunk[1] = (char)((chunktype >> 16) & 0xFF);
  194. chunk[2] = (char)((chunktype >> 8) & 0xFF);
  195. chunk[3] = (char)((chunktype ) & 0xFF);
  196. chunk[4] = '\0';
  197. // output the error:
  198. char temp[1000];
  199. sprintf( temp, "error playing chunk %s (%d)", chunk, chunkseq );
  200. Warning( temp );
  201. // No need for anymore decoding:
  202. KillTimer( hPicWin, 2 );
  203. // error occured;
  204. return MNG_FALSE;
  205. }
  206. //---------------------------------------------------------------------------------------------
  207. // Load a MNG/JNG/PNG file:
  208. //---------------------------------------------------------------------------------------------
  209. VOID LoadMNG( LPSTR Filename, HWND hwnd, HDC hdc )
  210. {
  211. // allocate our stream data structure
  212. mymngstuff = (mngstuff*)calloc(1, sizeof(*mymngstuff));
  213. if( mymngstuff == NULL )
  214. {
  215. Warning( "Unable to allocate MNG struct!" );
  216. return;
  217. }
  218. // pass the name of the file we want to play
  219. mymngstuff->filename = Filename;
  220. // set up the mng decoder for our stream
  221. Curmng = mng_initialize(mymngstuff, mymngalloc, mymngfree, MNG_NULL);
  222. if(Curmng == MNG_NULL)
  223. {
  224. free(mymngstuff);
  225. Warning( "MNG Init Error!" );
  226. return;
  227. }
  228. // No need to store chunks:
  229. mng_set_storechunks(Curmng, MNG_FALSE);
  230. // Set the colorprofile, lcms uses this:
  231. mng_set_srgb( Curmng, MNG_TRUE );
  232. char DestDir[2048];
  233. SearchPath( NULL, "MNGVIEW.EXE", NULL, sizeof(DestDir), DestDir, NULL );
  234. lstrcpyn( DestDir, DestDir, lstrlen(DestDir)-lstrlen("MNGVIEW.EXE") );
  235. catpath( DestDir, "sRGB.icm" );
  236. FILE *RGBfile = fopen( DestDir, "rb" );
  237. if( RGBfile == 0 )
  238. {
  239. mng_cleanup(&Curmng);
  240. free(mymngstuff);
  241. Warning( "Need file \"sRGB.icm\" !" );
  242. return;
  243. }
  244. fclose(RGBfile);
  245. mng_set_outputprofile(Curmng, DestDir);
  246. // Set white as background color:
  247. WORD Red = (255 << 8) + 255;
  248. WORD Green = (255 << 8) + 255;
  249. WORD Blue = (255 << 8) + 255;
  250. mng_set_bgcolor( Curmng, Red, Green, Blue );
  251. // If PNG Background is available, use it:
  252. mng_set_usebkgd( Curmng, MNG_TRUE );
  253. // set the callbacks
  254. mng_setcb_errorproc(Curmng, mymngerror);
  255. mng_setcb_openstream(Curmng, mymngopenstream);
  256. mng_setcb_closestream(Curmng, mymngclosestream);
  257. mng_setcb_readdata(Curmng, mymngreadstream);
  258. mng_setcb_gettickcount(Curmng, mymnggetticks);
  259. mng_setcb_settimer(Curmng, mymngsettimer);
  260. mng_setcb_processheader(Curmng, mymngprocessheader);
  261. mng_setcb_getcanvasline(Curmng, mymnggetcanvasline);
  262. mng_setcb_refresh(Curmng, mymngrefresh);
  263. // Read the stuff:
  264. mng_readdisplay(Curmng);
  265. AnimFile.CurFrame = mng_get_layercount( Curmng );
  266. AnimFile.MaxFrame = mng_get_framecount( Curmng );
  267. AnimFile.isAnimation = 1;
  268. AnimFile.Delay = mymngstuff->delay;
  269. // Start the whole thing:
  270. SetTimer( hPicWin, 2, mymngstuff->delay, 0 );
  271. }
  272. //---------------------------------------------------------------------------------------------
  273. // Called when loading a new file or Appquit:
  274. //---------------------------------------------------------------------------------------------
  275. void CleanUpMNG()
  276. {
  277. KillTimer( hPicWin, 2 );
  278. mng_cleanup(&Curmng);
  279. fclose( mymngstuff->file );
  280. free(mymngstuff);
  281. delete [] mngdestbuffer;
  282. }
  283. //---------------------------------------------------------------------------------------------
  284. // Called when timer says next frame/layer/update is needed:
  285. //---------------------------------------------------------------------------------------------
  286. void UpdateMNG()
  287. {
  288. mymngstuff->delay = 0;
  289. if( MNG_NEEDTIMERWAIT == mng_display_resume(Curmng) )
  290. {
  291. KillTimer( hPicWin, 2 );
  292. SetTimer( hPicWin, 2, mymngstuff->delay, 0 );
  293. }
  294. else
  295. {
  296. CleanUpMNG();
  297. AnimFile.CurFrame = -1;
  298. AnimFile.MaxFrame = -1;
  299. AnimFile.isAnimation = -1;
  300. AnimFile.Delay = -1;
  301. }
  302. }
  303. ///////////////////////////////////////////////////////////////////////////////////////////////
  304. ///////////////////////////////////////////////////////////////////////////////////////////////
  305. //---------------------------------------------------------------------------------------------
  306. // MNG WRITING STUFF:
  307. //---------------------------------------------------------------------------------------------
  308. ///////////////////////////////////////////////////////////////////////////////////////////////
  309. ///////////////////////////////////////////////////////////////////////////////////////////////
  310. int OffsetX=0,OffsetY=0,OffsetW=0,OffsetH=0;
  311. BYTE *srcbuffer=0, *tmpbuffer;
  312. //---------------------------------------------------------------------------------------------
  313. // Callback for writing data:
  314. //---------------------------------------------------------------------------------------------
  315. mng_bool mymngwritedata( mng_handle hMNG, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten )
  316. {
  317. mngstuff *pMydata = (mngstuff*)mng_get_userdata(hMNG);
  318. *iWritten = fwrite( pBuf, sizeof(BYTE), iSize, pMydata->file );
  319. if( *iWritten < iSize )
  320. {
  321. Warning( "write error" );
  322. return MNG_FALSE;
  323. }
  324. return MNG_TRUE;
  325. }
  326. //---------------------------------------------------------------------------------------------
  327. // swap Rs and Bs...
  328. //---------------------------------------------------------------------------------------------
  329. BOOL RGBFromBGR( BYTE *buf, UINT widthPix, UINT height )
  330. {
  331. UINT col, row;
  332. LPBYTE pRed, pBlu;
  333. BYTE tmp;
  334. if (buf==NULL)return FALSE;
  335. INT TmpRow = 0;
  336. INT WidthBytes = widthPix*3;
  337. if(WidthBytes & 0x003) WidthBytes = (WidthBytes | 3) + 1;
  338. INT OurCol = 0;
  339. for( row=0; row<height; row++ )
  340. {
  341. for( col=0; col<widthPix; col++ )
  342. {
  343. pRed = buf + TmpRow + OurCol;
  344. pBlu = pRed + 2;
  345. // swap red and blue
  346. tmp = *pBlu;
  347. *pBlu = *pRed;
  348. *pRed = tmp;
  349. OurCol += 3;
  350. }
  351. TmpRow += WidthBytes;
  352. OurCol = 0;
  353. }
  354. return TRUE;
  355. }
  356. //---------------------------------------------------------------------------------------------
  357. // Creates the srcuffer filled with data for saving:
  358. //---------------------------------------------------------------------------------------------
  359. VOID CreateSrcBuffer( int Frame, int FrameCount, HBITMAP hBmp2 )
  360. {
  361. PBITMAPINFO pbmi;
  362. BITMAP bmp;
  363. srcbuffer=0;
  364. // Get WidthBytes...
  365. INT WidthBytes = W*3;
  366. INT LineWidth = W*3;
  367. if(LineWidth & 0x003) LineWidth = (LineWidth | 3) + 1;
  368. // Bitmapstruct init...
  369. GetObject( hBmp2, sizeof(BITMAP), (LPSTR)&bmp );
  370. pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
  371. // Initialize the fields in the BITMAPINFO structure.
  372. pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  373. pbmi->bmiHeader.biWidth = bmp.bmWidth;
  374. pbmi->bmiHeader.biHeight = -bmp.bmHeight;
  375. pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
  376. pbmi->bmiHeader.biBitCount = 24;
  377. pbmi->bmiHeader.biCompression = BI_RGB;
  378. pbmi->bmiHeader.biSizeImage = LineWidth * H * FrameCount;
  379. pbmi->bmiHeader.biClrImportant = 0;
  380. // Alloc Memory...
  381. srcbuffer = 0;
  382. srcbuffer = new BYTE[LineWidth*H*FrameCount];
  383. if( srcbuffer == 0 )
  384. Warning( "srcbuffer == 0!" );
  385. // get the buffer and modify the format:
  386. if( 0 == GetDIBits( MemDC, hBmp2, 0, (WORD) (H*FrameCount), srcbuffer, pbmi, 0 ) )
  387. Warning( "no GetDIBits!!!" );
  388. RGBFromBGR( srcbuffer, W, H*FrameCount );
  389. if( srcbuffer == 0 )
  390. Warning( "srcbuffer == 0!" );
  391. // Freee.
  392. LocalFree((PBITMAPINFO)pbmi);
  393. }
  394. //---------------------------------------------------------------------------------------------
  395. // Writes a single PNG datastream
  396. //---------------------------------------------------------------------------------------------
  397. VOID WritePNG( mng_handle hMNG, int Frame, int FrameCount )
  398. {
  399. BYTE *dstbuffer;
  400. INT LineWidth;
  401. INT WidthBytes;
  402. OffsetX=0; OffsetY=0; OffsetW=W; OffsetH=H;
  403. // Get WidthBytes...
  404. WidthBytes = W*3;
  405. LineWidth = W*3;
  406. if(LineWidth & 0x003) LineWidth = (LineWidth | 3) + 1;
  407. tmpbuffer = new BYTE[(WidthBytes+1)*OffsetH];
  408. if( tmpbuffer == 0 ) Warning( "Out of Memory!" );
  409. // Write DEFI chunk.
  410. mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 );
  411. // Write Header:
  412. mng_putchunk_ihdr(
  413. hMNG,
  414. OffsetW, OffsetH,
  415. MNG_BITDEPTH_8/*iBitdepth*/,
  416. MNG_COLORTYPE_RGB/*iColortype*/,
  417. MNG_COMPRESSION_DEFLATE/*iCompression*/,
  418. MNG_FILTER_ADAPTIVE/*iFilter*/,
  419. MNG_INTERLACE_NONE /*iInterlace*/
  420. );
  421. // transfer data, add Filterbyte:
  422. for( int Row=0; Row<OffsetH; Row++ )
  423. {
  424. // First Byte in each Scanline is Filterbyte: Currently 0 -> No Filter.
  425. tmpbuffer[Row*(WidthBytes+1)]=0;
  426. // Copy the scanline:
  427. memcpy(
  428. tmpbuffer+Row*(WidthBytes+1)+1,
  429. srcbuffer+((OffsetY+Row)*(LineWidth))+OffsetX,
  430. WidthBytes
  431. );
  432. }
  433. // Free srcbuffer if not animated GIF:
  434. delete [] srcbuffer;
  435. // Compress data with ZLib (Deflate):
  436. dstbuffer = new BYTE[(WidthBytes+1)*OffsetH];
  437. if( dstbuffer == 0 ) Warning( "Out of Memory!" );
  438. DWORD dstbufferSize=(WidthBytes+1)*OffsetH;
  439. // Compress data:
  440. if( Z_OK != compress2(
  441. (Bytef *)dstbuffer, (ULONG *)&dstbufferSize,
  442. (const Bytef*)tmpbuffer, (ULONG) (WidthBytes+1)*OffsetH,
  443. 9
  444. )) Warning( "Unable to compress imagedata!" );
  445. // Write Data into MNG File:
  446. mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer);
  447. mng_putchunk_iend(hMNG);
  448. // Free the stuff:
  449. delete [] tmpbuffer;
  450. delete [] dstbuffer;
  451. }
  452. //---------------------------------------------------------------------------------------------
  453. // Writes a MNG (24bit)
  454. //---------------------------------------------------------------------------------------------
  455. VOID SaveMNG( LPSTR Filename, HDC hdc, HBITMAP hBmp )
  456. {
  457. mng_handle hMNG;
  458. // check if currently a MNG file is loaded:
  459. if( AnimFile.isAnimation == 1 )
  460. CleanUpMNG();
  461. // Creates the srcbuffer for imagedata:
  462. CreateSrcBuffer( 0, 1, hBmp );
  463. // allocate our stream data structure
  464. mymngstuff = (mngstuff*)calloc(1, sizeof(*mymngstuff));
  465. if( mymngstuff == NULL )
  466. {
  467. Warning( "Cannot allocate data buffer." );
  468. return;
  469. }
  470. // pass the name of the file we want to play
  471. mymngstuff->filename = Filename;
  472. // init the lib:
  473. hMNG = mng_initialize((mng_ptr)mymngstuff, mymngalloc, mymngfree, MNG_NULL);
  474. if( !hMNG )
  475. {
  476. Warning( "Cannot initialize libmng." );
  477. return;
  478. }
  479. else
  480. {
  481. mng_setcb_openstream(hMNG, mymngopenstreamwrite );
  482. mng_setcb_closestream(hMNG, mymngclosestream);
  483. mng_setcb_writedata(hMNG, mymngwritedata);
  484. // Write File:
  485. mng_create(hMNG);
  486. // Just a single Frame (save a normal PNG):
  487. WritePNG( hMNG, 0, 1 );
  488. // Now write file:
  489. mng_write(hMNG);
  490. // Free the stuff:
  491. fclose( mymngstuff->file );
  492. mng_cleanup(&hMNG);
  493. }
  494. free( mymngstuff );
  495. }