Jump to content


Photo

[MULTILENGUAJE]New GifViewer, versión GDI+ polivalente


  • Please log in to reply
7 replies to this topic

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 06 September 2018 - 10:01 AM

Hace algún tiempo publiqué una clase TGif que mostraba como es el estándar de ese formato y permitía extraer las imágenes, crear archivos gif desde varias imágenes, o crear un visor como el que publiqué aquí. La clase TGif estaba orientada a la VCL usando alguno de sus componentes, el visor TGifViewer pecaba de lo mismo.

Hoy os quiero presentar otro visor gif completamente distinto basado en el uso de GDI+ con lo que la dependencia de Windows es total pero ahorra mucho código. Este visor es totalmente independiente de la VCL y usará cualquier ventana, incluidas las de la VCL, para visualizar en ella nuestro gif. Para ello intercepta la función de tratamiento de mensajes evitando que se procese el mensaje WM_PAINT y controlando un evento que servirá para sincronizar un Thread. Este Thread será el encargado de realizar la visualización del gif.

El visor está implementado como una clase y no como un componente pero es muy intuitivo y fácil de usar, además de su constructor y destructor, tiene los siguientes métodos:
GifView(Handle: HWND; FileName: PWCHAR) Establece el fichero y la ventana donde se representará y comienza la visualización.
Finish: Termina la visualización pero no libera la ventana.
Start: Comienza la visualización si ya tenemos fichero y ventana
SetHandle(Handle: THANDLE): Asocia el visor a una ventana.
LoadFile(FileName: PWCHAR): Abre un fichero gif y obtiene sus características
GetWidth: Nos informa del ancho
GetHeight: Nos informa del alto
GetFrames: Nos informa del número de imágenes del gif

La característica fundamental de este visor es que cualquier ventana puede servir como “pantalla” y también funcionará en aplicaciones que no sean VCL, es decir, aplicaciones Windows API puras.

El código de la clase es el siguiente:


