]>
git.saurik.com Git - wxWidgets.git/blob - src/common/anidecod.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/anidecod.cpp
3 // Purpose: wxANIDecoder, ANI reader for wxImage and wxAnimation
4 // Author: Francesco Montorsi
6 // Copyright: (c) Francesco Montorsi
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
17 #if wxUSE_STREAMS && wxUSE_GIF
20 #include "wx/palette.h"
25 #include "wx/anidecod.h"
28 wxCURHandler
wxANIDecoder::sm_handler
;
32 //---------------------------------------------------------------------------
34 //---------------------------------------------------------------------------
39 wxANIFrameInfo(size_t delay
= 0, int idx
= -1)
40 { m_delay
=delay
; m_imageIndex
=idx
; }
46 #include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
47 WX_DEFINE_OBJARRAY(wxImageArray
);
49 #include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
50 WX_DEFINE_OBJARRAY(wxANIFrameInfoArray
);
55 //---------------------------------------------------------------------------
57 //---------------------------------------------------------------------------
59 wxANIDecoder::wxANIDecoder()
63 wxANIDecoder::~wxANIDecoder()
67 bool wxANIDecoder::ConvertToImage(size_t frame
, wxImage
*image
) const
69 size_t idx
= m_info
[frame
].m_imageIndex
;
70 *image
= m_images
[idx
]; // copy
75 //---------------------------------------------------------------------------
77 //---------------------------------------------------------------------------
79 wxSize
wxANIDecoder::GetFrameSize(size_t WXUNUSED(frame
)) const
81 // all frames are of the same size...
85 wxPoint
wxANIDecoder::GetFramePosition(size_t WXUNUSED(frame
)) const
87 // all frames are of the same size...
91 wxAnimationDisposal
wxANIDecoder::GetDisposalMethod(size_t WXUNUSED(frame
)) const
93 // this disposal is implicit for all frames inside an ANI file
94 return wxANIM_TOBACKGROUND
;
97 long wxANIDecoder::GetDelay(size_t frame
) const
99 return m_info
[frame
].m_delay
;
103 //---------------------------------------------------------------------------
104 // ANI reading and decoding
105 //---------------------------------------------------------------------------
107 bool wxANIDecoder::CanRead(wxInputStream
& stream
) const
113 memcpy( &riff32
, "RIFF", 4 );
115 memcpy( &list32
, "LIST", 4 );
117 memcpy( &ico32
, "icon", 4 );
119 memcpy( &anih32
, "anih", 4 );
122 if ( !stream
.Read(&FCC1
, 4) )
125 if ( FCC1
!= riff32
)
128 // we have a riff file:
129 while ( stream
.IsOk() )
131 if ( FCC1
== anih32
)
132 return true; // found the ANIH chunk - this should be an ANI file
134 // we always have a data size:
135 stream
.Read(&datalen
, 4);
136 datalen
= wxINT32_SWAP_ON_BE(datalen
) ;
138 // data should be padded to make even number of bytes
139 if (datalen
% 2 == 1) datalen
++ ;
141 // now either data or a FCC:
142 if ( (FCC1
== riff32
) || (FCC1
== list32
) )
144 stream
.Read(&FCC2
, 4);
148 stream
.SeekI(stream
.TellI() + datalen
);
151 // try to read next data chunk:
152 if ( !stream
.Read(&FCC1
, 4) )
154 // reading failed -- either EOF or IO error, bail out anyhow
162 // the "anih" RIFF chunk
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)
176 bool wxANIDecoder::Load( wxInputStream
& stream
)
180 size_t globaldelay
=0;
183 memcpy( &riff32
, "RIFF", 4 );
185 memcpy( &list32
, "LIST", 4 );
187 memcpy( &ico32
, "icon", 4 );
189 memcpy( &anih32
, "anih", 4 );
191 memcpy( &rate32
, "rate", 4 );
193 memcpy( &seq32
, "seq ", 4 );
196 stream
.Read(&FCC1
, 4);
197 if ( FCC1
!= riff32
)
201 m_szAnimation
= wxDefaultSize
;
206 // we have a riff file:
207 while ( stream
.IsOk() )
209 // we always have a data size:
210 stream
.Read(&datalen
, 4);
211 datalen
= wxINT32_SWAP_ON_BE(datalen
);
213 //data should be padded to make even number of bytes
214 if (datalen
% 2 == 1) datalen
++;
216 // now either data or a FCC:
217 if ( (FCC1
== riff32
) || (FCC1
== list32
) )
219 stream
.Read(&FCC2
, 4);
221 else if ( FCC1
== anih32
)
223 if ( datalen
!= sizeof(wxANIHeader
) )
227 return false; // already parsed an ani header?
229 struct wxANIHeader header
;
230 stream
.Read(&header
, sizeof(wxANIHeader
));
232 // we should have a global frame size
233 m_szAnimation
= wxSize(header
.cx
, header
.cy
);
235 // save interesting info from the header
236 m_nFrames
= header
.cSteps
; // NB: not cFrames!!
240 globaldelay
= wxINT32_SWAP_ON_BE(header
.JifRate
) * 1000 / 60;
242 m_images
.Alloc(header
.cFrames
);
243 m_info
.Add(wxANIFrameInfo(), m_nFrames
);
245 else if ( FCC1
== rate32
)
247 // did we already process the anih32 chunk?
249 return false; // rate chunks should always be placed after anih chunk
251 wxASSERT(m_info
.GetCount() == m_nFrames
);
252 for (size_t i
=0; i
<m_nFrames
; i
++)
254 stream
.Read(&FCC2
, 4);
255 m_info
[i
].m_delay
= wxINT32_SWAP_ON_BE(FCC2
) * 1000 / 60;
258 else if ( FCC1
== seq32
)
260 // did we already process the anih32 chunk?
262 return false; // seq chunks should always be placed after anih chunk
264 wxASSERT(m_info
.GetCount() == m_nFrames
);
265 for (size_t i
=0; i
<m_nFrames
; i
++)
267 stream
.Read(&FCC2
, 4);
268 m_info
[i
].m_imageIndex
= wxINT32_SWAP_ON_BE(FCC2
);
271 else if ( FCC1
== ico32
)
273 // use DoLoadFile() and not LoadFile()!
275 if (!sm_handler
.DoLoadFile(&image
, stream
, false /* verbose */, -1))
281 stream
.SeekI(stream
.TellI() + datalen
);
283 // try to read next data chunk:
284 stream
.Read(&FCC1
, 4);
290 if (m_nFrames
==m_images
.GetCount())
292 // if no SEQ chunk is available, display the frames in the order
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
;
299 // if some frame has an invalid delay, use the global delay given in the
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
;
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());
311 return m_szAnimation
!=wxDefaultSize
;
314 #endif // wxUSE_STREAMS && wxUSE_GIF