source: vendor/trolltech/current/src/kernel/qmngio.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 11.9 KB
Line 
1/****************************************************************************
2** $Id: qmngio.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of MNG QImage IOHandler
5**
6** Created : 970521
7**
8** Copyright (C) 1997-2004 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#ifndef QT_CLEAN_NAMESPACE
39#define QT_CLEAN_NAMESPACE
40#endif
41
42#include "qdatetime.h"
43
44#ifndef QT_NO_IMAGEIO_MNG
45
46#include "qimage.h"
47#include "qasyncimageio.h"
48#include "qiodevice.h"
49#include "qmngio.h"
50
51// Define XMD_H prohibits the included headers of libmng.h to typedef INT32.
52// This is needed for Borland with STL support, since in that case, INT32 is
53// already defined by some Borland header.
54#define XMD_H
55#if defined(Q_OS_UNIXWARE)
56# define HAVE_BOOLEAN // libjpeg under Unixware seems to need this
57#endif
58#include <libmng.h>
59#include <stdlib.h>
60
61
62#ifndef QT_NO_ASYNC_IMAGE_IO
63
64class QMNGFormat : public QImageFormat {
65public:
66 QMNGFormat();
67 virtual ~QMNGFormat();
68
69 int decode(QImage& img, QImageConsumer* consumer,
70 const uchar* buffer, int length);
71
72 bool openstream()
73 {
74 // ### We should figure out how many loops an MNG has, but for now always assume infinite.
75 if (consumer)
76 consumer->setLooping(0);
77 return TRUE;
78 }
79 bool closestream( )
80 {
81 if (consumer)
82 consumer->end();
83 return TRUE;
84 }
85 bool readdata( mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead )
86 {
87 uint m = ndata + nbuffer - ubuffer;
88 if ( iBuflen > m ) {
89 iBuflen = m;
90 }
91 *pRead = iBuflen;
92 uint n = nbuffer-ubuffer;
93 if ( iBuflen < n ) {
94 // enough in buffer
95 memcpy(pBuf, buffer+ubuffer, iBuflen);
96 ubuffer += iBuflen;
97 return TRUE;
98 }
99 if ( n ) {
100 // consume buffer
101 memcpy(pBuf, buffer+ubuffer, n );
102 pBuf = (mng_ptr)((char*)pBuf + n);
103 iBuflen -= n;
104 ubuffer = nbuffer;
105 }
106 if ( iBuflen ) {
107 // fill from incoming data
108 memcpy(pBuf, data, iBuflen);
109 data += iBuflen;
110 ndata -= iBuflen;
111 }
112 return TRUE;
113 }
114 bool errorproc( mng_int32 iErrorcode,
115 mng_int8 /*iSeverity*/,
116 mng_chunkid iChunkname,
117 mng_uint32 /*iChunkseq*/,
118 mng_int32 iExtra1,
119 mng_int32 iExtra2,
120 mng_pchar zErrortext )
121 {
122 qWarning("MNG error %d: %s; chunk %c%c%c%c; subcode %d:%d",
123 iErrorcode,zErrortext,
124 (iChunkname>>24)&0xff,
125 (iChunkname>>16)&0xff,
126 (iChunkname>>8)&0xff,
127 (iChunkname>>0)&0xff,
128 iExtra1,iExtra2);
129 return TRUE;
130 }
131 bool processheader( mng_uint32 iWidth, mng_uint32 iHeight )
132 {
133 image->create(iWidth,iHeight,32);
134 image->setAlphaBuffer(TRUE);
135 memset(image->bits(),0,iWidth*iHeight*4);
136 consumer->setSize(iWidth,iHeight);
137 mng_set_canvasstyle(handle,
138 QImage::systemByteOrder() == QImage::LittleEndian
139 ? MNG_CANVAS_BGRA8 : MNG_CANVAS_ARGB8 );
140 return TRUE;
141 }
142 mng_ptr getcanvasline( mng_uint32 iLinenr )
143 {
144 return image->scanLine(iLinenr);
145 }
146 mng_bool refresh( mng_uint32 x, mng_uint32 y, mng_uint32 w, mng_uint32 h )
147 {
148 QRect r(x,y,w,h);
149 consumer->changed(r);
150 consumer->setFramePeriod(0);
151 consumer->frameDone();
152 return TRUE;
153 }
154 mng_uint32 gettickcount( )
155 {
156 return timer.elapsed() - losttime;
157 }
158 bool settimer( mng_uint32 iMsecs )
159 {
160 consumer->setFramePeriod(iMsecs);
161 consumer->frameDone();
162 state = Time;
163 losingtimer.start();
164 losttime -= iMsecs;
165 return TRUE;
166 }
167
168private:
169 // Animation-level information
170 enum { MovieStart, Time, Data, Data2 } state;
171
172 // Image-level information
173 mng_handle handle;
174
175 // For storing unused data
176 uchar *buffer;
177 uint maxbuffer;
178 uint nbuffer;
179
180 // Timing
181 QTime timer;
182 QTime losingtimer;
183 int losttime;
184
185 void enlargeBuffer(uint n)
186 {
187 if ( n > maxbuffer ) {
188 maxbuffer = n;
189 buffer = (uchar*)realloc(buffer,n);
190 }
191 }
192
193 // Temporary locals during single data-chunk processing
194 const uchar* data;
195 uint ndata;
196 uint ubuffer;
197 QImageConsumer* consumer;
198 QImage* image;
199};
200
201class QMNGFormatType : public QImageFormatType
202{
203 QImageFormat* decoderFor(const uchar* buffer, int length);
204 const char* formatName() const;
205};
206
207
208/*
209 \class QMNGFormat qmngio.h
210 \brief Incremental image decoder for MNG image format.
211
212 \ingroup images
213 \ingroup graphics
214
215 This subclass of QImageFormat decodes MNG format images,
216 including animated MNGs.
217
218 Animated MNG images are standard MNG images. The MNG standard
219 defines two extension chunks that are useful for animations:
220
221 <dl>
222 <dt>gIFg - GIF-like Graphic Control Extension
223 <dd>Includes frame disposal, user input flag (we ignore this),
224 and inter-frame delay.
225 <dt>gIFx - GIF-like Application Extension
226 <dd>Multi-purpose, but we just use the Netscape extension
227 which specifies looping.
228 </dl>
229
230 The subimages usually contain a offset chunk (oFFs) but need not.
231
232 The first image defines the "screen" size. Any subsequent image that
233 doesn't fit is clipped.
234
235TODO: decide on this point. gIFg gives disposal types, so it can be done.
236 All images paste (\e not composite, just place all-channel copying)
237 over the previous image to produce a subsequent frame.
238*/
239
240/*
241 \class QMNGFormatType qasyncimageio.h
242 \brief Incremental image decoder for MNG image format.
243
244 \ingroup images
245 \ingroup graphics
246 \ingroup io
247
248 This subclass of QImageFormatType recognizes MNG
249 format images, creating a QMNGFormat when required. An instance
250 of this class is created automatically before any other factories,
251 so you should have no need for such objects.
252*/
253
254QImageFormat* QMNGFormatType::decoderFor( const uchar* buffer, int length )
255{
256 if (length < 8) return 0;
257
258 if (buffer[0]==138 // MNG signature
259 && buffer[1]=='M'
260 && buffer[2]=='N'
261 && buffer[3]=='G'
262 && buffer[4]==13
263 && buffer[5]==10
264 && buffer[6]==26
265 && buffer[7]==10
266 || buffer[0]==139 // JNG signature
267 && buffer[1]=='J'
268 && buffer[2]=='N'
269 && buffer[3]=='G'
270 && buffer[4]==13
271 && buffer[5]==10
272 && buffer[6]==26
273 && buffer[7]==10
274#ifdef QT_NO_IMAGEIO_PNG // if we don't have native PNG support use libmng
275 || buffer[0]==137 // PNG signature
276 && buffer[1]=='P'
277 && buffer[2]=='N'
278 && buffer[3]=='G'
279 && buffer[4]==13
280 && buffer[5]==10
281 && buffer[6]==26
282 && buffer[7]==10
283#endif
284 )
285 return new QMNGFormat;
286 return 0;
287}
288
289const char* QMNGFormatType::formatName() const
290{
291 return "MNG";
292}
293
294
295/*!
296 Constructs a QMNGFormat.
297*/
298QMNGFormat::QMNGFormat()
299{
300 state = MovieStart;
301 handle = 0;
302 nbuffer = 0;
303 maxbuffer = 0;
304 buffer = 0;
305 losttime = 0;
306}
307
308/*
309 Destroys a QMNGFormat.
310*/
311QMNGFormat::~QMNGFormat()
312{
313 mng_cleanup(&handle);
314}
315
316
317// C-callback to C++-member-function conversion
318//
319static mng_bool openstream( mng_handle handle )
320{
321 return ((QMNGFormat*)mng_get_userdata(handle))->openstream();
322}
323static mng_bool closestream( mng_handle handle )
324{
325 return ((QMNGFormat*)mng_get_userdata(handle))->closestream();
326}
327static mng_bool readdata( mng_handle handle, mng_ptr pBuf, mng_uint32 iBuflen, mng_uint32p pRead )
328{
329 return ((QMNGFormat*)mng_get_userdata(handle))->readdata(pBuf,iBuflen,pRead);
330}
331static mng_bool errorproc( mng_handle handle,
332 mng_int32 iErrorcode,
333 mng_int8 iSeverity,
334 mng_chunkid iChunkname,
335 mng_uint32 iChunkseq,
336 mng_int32 iExtra1,
337 mng_int32 iExtra2,
338 mng_pchar zErrortext )
339{
340 return ((QMNGFormat*)mng_get_userdata(handle))->errorproc(iErrorcode,
341 iSeverity,iChunkname,iChunkseq,iExtra1,iExtra2,zErrortext);
342}
343static mng_bool processheader( mng_handle handle,
344 mng_uint32 iWidth, mng_uint32 iHeight )
345{
346 return ((QMNGFormat*)mng_get_userdata(handle))->processheader(iWidth,iHeight);
347}
348static mng_ptr getcanvasline( mng_handle handle, mng_uint32 iLinenr )
349{
350 return ((QMNGFormat*)mng_get_userdata(handle))->getcanvasline(iLinenr);
351}
352static mng_bool refresh( mng_handle handle,
353 mng_uint32 iTop,
354 mng_uint32 iLeft,
355 mng_uint32 iBottom,
356 mng_uint32 iRight )
357{
358 return ((QMNGFormat*)mng_get_userdata(handle))->refresh(iTop,iLeft,iBottom,iRight);
359}
360static mng_uint32 gettickcount( mng_handle handle )
361{
362 return ((QMNGFormat*)mng_get_userdata(handle))->gettickcount();
363}
364static mng_bool settimer( mng_handle handle, mng_uint32 iMsecs )
365{
366 return ((QMNGFormat*)mng_get_userdata(handle))->settimer(iMsecs);
367}
368
369static mng_ptr memalloc( mng_size_t iLen )
370{
371 return calloc(1,iLen);
372}
373static void memfree( mng_ptr iPtr, mng_size_t /*iLen*/ )
374{
375 free(iPtr);
376}
377
378/*!
379 This function decodes some data into image changes.
380
381 Returns the number of bytes consumed.
382*/
383int QMNGFormat::decode( QImage& img, QImageConsumer* cons,
384 const uchar* buf, int length )
385{
386 consumer = cons;
387 image = &img;
388
389 data = buf;
390 ndata = length;
391 ubuffer = 0;
392
393 if ( state == MovieStart ) {
394 handle = mng_initialize( (mng_ptr)this, ::memalloc, ::memfree, 0 );
395 mng_set_suspensionmode( handle, MNG_TRUE );
396 mng_setcb_openstream( handle, ::openstream );
397 mng_setcb_closestream( handle, ::closestream );
398 mng_setcb_readdata( handle, ::readdata );
399 mng_setcb_errorproc( handle, ::errorproc );
400 mng_setcb_processheader( handle, ::processheader );
401 mng_setcb_getcanvasline( handle, ::getcanvasline );
402 mng_setcb_refresh( handle, ::refresh );
403 mng_setcb_gettickcount( handle, ::gettickcount );
404 mng_setcb_settimer( handle, ::settimer );
405 state = Data;
406 mng_readdisplay(handle);
407 losingtimer.start();
408 }
409
410 losttime += losingtimer.elapsed();
411 if ( ndata || !length )
412 mng_display_resume(handle);
413 losingtimer.start();
414
415 image = 0;
416
417 nbuffer -= ubuffer;
418 if ( nbuffer ) {
419 // Move back unused tail
420 memcpy(buffer,buffer+ubuffer,nbuffer);
421 }
422 if ( ndata ) {
423 // Not all used.
424 enlargeBuffer(nbuffer+ndata);
425 memcpy(buffer+nbuffer,data,ndata);
426 nbuffer += ndata;
427 }
428
429 return length;
430}
431
432static QMNGFormatType* globalMngFormatTypeObject = 0;
433
434#endif // QT_NO_ASYNC_IMAGE_IO
435
436#ifndef QT_NO_ASYNC_IMAGE_IO
437void qCleanupMngIO()
438{
439 if ( globalMngFormatTypeObject ) {
440 delete globalMngFormatTypeObject;
441 globalMngFormatTypeObject = 0;
442 }
443}
444#endif
445
446void qInitMngIO()
447{
448 static bool done = FALSE;
449 if ( !done ) {
450 done = TRUE;
451#ifndef QT_NO_ASYNC_IMAGE_IO
452 globalMngFormatTypeObject = new QMNGFormatType;
453 qAddPostRoutine( qCleanupMngIO );
454#endif
455 }
456}
457
458#endif // QT_NO_IMAGEIO_MNG
Note: See TracBrowser for help on using the repository browser.