source: liacs/MIR2010/SourceCode/cximage/ximamng.cpp@ 97

Last change on this file since 97 was 95, checked in by Rick van der Zwet, 15 years ago

Bad boy, improper move of directory

File size: 14.1 KB
RevLine 
[95]1/*
2 * File: ximamng.cpp
3 * Purpose: Platform Independent MNG Image Class Loader and Writer
4 * Author: 07/Aug/2001 Davide Pizzolato - www.xdp.it
5 * CxImage version 6.0.0 02/Feb/2008
6 */
7
8#include "ximamng.h"
9
10#if CXIMAGE_SUPPORT_MNG
11
12////////////////////////////////////////////////////////////////////////////////
13// callbacks for the mng decoder:
14////////////////////////////////////////////////////////////////////////////////
15
16////////////////////////////////////////////////////////////////////////////////
17// memory allocation; data must be zeroed
18static mng_ptr
19mymngalloc( mng_uint32 size )
20{
21 return (mng_ptr)calloc(1, size);
22}
23
24////////////////////////////////////////////////////////////////////////////////
25// memory deallocation
26static void mymngfree(mng_ptr p, mng_uint32 size)
27{
28 free(p);
29}
30
31////////////////////////////////////////////////////////////////////////////////
32// Stream open/close:
33// since the user is responsible for opening and closing the file,
34// we leave the default implementation open
35static mng_bool mymngopenstream(mng_handle mng) { return MNG_TRUE; }
36static mng_bool mymngopenstreamwrite(mng_handle mng) { return MNG_TRUE; }
37static mng_bool mymngclosestream(mng_handle mng) { return MNG_TRUE; }
38
39////////////////////////////////////////////////////////////////////////////////
40// feed data to the decoder
41static mng_bool mymngreadstream(mng_handle mng, mng_ptr buffer, mng_uint32 size, mng_uint32 *bytesread)
42{
43 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
44 // read the requested amount of data from the file
45 *bytesread = mymng->file->Read( buffer, sizeof(BYTE), size);
46 return MNG_TRUE;
47}
48
49////////////////////////////////////////////////////////////////////////////////
50static mng_bool mymngwritestream (mng_handle mng, mng_ptr pBuf, mng_uint32 iSize, mng_uint32 *iWritten)
51{
52 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
53 // write it
54 *iWritten = mymng->file->Write (pBuf, 1, iSize);
55 return MNG_TRUE;
56}
57
58////////////////////////////////////////////////////////////////////////////////
59// the header's been read. set up the display stuff
60static mng_bool mymngprocessheader( mng_handle mng, mng_uint32 width, mng_uint32 height )
61{
62 // normally the image buffer is allocated here,
63 // but in this module we don't know nothing about
64 // the final environment.
65
66 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
67
68 mymng->width = width;
69 mymng->height = height;
70 mymng->bpp = 24;
71 mymng->effwdt = ((((width * mymng->bpp) + 31) >> 5) << 2);
72
73 if (mng->bUseBKGD){
74 mymng->nBkgndIndex = 0;
75 mymng->nBkgndColor.rgbRed = mng->iBGred >> 8;
76 mymng->nBkgndColor.rgbGreen =mng->iBGgreen >> 8;
77 mymng->nBkgndColor.rgbBlue = mng->iBGblue >> 8;
78 }
79
80 mymng->image = (BYTE*)malloc(height * mymng->effwdt);
81
82 // tell the mng decoder about our bit-depth choice
83#if CXIMAGE_SUPPORT_ALPHA
84 mng_set_canvasstyle( mng, MNG_CANVAS_RGB8_A8 );
85 mymng->alpha = (BYTE*)malloc(height * width);
86#else
87 mng_set_canvasstyle( mng, MNG_CANVAS_BGR8);
88 mymng->alpha = NULL;
89#endif
90 return MNG_TRUE;
91}
92
93////////////////////////////////////////////////////////////////////////////////
94// return a row pointer for the decoder to fill
95static mng_ptr mymnggetcanvasline( mng_handle mng, mng_uint32 line )
96{
97 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
98 return (mng_ptr)(mymng->image + (mymng->effwdt * (mymng->height - 1 - line)));
99}
100////////////////////////////////////////////////////////////////////////////////
101// return a row pointer for the decoder to fill for alpha channel
102static mng_ptr mymnggetalphaline( mng_handle mng, mng_uint32 line )
103{
104 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
105 return (mng_ptr)(mymng->alpha + (mymng->width * (mymng->height - 1 - line)));
106}
107
108////////////////////////////////////////////////////////////////////////////////
109// timer
110static mng_uint32 mymnggetticks(mng_handle mng)
111{
112#ifdef WIN32
113 return (mng_uint32)GetTickCount();
114#else
115 return 0;
116#endif
117}
118
119////////////////////////////////////////////////////////////////////////////////
120// Refresh: actual frame need to be updated (Invalidate)
121static mng_bool mymngrefresh(mng_handle mng, mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
122{
123// mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
124 return MNG_TRUE;
125}
126
127////////////////////////////////////////////////////////////////////////////////
128// interframe delay callback
129static mng_bool mymngsettimer(mng_handle mng, mng_uint32 msecs)
130{
131 mngstuff *mymng = (mngstuff *)mng_get_userdata(mng);
132 mymng->delay = msecs; // set the timer for when the decoder wants to be woken
133 return MNG_TRUE;
134}
135
136////////////////////////////////////////////////////////////////////////////////
137static mng_bool mymngerror(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text)
138{
139 return mng_cleanup(&mng); //<Arkadiy Olovyannikov>
140}
141
142////////////////////////////////////////////////////////////////////////////////
143// CxImage members
144////////////////////////////////////////////////////////////////////////////////
145CxImageMNG::CxImageMNG(): CxImage(CXIMAGE_FORMAT_MNG)
146{
147 hmng = NULL;
148 memset(&mnginfo,0,sizeof(mngstuff));
149 mnginfo.nBkgndIndex = -1;
150 mnginfo.speed = 1.0f;
151}
152////////////////////////////////////////////////////////////////////////////////
153CxImageMNG::~CxImageMNG()
154{
155 // cleanup and return
156 if (mnginfo.thread){ //close the animation thread
157 mnginfo.animation_enabled=0;
158 ResumeThread(mnginfo.thread);
159 WaitForSingleObject(mnginfo.thread,500);
160 CloseHandle(mnginfo.thread);
161 }
162 // free objects
163 if (mnginfo.image) free(mnginfo.image);
164 if (mnginfo.alpha) free(mnginfo.alpha);
165 if (hmng) mng_cleanup(&hmng); //be sure it's not needed any more. (active timers ?)
166}
167////////////////////////////////////////////////////////////////////////////////
168void CxImageMNG::SetCallbacks(mng_handle mng)
169{
170 // set the callbacks
171 mng_setcb_errorproc(mng, mymngerror);
172 mng_setcb_openstream(mng, mymngopenstream);
173 mng_setcb_closestream(mng, mymngclosestream);
174 mng_setcb_readdata(mng, mymngreadstream);
175 mng_setcb_processheader(mng, mymngprocessheader);
176 mng_setcb_getcanvasline(mng, mymnggetcanvasline);
177 mng_setcb_refresh(mng, mymngrefresh);
178 mng_setcb_gettickcount(mng, mymnggetticks);
179 mng_setcb_settimer(mng, mymngsettimer);
180 mng_setcb_refresh(mng, mymngrefresh);
181 mng_setcb_getalphaline(mng, mymnggetalphaline);
182}
183////////////////////////////////////////////////////////////////////////////////
184// can't use the CxImage implementation because it looses mnginfo
185bool CxImageMNG::Load(const TCHAR * imageFileName){
186 FILE* hFile; //file handle to read the image
187#ifdef WIN32
188 if ((hFile=_tfopen(imageFileName,_T("rb")))==NULL) return false; // For UNICODE support
189#else
190 if ((hFile=fopen(imageFileName,"rb"))==NULL) return false;
191#endif
192 bool bOK = Decode(hFile);
193 fclose(hFile);
194 return bOK;
195}
196////////////////////////////////////////////////////////////////////////////////
197#if CXIMAGE_SUPPORT_DECODE
198////////////////////////////////////////////////////////////////////////////////
199bool CxImageMNG::Decode(CxFile *hFile)
200{
201 if (hFile == NULL) return false;
202
203 cx_try
204 {
205 // set up the mng decoder for our stream
206 hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL);
207 if (hmng == NULL) cx_throw("could not initialize libmng");
208
209 // set the file we want to play
210 mnginfo.file = hFile;
211
212 // Set the colorprofile, lcms uses this:
213 mng_set_srgb(hmng, MNG_TRUE );
214 // Set white as background color:
215 WORD Red,Green,Blue;
216 Red = Green = Blue = (255 << 8) + 255;
217 mng_set_bgcolor(hmng, Red, Green, Blue );
218 // If PNG Background is available, use it:
219 mng_set_usebkgd(hmng, MNG_TRUE );
220
221 // No need to store chunks:
222 mng_set_storechunks(hmng, MNG_FALSE);
223 // No need to wait: straight reading
224 mng_set_suspensionmode(hmng, MNG_FALSE);
225
226 SetCallbacks(hmng);
227
228 mng_datap pData = (mng_datap)hmng;
229
230 // read in the image
231 info.nNumFrames=0;
232 int retval=MNG_NOERROR;
233
234 retval = mng_readdisplay(hmng);
235
236 if (retval != MNG_NOERROR && retval != MNG_NEEDTIMERWAIT){
237 mng_store_error(hmng,retval,0,0);
238 if (hmng->zErrortext){
239 cx_throw(hmng->zErrortext);
240 } else {
241 cx_throw("Error in MNG file");
242 }
243 }
244
245 if (info.nEscape == -1) {
246 // Return output dimensions only
247 head.biWidth = hmng->iWidth;
248 head.biHeight = hmng->iHeight;
249 info.dwType = CXIMAGE_FORMAT_MNG;
250 return true;
251 }
252
253 // read all
254 while(pData->bReading){
255 retval = mng_display_resume(hmng);
256 info.nNumFrames++;
257 }
258
259 // single frame check:
260 if (retval != MNG_NEEDTIMERWAIT){
261 info.nNumFrames--;
262 } else {
263 mnginfo.animation=1;
264 }
265
266 if (info.nNumFrames<=0) info.nNumFrames=1;
267
268 if (mnginfo.animation_enabled==0){
269 // select the frame
270 if (info.nFrame>=0 && info.nFrame<info.nNumFrames){
271 for (int n=0;n<info.nFrame;n++) mng_display_resume(hmng);
272 } else cx_throw("Error: frame not present in MNG file");
273 }
274
275 if (mnginfo.nBkgndIndex >= 0){
276 info.nBkgndIndex = mnginfo.nBkgndIndex;
277 info.nBkgndColor.rgbRed = mnginfo.nBkgndColor.rgbRed;
278 info.nBkgndColor.rgbGreen = mnginfo.nBkgndColor.rgbGreen;
279 info.nBkgndColor.rgbBlue = mnginfo.nBkgndColor.rgbBlue;
280 }
281
282 //store the newly created image
283 if (Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG)){
284 memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);
285#if CXIMAGE_SUPPORT_ALPHA
286 SwapRGB2BGR();
287 AlphaCreate();
288 if(AlphaIsValid() && mnginfo.alpha){
289 memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);
290 }
291#endif
292 } else cx_throw("CxImageMNG::Decode cannot create image");
293
294
295 } cx_catch {
296 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
297 return false;
298 }
299 return true;
300}
301////////////////////////////////////////////////////////////////////////////////
302#endif //CXIMAGE_SUPPORT_DECODE
303////////////////////////////////////////////////////////////////////////////////
304#if CXIMAGE_SUPPORT_ENCODE
305////////////////////////////////////////////////////////////////////////////////
306bool CxImageMNG::Encode(CxFile *hFile)
307{
308 if (EncodeSafeCheck(hFile)) return false;
309
310 cx_try
311 {
312 if (head.biClrUsed != 0) cx_throw("MNG encoder can save only RGB images");
313 // set the file we want to play
314 mnginfo.file = hFile;
315 mnginfo.bpp = head.biBitCount;
316 mnginfo.effwdt = info.dwEffWidth;
317 mnginfo.height = head.biHeight;
318 mnginfo.width = head.biWidth;
319
320 mnginfo.image = (BYTE*)malloc(head.biSizeImage);
321 if (mnginfo.image == NULL) cx_throw("could not allocate memory for MNG");
322 memcpy(mnginfo.image,info.pImage, head.biSizeImage);
323
324 // set up the mng decoder for our stream
325 hmng = mng_initialize(&mnginfo, mymngalloc, mymngfree, MNG_NULL);
326 if (hmng == NULL) cx_throw("could not initialize libmng");
327
328 mng_setcb_openstream(hmng, mymngopenstreamwrite );
329 mng_setcb_closestream(hmng, mymngclosestream);
330 mng_setcb_writedata(hmng, mymngwritestream);
331
332 // Write File:
333 mng_create(hmng);
334 // Just a single Frame (save a normal PNG):
335 WritePNG(hmng, 0, 1 );
336 // Now write file:
337 mng_write(hmng);
338
339 } cx_catch {
340 if (strcmp(message,"")) strncpy(info.szLastError,message,255);
341 return false;
342 }
343 return true;
344}
345////////////////////////////////////////////////////////////////////////////////
346// Writes a single PNG datastream
347void CxImageMNG::WritePNG( mng_handle hMNG, int Frame, int FrameCount )
348{
349 mngstuff *mymng = (mngstuff *)mng_get_userdata(hMNG);
350
351 int OffsetX=0,OffsetY=0,OffsetW=mymng->width,OffsetH=mymng->height;
352
353 BYTE *tmpbuffer = new BYTE[ (mymng->effwdt+1) * mymng->height];
354 if( tmpbuffer == 0 ) return;
355
356 // Write DEFI chunk.
357 mng_putchunk_defi( hMNG, 0, 0, 0, MNG_TRUE, OffsetX, OffsetY, MNG_FALSE, 0, 0, 0, 0 );
358
359 // Write Header:
360 mng_putchunk_ihdr(
361 hMNG,
362 OffsetW, OffsetH,
363 MNG_BITDEPTH_8,
364 MNG_COLORTYPE_RGB,
365 MNG_COMPRESSION_DEFLATE,
366 MNG_FILTER_ADAPTIVE,
367 MNG_INTERLACE_NONE
368 );
369
370 // transfer data, add Filterbyte:
371 for( int Row=0; Row<OffsetH; Row++ ){
372 // First Byte in each Scanline is Filterbyte: Currently 0 -> No Filter.
373 tmpbuffer[Row*(mymng->effwdt+1)]=0;
374 // Copy the scanline: (reverse order)
375 memcpy(tmpbuffer+Row*(mymng->effwdt+1)+1,
376 mymng->image+((OffsetH-1-(OffsetY+Row))*(mymng->effwdt))+OffsetX,mymng->effwdt);
377 // swap red and blue components
378 RGBtoBGR(tmpbuffer+Row*(mymng->effwdt+1)+1,mymng->effwdt);
379 }
380
381 // Compress data with ZLib (Deflate):
382 BYTE *dstbuffer = new BYTE[(mymng->effwdt+1)*OffsetH];
383 if( dstbuffer == 0 ) return;
384 DWORD dstbufferSize=(mymng->effwdt+1)*OffsetH;
385
386 // Compress data:
387 if(Z_OK != compress2((Bytef *)dstbuffer,(ULONG *)&dstbufferSize,(const Bytef*)tmpbuffer,
388 (ULONG) (mymng->effwdt+1)*OffsetH,9 )) return;
389
390 // Write Data into MNG File:
391 mng_putchunk_idat( hMNG, dstbufferSize, (mng_ptr*)dstbuffer);
392 mng_putchunk_iend(hMNG);
393
394 // Free the stuff:
395 delete [] tmpbuffer;
396 delete [] dstbuffer;
397}
398////////////////////////////////////////////////////////////////////////////////
399long CxImageMNG::Resume()
400{
401 if (MNG_NEEDTIMERWAIT == mng_display_resume(hmng)){
402 if (info.pImage==NULL){
403 Create(mnginfo.width,mnginfo.height,mnginfo.bpp, CXIMAGE_FORMAT_MNG);
404 }
405 if (IsValid()){
406 memcpy(GetBits(), mnginfo.image, info.dwEffWidth * head.biHeight);
407#if CXIMAGE_SUPPORT_ALPHA
408 SwapRGB2BGR();
409 AlphaCreate();
410 if(AlphaIsValid() && mnginfo.alpha){
411 memcpy(AlphaGetPointer(),mnginfo.alpha,mnginfo.width * mnginfo.height);
412 }
413#endif
414 }
415 } else {
416 mnginfo.animation_enabled = 0;
417 }
418 return mnginfo.animation_enabled;
419}
420////////////////////////////////////////////////////////////////////////////////
421void CxImageMNG::SetSpeed(float speed)
422{
423 if (speed>10.0) mnginfo.speed = 10.0f;
424 else if (speed<0.1) mnginfo.speed = 0.1f;
425 else mnginfo.speed=speed;
426}
427////////////////////////////////////////////////////////////////////////////////
428#endif //CXIMAGE_SUPPORT_ENCODE
429////////////////////////////////////////////////////////////////////////////////
430#endif // CXIMAGE_SUPPORT_MNG
Note: See TracBrowser for help on using the repository browser.