https://git.reactos.org/?p=reactos.git;a=commitdiff;h=375a78e70680718d4525b…
commit 375a78e70680718d4525b89d1ec061844b3f10e0
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Wed Oct 24 19:51:30 2018 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Wed Oct 24 19:51:30 2018 +0900
[SHIMGVW] Play gif animation (#934)
Make "Picture and Fax Viewer" able to play GIF animation.
CORE-12680
---
dll/win32/shimgvw/shimgvw.c | 180 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 3 deletions(-)
diff --git a/dll/win32/shimgvw/shimgvw.c b/dll/win32/shimgvw/shimgvw.c
index 8339b66b16..683e9b3c7e 100644
--- a/dll/win32/shimgvw/shimgvw.c
+++ b/dll/win32/shimgvw/shimgvw.c
@@ -9,6 +9,7 @@
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
+#define INITGUID
#include <stdarg.h>
@@ -31,7 +32,6 @@
#include "shimgvw.h"
-
HINSTANCE hInstance;
SHIMGVW_SETTINGS shiSettings;
SHIMGVW_FILENODE *currentFile;
@@ -49,6 +49,137 @@ static const UINT ZoomSteps[] =
10, 25, 50, 100, 200, 400, 800, 1600
};
+/* animation */
+UINT m_nFrameIndex = 0;
+UINT m_nFrameCount = 0;
+UINT m_nLoopIndex = 0;
+UINT m_nLoopCount = (UINT)-1;
+PropertyItem *m_pDelayItem = NULL;
+
+#define ANIME_TIMER_ID 9999
+
+static void Anime_FreeInfo(void)
+{
+ if (m_pDelayItem)
+ {
+ free(m_pDelayItem);
+ m_pDelayItem = NULL;
+ }
+ m_nFrameIndex = 0;
+ m_nFrameCount = 0;
+ m_nLoopIndex = 0;
+ m_nLoopCount = (UINT)-1;
+}
+
+static BOOL Anime_LoadInfo(void)
+{
+ GUID *dims;
+ UINT nDimCount = 0;
+ UINT cbItem;
+ UINT result;
+ PropertyItem *pItem;
+
+ Anime_FreeInfo();
+ KillTimer(hDispWnd, ANIME_TIMER_ID);
+
+ if (!image)
+ return FALSE;
+
+ GdipImageGetFrameDimensionsCount(image, &nDimCount);
+ if (nDimCount)
+ {
+ dims = (GUID *)calloc(nDimCount, sizeof(GUID));
+ if (dims)
+ {
+ GdipImageGetFrameDimensionsList(image, dims, nDimCount);
+ GdipImageGetFrameCount(image, dims, &result);
+ m_nFrameCount = result;
+ free(dims);
+ }
+ }
+
+ result = 0;
+ GdipGetPropertyItemSize(image, PropertyTagFrameDelay, &result);
+ cbItem = result;
+ if (cbItem)
+ {
+ m_pDelayItem = (PropertyItem *)malloc(cbItem);
+ GdipGetPropertyItem(image, PropertyTagFrameDelay, cbItem, m_pDelayItem);
+ }
+
+ result = 0;
+ GdipGetPropertyItemSize(image, PropertyTagLoopCount, &result);
+ cbItem = result;
+ if (cbItem)
+ {
+ pItem = (PropertyItem *)malloc(cbItem);
+ if (pItem)
+ {
+ if (GdipGetPropertyItem(image, PropertyTagLoopCount, cbItem, pItem) == Ok)
+ {
+ m_nLoopCount = *(WORD *)pItem->value;
+ }
+ free(pItem);
+ }
+ }
+
+ if (m_pDelayItem)
+ {
+ SetTimer(hDispWnd, ANIME_TIMER_ID, 0, NULL);
+ }
+
+ return m_pDelayItem != NULL;
+}
+
+static void Anime_SetFrameIndex(UINT nFrameIndex)
+{
+ if (nFrameIndex < m_nFrameCount)
+ {
+ GUID guid = FrameDimensionTime;
+ if (Ok != GdipImageSelectActiveFrame(image, &guid, nFrameIndex))
+ {
+ guid = FrameDimensionPage;
+ GdipImageSelectActiveFrame(image, &guid, nFrameIndex);
+ }
+ }
+ m_nFrameIndex = nFrameIndex;
+}
+
+DWORD Anime_GetFrameDelay(UINT nFrameIndex)
+{
+ if (nFrameIndex < m_nFrameCount && m_pDelayItem)
+ {
+ return ((DWORD *)m_pDelayItem->value)[m_nFrameIndex] * 10;
+ }
+ return 0;
+}
+
+BOOL Anime_Step(DWORD *pdwDelay)
+{
+ *pdwDelay = INFINITE;
+ if (m_nLoopCount == (UINT)-1)
+ return FALSE;
+
+ if (m_nFrameIndex + 1 < m_nFrameCount)
+ {
+ *pdwDelay = Anime_GetFrameDelay(m_nFrameIndex);
+ Anime_SetFrameIndex(m_nFrameIndex);
+ ++m_nFrameIndex;
+ return TRUE;
+ }
+
+ if (m_nLoopCount == 0 || m_nLoopIndex < m_nLoopCount)
+ {
+ *pdwDelay = Anime_GetFrameDelay(m_nFrameIndex);
+ Anime_SetFrameIndex(m_nFrameIndex);
+ m_nFrameIndex = 0;
+ ++m_nLoopIndex;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void ZoomInOrOut(BOOL bZoomIn)
{
INT i;
@@ -171,6 +302,7 @@ static void pLoadImage(LPWSTR szOpenFileName)
DPRINT1("GdipLoadImageFromFile() failed\n");
return;
}
+ Anime_LoadInfo();
/* reset zoom */
ResetZoom();
@@ -257,9 +389,26 @@ static void pSaveImageAs(HWND hwnd)
if (GetSaveFileNameW(&sfn))
{
- if (GdipSaveImageToFile(image, szSaveFileName, &codecInfo[sfn.nFilterIndex -
1].Clsid, NULL) != Ok)
+ if (m_pDelayItem)
+ {
+ /* save animation */
+ KillTimer(hDispWnd, ANIME_TIMER_ID);
+
+ DPRINT1("FIXME: save animation\n");
+ if (GdipSaveImageToFile(image, szSaveFileName,
&codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
+ {
+ DPRINT1("GdipSaveImageToFile() failed\n");
+ }
+
+ SetTimer(hDispWnd, ANIME_TIMER_ID, 0, NULL);
+ }
+ else
{
- DPRINT1("GdipSaveImageToFile() failed\n");
+ /* save non-animation */
+ if (GdipSaveImageToFile(image, szSaveFileName,
&codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
+ {
+ DPRINT1("GdipSaveImageToFile() failed\n");
+ }
}
}
@@ -595,6 +744,19 @@ ImageView_CreateToolBar(HWND hwnd)
return FALSE;
}
+static void ImageView_OnTimer(HWND hwnd)
+{
+ DWORD dwDelay;
+
+ KillTimer(hwnd, ANIME_TIMER_ID);
+ InvalidateRect(hwnd, NULL, TRUE);
+
+ if (Anime_Step(&dwDelay))
+ {
+ SetTimer(hwnd, ANIME_TIMER_ID, dwDelay, NULL);
+ }
+}
+
LRESULT CALLBACK
ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
@@ -605,6 +767,15 @@ ImageView_DispWndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM
lParam)
ImageView_DrawImage(hwnd);
return 0L;
}
+ case WM_TIMER:
+ {
+ if (wParam == ANIME_TIMER_ID)
+ {
+ ImageView_OnTimer(hwnd);
+ return 0;
+ }
+ break;
+ }
}
return CallWindowProc(PrevProc, hwnd, Message, wParam, lParam);
}
@@ -874,6 +1045,9 @@ ImageView_CreateWindow(HWND hwnd, LPWSTR szFileName)
if (image)
GdipDisposeImage(image);
+
+ Anime_FreeInfo();
+
GdiplusShutdown(gdiplusToken);
return -1;
}