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