Un Gif est composé de plusieurs images et l'on peut pour chacune d'entre elles affecter un temps d'affichage, c'est à dire que chaque image d'un Gif s'affiche plus ou mois longtemps selon le temps qui lui a été affecté.
Il se trouve que j'ai trouvé des images Gifs sur le net qui n'ont pas ce paramètre d'affichage pour chaque images, ce que j'ai pu vérifier avec Gif Movie Gear 4, cependant il semble qu'il y ai quelque part un timer qui permet de passer d'une image à une autre et qu'il soit différent d'un Gif à un autre (Le navigateur internet les affichent bien lui!) mais je ne sais pas où peut bien se trouver ce paramètre.
C'est pour cela que dans le premier code, si le programme ne trouve pas de temps affecté pour chaque image, je lui en attribut un par défaut de 250ms.
1er code:
Pour faire fonctionner ce code vous devez télécharger le package GDI+ de Denis dont vous trouverez le lien dans sa signature.Les fichiers gdiplus.pbi, gdiplus_Constants.pbi, gdiplus_GUID.pbi et gdiplus_Structures.pbi doivent se trouver dans le même répertoire que le source et la lib GdiPlus.lib se trouvant dans le package sous le dossier fichier_Lib_Vista32 doit être copier dans le dossier: PureBasic\PureLibraries\Windows\Libraries
Pour les OS inférieur à XP, il faut télécharger la dll redistribuable à mettre sous le même dossier que l'exécutable.
Lien de la dll:
gdiplus.zip
Voici un lien pour télécharger directement l'exécutable:
Gif_Animated
Si quelqu'un pouvait tester sous Win98 et dire si ça fonctionne, merci!
Code : Tout sélectionner
XIncludeFile "gdiplus.pbi"
Structure GIFDATA
; image
* image
; animation frame delays
* delays.PropertyItem
fTimerActive.l
nFrameCount.l
nCurrentFrame.l
EndStructure
Global pData.GIFDATA, * token
Declare gdiLoadImage( * pData.GIFDATA, * stream.IStream)
Declare OnPaint( * image)
Declare.l TestForAnimatedGIF( * pData.GIFDATA)
Procedure ProcedureCallback(Window, Message, wParam, lParam)
Resultat = #PB_ProcessPureBasicEvents
Select Message
Case #WM_TIMER
If wParam = 1
; stop the timer
KillTimer_(Window, 1)
; next frame
pData\nCurrentFrame = pData\nCurrentFrame + 1
If (pData\nCurrentFrame >= pData\nFrameCount) : pData\nCurrentFrame = 0 : EndIf
; restart the timer
Time = PeekL(pData\delays\value +(4 * pData\nCurrentFrame)) * 10
If Time = 0
Time = 250
EndIf
SetTimer_(Window, 1, Time, 0)
; change animation frame
GdipImageSelectActiveFrame(pData\image, ?FrameDimensionTime, pData\nCurrentFrame)
OnPaint(pData\image)
SetWindowTitle(0, "Frame N°:" + Str(pData\nCurrentFrame + 1) + " sur " + Str(pData\nFrameCount))
EndIf
Resultat = 0
Case #WM_PAINT
OnPaint(pData\image)
EndSelect
ProcedureReturn Resultat
EndProcedure
If OpenWindow(0, 100, 200, 400, 400, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
SetWindowCallback(@ProcedureCallback(), 0)
If CreateMenu(0, WindowID(0))
MenuTitle("Fichier")
MenuItem(1, "Charger une image Gif")
EndIf
* token = Gdiplus_New()
If (URLOpenBlockingStream_(0, "http://www.gifs-animes.net/images-image/Cartoons/Simpson/Simpson-21.gif", @ * stream.ISTREAM, 0, 0) = 0)
gdiLoadImage(pData, * stream)
* stream\Release()
EndIf
Repeat
Event.l = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
If (pData\image) : GdipDisposeImage(pData\image) : EndIf
FreeMemory(pData\delays)
Gdiplus_Del( * token)
quit = 1
Case #PB_Event_Menu
Select EventMenu()
Case 1
FichierParDefaut$ = "C:"
Filtre$ = "GIF Files|*.gif"
Filtre = 0
Fichier$ = OpenFileRequester("Choisissez un fichier à charger", FichierParDefaut$, Filtre$, Filtre)
If Fichier$
If (GdipCreateStreamOnFile(Fichier$, #GENERIC_READ, @ * stream.IStream) = #S_OK)
gdiLoadImage(@pData, * stream)
* stream\Release()
EndIf
EndIf
EndSelect
EndSelect
Until quit = 1
EndIf
Procedure gdiLoadImage( * pData.GIFDATA, * stream.IStream)
Debug * stream
If (GdipLoadImageFromStream( * stream, @ * image) = 0)
; stop animation
If ( * pData\fTimerActive)
KillTimer_(WindowID(0), 1)
* pData\fTimerActive = #False
EndIf
; switch images
If ( * pData\image) : GdipDisposeImage( * pData\image) : EndIf
* pData\image = * image
* pData\nCurrentFrame = 1
; grow client area if needed
GdipGetImageWidth( * pData\image, @imgwidth.l)
GdipGetImageHeight( * pData\image, @imgheight.l)
GetClientRect_(WindowID(0), @rc.RECT)
rc\right = imgwidth
rc\bottom = imgheight
AdjustWindowRect_(@rc, GetWindowLong_(WindowID(0), #GWL_STYLE), GetMenu_(WindowID(0)))
SetWindowPos_(WindowID(0), 0, 0, 0, rc\right - rc\left, rc\bottom - rc\top, #SWP_NOZORDER | #SWP_NOMOVE)
; restart animation
If TestForAnimatedGIF( * pData)
Time = PeekL(pData\delays\value) * 10
If Time = 0
Time = 250
EndIf
SetTimer_(WindowID(0), 1, Time, 0)
* pData\fTimerActive = #True
EndIf
; invalidate the client area
;InvalidateRect_(WindowID(0), #Null, #True)
OnPaint( * pData\image)
EndIf
EndProcedure
Procedure OnPaint( * image)
dc.l = GetDC_(WindowID(0))
Hbrush = CreateSolidBrush_(RGB(255, 255, 255))
GetClientRect_(WindowID(0), @rc.RECT)
FillRect_(dc, @rc, Hbrush)
If (GdipCreateFromHDC(dc, @ * graphics) = 0)
GdipDrawImageI( * graphics, * image, 0, 0)
GdipDeleteGraphics( * graphics)
EndIf
ReleaseDC_(WindowID(0), dc)
DeleteObject_(Hbrush)
EndProcedure
Procedure.l TestForAnimatedGIF( * pData.GIFDATA)
* pData\nFrameCount = 1
If ((GdipImageGetFrameDimensionsCount( * pData\image, @count) = 0) And count)
* pDimensionIDs.GUID = AllocateMemory(SizeOf(GUID) * count)
If * pDimensionIDs
; Get the List of frame dimensions from the Image object.
GdipImageGetFrameDimensionsList( * pData\image, * pDimensionIDs, count)
; Get the number of frames in the first dimension.
If ((GdipImageGetFrameCount( * pData\image, * pDimensionIDs, @ * pData\nFrameCount) = 0) And ( * pData\nFrameCount > 1))
; Assume that the image has a property item of type PropertyItemEquipMake.
; Get the size of that property item.
GdipGetPropertyItemSize( * pData\image, #PropertyTagFrameDelay, @nSize)
If ( * pData\delays) : FreeMemory( * pData\delays) : EndIf
If nSize <> 0
; Allocate a buffer to receive the property item.
* pData\delays = AllocateMemory(nSize)
If * pData\delays
GdipGetPropertyItem( * pData\image, #PropertyTagFrameDelay, nSize, * pData\delays)
EndIf
Else
* pData\nFrameCount = 1
EndIf
EndIf
FreeMemory( * pDimensionIDs)
EndIf
EndIf
ProcedureReturn * pData\nFrameCount
EndProcedure
2ème code:
Ce code ne fonctionne que sur Window XP et supérieur
Code : Tout sélectionner
Interface IShellImageDatasFactory Extends IUnknown
CreateIShellImageDatas(a.l)
;/ *[out] * / IShellImageDatas * * ppshimg) = 0;
CreateImageFromFile(a.p - unicode, b.l)
;/ *[in] * / LPCWSTR pszPath,
;/ *[out] * / IShellImageDatas * * ppshimg) = 0;
CreateImageFromStream(a.l, b.l)
;/ *[in] * / IStream * pStream,
;/ *[out] * / IShellImageDatas * * ppshimg) = 0;
GetDatasFormatFromPath(a.l, b.l)
;/ *[in] * / LPCWSTR pszPath,
;/ *[out] * / GUID * pDatasFormat) = 0;
EndInterface
Interface IShellImageDatas Extends IUnknown
Decode(a.l, b.l, c.l)
;/ *[in] * / DWORD dwFlags,
;/ *[in] * / ULONG cxDesired,
;/ *[in] * / ULONG cyDesired) = 0;
Draw(a.l, b.l, c.l)
;/ *[in] * / HDC hdc,
;/ *[in] * / LPRECT prcDest,
;/ *[in] * / LPRECT prcSrc) = 0;
NextFrame()
NextPage()
PrevPage()
IsTransparent()
IsAnimated()
IsVector()
IsMultipage()
IsEditable()
IsPrintable()
IsDecoded()
GetCurrentPage(a.l)
;/ *[out] * / ULONG * pnPage) = 0;
GetPageCount(a.l)
;/ *[out] * / ULONG * pcPages) = 0;
SelectPage(a.l)
;/ *[in] * / ULONG iPage) = 0;
GetSize(a.l)
;/ *[out] * / SIZE * pSize) = 0;
GetRawDatasFormat(a.l)
;/ *[out] * / GUID * pDatasFormat) = 0;
GetPixelFormat(a.l)
;/ *[out] * / PixelFormat * pFormat) = 0;
GetDelay(a.l)
;/ *[out] * / DWORD * pdwDelay) = 0;
GetProperties(a.l, b.l)
;/ *[in] * / DWORD dwMode,
;/ *[out] * / IPropertySetStorage * * ppPropSet) = 0;
Rotate(a.l)
;/ *[in] * / DWORD dwAngle) = 0;
Scale(a.l, b.l, c.l)
;/ *[in] * / ULONG cx,
;/ *[in] * / ULONG cy,
;/ *[in] * / InterpolationMode hints) = 0;
DiscardEdit()
SetEncoderParams(a.l)
;/ *[in] * / IPropertyBag * pbagEnc) = 0;
DisplayName(a.l, b.l)
;/ *[out][in] * / LPWSTR wszName,
;/ *[in] * / UINT cch) = 0;
GetResolution(a.l, b.l)
;/ *[out] * / ULONG * puResolutionX,
;/ *[out] * / ULONG * puResolutionY) = 0;
GetEncoderParams(a.l, b.l)
;/ *[in] * / GUID * pguidFmt,
;/ *[out] * / EncoderParameters * * ppEncParams) = 0;
;
RegisterAbort(a.l, b.l)
;/ *[in] * / IShellImageDatasAbort * pAbort,
;/ *[optional][out] * / IShellImageDatasAbort * * ppAbortPrev) = 0;
CloneFrame(a.l)
;/ *[out] * / Image * * ppImg) = 0;
ReplaceFrame(a.l)
;/ *[in] * / Image * pImg) = 0;
EndInterface
#CLSCTX_INPROC_SERVER = 1
#SHIMGDEC_DEFAULT = 0
CoInitialize_(0);
CallDebugger
;_dwstring wszPath[MAX_PATH]; // download a .gif to cache
wszPath.s = Space(#MAX_PATH)
If URLDownloadToCacheFile_(0, "http://www.gifs-animes.net/images-image/Disney/Blanche-neige/Blanche-neige-104.gif", @wszPath, #MAX_PATH, 0, 0) = 0
If CoCreateInstance_(?CLSID_ShellImageDatasFactory, #Null, #CLSCTX_INPROC_SERVER, ?IID_IShellImageDatasFactory, @ * factory.IShellImageDatasFactory) = 0
* Datas.IShellImageDatas
If * factory\CreateImageFromFile(wszPath, @ * Datas) = 0
* Datas\Decode(#SHIMGDEC_DEFAULT, 0, 0);
rc.RECT
rc\left = 0;
rc\top = 0;
* Datas\GetSize(@rc\right);
dc.l = GetDC_(0);
* Datas\Draw(dc, @rc, @rc);
If * Datas\IsAnimated() = 0
While GetAsyncKeyState_(#VK_ESCAPE) = 0
time.l
TextOut_(dc, 4, rc\bottom, "Press ESC to quit", 17);
* Datas\GetDelay(@time);
Sleep_(time);
If * Datas\NextFrame()
* Datas\SelectPage(0);
EndIf
Debug rc\right
Debug rc\bottom
InvalidateRect_(0, @rc, #True)
* Datas\Draw(dc, @rc, @rc);
Wend
Else
Sleep_(2000);
EndIf
ReleaseDC_(0, dc);
;/ / remove image from desktop
rc\bottom = rc\bottom + 20;
InvalidateRect_(0, @rc, #True);
* Datas\Release();
EndIf
* factory\Release();
EndIf
EndIf
CoUninitialize_();
Macro DefineGUID(IID, Data1, Data2, Data3, Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11)
DataSection
IID :
Data.l Data1
Data.w Data2, Data3
Data.b Data4, Data5, Data6, Data7, Data8, Data9, Data10, Data11
EndDataSection
EndMacro
DefineGUID(CLSID_ShellImageDatasFactory, $66e4e4fb, $f385, $4dd0, $8d, $74, $a2, $ef, $d1, $bc, $61, $78)
DefineGUID(IID_IShellImageDatasFactory, $9be8ed5c, $edab, $4d75, $90, $f3, $bd, $5b, $db, $b2, $1c, $82)