delphi
  1. unit _GifViewer;
  2.  
  3. //------------------------------------------------------------------------------
  4. // GifViewer V 2.0
  5. // escafandra 2018
  6. // Clase para representar un gif estático o animado sobre cualquier ventana.
  7. // Usa GDI+
  8.  
  9.  
  10. interface
  11.  
  12. uses Windows, Messages;
  13.  
  14. //function SetWindowLongPtr(hWnd: HWND; nIndex: Integer; dwNewLong: Pointer): Pointer; stdcall external 'user32';
  15. function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): DWORD; stdcall external 'gdiplus';
  16. function GdipLoadImageFromFile(lpFileName: PWideChar; var hImage: THANDLE): DWORD; stdcall external 'gdiplus';
  17. function GdipDrawImageRectI(hGraphics, hImage: THANDLE; Left, Top, Width, Height: Integer): DWORD; stdcall external 'gdiplus';
  18. function GdipCreateFromHDC(DC: HDC; var hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
  19. function GdipImageSelectActiveFrame(hImage: THANDLE; DimensionID: PGUID; frameIndex: Integer): DWORD; stdcall external 'gdiplus';
  20. function GdipImageGetFrameDimensionsList(hImage: THANDLE; dimensionIDs: PGUID; Count: Integer): DWORD; stdcall external 'gdiplus';
  21. function GdipGetPropertyItemSize(hImage: THANDLE; dwPropId: Integer; var Size: UINT): Integer; stdcall external 'gdiplus';
  22. function GdipGetPropertyItem(hImage: THANDLE; dwPropID, Size: Integer; lpBuffer: Pointer): DWORD; stdcall external 'gdiplus';
  23. function GdipImageGetFrameCount(hImage: THANDLE; lpDimensionID: PGUID; out Count: UINT): DWORD; stdcall external 'gdiplus';
  24. function GdipGetImageWidth(hImage: THANDLE; var Width: UINT): DWORD; stdcall external 'gdiplus';
  25. function GdipGetImageHeight(hImage: THANDLE; var Height: UINT): DWORD; stdcall external 'gdiplus';
  26. function GdipDeleteGraphics(hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
  27. function GdipDisposeImage(hImage: THANDLE): DWORD; stdcall external 'gdiplus';
  28. procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
  29.  
  30. type
  31. TGifViewer = class
  32. private
  33. Wnd: HWND;
  34. OldWndProc: Pointer;
  35. OldUserData: DWORD;
  36. gdiplusToken: DWORD;
  37. hThread: THANDLE;
  38. hGdipImage: THANDLE;
  39. Width: integer;
  40. Height: integer;
  41. Frames: UINT;
  42. function WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  43.  
  44. public
  45. Left: integer;
  46. Top: integer;
  47. function GifView(Handle: HWND; FileName: PWCHAR): boolean;
  48. function SetHandle(Handle: THANDLE): boolean;
  49. function LoadFile(FileName: PWCHAR): boolean;
  50. function GetWidth: integer;
  51. function GetHeight: integer;
  52. function GetFrames: UINT;
  53. function Start: boolean;
  54. procedure Finish;
  55.  
  56. constructor Create;
  57. destructor Destroy; override;
  58. end;
  59. PGifViewer = ^TGifViewer;
  60.  
  61. TPropertyItem = record
  62. id: ULONG;
  63. length: ULONG;
  64. _type: WORD;
  65. value: Pointer;
  66. end;
  67. PPropertyItem = ^TPropertyItem;
  68.  
  69. const
  70. PropertyTagFrameDelay = $5100;
  71. var
  72. GDI: DWORD = 0;
  73. hEvent: THandle = 0;
  74.  
  75. implementation
  76.  
  77. function RePaintWindow(Wnd: HWND): boolean;
  78. var
  79. Rect: TRect;
  80. begin
  81. GetClientRect(Wnd, Rect);
  82. Result:= RedrawWindow(Wnd, @Rect, 0, RDW_INVALIDATE or RDW_ERASE or RDW_UPDATENOW or RDW_ALLCHILDREN);
  83. end;
  84.  
  85. function ThGif(GV: TGifViewer): DWORD; stdcall;
  86. var
  87. Wait: PIntegerArray;
  88. Pi: PPropertyItem;
  89. DC: HDC;
  90. hGdipGraphics: THANDLE;
  91. nBytes, Frames, Index: UINT;
  92. FrameDimensionTime: TGUID;
  93. begin
  94. // Esperamos a que se pinte una ventana WM_PAINT
  95. if hEvent <> 0 then WaitForSingleObject(hEvent, INFINITE);
  96.  
  97. if (GV.hGdipImage <> 0) and (GV.Wnd <> 0) then
  98. begin
  99. GdipGetPropertyItemSize(GV.hGdipImage, PropertyTagFrameDelay, nBytes);
  100. Pi:= Pointer(LocalAlloc(LMEM_FIXED, nBytes));
  101. GdipGetPropertyItem(GV.hGdipImage, PropertyTagFrameDelay, nBytes, Pi);
  102. GdipImageGetFrameDimensionsList(GV.hGdipImage, @FrameDimensionTime, 1);
  103. GdipImageGetFrameCount(GV.hGdipImage, @FrameDimensionTime, Frames);
  104.  
  105. Index:= 0;
  106. Wait:= PIntegerArray(Pi.value);
  107. if Pi._type = sizeof(DWORD) then
  108. repeat
  109. DC:= GetDC(GV.Wnd);
  110. GdipCreateFromHDC(DC, hGdipGraphics);
  111. GdipImageSelectActiveFrame(GV.hGdipImage, @FrameDimensionTime, Index);
  112. GdipDrawImageRectI(hGdipGraphics, GV.hGdipImage, GV.Left, GV.Top, GV.Width, GV.Height);
  113. GdipDeleteGraphics(hGdipGraphics);
  114. ReleaseDC(GV.Wnd, DC);
  115. Sleep(Wait[Index] * 10);
  116. Index:= (Index + 1) mod Frames;
  117. until (GV.Wnd = 0) or (GV.hGdipImage = 0);
  118. end;
  119. LocalFree(HLOCAL(Pi));
  120. Result:= 0;
  121. end;
  122.  
  123. function DefWndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  124. var
  125. pGifViewer: TGifViewer;
  126. begin
  127. if (Msg = WM_PAINT) and (hEvent <> 0) then SetEvent(hEvent); // Pemitimos que arranque el Thread
  128.  
  129. pGifViewer:= TGifViewer(GetWindowLong(Handle, GWL_USERDATA));
  130. if pGifViewer <> nil then
  131. Result:= pGifViewer.WndProc(Handle, Msg, WParam, LParam)
  132. else
  133. Result:= DefWindowProc(Handle, Msg, WParam, LParam);
  134. end;
  135.  
  136. function TGifViewer.WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  137. var
  138. R: TRect;
  139. begin
  140. if (Msg = WM_PAINT) and (hGdipImage <> 0) then
  141. begin
  142. R.Left:= Left; R.Top:= Top; R.Right:= Left+Width; R.Bottom:= Top+Height;
  143. ValidateRect(Wnd, @R);
  144. //Result:= DefWindowProc(Handle, Msg, WParam, LParam);
  145. //Exit;
  146. end;
  147. Result:= CallWindowProc(OldWndProc, Handle, Msg, WParam, LParam);
  148. end;
  149.  
  150. function TGifViewer.SetHandle(Handle: THANDLE): boolean;
  151. begin
  152. Result:= false;
  153. if(Pointer(GetWindowLong(Handle, GWL_WNDPROC)) <> @DefWndProc) then
  154. begin
  155. SuspendThread(hThread);
  156. if (Wnd <> 0) then
  157. begin
  158. SetWindowLong(Wnd, GWL_USERDATA, OldUserData);
  159. SetWindowLong(Wnd, GWL_WNDPROC, LongInt(OldWndProc));
  160. RePaintWindow(Wnd);
  161. Wnd:= 0;
  162. end;
  163.  
  164. if (Handle <> 0) and IsWindow(Handle) then
  165. begin
  166. Wnd:= Handle;
  167. OldUserData:= SetWindowLong(Wnd, GWL_USERDATA, LongInt(self));
  168. OldWndProc:= Pointer(SetWindowLong(Wnd, GWL_WNDPROC, LongInt(@DefWndProc)));
  169. RePaintWindow(Wnd);
  170. end;
  171. Result:= true;
  172. ResumeThread(hThread);
  173. end;
  174. end;
  175.  
  176. function TGifViewer.LoadFile(FileName: PWCHAR): boolean;
  177. var
  178. FrameDimensionTime: TGUID;
  179. begin
  180. Finish;
  181. if GdipLoadImageFromFile(FileName, hGdipImage) = 0 then
  182. begin
  183. GdipGetImageWidth(hGdipImage, UINT(Width));
  184. GdipGetImageHeight(hGdipImage, UINT(Height));
  185. GdipImageGetFrameDimensionsList(hGdipImage, @FrameDimensionTime, 1);
  186. GdipImageGetFrameCount(hGdipImage, @FrameDimensionTime, UINT(Frames));
  187. end
  188. else hGdipImage:= 0;
  189.  
  190. Result:= hGdipImage <> 0;
  191. end;
  192.  
  193. function TGifViewer.GifView(Handle: HWND; FileName: PWCHAR): boolean;
  194. begin
  195. Finish;
  196. LoadFile(FileName);
  197. SetHandle(Handle);
  198. Result:= Start;
  199. end;
  200.  
  201. procedure TGifViewer.Finish;
  202. begin
  203. if hGdipImage <> 0 then
  204. begin
  205. GdipDisposeImage(hGdipImage);
  206. hGdipImage:= 0;
  207. WaitForSingleObject(hThread, INFINITE);
  208. CloseHandle(hThread);
  209. hThread:= 0;
  210. end;
  211. RePaintWindow(Wnd);
  212. end;
  213.  
  214. function TGifViewer.Start(): boolean;
  215. begin
  216. if (Wnd <> 0) and (hGdipImage <> 0) and (hThread = 0) then
  217. hThread:= CreateThread(nil, 0, @ThGif, self, 0, PDWORD(0)^);
  218. Result:= hThread <> 0;
  219. end;
  220.  
  221. function TGifViewer.GetWidth: integer;
  222. begin
  223. Result:= Width;
  224. end;
  225.  
  226. function TGifViewer.GetHeight: integer;
  227. begin
  228. Result:= Height;
  229. end;
  230.  
  231. function TGifViewer.GetFrames: UINT;
  232. begin
  233. Result:= Frames;
  234. end;
  235.  
  236. constructor TGifViewer.Create;
  237. var
  238. GdiPlusStartupInput: array[0..2] of int64;
  239. begin
  240. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0;
  241. if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) = 0 then inc(GDI);
  242. if hEvent = 0 then hEvent:= CreateEvent(nil, true, false, nil);
  243. end;
  244.  
  245. destructor TGifViewer.Destroy;
  246. begin
  247. dec(GDI);
  248. Finish;
  249. SetHandle(0);
  250. if GDI = 0 then GdiplusShutdown(gdiplusToken);
  251. inherited Destroy;
  252. end;
  253.  
  254. end.

Un ejemplo con VCL:


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, _GifViewer, StdCtrls, ExtCtrls;
  8.  
  9. type
  10. TForm1 = class(TForm)
  11. Panel1: TPanel;
  12. Button1: TButton;
  13. OpenDialog1: TOpenDialog;
  14. Panel2: TPanel;
  15. Button2: TButton;
  16. Button3: TButton;
  17. Button4: TButton;
  18. procedure FormCreate(Sender: TObject);
  19. procedure Button1Click(Sender: TObject);
  20. procedure Button2Click(Sender: TObject);
  21. procedure Button3Click(Sender: TObject);
  22. procedure Button4Click(Sender: TObject);
  23. private
  24. GV1: TGifViewer;
  25. GV2: TGifViewer;
  26. public
  27. { Public declarations }
  28. end;
  29.  
  30. var
  31. Form1: TForm1;
  32.  
  33. implementation
  34.  
  35. {$R *.dfm}
  36.  
  37. procedure TForm1.FormCreate(Sender: TObject);
  38. begin
  39. GV1:= TGifViewer.Create;
  40. GV2:= TGifViewer.Create;
  41. //GV1.GifView(Panel1.Handle, 'Muerte.gif');
  42. if not GV1.GifView(Panel1.Handle, 'Muerte.gif') then GV1.SetHandle(0);
  43. end;
  44.  
  45. procedure TForm1.Button1Click(Sender: TObject);
  46. begin
  47. if OpenDialog1.Execute then
  48. GV1.GifView(Panel1.Handle, PWCHAR(WideString(OpenDialog1.FileName)));
  49. end;
  50.  
  51. procedure TForm1.Button2Click(Sender: TObject);
  52. begin
  53. if OpenDialog1.Execute then
  54. begin
  55. if GV2 = nil then GV2:= TGifViewer.Create;
  56. GV2.GifView(Panel2.Handle, PWCHAR(WideString(OpenDialog1.FileName)));
  57. end;
  58. end;
  59.  
  60. procedure TForm1.Button3Click(Sender: TObject);
  61. begin
  62. GV2.Free;
  63. GV2:= nil;
  64. end;
  65.  
  66. procedure TForm1.Button4Click(Sender: TObject);
  67. begin
  68. if Assigned(GV2) then
  69. begin
  70. GV1.SetHandle(0);
  71. // GV2.SetHandle(0);
  72. GV2.SetHandle(Panel1.Handle);
  73. end;
  74. end;
  75.  
  76. end.

Un ejemplo usando sólo API:


delphi
  1. program GifTopMost;
  2.  
  3. uses
  4. Windows,
  5. Messages,
  6. _GifViewer;
  7.  
  8. var
  9. lpFileName: PWCHAR;
  10. GV: TGifViewer;
  11. WinClass: WNDCLASS;
  12. Rect: TRect;
  13. hFrame: HWND;
  14. Msg: TMsg;
  15.  
  16. begin
  17. if ParamStr(1) = '' then
  18. lpFileName := 'muerte.gif'
  19. else
  20. lpFileName:= PWideChar(WideString(ParamStr(1)));
  21.  
  22. // Abrimos un archivo Gif para saber sus dimnesiones y crear una ventana
  23. GV:= TGifViewer.Create;
  24. GV.LoadFile(lpFileName);
  25.  
  26. // Creamos una ventana...
  27. GetClientRect(GetDesktopWindow, Rect);
  28. ZeroMemory(@WinClass, sizeof(WinClass));
  29. WinClass.lpfnWndProc:= @DefWindowProc;
  30. WinClass.lpszClassName:= 'GIFFRAME';
  31. WinClass.hCursor:= LoadCursor(0, IDC_ARROW);
  32. RegisterClass(WinClass);
  33. hFrame:= CreateWindowEx(WS_EX_LAYERED or WS_EX_TOPMOST or WS_EX_TOOLWINDOW, 'GIFFRAME', '', WS_VISIBLE or WS_POPUP,
  34. (Rect.right - integer(GV.GetWidth)) div 2,
  35. (Rect.bottom - integer(GV.GetHeight)) div 2,
  36. GV.GetWidth, GV.GetHeight,
  37. HWND_DESKTOP, HMENU(0), 0, nil);
  38. SetLayeredWindowAttributes(hFrame, 0, 220, LWA_ALPHA);
  39.  
  40. GV.SetHandle(hFrame); // Asociamos el Handle de nuestra ventana donde pintará el Gif
  41. if GV.Start then // Si el Gif arranca iniciamos el bucle de mensajes de la app
  42. repeat
  43. GetMessage(Msg, 0, 0, 0);
  44. TranslateMessage(Msg);
  45. DispatchMessage(Msg);
  46. until not IsWindow(hFrame);
  47.  
  48. // Alt+F4 Cerrará la ventana y termina la app
  49. GV.Free;
  50. end.

 
 
Está probado en delphi 6, 7, y Berlin.
 
Por las limitaciones de D6 y 7 he usado la API SetWindowLong para realizar el subclassing. En el caso de querer compilar para 64bits debería usarse SetWindowLongPtr. más abajo publico una versión de la clase adaptada a Lazarus que está preparada para compilar a 32 y 64 bits y puede servir de guía. Aprovechando la adaptación a Lazarus, he incluido alguna pequeña mejora a la clase que publico en las entradas correspondientes a delphi y C++
 

Saludos.

Attached Files


  • 1

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 06 September 2018 - 10:24 AM

Ahora le toca a C++ aunque en realidad el código delphi es una traducción y adaptación del código inicialmente escrito en C++.

La clase es totalmente equivalente a la mostrada.
 
GifViewer.h


cpp
  1. //------------------------------------------------------------------------------
  2. // GifViewer V 2.0
  3. // escafandra 2018
  4. // Clase para representar un gif estático o animado sobre cualquier ventana.
  5. // Usa GDI+
  6.  
  7. #ifndef GifViewer_H
  8. #define GifViewer_H
  9.  
  10. #include <windows.h>
  11.  
  12. #ifndef STRICT
  13. typedef int (__stdcall *PLRESULT)();
  14. #else
  15. typedef WNDPROC PLRESULT;
  16. #endif
  17.  
  18. class TGifViewer
  19. {
  20. private:
  21. ULONG_PTR gdiplusToken;
  22. HWND hWnd;
  23. PLRESULT OldWndProc;
  24. LONG_PTR OldUserData;
  25. HANDLE hThread;
  26. HANDLE hGdipImage;
  27. INT Width;
  28. INT Height;
  29. UINT Frames;
  30.  
  31. static HANDLE hEvent;
  32. static DWORD GDI;
  33.  
  34. static LRESULT __stdcall DefWndProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM LParam);
  35. LRESULT __stdcall WndProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM LParam);
  36. static DWORD __stdcall ThGif(PVOID GifViewer);
  37.  
  38. public:
  39. INT Left;
  40. INT Top;
  41. BOOL GifView(HWND hWnd, PWCHAR FileName);
  42. BOOL SetHandle(HWND hWnd);
  43. BOOL LoadFile(PWCHAR FileName);
  44. INT GetWidth() {return Width;}
  45. INT GetHeight() {return Height;}
  46. UINT GetFrames() {return Frames;}
  47. BOOL Start();
  48. void End();
  49.  
  50. TGifViewer();
  51. ~TGifViewer();
  52. };
  53.  
  54. #endif

