]>
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
5 // Copyright: (c) Francesco Montorsi
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
16 #if wxUSE_STREAMS && wxUSE_ICO_CUR
18 #include "wx/anidecod.h"
21 #include "wx/palette.h"
28 wxCURHandler
wxANIDecoder::sm_handler
;
30 //---------------------------------------------------------------------------
32 //---------------------------------------------------------------------------
37 wxANIFrameInfo(unsigned int delay
= 0, int idx
= -1)
38 { m_delay
=delay
; m_imageIndex
=idx
; }
44 #include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
45 WX_DEFINE_OBJARRAY(wxImageArray
)
47 #include "wx/arrimpl.cpp" // this is a magic incantation which must be done!
48 WX_DEFINE_OBJARRAY(wxANIFrameInfoArray
)
51 //---------------------------------------------------------------------------
53 //---------------------------------------------------------------------------
55 wxANIDecoder::wxANIDecoder()
59 wxANIDecoder::~wxANIDecoder()
63 bool wxANIDecoder::ConvertToImage(unsigned int frame
, wxImage
*image
) const
65 unsigned int idx
= m_info
[frame
].m_imageIndex
;
66 *image
= m_images
[idx
]; // copy
71 //---------------------------------------------------------------------------
73 //---------------------------------------------------------------------------
75 wxSize
wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame
)) const
77 // all frames are of the same size...
81 wxPoint
wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame
)) const
83 // all frames are of the same size...
87 wxAnimationDisposal
wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame
)) const
89 // this disposal is implicit for all frames inside an ANI file
90 return wxANIM_TOBACKGROUND
;
93 long wxANIDecoder::GetDelay(unsigned int frame
) const
95 return m_info
[frame
].m_delay
;
98 wxColour
wxANIDecoder::GetTransparentColour(unsigned int frame
) const
100 unsigned int idx
= m_info
[frame
].m_imageIndex
;
102 if (!m_images
[idx
].HasMask())
105 return wxColour(m_images
[idx
].GetMaskRed(),
106 m_images
[idx
].GetMaskGreen(),
107 m_images
[idx
].GetMaskBlue());
111 //---------------------------------------------------------------------------
112 // ANI reading and decoding
113 //---------------------------------------------------------------------------
115 bool wxANIDecoder::DoCanRead(wxInputStream
& stream
) const
121 memcpy( &riff32
, "RIFF", 4 );
123 memcpy( &list32
, "LIST", 4 );
125 memcpy( &ico32
, "icon", 4 );
127 memcpy( &anih32
, "anih", 4 );
129 if ( stream
.IsSeekable() && stream
.SeekI(0) == wxInvalidOffset
)
134 if ( !stream
.Read(&FCC1
, 4) )
137 if ( FCC1
!= riff32
)
140 // we have a riff file:
141 while ( stream
.IsOk() )
143 if ( FCC1
== anih32
)
144 return true; // found the ANIH chunk - this should be an ANI file
146 // we always have a data size:
147 stream
.Read(&datalen
, 4);
148 datalen
= wxINT32_SWAP_ON_BE(datalen
) ;
150 // data should be padded to make even number of bytes
151 if (datalen
% 2 == 1) datalen
++ ;
153 // now either data or a FCC:
154 if ( (FCC1
== riff32
) || (FCC1
== list32
) )
156 stream
.Read(&FCC2
, 4);
160 if ( stream
.SeekI(stream
.TellI() + datalen
) == wxInvalidOffset
)
164 // try to read next data chunk:
165 if ( !stream
.Read(&FCC1
, 4) )
167 // reading failed -- either EOF or IO error, bail out anyhow
175 // the "anih" RIFF chunk
178 wxInt32 cbSizeOf
; // Num bytes in AniHeader (36 bytes)
179 wxInt32 cFrames
; // Number of unique Icons in this cursor
180 wxInt32 cSteps
; // Number of Blits before the animation cycles
181 wxInt32 cx
; // width of the frames
182 wxInt32 cy
; // height of the frames
183 wxInt32 cBitCount
; // bit depth
184 wxInt32 cPlanes
; // 1
185 wxInt32 JifRate
; // Default Jiffies (1/60th of a second) if rate chunk not present.
186 wxInt32 flags
; // Animation Flag (see AF_ constants)
188 // ANI files are always little endian so we need to swap bytes on big
189 // endian architectures
190 #ifdef WORDS_BIGENDIAN
191 void AdjustEndianness()
193 // this works because all our fields are wxInt32 and they must be
194 // packed without holes between them (if they're not, they wouldn't map
195 // to the file header!)
196 wxInt32
* const start
= (wxInt32
*)this;
197 wxInt32
* const end
= start
+ sizeof(wxANIHeader
)/sizeof(wxInt32
);
198 for ( wxInt32
*p
= start
; p
!= end
; p
++ )
200 *p
= wxINT32_SWAP_ALWAYS(*p
);
204 void AdjustEndianness() { }
208 bool wxANIDecoder::Load( wxInputStream
& stream
)
212 unsigned int globaldelay
=0;
215 memcpy( &riff32
, "RIFF", 4 );
217 memcpy( &list32
, "LIST", 4 );
219 memcpy( &ico32
, "icon", 4 );
221 memcpy( &anih32
, "anih", 4 );
223 memcpy( &rate32
, "rate", 4 );
225 memcpy( &seq32
, "seq ", 4 );
227 if ( stream
.IsSeekable() && stream
.SeekI(0) == wxInvalidOffset
)
232 if ( !stream
.Read(&FCC1
, 4) )
234 if ( FCC1
!= riff32
)
238 m_szAnimation
= wxDefaultSize
;
243 // we have a riff file:
244 while ( !stream
.Eof() )
246 // we always have a data size:
247 if (!stream
.Read(&datalen
, 4))
250 datalen
= wxINT32_SWAP_ON_BE(datalen
);
252 //data should be padded to make even number of bytes
253 if (datalen
% 2 == 1) datalen
++;
255 // now either data or a FCC:
256 if ( (FCC1
== riff32
) || (FCC1
== list32
) )
258 if (!stream
.Read(&FCC2
, 4))
261 else if ( FCC1
== anih32
)
263 if ( datalen
!= sizeof(wxANIHeader
) )
267 return false; // already parsed an ani header?
269 struct wxANIHeader header
;
270 if (!stream
.Read(&header
, sizeof(wxANIHeader
)))
272 header
.AdjustEndianness();
274 // we should have a global frame size
275 m_szAnimation
= wxSize(header
.cx
, header
.cy
);
277 // save interesting info from the header
278 m_nFrames
= header
.cSteps
; // NB: not cFrames!!
279 if ( m_nFrames
== 0 )
282 globaldelay
= header
.JifRate
* 1000 / 60;
284 m_images
.Alloc(header
.cFrames
);
285 m_info
.Add(wxANIFrameInfo(), m_nFrames
);
287 else if ( FCC1
== rate32
)
289 // did we already process the anih32 chunk?
291 return false; // rate chunks should always be placed after anih chunk
293 wxASSERT(m_info
.GetCount() == m_nFrames
);
294 for (unsigned int i
=0; i
<m_nFrames
; i
++)
296 if (!stream
.Read(&FCC2
, 4))
298 m_info
[i
].m_delay
= wxINT32_SWAP_ON_BE(FCC2
) * 1000 / 60;
301 else if ( FCC1
== seq32
)
303 // did we already process the anih32 chunk?
305 return false; // seq chunks should always be placed after anih chunk
307 wxASSERT(m_info
.GetCount() == m_nFrames
);
308 for (unsigned int i
=0; i
<m_nFrames
; i
++)
310 if (!stream
.Read(&FCC2
, 4))
312 m_info
[i
].m_imageIndex
= wxINT32_SWAP_ON_BE(FCC2
);
315 else if ( FCC1
== ico32
)
317 // use DoLoadFile() and not LoadFile()!
319 if (!sm_handler
.DoLoadFile(&image
, stream
, false /* verbose */, -1))
322 image
.SetType(wxBITMAP_TYPE_ANI
);
327 if ( stream
.SeekI(stream
.TellI() + datalen
) == wxInvalidOffset
)
331 // try to read next data chunk:
332 if ( !stream
.Read(&FCC1
, 4) && !stream
.Eof())
334 // we didn't reach the EOF! An other kind of error has occurred...
337 //else: proceed with the parsing of the next header block or
338 // exiting this loop (if stream.Eof() == true)
344 if (m_nFrames
==m_images
.GetCount())
346 // if no SEQ chunk is available, display the frames in the order
348 for (unsigned int i
=0; i
<m_nFrames
; i
++)
349 if (m_info
[i
].m_imageIndex
== -1)
350 m_info
[i
].m_imageIndex
= i
;
353 // if some frame has an invalid delay, use the global delay given in the
355 for (unsigned int i
=0; i
<m_nFrames
; i
++)
356 if (m_info
[i
].m_delay
== 0)
357 m_info
[i
].m_delay
= globaldelay
;
359 // if the header did not contain a valid frame size, try to grab
360 // it from the size of the first frame (all frames are of the same size)
361 if (m_szAnimation
.GetWidth() == 0 ||
362 m_szAnimation
.GetHeight() == 0)
363 m_szAnimation
= wxSize(m_images
[0].GetWidth(), m_images
[0].GetHeight());
365 return m_szAnimation
!= wxDefaultSize
;
368 #endif // wxUSE_STREAMS && wxUSE_ICO_CUR