• win32


    今天做case的时候遇到一个这样的问题,故记录下来。

    Codeproject有类似的案例,不过是使用的MFC模板编译的。 因为我们只需要win32程序,所以就....代码如下:

    CodeProject: Play GIF using GDI+

    另一个是使用双缓冲实现的,我没尝试:win32双缓冲实现gif图片的动态显示 (有兴趣的可以尝试一下)

    #include <windows.h>
    #include <objidl.h>
    #include <gdiplus.h>
    using namespace Gdiplus;
    #pragma comment (lib,"Gdiplus.lib")
    #define ID_TIMER 101
    
    //Image* m_pImage;
    
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
    
    INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
    {
        HWND                hWnd;
        MSG                 msg;
        WNDCLASS            wndClass;
        GdiplusStartupInput gdiplusStartupInput;
        ULONG_PTR           gdiplusToken;
    
        // Initialize GDI+.
        GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
        wndClass.style = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc = WndProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = hInstance;
        wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = TEXT("GettingStarted");
    
        RegisterClass(&wndClass);
    
        hWnd = CreateWindow(
            TEXT("GettingStarted"),   // window class name
            TEXT("Getting Started"),  // window caption
            WS_OVERLAPPEDWINDOW,      // window style
            CW_USEDEFAULT,            // initial x position
            CW_USEDEFAULT,            // initial y position
            CW_USEDEFAULT,            // initial x size
            CW_USEDEFAULT,            // initial y size
            NULL,                     // parent window handle
            NULL,                     // window menu handle
            hInstance,                // program instance handle
            NULL);                    // creation parameters
    
        ShowWindow(hWnd, iCmdShow);
        UpdateWindow(hWnd);
    
        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        GdiplusShutdown(gdiplusToken);
        return msg.wParam;
    }  // WinMain
    
    
    PropertyItem* m_pItem = 0;
    UINT m_iCurrentFrame = 0;
    UINT m_FrameCount = 0;
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
        WPARAM wParam, LPARAM lParam)
    {
        HDC          hdc;
        PAINTSTRUCT  ps;
        Image* m_pImage = new Image(L"Your_Gif.gif");
       
        switch (message)
        {
        case WM_CREATE:
        {
            //First of all we should get the number of frame dimensions
            //Images considered by GDI+ as:
            //frames[animation_frame_index][how_many_animation];
            UINT count = m_pImage->GetFrameDimensionsCount();
    
            //Now we should get the identifiers for the frame dimensions 
            GUID* m_pDimensionIDs = new GUID[count];
            m_pImage->GetFrameDimensionsList(m_pDimensionIDs, count);
    
            //For gif image , we only care about animation set#0
            WCHAR strGuid[40];
            StringFromGUID2(m_pDimensionIDs[0], strGuid, 40);
            m_FrameCount = m_pImage->GetFrameCount(&m_pDimensionIDs[0]);
    
            //PropertyTagFrameDelay is a pre-defined identifier 
            //to present frame-delays by GDI+
            UINT TotalBuffer = m_pImage->GetPropertyItemSize(PropertyTagFrameDelay);
            m_pItem = (PropertyItem*)malloc(TotalBuffer);
            m_pImage->GetPropertyItem(PropertyTagFrameDelay, TotalBuffer, m_pItem);
        }
        break;
        case WM_TIMER: {
            //Because there will be a new delay value
            KillTimer(hWnd, ID_TIMER);
            //Change Active frame
            GUID Guid = FrameDimensionTime;
            m_pImage->SelectActiveFrame(&Guid, m_iCurrentFrame);
            //New timer
            SetTimer(hWnd, ID_TIMER, ((UINT*)m_pItem[0].value)[m_iCurrentFrame] * 10, NULL);
            //Again move to the next
            m_iCurrentFrame = (++m_iCurrentFrame) % m_FrameCount;
            InvalidateRect(hWnd, NULL, FALSE);
            break;
        }
        case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd, &ps);
    
            Graphics graphics(hdc);
    
            //Set Current Frame at #0
            GUID Guid = FrameDimensionTime;
            m_pImage->SelectActiveFrame(&Guid, m_iCurrentFrame);
    
            //Use Timer
            //NOTE HERE: frame-delay values should be multiply by 10
            SetTimer(hWnd, ID_TIMER, ((UINT*)m_pItem[0].value)[m_iCurrentFrame] * 10, (TIMERPROC)NULL);
    
            //Move to the next frame
            ++m_iCurrentFrame;
            InvalidateRect(hWnd, NULL, FALSE);
    
            //Finally simply draw
            graphics.DrawImage(m_pImage, 120, 120, 800, 600);
    
            EndPaint(hWnd, &ps);
            break;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    } // WndProc

    步骤: 创建一个win32的空项目, 然后把代码复制进去。

                代码中你们唯一需要改的就是gif文件路径: Image* m_pImage = new Image(L"Your_Gif.gif"); =》这一行 

                也可以根据需

    要改变显示图片的大小: graphics.DrawImage(m_pImage, 120, 120, 800, 600);

    更新:

    gif循环播放代码,

    #include <memory>
    #include <vector>
    #include <algorithm>
    #include <windows.h>
    #include <objidl.h>
    #include <GdiPlus.h>
    #include <gdiplusimaging.h>
    #include <tchar.h>
    using namespace Gdiplus;
    #pragma comment (lib,"Gdiplus.lib")
    
    #define TIMER_ID 101
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
    
    int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
    {
        ULONG_PTR m_gdiplusToken;
        GdiplusStartupInput gdiplusStartupInput;
        GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
    
        Image gif(_T("spinner.gif"));
    
        MSG msg = { 0 };
        WNDCLASS wc = { 0 };
        wc.lpfnWndProc = WndProc;
        wc.hInstance = hInstance;
        wc.hbrBackground = NULL; // <= Do not provide a background brush.
        wc.lpszClassName = L"anim_gif_player";
        if (!RegisterClass(&wc))
            return -1;
    
        if (!CreateWindow(wc.lpszClassName,
            L"Animated GIF player",
            WS_OVERLAPPEDWINDOW | WS_VISIBLE,
            0, 0, 1080, 800, 0, 0, hInstance, &gif))
            return -2;
    
        while (GetMessage(&msg, NULL, 0, 0) > 0)
            DispatchMessage(&msg);
    
        return 0;
    }
    
    std::vector<unsigned int> LoadGifFrameInfo(Image* image)
    {
        // I think animated gifs will always only have 1 frame dimension...
        // the "dimension" being the frame count, but I could be wrong about this
        int count = image->GetFrameDimensionsCount();
        if (count != 1)
            return std::vector<unsigned int>();
    
        GUID guid;
        if (image->GetFrameDimensionsList(&guid, 1) != 0)
            return std::vector<unsigned int>();
        int frame_count = image->GetFrameCount(&guid);
    
        auto sz = image->GetPropertyItemSize(PropertyTagFrameDelay);
        if (sz == 0)
            return std::vector<unsigned int>();
    
        // copy the frame delay property into the buffer backing an std::vector
        // of bytes and then get a pointer to its value, which will be an array of 
        // unsigned ints
        std::vector<unsigned char> buffer(sz);
        PropertyItem* property_item = reinterpret_cast<PropertyItem*>(&buffer[0]);
        image->GetPropertyItem(PropertyTagFrameDelay, sz, property_item);
        unsigned int* frame_delay_array = (unsigned int*)property_item[0].value;
    
        // copy the delay values into an std::vector while converting to milliseconds.
        std::vector<unsigned int> frame_delays(frame_count);
        std::transform(frame_delay_array, frame_delay_array + frame_count, frame_delays.begin(),
            [](unsigned int n) {return n * 10; }
        );
    
        return frame_delays;
    }
    
    void GenerateFrame(Bitmap* bmp, Image* gif)
    {
        Graphics dest(bmp);
    
        SolidBrush white(Color::White);
        dest.FillRectangle(&white, 0, 0, bmp->GetWidth(), bmp->GetHeight());
    
        if (gif)
            dest.DrawImage(gif, 0, 0);
    }
    
    std::unique_ptr<Bitmap> CreateBackBuffer(HWND hWnd)
    {
        RECT r;
        GetClientRect(hWnd, &r);
        return std::make_unique<Bitmap>(r.right - r.left, r.bottom - r.top);
    }
    
    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        static Image* animated_gif;
        static std::unique_ptr<Bitmap> back_buffer;
        static std::vector<unsigned int> frame_delays;
        static int current_frame;
    
        switch (message) {
        case WM_CREATE: {
            animated_gif = reinterpret_cast<Image*>(
                reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams
                );
    
            if (!animated_gif || animated_gif->GetLastStatus() != 0) {
                MessageBox(hWnd, _T("Unable to load animated gif"), _T("error"), MB_ICONERROR);
                return 0;
            }
    
            // Create a bitmap the size of the window's clent area
            back_buffer = CreateBackBuffer(hWnd);
    
            // get the frame delays and thereby test that this is really an animated gif
            frame_delays = LoadGifFrameInfo(animated_gif);
            if (frame_delays.empty()) {
                MessageBox(hWnd, _T("Invalid gif or not an animated gif"), _T("error"), MB_ICONERROR);
                return 0;
            }
    
            current_frame = 0;
            animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
    
            GenerateFrame(back_buffer.get(), animated_gif);
    
            SetTimer(hWnd, TIMER_ID, frame_delays[0], nullptr);
            InvalidateRect(hWnd, nullptr, FALSE);
        }
                      break;
    
        case WM_TIMER: {
            KillTimer(hWnd, TIMER_ID);
            current_frame = (current_frame + 1) % frame_delays.size();
            animated_gif->SelectActiveFrame(&FrameDimensionTime, current_frame);
            GenerateFrame(back_buffer.get(), animated_gif);
            SetTimer(hWnd, TIMER_ID, frame_delays[current_frame], nullptr);
            InvalidateRect(hWnd, nullptr, FALSE);
        } break;
    
        case WM_PAINT: {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            Graphics g(hdc);
            g.DrawImage(back_buffer.get(), 0, 0);
            EndPaint(hWnd, &ps);
        } break;
    
        case WM_SIZE: {
            back_buffer = CreateBackBuffer(hWnd);
            GenerateFrame(back_buffer.get(), animated_gif);
        } break;
    
        case WM_CLOSE:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        return 0;
    }
  • 相关阅读:
    串口RS232和485通信的波形分析
    Ubuntu添加中文输入法
    虚拟机桥接模式联网方法,Xshell的连接与使用
    waitpid 函数详解
    linux for循环 fork() 产生子进程
    【LeetCode解题总结】动态规划篇
    【LeetCode解题总结】递归篇
    【LeetCode解题总结】排序篇
    【LeetCode解题总结】树/图篇
    【LeetCode解题总结】栈/队列篇
  • 原文地址:https://www.cnblogs.com/strive-sun/p/14452464.html
Copyright © 2020-2023  润新知