source: psi/trunk/libpsi/psipng/psimng.cpp@ 5

Last change on this file since 5 was 2, checked in by dmik, 19 years ago

Imported original Psi 0.10 sources from Affinix

File size: 7.8 KB
Line 
1/*
2 * psimng.cpp - QImageFormat for loading MNG animations at once
3 * Copyright (C) 2003 Michail Pishchagin
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include "psimng.h"
22
23#include <qdatetime.h>
24
25#include <qimage.h>
26#include <qasyncimageio.h>
27#include <qiodevice.h>
28
29// Define XMD_H prohibits the included headers of libmng.h to typedef INT32.
30// This is needed for Borland with STL support, since in that case, INT32 is
31// already defined by some Borland header.
32#define XMD_H
33#if defined(Q_OS_UNIXWARE)
34# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
35#endif
36#include <libmng.h>
37#include <stdlib.h>
38
39class PsiMNGFormat : public QImageFormat {
40public:
41 PsiMNGFormat();
42 ~PsiMNGFormat();
43
44 int decode(QImage& img, QImageConsumer *cons, const uchar *buf, int length);
45
46 bool openstream();
47 bool closestream();
48 bool readdata(mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead);
49 bool errorproc(mng_int32 iErrorcode, mng_int8 /*iSeverity*/, mng_chunkid iChunkname, mng_uint32 /*iChunkseq*/, mng_int32 iExtra1, mng_int32 iExtra2, mng_pchar zErrortext);
50 bool processheader(mng_uint32 iWidth, mng_uint32 iHeight);
51 mng_ptr getcanvasline(mng_uint32 iLinenr);
52 mng_bool refresh(mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h);
53 mng_uint32 gettickcount();
54 bool settimer(mng_uint32 iMsecs);
55
56private:
57 // Animation-level information
58 enum {
59 MovieStart,
60 Data,
61 } state;
62
63 // Image-level information
64 mng_handle handle;
65
66 // Timing
67 int time;
68
69 // Temporary locals during single data-chunk processing
70 const uchar *data;
71 int dataSize, processedData;
72
73 QImageConsumer *consumer;
74 QImage *image;
75};
76
77//----------------------------------------------------------------------------
78// C-callback to C++-member-function conversion
79//----------------------------------------------------------------------------
80
81static mng_bool openstream( mng_handle handle )
82{
83 return ((PsiMNGFormat*)mng_get_userdata(handle))->openstream();
84}
85static mng_bool closestream( mng_handle handle )
86{
87 return ((PsiMNGFormat*)mng_get_userdata(handle))->closestream();
88}
89static mng_bool readdata( mng_handle handle, mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead )
90{
91 return ((PsiMNGFormat*)mng_get_userdata(handle))->readdata(pBuf,iBuflen,pRead);
92}
93static mng_bool errorproc( mng_handle handle,
94 mng_int32 iErrorcode,
95 mng_int8 iSeverity,
96 mng_chunkid iChunkname,
97 mng_uint32 iChunkseq,
98 mng_int32 iExtra1,
99 mng_int32 iExtra2,
100 mng_pchar zErrortext )
101{
102 return ((PsiMNGFormat*)mng_get_userdata(handle))->errorproc(iErrorcode,
103 iSeverity,iChunkname,iChunkseq,iExtra1,iExtra2,zErrortext);
104}
105static mng_bool processheader( mng_handle handle,
106 mng_uint32 iWidth, mng_uint32 iHeight )
107{
108 return ((PsiMNGFormat*)mng_get_userdata(handle))->processheader(iWidth,iHeight);
109}
110static mng_ptr getcanvasline( mng_handle handle, mng_uint32 iLinenr )
111{
112 return ((PsiMNGFormat*)mng_get_userdata(handle))->getcanvasline(iLinenr);
113}
114static mng_bool refresh( mng_handle handle,
115 mng_uint32 iTop,
116 mng_uint32 iLeft,
117 mng_uint32 iBottom,
118 mng_uint32 iRight )
119{
120 return ((PsiMNGFormat*)mng_get_userdata(handle))->refresh(iTop,iLeft,iBottom,iRight);
121}
122static mng_uint32 gettickcount( mng_handle handle )
123{
124 return ((PsiMNGFormat*)mng_get_userdata(handle))->gettickcount();
125}
126static mng_bool settimer( mng_handle handle, mng_uint32 iMsecs )
127{
128 return ((PsiMNGFormat*)mng_get_userdata(handle))->settimer(iMsecs);
129}
130
131static mng_ptr memalloc( mng_size_t iLen )
132{
133 return calloc(1,iLen);
134}
135static void memfree( mng_ptr iPtr, mng_size_t /*iLen*/ )
136{
137 free(iPtr);
138}
139
140//----------------------------------------------------------------------------
141
142PsiMNGFormat::PsiMNGFormat()
143{
144 state = MovieStart;
145 handle = 0;
146 time = 0;
147}
148
149PsiMNGFormat::~PsiMNGFormat()
150{
151}
152
153bool PsiMNGFormat::openstream()
154{
155 return true;
156}
157
158bool PsiMNGFormat::closestream()
159{
160 return true;
161}
162
163bool PsiMNGFormat::readdata(mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead)
164{
165 if ( iBuflen <= (uint)dataSize ) {
166 memcpy(pBuf, data + processedData, iBuflen);
167 *pRead = iBuflen;
168 }
169
170 processedData += iBuflen;
171
172 return true;
173}
174
175bool PsiMNGFormat::errorproc( mng_int32 iErrorcode, mng_int8 /*iSeverity*/, mng_chunkid iChunkname, mng_uint32 /*iChunkseq*/, mng_int32 iExtra1, mng_int32 iExtra2, mng_pchar zErrortext )
176{
177 qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d",
178 iErrorcode,zErrortext,
179 (iChunkname>>24)&0xff,
180 (iChunkname>>16)&0xff,
181 (iChunkname>>8)&0xff,
182 (iChunkname>>0)&0xff,
183 iExtra1,iExtra2);
184 return TRUE;
185}
186
187bool PsiMNGFormat::processheader(mng_uint32 iWidth, mng_uint32 iHeight)
188{
189 image->create(iWidth, iHeight, 32);
190 image->setAlphaBuffer(TRUE);
191 memset(image->bits(), 0, iWidth*iHeight*4);
192 consumer->setSize(iWidth, iHeight);
193 mng_set_canvasstyle(handle,
194 QImage::systemByteOrder() == QImage::LittleEndian
195 ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8 );
196 return TRUE;
197}
198
199mng_ptr PsiMNGFormat::getcanvasline(mng_uint32 iLinenr)
200{
201 return image->scanLine(iLinenr);
202}
203
204mng_bool PsiMNGFormat::refresh(mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h)
205{
206 QRect r(x,y,w,h);
207 consumer->changed(r);
208 consumer->setFramePeriod(0);
209 consumer->frameDone();
210 return TRUE;
211}
212
213mng_uint32 PsiMNGFormat::gettickcount()
214{
215 return time;
216}
217
218bool PsiMNGFormat::settimer(mng_uint32 iMsecs)
219{
220 consumer->setFramePeriod(iMsecs);
221 consumer->frameDone();
222 time += iMsecs;
223 return TRUE;
224}
225
226int PsiMNGFormat::decode(QImage &img, QImageConsumer *cons, const uchar *buf, int length)
227{
228 //if ( !length ) // there's no more data then
229 // return 0;
230
231 consumer = cons;
232 image = &img;
233
234 data = buf;
235 dataSize = length;
236 processedData = 0;
237
238 if ( state == MovieStart ) {
239 handle = mng_initialize( (mng_ptr)this, ::memalloc, ::memfree, 0 );
240 //mng_set_suspensionmode( handle, MNG_FALSE );
241 mng_setcb_openstream( handle, ::openstream );
242 mng_setcb_closestream( handle, ::closestream );
243 mng_setcb_readdata( handle, ::readdata );
244 mng_setcb_errorproc( handle, ::errorproc );
245 mng_setcb_processheader( handle, ::processheader );
246 mng_setcb_getcanvasline( handle, ::getcanvasline );
247 mng_setcb_refresh( handle, ::refresh );
248 mng_setcb_gettickcount( handle, ::gettickcount );
249 mng_setcb_settimer( handle, ::settimer );
250 state = Data;
251
252 mng_readdisplay(handle);
253 }
254 else
255 mng_display_resume(handle);
256
257 image = 0;
258
259 return processedData;
260}
261
262//----------------------------------------------------------------------------
263
264class PsiMNGFormatType : public QImageFormatType
265{
266 QImageFormat *decoderFor(const uchar *buffer, int length)
267 {
268 if (length < 8)
269 return 0;
270
271 if (buffer[0]==138 // MNG signature
272 && buffer[1]=='M'
273 && buffer[2]=='N'
274 && buffer[3]=='G'
275 && buffer[4]==13
276 && buffer[5]==10
277 && buffer[6]==26
278 && buffer[7]==10) {
279 return new PsiMNGFormat;
280 }
281
282 return 0;
283 }
284
285 const char *formatName() const
286 {
287 return "PsiMNG";
288 }
289};
290
291static PsiMNGFormatType *globalMngFormatTypeObject = 0;
292
293void cleanupPsiMngIO()
294{
295 if ( globalMngFormatTypeObject ) {
296 delete globalMngFormatTypeObject;
297 globalMngFormatTypeObject = 0;
298 }
299}
300
301void initPsiMngIO()
302{
303 static bool done = FALSE;
304 if ( !done ) {
305 done = TRUE;
306 globalMngFormatTypeObject = new PsiMNGFormatType;
307 qAddPostRoutine( cleanupPsiMngIO );
308 }
309}
Note: See TracBrowser for help on using the repository browser.