GifViewer.cpp


cpp
  1. //------------------------------------------------------------------------------
  2. // GifViewer V 2.0
  3. // escafandra 2018
  4. // Clase para representar un gif estático o animado sobre cualquier ventana.
  5. // Usa GDI+
  6.  
  7.  
  8. #include <windows.h>
  9. #include <initguid.h>
  10. #pragma hdrstop
  11. #include "GifViewer.h"
  12.  
  13. #pragma link "gdiplus.lib"
  14.  
  15. extern "C"{
  16. DWORD __stdcall GdiplusStartup(ULONG_PTR *hToken, void *input, void *Output);
  17. void __stdcall GdiplusShutdown(ULONG_PTR token);
  18. DWORD __stdcall GdipLoadImageFromFile(PWCHAR FileName, HANDLE &hImage);
  19. DWORD __stdcall GdipDrawImageRectI(HANDLE hGraphics, HANDLE hImage, INT Left, INT Top, INT Width, INT Height);
  20. DWORD __stdcall GdipCreateFromHDC(HDC hDC, HANDLE* hGraphics);
  21. DWORD __stdcall GdipImageGetFrameDimensionsList(HANDLE image, GUID* dimensionIDs, UINT count);
  22. DWORD __stdcall GdipImageGetFrameCount(HANDLE image, const GUID* dimensionIDs, UINT *count);
  23. DWORD __stdcall GdipImageSelectActiveFrame(HANDLE image, const GUID* dimensionIDs, UINT frameIndex);
  24. DWORD __stdcall GdipGetPropertyItemSize(HANDLE image, UINT dwPropId, PUINT Size);
  25. DWORD __stdcall GdipGetPropertyItem(HANDLE image, UINT dwPropId, UINT Size, PVOID lpBuffer);
  26. DWORD __stdcall GdipGetImageWidth(HANDLE image, PUINT Width);
  27. DWORD __stdcall GdipGetImageHeight(HANDLE image, PUINT Height);
  28. DWORD __stdcall GdipDeleteGraphics(HANDLE hGraphics);
  29. DWORD __stdcall GdipDisposeImage(HANDLE hImage);
  30. }
  31.  
  32.  
  33. struct TPropertyItem
  34. {
  35. PROPID id;
  36. ULONG length;
  37. WORD type;
  38. PVOID value;
  39. };
  40. typedef TPropertyItem* PPropertyItem;
  41.  
  42. #define PropertyTagFrameDelay 0x5100
  43. DEFINE_GUID(FrameDimensionTime, 0x6aedbd6d,0x3fb5,0x418a,0x83,0xa6,0x7f,0x45,0x22,0x9d,0xc8,0x72);
  44.  
  45. WCHAR lpFileName[MAX_PATH];
  46.  
  47. BOOL RePaintWindow(HWND hWnd)
  48. {
  49. RECT Rect;
  50. GetClientRect(hWnd, &Rect);
  51. return RedrawWindow(hWnd, &Rect, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW|RDW_ALLCHILDREN);
  52. }
  53.  
  54. //---------------------------------------------------------------------------
  55. void TGifViewer::End()
  56. {
  57. if(hGdipImage){
  58. GdipDisposeImage(hGdipImage);
  59. hGdipImage = 0;
  60. WaitForSingleObject(hThread, INFINITE);
  61. CloseHandle(hThread);
  62. hThread = 0;
  63. }
  64. RePaintWindow(hWnd);
  65. }
  66. //---------------------------------------------------------------------------
  67.  
  68. BOOL TGifViewer::Start()
  69. {
  70. if(hWnd && hGdipImage && !hThread)
  71. hThread = CreateThread(0, 0, &TGifViewer::ThGif, this, 0, 0);
  72.  
  73. return hThread != 0;
  74. }
  75. //---------------------------------------------------------------------------
  76.  
  77.  
  78. BOOL TGifViewer::LoadFile(PWCHAR FileName)
  79. {
  80. End();
  81. if(GdipLoadImageFromFile(FileName, hGdipImage) == 0){
  82. GdipGetImageWidth(hGdipImage, (PUINT)&Width);
  83. GdipGetImageHeight(hGdipImage, (PUINT)&Height);
  84. GdipImageGetFrameCount(hGdipImage, &FrameDimensionTime, (PUINT)&Frames);
  85. }
  86. else hGdipImage = 0;
  87.  
  88. return hGdipImage != 0;
  89. }
  90. //---------------------------------------------------------------------------
  91.  
  92. DWORD __stdcall TGifViewer::ThGif(PVOID Param)
  93. {
  94. RECT Rect, RParent;
  95. PDWORD Wait;
  96. PPropertyItem Pi;
  97. //GUID FrameDimensionTime;
  98. HDC hDC;
  99. HANDLE hGraphics;
  100. UINT nBytes, Frames, Index;
  101. TGifViewer *GV = (TGifViewer*)Param;
  102.  
  103. // Esperamos a que se inicien los mensajes de ventana
  104. if(hEvent) WaitForSingleObject(hEvent, INFINITE);
  105. if(GV->hGdipImage && GV->hWnd){
  106. GdipGetPropertyItemSize(GV->hGdipImage, PropertyTagFrameDelay, &nBytes);
  107. Pi = (PPropertyItem)LocalAlloc(LMEM_FIXED, nBytes);
  108. GdipGetPropertyItem(GV->hGdipImage, PropertyTagFrameDelay, nBytes, Pi);
  109. // GdipImageGetFrameDimensionsList(hImage, &_FrameDimensionTime, 1);
  110. GdipImageGetFrameCount(GV->hGdipImage, &FrameDimensionTime, &Frames);
  111.  
  112. Index = 0;
  113. Wait = PDWORD(Pi->value);
  114. if(Pi->type == sizeof(DWORD))
  115. do{
  116. hDC = GetDC(GV->hWnd);
  117. GdipCreateFromHDC(hDC, &hGraphics);
  118. GdipImageSelectActiveFrame(GV->hGdipImage, &FrameDimensionTime, Index);
  119. GdipDrawImageRectI(hGraphics, GV->hGdipImage, GV->Left, GV->Top, GV->Width, GV->Height);
  120. GdipDeleteGraphics(hGraphics);
  121. ReleaseDC(GV->hWnd, hDC);
  122. Sleep(Wait[Index] * 10);
  123. Index = (Index + 1) % Frames;
  124. } while(GV->hWnd && GV->hGdipImage);
  125. }
  126. LocalFree(Pi);
  127. return 0;
  128. }
  129.  
  130. //---------------------------------------------------------------------------
  131. // Tratamiento de Mensajes
  132. LRESULT __stdcall TGifViewer::DefWndProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM LParam)
  133. {
  134. if(Msg == WM_PAINT && hEvent) SetEvent(hEvent); // Pemitimos que arranque el Thread
  135.  
  136. TGifViewer* pGifViewer = (TGifViewer*)GetWindowLongPtr(hWnd, GWL_USERDATA);
  137. if(pGifViewer)
  138. return pGifViewer->WndProc(hWnd, Msg, WParam, LParam);
  139. else return DefWindowProc(hWnd, Msg, WParam, LParam);
  140. }
  141.  
  142. LRESULT __stdcall TGifViewer::WndProc(HWND hWnd, UINT Msg, WPARAM WParam, LPARAM LParam)
  143. {
  144. if(Msg == WM_PAINT && hGdipImage){ // && hGdipImage)
  145. RECT R = {Left, Top, Left+Width, Top+Height};
  146. ValidateRect(hWnd, &R);
  147. // return DefWindowProc(hWnd, Msg, WParam, LParam);
  148. }
  149. return CallWindowProc(OldWndProc, hWnd, Msg, WParam, LParam);
  150. }
  151. //---------------------------------------------------------------------------
  152.  
  153. BOOL TGifViewer::SetHandle(HWND Handle)
  154. {
  155. if((PVOID)GetWindowLongPtr(Handle, GWL_WNDPROC) != &TGifViewer::DefWndProc){
  156. SuspendThread(hThread);
  157. if(hWnd){
  158. SetWindowLongPtr(hWnd, GWL_USERDATA, OldUserData);
  159. SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG_PTR)OldWndProc);
  160. RePaintWindow(hWnd);
  161. hWnd = 0;
  162. }
  163.  
  164. if(Handle && IsWindow(Handle)){
  165. hWnd = Handle;
  166. OldUserData = SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)this);
  167. OldWndProc = (PLRESULT)SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)&TGifViewer::DefWndProc);
  168. RePaintWindow(hWnd);
  169. // PostMessage(hWnd, WM_PAINT, 0, 0);
  170. }
  171. ResumeThread(hThread);
  172. return true;
  173. }
  174. return false;
  175. }
  176. //---------------------------------------------------------------------------
  177.  
  178. BOOL TGifViewer::GifView(HWND Wnd, PWCHAR FileName)
  179. {
  180. End();
  181. LoadFile(FileName);
  182. SetHandle(Wnd);
  183. return Start();
  184. }
  185. //---------------------------------------------------------------------------
  186.  
  187. TGifViewer::TGifViewer()
  188. {
  189. char GdiPlusStartupInput[16] = {1,0};
  190. if(!GDI) GdiplusStartup(&gdiplusToken, GdiPlusStartupInput, NULL);
  191. GDI++;
  192. hThread = 0;
  193. hGdipImage = 0;
  194. Left = 0;
  195. Top = 0;
  196. Width = 0;
  197. Height = 0;
  198. }
  199. //---------------------------------------------------------------------------
  200.  
  201. TGifViewer::~TGifViewer()
  202. {
  203. GDI--;
  204. End();
  205. SetHandle(0);
  206. if(!GDI) GdiplusShutdown(gdiplusToken);
  207. }
  208.  
  209. HANDLE TGifViewer::hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  210. DWORD TGifViewer::GDI = 0;

