Lecture d'un Gif animé

Partagez votre expérience de PureBasic avec les autres utilisateurs.
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Lecture d'un Gif animé

Message par nico »

J'ai traduit deux codes de Sapero du Forum Aurora Compiler et Emergence Basic qui permettent d'afficher des Gifs animés.

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)
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Lecture d'un Gif animé

Message par djes »

Pas de problème, ça fonctionne très bien! Merci pour ce très bon code, j'en connais un qui va être content ;)

Au passage, tu pourrais nous faire un zip et le mettre sur le site de GallyHC, c'est vachement pratique :)
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Lecture d'un Gif animé

Message par Kwai chang caine »

Enfin un maitre qui décide de se pencher sur ce que la TEAM dédaigne 8)
Merci mille fois NICO de te pencher sur ces jolies petites images que j'adore et surtout de partager le fruit de ton travail.

Parce que travail....c'est rien de le dire..
C'est un truc de fou tout ce qu'il faut comme instructions de la mort pour juste un petit personnage 8O

On perçoit une idée de ce que voulais dire FREAK...mais ça n'empeche pas que les GIFS font partie integrante de la programmation et sont tout aussi present que les autres formats, si ce n'est plus :?

Par contre comme d'habitude car comme moi je change jamais une equipe qui perd :oops:
Et bien le petit nain, il saccade un max
J'ai enlevé le debugger et commenté les lignes de DEBUG
Mais il saccade toujours un max :(

Quand je pense NICO y sort un code a etre foudroyé droit debout ...et KCC il arrive meme pas a appuyer sur "on" :oops:
J'ai XP, et essayé la v4.30 et 4.40B5 ça fait pareil.

En tout cas encore merci, c'est vraiment génial...
Et qu'il en prenne de la graine .....Car tu prouve une fois de plus ....que le "FRIC" ne fait pas tout :lol:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Lecture d'un Gif animé

Message par nico »

Merci mille fois NICO de te pencher sur ces jolies petites images que j'adore et surtout de partager le fruit de ton travail.
Oui, mais bon je n'ai fait que traduire un code parce que moi j'en serais incapable!
Et encore j'ai pu le faire parce que Denis nous a pondu une merveilleuse aide sur GDI+, car certaines fonctions sont hard à comprendre.
C'est un truc de fou tout ce qu'il faut comme instructions de la mort pour juste un petit personnage 8O
Là, je suis entièrement d'accord avec toi.
Et bien le petit nain, il saccade un max
Tu parle du deuxième code?
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Lecture d'un Gif animé

Message par Kwai chang caine »

En tout cas c'est super cool, meme de traduire :wink:

Oui oui, je parle du deuxieme code, je sais pas si c'est normal....ou si encore une fois ça n'arrive qu'a moi :(
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
nico
Messages : 3702
Inscription : ven. 13/févr./2004 0:57

Re: Lecture d'un Gif animé

Message par nico »

Oui, c'est normal c'est pareil chez moi; c'est à cause des invalidaterect du fait qu'on affiche le Gif sur le bureau plutôt que dans une fenêtre.
Pour bien faire, faudrait afficher le Gif dans une fenêtre voire dans un imagegadget.
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Lecture d'un Gif animé

Message par Kwai chang caine »

Ah d'accord :D
Encore merci 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Répondre