1 /*
2  * PROJECT:    PAINT for ReactOS
3  * LICENSE:    LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:    Loading/Saving an image file with getting/setting resolution
5  * COPYRIGHT:  Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  */
7 
8 #pragma once
9 
10 class CImageDx : public CImage
11 {
12 public:
13     CImageDx() : CImage()
14     {
15         GetImageHorizontalResolution = NULL;
16         GetImageVerticalResolution = NULL;
17         BitmapSetResolution = NULL;
18     }
19 
20     BOOL GetResolution(Gdiplus::GpImage *pImage, float *pxDpi, float *pyDpi)
21     {
22         *pxDpi = 96;
23         *pyDpi = 96;
24 
25         if (GetImageHorizontalResolution == NULL || GetImageVerticalResolution == NULL)
26         {
27             GetImageHorizontalResolution =
28                 AddrOf<GETIMAGEHORIZONTALRESOLUTION>("GdipGetImageHorizontalResolution");
29             GetImageVerticalResolution =
30                 AddrOf<GETIMAGEVERTICALRESOLUTION>("GdipGetImageVerticalResolution");
31         }
32 
33         if (GetImageHorizontalResolution == NULL || GetImageVerticalResolution == NULL)
34             return FALSE;
35 
36         GetImageHorizontalResolution(pImage, pxDpi);
37         GetImageVerticalResolution(pImage, pyDpi);
38         return TRUE;
39     }
40 
41     BOOL SetResolution(Gdiplus::GpBitmap *pBitmap, float xDpi, float yDpi) const
42     {
43         if (BitmapSetResolution == NULL)
44             BitmapSetResolution = AddrOf<BITMAPSETRESOLUTION>("GdipBitmapSetResolution");
45 
46         if (BitmapSetResolution == NULL)
47             return FALSE;
48 
49         BitmapSetResolution(pBitmap, xDpi, yDpi);
50         return TRUE;
51     }
52 
53     HRESULT LoadDx(LPCTSTR pszFileName, float *pxDpi, float *pyDpi) throw()
54     {
55         // convert the file name string into Unicode
56         CStringW pszNameW(pszFileName);
57 
58         // create a GpBitmap object from file
59         using namespace Gdiplus;
60         GpBitmap *pBitmap = NULL;
61         if (GetCommon().CreateBitmapFromFile(pszNameW, &pBitmap) != Ok)
62         {
63             return E_FAIL;
64         }
65 
66         // get bitmap handle
67         HBITMAP hbm = NULL;
68         Color color(0xFF, 0xFF, 0xFF);
69         Gdiplus::Status status;
70         status = GetCommon().CreateHBITMAPFromBitmap(pBitmap, &hbm, color.GetValue());
71 
72         // get the resolution
73         GetResolution((Gdiplus::GpImage*)pBitmap, pxDpi, pyDpi);
74 
75         // delete GpBitmap
76         GetCommon().DisposeImage(pBitmap);
77 
78         // attach it
79         if (status == Ok)
80             Attach(hbm);
81         return (status == Ok ? S_OK : E_FAIL);
82     }
83 
84     HRESULT SaveDx(LPCTSTR pszFileName, REFGUID guidFileType = GUID_NULL,
85                    float xDpi = 0, float yDpi = 0) const throw()
86     {
87         using namespace Gdiplus;
88         ATLASSERT(m_hbm);
89 
90         // TODO & FIXME: set parameters (m_rgbTransColor etc.)
91 
92         // convert the file name string into Unicode
93         CStringW pszNameW(pszFileName);
94 
95         // if the file type is null, get the file type from extension
96         const GUID *FileType = &guidFileType;
97         if (IsGuidEqual(guidFileType, GUID_NULL))
98         {
99             LPCWSTR pszExt = GetFileExtension(pszNameW);
100             FileType = FileTypeFromExtension(pszExt);
101         }
102 
103         // get CLSID from file type
104         CLSID clsid;
105         if (!GetClsidFromFileType(&clsid, FileType))
106             return E_FAIL;
107 
108         // create a GpBitmap from HBITMAP
109         GpBitmap *pBitmap = NULL;
110         GetCommon().CreateBitmapFromHBITMAP(m_hbm, NULL, &pBitmap);
111 
112         // set the resolution
113         SetResolution(pBitmap, xDpi, yDpi);
114 
115         // save to file
116         Status status;
117         status = GetCommon().SaveImageToFile(pBitmap, pszNameW, &clsid, NULL);
118 
119         // destroy GpBitmap
120         GetCommon().DisposeImage(pBitmap);
121 
122         return (status == Ok ? S_OK : E_FAIL);
123     }
124 
125 protected:
126     // get procedure address of the DLL
127     template <typename TYPE>
128     TYPE AddrOf(const char *name) const
129     {
130         FARPROC proc = ::GetProcAddress(GetCommon().hinstGdiPlus, name);
131         return reinterpret_cast<TYPE>(proc);
132     }
133 
134     typedef St (WINGDIPAPI *GETIMAGEHORIZONTALRESOLUTION)(Im *, float*);
135     typedef St (WINGDIPAPI *GETIMAGEVERTICALRESOLUTION)(Im *, float*);
136     typedef St (WINGDIPAPI *BITMAPSETRESOLUTION)(Bm *, float, float);
137 
138     GETIMAGEHORIZONTALRESOLUTION    GetImageHorizontalResolution;
139     GETIMAGEVERTICALRESOLUTION      GetImageVerticalResolution;
140     mutable BITMAPSETRESOLUTION     BitmapSetResolution;
141 };
142