Un ejemplo usando VCL:


cpp
  1. //---------------------------------------------------------------------------
  2.  
  3. #include <vcl.h>
  4. #pragma hdrstop
  5.  
  6. #include "Unit1.h"
  7. #include "GifViewer.h"
  8. //---------------------------------------------------------------------------
  9. #pragma package(smart_init)
  10. #pragma resource "*.dfm"
  11. TForm1 *Form1;
  12.  
  13. TGifViewer GV1;
  14. TGifViewer *GV2 = 0;
  15. //---------------------------------------------------------------------------
  16. __fastcall TForm1::TForm1(TComponent* Owner)
  17. : TForm(Owner)
  18. {
  19. // GV1.GifView(Panel1->Handle, L"Muerte.gif");
  20. if(!GV1.GifView(Panel1->Handle, L"Muerte.gif")) GV1.SetHandle(0);
  21. }
  22. //---------------------------------------------------------------------------
  23.  
  24. void __fastcall TForm1::Button1Click(TObject *Sender)
  25. {
  26. if(OpenDialog1->Execute()) {
  27. GV1.GifView(Panel1->Handle, WideString(OpenDialog1->FileName).c_bstr());
  28. }
  29. }
  30. //---------------------------------------------------------------------------
  31. void __fastcall TForm1::Button2Click(TObject *Sender)
  32. {
  33. if(OpenDialog1->Execute()) {
  34. if(GV2) delete GV2;
  35. GV2 = new TGifViewer;
  36. GV2->GifView(Panel2->Handle, WideString(OpenDialog1->FileName).c_bstr());
  37. }
  38. }
  39. //---------------------------------------------------------------------------
  40.  
  41. void __fastcall TForm1::Button3Click(TObject *Sender)
  42. {
  43. delete GV2;
  44. GV2 = 0;
  45. }
  46. //---------------------------------------------------------------------------
  47.  
  48. void __fastcall TForm1::Button4Click(TObject *Sender)
  49. {
  50. if(GV2){
  51. GV1.SetHandle(0);
  52. GV2->SetHandle(Panel1->Handle);
  53. }
  54. }
  55. //---------------------------------------------------------------------------

