ReactOS 0.4.16-dev-980-g00983aa
loader.cpp
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Picture and Fax Viewer
3 * LICENSE: GPL-2.0 (https://spdx.org/licenses/GPL-2.0)
4 * PURPOSE: Image file browsing and manipulation
5 * COPYRIGHT: Copyright 2025 Whindmar Saksit <whindsaks@proton.me>
6 */
7
8#include <windows.h>
9#include <objbase.h>
10#include <gdiplus.h>
11using namespace Gdiplus;
12#include "shimgvw.h"
13
14#define HResultFromWin32 SHIMGVW_HResultFromWin32
15
17{
18 DWORD Transferred;
19 if (!ReadFile(hFile, Buffer, Size, &Transferred, NULL))
21 return Size == Transferred ? S_OK : HResultFromWin32(ERROR_HANDLE_EOF);
22}
23
25{
28};
29
31{
32public:
34 BitmapInfoHeader(const void* pbmiHeader) { Initialize(pbmiHeader); }
35
36 void Initialize(const void* pbmiHeader)
37 {
38 BITMAPINFOHEADER& bih = *(BITMAPINFOHEADER*)pbmiHeader;
39 if (bih.biSize >= sizeof(BITMAPINFOHEADER))
40 {
41 CopyMemory(this, &bih, min(bih.biSize, sizeof(*this)));
42 }
43 else
44 {
45 ZeroMemory(this, sizeof(*this));
46 BITMAPCOREHEADER& bch = *(BITMAPCOREHEADER*)pbmiHeader;
47 if (bih.biSize >= sizeof(BITMAPCOREHEADER))
48 {
49 biSize = bch.bcSize;
50 biWidth = bch.bcWidth;
51 biHeight = bch.bcHeight;
52 biPlanes = bch.bcPlanes;
55 }
56 }
57 }
58};
59
60#include <pshpack1.h>
66{
71};
73#include <poppack.h>
74
75static inline bool IsPngSignature(const void* buffer)
76{
77 const BYTE* p = (BYTE*)buffer;
78 return p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G' &&
79 p[4] == 0x0D && p[5] == 0x0A && p[6] == 0x1A && p[7] == 0x0A;
80}
81
82static inline bool IsPngSignature(const void* buffer, SIZE_T size)
83{
84 return size >= sizeof(PNGSIGNATURE) && IsPngSignature(buffer);
85}
86
88{
89 static const BYTE channels[] = { 1, 0, 3, 1, 2, 0, 4 };
90 const BYTE* p = (BYTE*)buffer, depth = p[8], type = p[8 + 1];
91 return (depth <= 16 && type <= 6) ? channels[type] * depth : 0;
92}
93
94static bool GetInfoFromPng(const void* file, SIZE_T size, IMAGESTATS& info)
95{
96 C_ASSERT(sizeof(PNGSIGNATURE) == 8);
97 C_ASSERT(sizeof(PNGSIGANDIHDR) == 8 + (4 + 4 + (4 + 4 + 5) + 4));
98
99 if (size > sizeof(PNGSIGANDIHDR) + sizeof(PNGFOOTER) && IsPngSignature(file))
100 {
101 const UINT PNGIHDRSIG = 0x52444849; // Note: Big endian
102 const UINT* chunkhdr = (UINT*)((char*)file + sizeof(PNGSIGNATURE));
103 if (BigToHost32(chunkhdr[0]) >= sizeof(PNGIHDR) && chunkhdr[1] == PNGIHDRSIG)
104 {
105 info.w = BigToHost32(chunkhdr[2]);
106 info.h = BigToHost32(chunkhdr[3]);
107 info.bpp = GetPngBppFromIHDRData(&chunkhdr[2]);
108 return info.bpp != 0;
109 }
110 }
111 return false;
112}
113
114static bool GetInfoFromBmp(const void* pBitmapInfo, IMAGESTATS& info)
115{
116 BitmapInfoHeader bih(pBitmapInfo);
117 info.w = bih.biWidth;
118 info.h = abs((int)bih.biHeight);
119 UINT bpp = bih.biBitCount * bih.biPlanes;
120 info.bpp = LOBYTE(bpp);
121 return info.w && bpp == info.bpp;
122}
123
124static bool GetInfoFromIcoBmp(const void* pBitmapInfo, IMAGESTATS& info)
125{
126 bool ret = GetInfoFromBmp(pBitmapInfo, info);
127 info.h /= 2; // Don't include mask
128 return ret && info.h;
129}
130
132{
133 return L"*.CUR"; // "*.FOO;*.BAR" etc.
134}
135
137{
138 PBYTE buffer = (PBYTE)GlobalLock(hMem);
139 if (!buffer)
140 return;
141
142 // TODO: We could try to load an ICO/PNG/BMP resource from a PE file here into buffer
143
144 // ICO/CUR
145 struct ICOHDR { WORD Sig, Type, Count; };
146 ICOHDR* pIcoHdr = (ICOHDR*)buffer;
147 if (Size > sizeof(ICOHDR) && !pIcoHdr->Sig && pIcoHdr->Type > 0 && pIcoHdr->Type < 3 && pIcoHdr->Count)
148 {
149 const UINT minbmp = sizeof(BITMAPCOREHEADER) + 1, minpng = sizeof(PNGSIGANDIHDR);
150 const UINT minfile = min(minbmp, minpng), count = pIcoHdr->Count;
151 struct ICOENTRY { BYTE w, h, pal, null; WORD planes, bpp; UINT size, offset; };
152 ICOENTRY* entries = (ICOENTRY*)&pIcoHdr[1];
153 if (Size - sizeof(ICOHDR) > (sizeof(ICOENTRY) + minfile) * count)
154 {
155 UINT64 best = 0;
156 int bestindex = -1;
157 // Inspect all the images and find the "best" image
158 for (UINT i = 0; i < count; ++i)
159 {
160 BOOL valid = FALSE;
162 const BYTE* data = buffer + entries[i].offset;
163 if (IsPngSignature(data, entries[i].size))
164 valid = GetInfoFromPng(data, entries[i].size, info);
165 else
167
168 if (valid)
169 {
170 // Note: This treats bpp as more important compared to LookupIconIdFromDirectoryEx
171 UINT64 score = UINT64(info.w) * info.h * info.bpp;
172 if (score > best)
173 {
174 best = score;
175 bestindex = i;
176 }
177 }
178 }
179 if (bestindex >= 0)
180 {
181 if (pIcoHdr->Type == 2)
182 {
183 // GDI+ does not support .cur files, convert to .ico
184 pIcoHdr->Type = 1;
185#if 0 // Because we are already overriding the order, we don't need to correct the ICOENTRY lookup info
186 for (UINT i = 0; i < count; ++i)
187 {
189 const BYTE* data = buffer + entries[i].offset;
190 if (IsPngSignature(data, entries[i].size))
191 {
193 if (!GetInfoFromPng(data, entries[i].size, info))
194 continue;
195 bih.biPlanes = 1;
196 bih.biBitCount = info.bpp;
197 entries[i].pal = 0;
198 }
199 else
200 {
201 bih.Initialize(data);
202 entries[i].pal = bih.biPlanes * bih.biBitCount <= 8 ? bih.biClrUsed : 0;
203 }
204 entries[i].planes = (WORD)bih.biPlanes;
205 entries[i].bpp = (WORD)bih.biBitCount;
206 }
207#endif
208 }
209#if 0
210 // Convert to a .ico with a single image
211 pIcoHdr->Count = 1;
212 const BYTE* data = buffer + entries[bestindex].offset;
213 entries[0] = entries[bestindex];
214 entries[0].offset = (UINT)UINT_PTR((PBYTE)&entries[1] - buffer);
215 MoveMemory(buffer + entries[0].offset, data, entries[0].size);
216 Size = entries[0].offset + entries[0].size;
217#else
218 // Place the best image first, GDI+ will return the first image
219 ICOENTRY temp = entries[0];
220 entries[0] = entries[bestindex];
221 entries[bestindex] = temp;
222#endif
223 }
224 }
225 }
226
227 GlobalUnlock(hMem);
228}
229
230static HRESULT LoadImageFromStream(IStream* pStream, GpImage** ppImage)
231{
232 Status status = DllExports::GdipLoadImageFromStream(pStream, ppImage);
234}
235
237{
239 if (!size || size == INVALID_FILE_SIZE)
241
243 if (!hMem)
245 HRESULT hr = E_FAIL;
246 void* buffer = GlobalLock(hMem);
247 if (buffer)
248 {
249 hr = Read(hFile, buffer, size);
250 GlobalUnlock(hMem);
251 if (SUCCEEDED(hr))
252 {
254 IStream* pStream;
255 if (SUCCEEDED(hr = CreateStreamOnHGlobal(hMem, TRUE, &pStream)))
256 {
257 // CreateStreamOnHGlobal does not know the real size, we do
258 pStream->SetSize(MakeULargeInteger(size));
259 hr = LoadImageFromStream(pStream, ppImage);
260 pStream->Release(); // Calls GlobalFree
261 return hr;
262 }
263 }
264 }
265 GlobalFree(hMem);
266 return hr;
267}
268
270{
271 // NOTE: GdipLoadImageFromFile locks the file.
272 // Avoid file locking by using GdipLoadImageFromStream and memory stream.
273
277 {
280 return hr;
281 }
283}
unsigned long long UINT64
PRTL_UNICODE_STRING_BUFFER Path
Type
Definition: Type.h:7
int null(void)
Definition: ftp.c:1794
#define EXTERN_C
Definition: basetyps.h:12
void Initialize(const void *pbmiHeader)
Definition: loader.cpp:36
BitmapInfoHeader(const void *pbmiHeader)
Definition: loader.cpp:34
Definition: bufpool.h:45
#define E_FAIL
Definition: ddrawi.h:102
#define ERROR_OUTOFMEMORY
Definition: deptool.c:13
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
DWORD bpp
Definition: surface.c:185
#define CloseHandle
Definition: compat.h:739
#define OPEN_EXISTING
Definition: compat.h:775
#define ReadFile(a, b, c, d, e)
Definition: compat.h:742
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define ERROR_NOT_SUPPORTED
Definition: compat.h:100
#define CreateFileW
Definition: compat.h:741
#define FILE_SHARE_READ
Definition: compat.h:136
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:331
HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL fDeleteOnRelease, LPSTREAM *ppstm)
#define BI_RGB
Definition: precomp.h:56
#define abs(i)
Definition: fconv.c:206
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
BOOLEAN valid
Status
Definition: gdiplustypes.h:25
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLfloat GLfloat p
Definition: glext.h:8902
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
LPVOID NTAPI GlobalLock(HGLOBAL hMem)
Definition: heapmem.c:755
HGLOBAL NTAPI GlobalFree(HGLOBAL hMem)
Definition: heapmem.c:611
BOOL NTAPI GlobalUnlock(HGLOBAL hMem)
Definition: heapmem.c:1190
HGLOBAL NTAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:368
HRESULT SetSize([in] ULARGE_INTEGER libNewSize)
ULONG Release()
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define C_ASSERT(e)
Definition: intsafe.h:73
#define LOBYTE(W)
Definition: jmemdos.c:487
static bool GetInfoFromIcoBmp(const void *pBitmapInfo, IMAGESTATS &info)
Definition: loader.cpp:124
static HRESULT LoadImageFromStream(IStream *pStream, GpImage **ppImage)
Definition: loader.cpp:230
static BYTE GetPngBppFromIHDRData(const void *buffer)
Definition: loader.cpp:87
static bool GetInfoFromBmp(const void *pBitmapInfo, IMAGESTATS &info)
Definition: loader.cpp:114
EXTERN_C PCWSTR GetExtraExtensionsGdipList(VOID)
Definition: loader.cpp:131
static bool IsPngSignature(const void *buffer)
Definition: loader.cpp:75
static void OverrideFileContent(HGLOBAL &hMem, DWORD &Size)
Definition: loader.cpp:136
static HRESULT LoadImageFromFileHandle(HANDLE hFile, GpImage **ppImage)
Definition: loader.cpp:236
static bool GetInfoFromPng(const void *file, SIZE_T size, IMAGESTATS &info)
Definition: loader.cpp:94
#define HResultFromWin32
Definition: loader.cpp:14
EXTERN_C HRESULT LoadImageFromPath(LPCWSTR Path, GpImage **ppImage)
Definition: loader.cpp:269
#define FILE_FLAG_SEQUENTIAL_SCAN
Definition: disk.h:43
#define min(a, b)
Definition: monoChain.cc:55
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
_In_ HANDLE hFile
Definition: mswsock.h:90
unsigned int UINT
Definition: ndis.h:50
int Count
Definition: noreturn.cpp:7
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
#define L(x)
Definition: ntvdm.h:50
BYTE * PBYTE
Definition: pedump.c:66
int This channels
Definition: rdpsnd_libao.c:37
static calc_node_t temp
Definition: rpn_ieee.c:38
static HRESULT HResultFromGdiplus(Status status)
Definition: shimgvw.h:119
static ULARGE_INTEGER MakeULargeInteger(UINT64 value)
Definition: shimgvw.h:106
HRESULT hr
Definition: shlfolder.c:183
_In_ BOOLEAN Read
Definition: strmini.h:479
DWORD biCompression
Definition: amvideo.idl:35
BYTE bpp
Definition: loader.cpp:27
UINT w
Definition: loader.cpp:26
UINT h
Definition: loader.cpp:26
PNGCHUNKHEADER chunkheader
Definition: loader.cpp:72
PNGCHUNKFOOTER footer
Definition: loader.cpp:72
UINT h
Definition: loader.cpp:64
BYTE depth
Definition: loader.cpp:64
BYTE filter
Definition: loader.cpp:64
UINT w
Definition: loader.cpp:64
BYTE interlace
Definition: loader.cpp:64
BYTE compression
Definition: loader.cpp:64
BYTE type
Definition: loader.cpp:64
PNGCHUNKFOOTER chunkfooter
Definition: loader.cpp:70
PNGCHUNKHEADER chunkheader
Definition: loader.cpp:68
PNGIHDR ihdr
Definition: loader.cpp:69
PNGSIGNATURE sig
Definition: loader.cpp:67
Definition: fci.c:127
Definition: ps.c:97
const uint16_t * PCWSTR
Definition: typedefs.h:57
ULONG_PTR SIZE_T
Definition: typedefs.h:80
UINT64 number
Definition: loader.cpp:61
BYTE bytes[8]
Definition: loader.cpp:61
int ret
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
#define ZeroMemory
Definition: winbase.h:1743
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CopyMemory
Definition: winbase.h:1741
#define INVALID_FILE_SIZE
Definition: winbase.h:574
#define MoveMemory
Definition: winbase.h:1740
#define GMEM_MOVEABLE
Definition: winbase.h:320
#define ERROR_HANDLE_EOF
Definition: winerror.h:140
struct tagBITMAPCOREHEADER BITMAPCOREHEADER
static void Initialize()
Definition: xlate.c:212
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
unsigned char BYTE
Definition: xxhash.c:193