[SHIMGVW] Play gif animation (#934)

Make "Picture and Fax Viewer" able to play GIF animation.
CORE-12680
This commit is contained in:
Katayama Hirofumi MZ 2018-10-24 19:51:30 +09:00 committed by GitHub
parent efbebf983c
commit 375a78e706
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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,10 +389,27 @@ static void pSaveImageAs(HWND hwnd)
if (GetSaveFileNameW(&sfn))
{
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
{
/* save non-animation */
if (GdipSaveImageToFile(image, szSaveFileName, &codecInfo[sfn.nFilterIndex - 1].Clsid, NULL) != Ok)
{
DPRINT1("GdipSaveImageToFile() failed\n");
}
}
}
free(szFilterMask);
@ -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;
}