Un ejemplo usando API:


cpp
  1. //---------------------------------------------------------------------------
  2.  
  3. #include <windows.h>
  4. #include "GifViewer.h"
  5.  
  6. #pragma hdrstop
  7.  
  8. //---------------------------------------------------------------------------
  9.  
  10. #pragma argsused
  11. WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  12. {
  13. MSG Msg;
  14. WNDCLASS WinClass = {0};
  15. HWND hFrame;
  16. RECT Rect;
  17. PWCHAR lpFileName;
  18.  
  19. int Argc;
  20. LPWSTR *Argv = CommandLineToArgvW(GetCommandLineW(), &Argc);
  21. if(Argc >= 2)
  22. lpFileName = Argv[1];
  23. else
  24. lpFileName = L"muerte.gif";
  25.  
  26. // Abrimos un archivo Gif para saber sus dimnesiones y crear una ventana
  27. TGifViewer GV;
  28. GV.LoadFile(lpFileName);
  29. GetClientRect(GetDesktopWindow(), &Rect);
  30.  
  31. // Creamos una ventana...
  32. WinClass.lpfnWndProc = DefWindowProc;
  33. WinClass.lpszClassName = "GIFFRAME";
  34. WinClass.hCursor = LoadCursor(0, IDC_ARROW);
  35. RegisterClass(&WinClass);
  36. hFrame = CreateWindowEx(WS_EX_LAYERED|WS_EX_TOPMOST|WS_EX_TOOLWINDOW, "GIFFRAME", "", WS_VISIBLE|WS_POPUP,
  37. (Rect.right - GV.GetWidth())/2,
  38. (Rect.bottom - GV.GetHeight())/2,
  39. GV.GetWidth(), GV.GetHeight(),
  40. HWND_DESKTOP, (HMENU)0, 0, 0);
  41. SetLayeredWindowAttributes(hFrame, 0, 220, LWA_ALPHA);
  42.  
  43. GV.SetHandle(hFrame); // Asociamos el Handle de nuestra ventana
  44. if(GV.Start()) // Si el Gif arranca iniciamos el bucle de mensajes de la app
  45. do{
  46. GetMessage(&Msg, 0, 0, 0);
  47. TranslateMessage(&Msg);
  48. DispatchMessage(&Msg);
  49. }while(IsWindow(hFrame));
  50.  
  51. // Alt+F4 Cerrará la ventana y termina la app
  52. return 0;
  53. }
  54. //---------------------------------------------------------------------------

Probado en Builder BCB5 y Berlin
 
BCB5 no tiene las limitaciones de D6 y 7 por lo que he usado la API SetWindowLongPtr para realizar el subclassing. Aprovechando la adaptación de la clase a Lazarus, para incluir alguna pequeña mejora a la clase.
 
 
Saludos.

