]> git.saurik.com Git - wxWidgets.git/blame - src/common/anidecod.cpp
Compile fix.
[wxWidgets.git] / src / common / anidecod.cpp
CommitLineData
72045d57
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/anidecod.cpp
3// Purpose: wxANIDecoder, ANI reader for wxImage and wxAnimation
4// Author: Francesco Montorsi
5// RCS-ID: $Id$
6// Copyright: (c) Francesco Montorsi
7// Licence: wxWindows licence
8/////////////////////////////////////////////////////////////////////////////
9
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
13#ifdef __BORLANDC__
14 #pragma hdrstop
15#endif
16
17#if wxUSE_STREAMS && wxUSE_GIF
18
19#ifndef WX_PRECOMP
20 #include "wx/palette.h"
21#endif
22
23#include <stdlib.h>
24#include <string.h>
25#include "wx/anidecod.h"
26
27// static
28wxCURHandler wxANIDecoder::sm_handler;
29
30
31
32//---------------------------------------------------------------------------
33// wxANIFrameInfo
34//---------------------------------------------------------------------------
35
36class wxANIFrameInfo
37{
38public:
39 wxANIFrameInfo(size_t delay = 0, int idx = -1)
40 { m_delay=delay; m_imageIndex=idx; }
41
42 size_t m_delay;
43 int m_imageIndex;
44};
45
46#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
47WX_DEFINE_OBJARRAY(wxImageArray);
48
49#include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
50WX_DEFINE_OBJARRAY(wxANIFrameInfoArray);
51
52
53
54
55//---------------------------------------------------------------------------
56// wxANIDecoder
57//---------------------------------------------------------------------------
58
59wxANIDecoder::wxANIDecoder()
60{
61}
62
63wxANIDecoder::~wxANIDecoder()
64{
65}
66
67bool wxANIDecoder::ConvertToImage(size_t frame, wxImage *image) const
68{
69 size_t idx = m_info[frame].m_imageIndex;
70 *image = m_images[idx]; // copy
71 return image->Ok();
72}
73
74
75//---------------------------------------------------------------------------
76// Data accessors
77//---------------------------------------------------------------------------
78
79wxSize wxANIDecoder::GetFrameSize(size_t WXUNUSED(frame)) const
80{
81 // all frames are of the same size...
82 return m_szAnimation;
83}
84
85wxPoint wxANIDecoder::GetFramePosition(size_t WXUNUSED(frame)) const
86{
87 // all frames are of the same size...
88 return wxPoint(0,0);
89}
90
91wxAnimationDisposal wxANIDecoder::GetDisposalMethod(size_t WXUNUSED(frame)) const
92{
93 // this disposal is implicit for all frames inside an ANI file
94 return wxANIM_TOBACKGROUND;
95}
96
97long wxANIDecoder::GetDelay(size_t frame) const
98{
99 return m_info[frame].m_delay;
100}
101
102
103//---------------------------------------------------------------------------
104// ANI reading and decoding
105//---------------------------------------------------------------------------
106
107bool wxANIDecoder::CanRead(wxInputStream& stream) const
108{
109 wxInt32 FCC1, FCC2;
110 wxUint32 datalen ;
111
112 wxInt32 riff32;
113 memcpy( &riff32, "RIFF", 4 );
114 wxInt32 list32;
115 memcpy( &list32, "LIST", 4 );
116 wxInt32 ico32;
117 memcpy( &ico32, "icon", 4 );
118 wxInt32 anih32;
119 memcpy( &anih32, "anih", 4 );
120
121 stream.SeekI(0);
122 if ( !stream.Read(&FCC1, 4) )
123 return false;
124
125 if ( FCC1 != riff32 )
126 return false;
127
128 // we have a riff file:
129 while ( stream.IsOk() )
130 {
131 if ( FCC1 == anih32 )
132 return true; // found the ANIH chunk - this should be an ANI file
133
134 // we always have a data size:
135 stream.Read(&datalen, 4);
136 datalen = wxINT32_SWAP_ON_BE(datalen) ;
137
138 // data should be padded to make even number of bytes
139 if (datalen % 2 == 1) datalen ++ ;
140
141 // now either data or a FCC:
142 if ( (FCC1 == riff32) || (FCC1 == list32) )
143 {
144 stream.Read(&FCC2, 4);
145 }
146 else
147 {
148 stream.SeekI(stream.TellI() + datalen);
149 }
150
151 // try to read next data chunk:
152 if ( !stream.Read(&FCC1, 4) )
153 {
154 // reading failed -- either EOF or IO error, bail out anyhow
155 return false;
156 }
157 }
158
159 return false;
160}
161
162// the "anih" RIFF chunk
163struct wxANIHeader
164{
165 wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes)
166 wxInt32 cFrames; // Number of unique Icons in this cursor
167 wxInt32 cSteps; // Number of Blits before the animation cycles
168 wxInt32 cx; // width of the frames
169 wxInt32 cy; // height of the frames
170 wxInt32 cBitCount; // bit depth
171 wxInt32 cPlanes; // 1
172 wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present.
173 wxInt32 flags; // Animation Flag (see AF_ constants)
174};
175
176bool wxANIDecoder::Load( wxInputStream& stream )
177{
178 wxInt32 FCC1, FCC2;
179 wxUint32 datalen;
180 size_t globaldelay=0;
181
182 wxInt32 riff32;
183 memcpy( &riff32, "RIFF", 4 );
184 wxInt32 list32;
185 memcpy( &list32, "LIST", 4 );
186 wxInt32 ico32;
187 memcpy( &ico32, "icon", 4 );
188 wxInt32 anih32;
189 memcpy( &anih32, "anih", 4 );
190 wxInt32 rate32;
191 memcpy( &rate32, "rate", 4 );
192 wxInt32 seq32;
193 memcpy( &seq32, "seq ", 4 );
194
195 stream.SeekI(0);
196 stream.Read(&FCC1, 4);
197 if ( FCC1 != riff32 )
198 return false;
199
200 m_nFrames = 0;
201 m_szAnimation = wxDefaultSize;
202
203 m_images.Clear();
204 m_info.Clear();
205
206 // we have a riff file:
207 while ( stream.IsOk() )
208 {
209 // we always have a data size:
210 stream.Read(&datalen, 4);
211 datalen = wxINT32_SWAP_ON_BE(datalen);
212
213 //data should be padded to make even number of bytes
214 if (datalen % 2 == 1) datalen++;
215
216 // now either data or a FCC:
217 if ( (FCC1 == riff32) || (FCC1 == list32) )
218 {
219 stream.Read(&FCC2, 4);
220 }
221 else if ( FCC1 == anih32 )
222 {
223 if ( datalen != sizeof(wxANIHeader) )
224 return false;
225
226 if (m_nFrames > 0)
227 return false; // already parsed an ani header?
228
229 struct wxANIHeader header;
230 stream.Read(&header, sizeof(wxANIHeader));
231
232 // we should have a global frame size
233 m_szAnimation = wxSize(header.cx, header.cy);
234
235 // save interesting info from the header
236 m_nFrames = header.cSteps; // NB: not cFrames!!
237 if (m_nFrames==0)
238 return false;
239
240 globaldelay = wxINT32_SWAP_ON_BE(header.JifRate) * 1000 / 60;
241
242 m_images.Alloc(header.cFrames);
243 m_info.Add(wxANIFrameInfo(), m_nFrames);
244 }
245 else if ( FCC1 == rate32 )
246 {
247 // did we already process the anih32 chunk?
248 if (m_nFrames == 0)
249 return false; // rate chunks should always be placed after anih chunk
250
251 wxASSERT(m_info.GetCount() == m_nFrames);
252 for (size_t i=0; i<m_nFrames; i++)
253 {
254 stream.Read(&FCC2, 4);
255 m_info[i].m_delay = wxINT32_SWAP_ON_BE(FCC2) * 1000 / 60;
256 }
257 }
258 else if ( FCC1 == seq32 )
259 {
260 // did we already process the anih32 chunk?
261 if (m_nFrames == 0)
262 return false; // seq chunks should always be placed after anih chunk
263
264 wxASSERT(m_info.GetCount() == m_nFrames);
265 for (size_t i=0; i<m_nFrames; i++)
266 {
267 stream.Read(&FCC2, 4);
268 m_info[i].m_imageIndex = wxINT32_SWAP_ON_BE(FCC2);
269 }
270 }
271 else if ( FCC1 == ico32 )
272 {
273 // use DoLoadFile() and not LoadFile()!
274 wxImage image;
275 if (!sm_handler.DoLoadFile(&image, stream, false /* verbose */, -1))
276 return false;
277
278 m_images.Add(image);
279 }
280 else
281 stream.SeekI(stream.TellI() + datalen);
282
283 // try to read next data chunk:
284 stream.Read(&FCC1, 4);
285 }
286
287 if (m_nFrames==0)
288 return false;
289
290 if (m_nFrames==m_images.GetCount())
291 {
292 // if no SEQ chunk is available, display the frames in the order
293 // they were loaded
294 for (size_t i=0; i<m_nFrames; i++)
295 if (m_info[i].m_imageIndex == -1)
296 m_info[i].m_imageIndex = i;
297 }
298
299 // if some frame has an invalid delay, use the global delay given in the
300 // ANI header
301 for (size_t i=0; i<m_nFrames; i++)
302 if (m_info[i].m_delay == 0)
303 m_info[i].m_delay = globaldelay;
304
305 // if the header did not contain a valid frame size, try to grab
306 // it from the size of the first frame (all frames are of the same size)
307 if (m_szAnimation.GetWidth() == 0 ||
308 m_szAnimation.GetHeight() == 0)
309 m_szAnimation = wxSize(m_images[0].GetWidth(), m_images[0].GetHeight());
310
311 return m_szAnimation!=wxDefaultSize;
312}
313
314#endif // wxUSE_STREAMS && wxUSE_GIF