Attached Files


  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 07 September 2018 - 08:49 AM

Vaya, que daría por tener el tiempo para aprender C++ y poder "traducir" de un lenguaje a otro como lo haces tu amigo escafandra(y)

 

Muy buen aporte.

 

Saludos


  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 07 September 2018 - 02:23 PM

Vaya, que daría por tener el tiempo para aprender C++ y poder "traducir" de un lenguaje a otro como lo haces tu amigo escafandra(y)

 

Muy buen aporte.

 

Saludos

 

En realidad no es complejo en absoluto una vez que has parido el código :) y personalmente paso buenos ratos con estas cosas.

 

Saludos.


  • 1

#5 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 07 September 2018 - 02:24 PM

No he podido resistir la tentación de probar el código en Lazarus. Para ello he tenido que realizar algún cambio para adaptarlo desde delphi ya que a bajo nivel hay alguna pequeña diferencia sintáctica con los punteros y algún tipo, además, he aprovechado para que compile también en 64bits y dotarle de alguna mejora que he trasladado a las versiones delphi y cpp.

 

La explicación de la primera entrada de delphi, es totalmente válida para la versión Lazarus dado que la clase es básicamente la misma. 

 

Este es el código de la clase, adjunto un archivo con el código y una APP de ejemplo similar a las versiones delphi y cpp.


delphi
  1. unit Lz_gifviewer;
  2.  
  3. //------------------------------------------------------------------------------
  4. // GifViewer V 2.0
  5. // escafandra 2018
  6. // Clase para representar un gif estático o animado sobre cualquier ventana.
  7. // Usa GDI+
  8. // Versión Lazarus para compilar en 32 y 64 bits
  9.  
  10.  
  11. interface
  12.  
  13. uses Windows, Messages;
  14.  
  15. function GdiplusStartup(var GdiToken: DWORD; Startup, Output: PBYTE): DWORD; stdcall external 'gdiplus';
  16. function GdipLoadImageFromFile(lpFileName: PWideChar; var hImage: THANDLE): DWORD; stdcall external 'gdiplus';
  17. function GdipDrawImageRectI(hGraphics, hImage: THANDLE; Left, Top, Width, Height: Integer): DWORD; stdcall external 'gdiplus';
  18. function GdipCreateFromHDC(DC: HDC; var hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
  19. function GdipImageSelectActiveFrame(hImage: THANDLE; DimensionID: PGUID; frameIndex: Integer): DWORD; stdcall external 'gdiplus';
  20. function GdipImageGetFrameDimensionsList(hImage: THANDLE; dimensionIDs: PGUID; Count: Integer): DWORD; stdcall external 'gdiplus';
  21. function GdipGetPropertyItemSize(hImage: THANDLE; dwPropId: Integer; var Size: UINT): Integer; stdcall external 'gdiplus';
  22. function GdipGetPropertyItem(hImage: THANDLE; dwPropID, Size: Integer; lpBuffer: Pointer): DWORD; stdcall external 'gdiplus';
  23. function GdipImageGetFrameCount(hImage: THANDLE; lpDimensionID: PGUID; out Count: UINT): DWORD; stdcall external 'gdiplus';
  24. function GdipGetImageWidth(hImage: THANDLE; var Width: UINT): DWORD; stdcall external 'gdiplus';
  25. function GdipGetImageHeight(hImage: THANDLE; var Height: UINT): DWORD; stdcall external 'gdiplus';
  26. function GdipDeleteGraphics(hGraphics: THANDLE): DWORD; stdcall external 'gdiplus';
  27. function GdipDisposeImage(hImage: THANDLE): DWORD; stdcall external 'gdiplus';
  28. procedure GdiplusShutdown(GdiToken: DWORD); stdcall external 'gdiplus';
  29.  
  30. type
  31. TWNDPROC = function(Wnd: HWND; msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
  32. TDWORDArray = array[0..0] of DWORD;
  33. PDWORDArray = ^TDWORDArray;
  34.  
  35. TGifViewer = class
  36. private
  37. Wnd: HWND;
  38. OldWndProc: TWNDPROC;
  39. OldUserData: DWORD;
  40. gdiplusToken: DWORD;
  41. hThread: THANDLE;
  42. hGdipImage: THANDLE;
  43. Width: integer;
  44. Height: integer;
  45. Frames: UINT;
  46. function WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  47.  
  48. public
  49. Left: integer;
  50. Top: integer;
  51. function GifView(Handle: HWND; FileName: PWCHAR): boolean;
  52. function SetHandle(Handle: THANDLE): boolean;
  53. function LoadFile(FileName: PWCHAR): boolean;
  54. function GetWidth: integer;
  55. function GetHeight: integer;
  56. function GetFrames: UINT;
  57. function Start: boolean;
  58. procedure Finish;
  59.  
  60. constructor Create;
  61. destructor Destroy; override;
  62. end;
  63. PGifViewer = ^TGifViewer;
  64.  
  65. TPropertyItem = record
  66. id: ULONG;
  67. length: ULONG;
  68. _type: WORD;
  69. value: Pointer;
  70. end;
  71. PPropertyItem = ^TPropertyItem;
  72.  
  73.  
  74. const
  75. PropertyTagFrameDelay = $5100;
  76. var
  77. GDI: DWORD = 0;
  78. hEvent: THandle = 0;
  79.  
  80. implementation
  81.  
  82. function RePaintWindow(Wnd: HWND): boolean;
  83. var
  84. Rect: TRect;
  85. begin
  86. GetClientRect(Wnd, @Rect);
  87. Result:= RedrawWindow(Wnd, @Rect, 0, RDW_INVALIDATE or RDW_ERASE or RDW_UPDATENOW or RDW_ALLCHILDREN);
  88. end;
  89.  
  90. function ThGif(GV: TGifViewer): DWORD; stdcall;
  91. var
  92. Pi: PPropertyItem;
  93. Wait: PDWORDArray;
  94. DC: HDC;
  95. hGdipGraphics: THANDLE;
  96. nBytes, Frames, Index: UINT;
  97. FrameDimensionTime: TGUID;
  98. begin
  99. // Esperamos a que se pinte una ventana WM_PAINT
  100. if hEvent <> 0 then WaitForSingleObject(hEvent, INFINITE);
  101.  
  102. if (GV.hGdipImage <> 0) and (GV.Wnd <> 0) then
  103. begin
  104. GdipGetPropertyItemSize(GV.hGdipImage, PropertyTagFrameDelay, nBytes);
  105. Pi:= PPropertyItem(LocalAlloc(LMEM_FIXED, nBytes));
  106. GdipGetPropertyItem(GV.hGdipImage, PropertyTagFrameDelay, nBytes, Pi);
  107. GdipImageGetFrameDimensionsList(GV.hGdipImage, @FrameDimensionTime, 1);
  108. GdipImageGetFrameCount(GV.hGdipImage, @FrameDimensionTime, Frames);
  109.  
  110. Index:= 0;
  111. Wait:= PDWORDArray(Pi^.value);
  112. if Pi^._type = sizeof(DWORD) then
  113. repeat
  114. DC:= GetDC(GV.Wnd);
  115. GdipCreateFromHDC(DC, hGdipGraphics);
  116. GdipImageSelectActiveFrame(GV.hGdipImage, @FrameDimensionTime, Index);
  117. GdipDrawImageRectI(hGdipGraphics, GV.hGdipImage, GV.Left, GV.Top, GV.Width, GV.Height);
  118. GdipDeleteGraphics(hGdipGraphics);
  119. ReleaseDC(GV.Wnd, DC);
  120. Sleep(Wait^[Index] * 10);
  121. Index:= (Index + 1) mod Frames;
  122. until (GV.Wnd = 0) or (GV.hGdipImage = 0);
  123. end;
  124. LocalFree(HLOCAL(Pi));
  125. Result:= 0;
  126. end;
  127.  
  128. function DefWndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  129. var
  130. pGifViewer: TGifViewer;
  131. begin
  132. if (Msg = WM_PAINT) and (hEvent <> 0) then SetEvent(hEvent); // Pemitimos que arranque el Thread
  133.  
  134. pGifViewer:= TGifViewer(GetWindowLongPtr(Handle, GWL_USERDATA));
  135. if pGifViewer <> nil then
  136. Result:= pGifViewer.WndProc(Handle, Msg, WParam, LParam)
  137. else
  138. Result:= DefWindowProc(Handle, Msg, WParam, LParam);
  139. end;
  140.  
  141. function TGifViewer.WndProc(Handle: HWND; Msg: DWORD; WParam: DWORD; LParam: DWORD): DWORD; stdcall;
  142. var
  143. R: TRect;
  144. begin
  145. if (Msg = WM_PAINT) and (hGdipImage <> 0) then
  146. begin
  147. R.Left:= Left; R.Top:= Top; R.Right:= Left+Width; R.Bottom:= Top+Height;
  148. ValidateRect(Wnd, R);
  149. //Result:= DefWindowProc(Handle, Msg, WParam, LParam);
  150. //Exit;
  151. end;
  152. Result:= CallWindowProc(OldWndProc, Handle, Msg, WParam, LParam);
  153. end;
  154.  
  155. function TGifViewer.SetHandle(Handle: THANDLE): boolean;
  156. begin
  157. Result:= false;
  158. if Pointer(GetWindowLongPtr(Handle, GWL_WNDPROC)) <> Pointer(@DefWndProc) then
  159. begin
  160. SuspendThread(hThread);
  161. if (Wnd <> 0) then
  162. begin
  163. SetWindowLongPtr(Wnd, GWL_USERDATA, OldUserData);
  164. SetWindowLongPtr(Wnd, GWL_WNDPROC, LongInt(OldWndProc));
  165. RePaintWindow(Wnd);
  166. Wnd:= 0;
  167. end;
  168.  
  169. if (Handle <> 0) and IsWindow(Handle) then
  170. begin
  171. Wnd:= Handle;
  172. OldUserData:= SetWindowLongPtr(Wnd, GWL_USERDATA, LONG_PTR(self));
  173. OldWndProc:= TWNDPROC(SetWindowLongPtr(Wnd, GWL_WNDPROC, LONG_PTR(@DefWndProc)));
  174. RePaintWindow(Wnd);
  175. end;
  176. Result:= true;
  177. ResumeThread(hThread);
  178. end;
  179. end;
  180.  
  181. function TGifViewer.LoadFile(FileName: PWCHAR): boolean;
  182. var
  183. FrameDimensionTime: TGUID;
  184. begin
  185. Finish;
  186. if GdipLoadImageFromFile(FileName, hGdipImage) = 0 then
  187. begin
  188. GdipGetImageWidth(hGdipImage, UINT(Width));
  189. GdipGetImageHeight(hGdipImage, UINT(Height));
  190. GdipImageGetFrameDimensionsList(hGdipImage, @FrameDimensionTime, 1);
  191. GdipImageGetFrameCount(hGdipImage, @FrameDimensionTime, UINT(Frames));
  192. end
  193. else hGdipImage:= 0;
  194.  
  195. Result:= hGdipImage <> 0;
  196. end;
  197.  
  198. function TGifViewer.GifView(Handle: HWND; FileName: PWCHAR): boolean;
  199. begin
  200. Finish;
  201. LoadFile(FileName);
  202. SetHandle(Handle);
  203. Result:= Start;
  204. end;
  205.  
  206. procedure TGifViewer.Finish;
  207. begin
  208. if hGdipImage <> 0 then
  209. begin
  210. GdipDisposeImage(hGdipImage);
  211. hGdipImage:= 0;
  212. WaitForSingleObject(hThread, INFINITE);
  213. CloseHandle(hThread);
  214. hThread:= 0;
  215. end;
  216. RePaintWindow(Wnd);
  217. end;
  218.  
  219. function TGifViewer.Start(): boolean;
  220. begin
  221. if (Wnd <> 0) and (hGdipImage <> 0) and (hThread = 0) then
  222. hThread:= CreateThread(nil, 0, @ThGif, self, 0, PDWORD(0)^);
  223. Result:= hThread <> 0;
  224. end;
  225.  
  226. function TGifViewer.GetWidth: integer;
  227. begin
  228. Result:= Width;
  229. end;
  230.  
  231. function TGifViewer.GetHeight: integer;
  232. begin
  233. Result:= Height;
  234. end;
  235.  
  236. function TGifViewer.GetFrames: UINT;
  237. begin
  238. Result:= Frames;
  239. end;
  240.  
  241. constructor TGifViewer.Create;
  242. var
  243. GdiPlusStartupInput: array[0..2] of int64;
  244. begin
  245. GdiPlusStartupInput[0]:= 1; GdiPlusStartupInput[1]:= 0;
  246. if GdiplusStartup(gdiplusToken, @GdiPlusStartupInput, nil) = 0 then inc(GDI);
  247. if hEvent = 0 then hEvent:= CreateEvent(nil, true, false, nil);
  248. end;
  249.  
  250. destructor TGifViewer.Destroy;
  251. begin
  252. dec(GDI);
  253. Finish;
  254. SetHandle(0);
  255. if GDI = 0 then GdiplusShutdown(gdiplusToken);
  256. inherited Destroy;
  257. end;
  258.  
  259. end.

Saludos.

Attached Files


  • 1

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 02 April 2022 - 01:59 PM

GifViewer V 3.1

He necesitado usar este visor portando la imagen Gif en un archivo de recursos. Como ya ocurrió con el componente VCL TGifViewer al que tuve que dotarle de la posibilidad de cargar la imagen desde el archivo de recursos, ahora lo hago para este visor API GDIplus.

Siguiendo la filosofía de este visor, no uso la VCL y me ciño al uso exclusivo de la API de Windows. Hay dos novedades interesantes. por un lado permite cargar archivos desde un recurso RCDATA. Por otro lado permite centrar la imagen en la ventana seleccionada. Desde el punto de vista del usuario estas son las funciones añadidas:

delphi y Lazarus:


delphi
  1. function GifView(Handle: HWND; FileName: PWCHAR; VCenter: boolean = false): boolean;
  2. function GifViewFromResource(Handle: HWND; ID_GIF: PWCHAR; VCenter: boolean = false): boolean;
  3. function LoadFromResource(ID_GIF: PWCHAR): boolean;

C++


cpp
  1. BOOL GifView(HWND hWnd, PWCHAR FileName, BOOL Center = false);
  2. BOOL GifViewFromResource(HWND hWnd, PWCHAR ID_GIF, BOOL Center = false);
  3. BOOL LoadFromResource(PWCHAR ID_GIF);

El método GifView sustituye al anterior del mismo nombre, siendo ambos totalmente compatibles, sólo añade la posibilidad de centrar el Gif en la ventana destino y por defecto no se centra.

 

El código que permite la carga del recurso es como sigue:


delphi
  1. uses Windows, Messages, ActiveX;
  2.  
  3. //------------------
  4. function SHCreateMemStream(pInit: PBYTE; cbInit: DWORD): Pointer; stdcall external 'shlwapi';
  5.  
  6. //------------------
  7.  
  8. function TGifViewer.LoadFromResource(ID_GIF: PWCHAR): boolean;
  9. const
  10. RT_RCDATAW: PWCHAR = MakeIntResourceW(10);
  11. var
  12. FrameDimensionTime: TGUID;
  13. Res: HRSRC;
  14. ResSize: DWORD;
  15. ResData: HGLOBAL;
  16. Stream: IStream;
  17. begin
  18. Finish;
  19. Res:= FindResourceW(0, ID_GIF, RT_RCDATAW);
  20. if Res <> 0 then
  21. begin
  22. ResSize:= SizeofResource(0, Res);
  23. ResData:= LoadResource(0, Res);
  24. Stream:= IStream(SHCreateMemStream(PBYTE(LockResource(ResData)), ResSize));
  25. if GdipLoadImageFromStream(Stream, hGdipImage) = 0 then
  26. begin
  27. GdipGetImageWidth(hGdipImage, UINT(Width));
  28. GdipGetImageHeight(hGdipImage, UINT(Height));
  29. GdipImageGetFrameCount(hGdipImage, @FrameDimensionTime, UINT(Frames));
  30. end
  31. else hGdipImage:= 0;
  32. Stream._Release;
  33. end;
  34. Result:= hGdipImage <> 0;
  35. end;

Para CBC5 y C++ Berlin


cpp
  1. #ifndef BERLIN
  2. IStream* __stdcall SHCreateMemStream(const BYTE *pInit, UINT cbInit);
  3. typedef IStream* (__stdcall *PSHCreateMemStream)(const BYTE *pInit, UINT cbInit);
  4.  
  5. PSHCreateMemStream _SHCreateMemStream = 0;
  6. #endif
  7.  
  8.  
  9. //-------------------------
  10.  
  11.  
  12. #define RT_RCDATAW MAKEINTRESOURCEW(10)
  13. BOOL TGifViewer::LoadFromResource(PWCHAR ID_GIF)
  14. {
  15. End();
  16. // HRSRC Res = ::FindResourceA(NULL, ID_GIF, RT_RCDATA);
  17. HRSRC Res = ::FindResourceW(NULL, ID_GIF, RT_RCDATAW);
  18. HGLOBAL ResData = ::LoadResource(NULL, Res);
  19. UINT ResSize = ::SizeofResource(NULL, Res);
  20.  
  21. #ifndef BERLIN
  22. if(!_SHCreateMemStream)
  23. _SHCreateMemStream = (PSHCreateMemStream)GetProcAddress(LoadLibraryA("SHLWAPI.DLL"), "SHCreateMemStream");
  24.  
  25. if(!_SHCreateMemStream)
  26. return false;
  27.  
  28. IStream *pStream = _SHCreateMemStream((LPBYTE)LockResource(ResData), ResSize);
  29. #else
  30. IStream *pStream = SHCreateMemStream((LPBYTE)LockResource(ResData), ResSize);
  31. #endif
  32. if(GdipLoadImageFromStream(pStream, hGdipImage) == 0){
  33. GdipGetImageWidth(hGdipImage, (PUINT)&Width);
  34. GdipGetImageHeight(hGdipImage, (PUINT)&Height);
  35. GdipImageGetFrameCount(hGdipImage, &FrameDimensionTime, (PUINT)&Frames);
  36. }
  37. else hGdipImage = 0;
  38. pStream->Release();
  39.  
  40. return hGdipImage != 0;
  41. }

En el  caso de que vuestro compilador defina la API SHCreateMemStream puede incluirse  una linea  #define BERLIN al principio del código de GifViewer.cpp. He comprobado que es una API bastante desconocida y que delphi Berlin no la incluye aunque si lo hace Builder Berlin. Si buscáis información para delphi en la web, no la vais a encontrar. Al menos hasta la fecha yo no lo he podido hacer.

 

Propongo un ejemplo de uso para visualizar un GIF desde un archivo de recursos:


delphi
  1. MiGif.rc:
  2.  
  3. ID_WAIT RCDATA "busy.gif"

Así lo usamos en delphi y Lazarus:


delphi
  1. GV.GifViewFromResource(Panel1.Handle, 'ID_WAIT', true);

En la versión C++ sería muy similar:


cpp
  1. GV.GifViewFromResource(Panel1->Handle, L"ID_WAIT", true);

Como resumen completo de los métodos de la clase:

GifView(Handle: HWND; FileName: PWCHAR; VCenter: boolean = false) Establece el fichero y la ventana donde se representará y comienza la visualización.
GifViewFromResource(Handle: HWND; ID_GIF: PWCHAR; VCenter: boolean = false) Establece el Gif desde un recurso y comienza la visualización.

Finish: Termina la visualización pero no libera la ventana.
Start: Comienza la visualización si ya tenemos fichero y ventana
SetHandle(Handle: THANDLE): Asocia el visor a una ventana.
LoadFile(FileName: PWCHAR): Abre un fichero gif y obtiene sus características.
LoadFromResource(ID_GIF: PWCHAR) Carga un Gif desde un recurso,

GetWidth: Nos informa del ancho.
GetHeight: Nos informa del alto.
GetFrames: Nos informa del número de imágenes del gif.

 

 

 

Adjunto el código de la actualización para
C++ BCB5 y Berlin
delphi 7 y Berlin
Lazarus 32 y 64 bits


Saludos

Attached Files


  • 1

#7 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14460 posts
  • LocationMéxico

Posted 03 April 2022 - 03:20 PM

A esto es lo que yo llamo un código multilenguaje. mis respetos  (b)

 

Saludo amigo escafandra


  • 0

#8 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4111 posts
  • LocationMadrid - España

Posted 04 April 2022 - 01:20 PM

Para mejorar el comportamiento gráfico al centrar el Gif, he actualizado a GifViewer V 3.1

Los nuevos enlaces del código están en esa entrada a la que he añadido un pequeño resumen de todos métodos para compactar la publicación.

Saludos.


  • 1




IP.Board spam blocked by CleanTalk.