Skip to content

Commit 40d9091

Browse files
committed
Add support for PSB files
1 parent 8c9e40a commit 40d9091

4 files changed

Lines changed: 67 additions & 47 deletions

File tree

PsdThumbnailProvider/GetThumbnail.cpp

Lines changed: 62 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22
#include "gdiplus.h"
33
#include <Shlwapi.h>
44
#include <math.h>
5+
#include <objidl.h> // Gdiplus
6+
#include <gdiplus.h> // Gdiplus
57

68
#pragma comment(lib, "Shlwapi.lib")
9+
#pragma comment (lib, "Gdiplus.lib") // Gdiplus
10+
#pragma comment (lib, "Msimg32.lib") // AlphaBlend
711

812
using namespace Gdiplus;
913

10-
void ReadData(IStream *pStream, BYTE *data, ULONG length) {
14+
inline void ReadData(IStream *pStream, BYTE *data, ULONG length) {
1115
ULONG read, total = 0;
1216
HRESULT hr;
1317

@@ -17,51 +21,66 @@ void ReadData(IStream *pStream, BYTE *data, ULONG length) {
1721
} while (total < length && hr == S_OK);
1822
}
1923

20-
UINT ReadUInt32(IStream *pStream) {
24+
inline UINT ReadUInt32(IStream *pStream) {
2125
BYTE b[4];
2226
ReadData(pStream, b, 4);
2327
return b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
2428
}
2529

26-
SHORT ReadInt16(IStream *pStream) {
30+
inline ULONG64 ReadUInt64(IStream *pStream) {
31+
BYTE b[8];
32+
ReadData(pStream, b, 8);
33+
return (ULONG64)b[0] << 56 | (ULONG64)b[1] << 48 | (ULONG64)b[2] << 40 | (ULONG64)b[3] << 32 | (ULONG64)b[4] << 24 | (ULONG64)b[5] << 16 | (ULONG64)b[6] << 8 | (ULONG64)b[7];
34+
}
35+
36+
inline SHORT ReadInt16(IStream *pStream) {
2737
BYTE b[2];
2838
ReadData(pStream, b, 2);
2939
return b[0] << 8 | b[1];
3040
}
3141

32-
USHORT ReadUInt16(IStream *pStream) {
42+
inline USHORT ReadUInt16(IStream *pStream) {
3343
BYTE b[2];
3444
ReadData(pStream, b, 2);
3545
return b[0] << 8 | b[1];
3646
}
3747

38-
BYTE ReadByte(IStream *pStream) {
48+
inline BYTE ReadByte(IStream *pStream) {
3949
BYTE b;
4050
ReadData(pStream, &b, 1);
4151
return b;
4252
}
4353

44-
void Seek(IStream *pStream, int offset, DWORD origin) {
45-
LARGE_INTEGER pos;
46-
pos.QuadPart = offset;
47-
pStream->Seek(pos, origin, NULL);
54+
inline LONGLONG ReadSectionLength(IStream *pStream, int version = 1) {
55+
if (version == 1) {
56+
return (LONGLONG)ReadUInt32(pStream);
57+
} else {
58+
return (LONGLONG)ReadUInt64(pStream);
59+
}
4860
}
4961

50-
UINT Tell(IStream *pStream) {
62+
inline void Seek(IStream *pStream, LONGLONG offset, DWORD origin) {
63+
if (offset > 0) {
64+
LARGE_INTEGER pos;
65+
pos.QuadPart = offset;
66+
pStream->Seek(pos, origin, NULL);
67+
}
68+
}
69+
70+
inline ULONGLONG Tell(IStream *pStream) {
5171
LARGE_INTEGER pos;
5272
ULARGE_INTEGER newPos;
5373
pos.QuadPart = 0;
5474
pStream->Seek(pos, STREAM_SEEK_CUR, &newPos);
55-
return (UINT)newPos.QuadPart;
75+
return newPos.QuadPart;
5676
}
5777

5878
HBITMAP GetPSDThumbnail(IStream* stream) {
5979
HBITMAP result = NULL;
6080
UINT signature = ReadUInt32(stream);
6181
USHORT version = ReadUInt16(stream);
6282

63-
if (signature != 0x38425053 || version != 1)
64-
return NULL;
83+
if (signature != 0x38425053 || (version != 1 && version != 2)) return NULL;
6584

6685
Seek(stream, 6, STREAM_SEEK_CUR);
6786

@@ -70,46 +89,48 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
7089
int width = ReadUInt32(stream);
7190
USHORT bitsPerChannel = ReadUInt16(stream);
7291
USHORT colorMode = ReadUInt16(stream);
73-
UINT length = ReadUInt32(stream);
92+
int maxSize = version == 1 ? 30000 : 300000;
93+
if (width > maxSize || height > maxSize) return NULL;
7494

75-
if (length > 0) {
76-
Seek(stream, length, STREAM_SEEK_CUR);
77-
}
95+
// color mode data
96+
auto colorModeLength = ReadSectionLength(stream);
97+
Seek(stream, colorModeLength, STREAM_SEEK_CUR);
7898

79-
UINT resourcesLength = ReadUInt32(stream);
80-
UINT reasourceOffset = Tell(stream);
81-
UINT thumbnailOffset = 0;
82-
UINT resourceAdvanced = 0;
99+
// image resources
100+
auto resourcesLength = ReadSectionLength(stream);
101+
auto reasourceOffset = Tell(stream);
102+
ULONGLONG resourceEnd = reasourceOffset + resourcesLength;
103+
LONGLONG thumbnailOffset = 0;
104+
ULONG thumbnailLength = 0;
83105

84-
while (resourcesLength > resourceAdvanced) {
85-
Seek(stream, 4, STREAM_SEEK_CUR);
106+
while (Tell(stream) < resourceEnd) {
107+
Seek(stream, 4, STREAM_SEEK_CUR); // signature
86108

87109
USHORT id = ReadUInt16(stream);
88-
BYTE strl = ReadByte(stream);
89110

90-
Seek(stream, strl % 2 == 0 ? strl + 1 : strl, STREAM_SEEK_CUR);
111+
BYTE nameLength = ReadByte(stream); // name
112+
Seek(stream, ((nameLength + 1) % 2) ? nameLength + 1 : nameLength, STREAM_SEEK_CUR);
91113

92-
length = ReadUInt32(stream);
114+
auto length = ReadSectionLength(stream);
93115

94116
if (id == 1036) {
95117
thumbnailOffset = Tell(stream);
118+
thumbnailLength = (ULONG)length;
96119
break;
97120
}
98121

99-
Seek(stream, length % 2 ? length + 1 : length, STREAM_SEEK_CUR);
100-
101-
resourceAdvanced += 6 + 1 + (strl % 2 == 0 ? strl + 1 : strl) +
102-
4 + (length % 2 ? length + 1 : length);
122+
Seek(stream, length, STREAM_SEEK_CUR);
123+
if (Tell(stream) % 2) Seek(stream, 1, STREAM_SEEK_CUR);
103124
}
104125

105126
// read composite image
106-
if (colorMode == 3 && ((width <= 256 && height <= 256) || !thumbnailOffset)) {
127+
if (false && colorMode == 3 && ((width <= 256 && height <= 256) || !thumbnailOffset)) {
107128
Seek(stream, reasourceOffset + resourcesLength, STREAM_SEEK_SET);
108129

109-
UINT layerAndMaskInfoLength = ReadUInt32(stream);
110-
UINT layerAndMastInfoOffset = Tell(stream);
130+
auto layerAndMaskInfoLength = ReadSectionLength(stream);
131+
auto layerAndMastInfoOffset = Tell(stream);
111132

112-
UINT layerInfoLength = ReadUInt32(stream);
133+
auto layerInfoLength = ReadSectionLength(stream);
113134
SHORT layerCount = ReadInt16(stream);
114135
bool globalAlpha = layerCount < 0;
115136

@@ -160,8 +181,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
160181
for (int y = 0; y < height; y++, li++) {
161182
Seek(stream, lengths[li], STREAM_SEEK_CUR);
162183
}
163-
}
164-
else {
184+
} else {
165185
for (int y = 0, p = offset; y < height; y++, li++) {
166186
int length = lengths[li];
167187
ReadData(stream, buffer, length);
@@ -177,8 +197,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
177197
data[p] = value;
178198
p += step;
179199
}
180-
}
181-
else { // header < 128
200+
} else { // header < 128
182201
for (int j = 0; j <= header; j++) {
183202
data[p] = buffer[++i];
184203
p += step;
@@ -224,8 +243,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
224243
if (width > height) {
225244
thumbWidth = 256;
226245
thumbHeight = height * thumbWidth / width;
227-
}
228-
else {
246+
} else {
229247
thumbHeight = 256;
230248
thumbWidth = width * thumbHeight / height;
231249
}
@@ -253,8 +271,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
253271
DeleteDC(srcDC);
254272
DeleteDC(memDC);
255273
ReleaseDC(NULL, dc);
256-
}
257-
else {
274+
} else {
258275
result = CreateBitmap(width, height, 1, 32, data);
259276
}
260277
}
@@ -272,9 +289,9 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
272289
if (Ok == GdiplusStartup(&token, &input, NULL)) {
273290
Seek(stream, 4 + 4 + 4 + 4 + 4 + 4 + 2 + 2, STREAM_SEEK_CUR);
274291

275-
BYTE *data = new BYTE[length];
276-
ReadData(stream, data, length);
277-
IStream *memory = SHCreateMemStream(data, length);
292+
BYTE *data = new BYTE[thumbnailLength]; // TODO: should this be freed?
293+
ReadData(stream, data, thumbnailLength);
294+
IStream *memory = SHCreateMemStream(data, thumbnailLength);
278295

279296
if (memory) {
280297
Seek(memory, 0, STREAM_SEEK_SET);

Setup/Product.wxs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
3-
<Product Id="*" Name="PSD Thumbnail Provider" Language="1033" Version="1.5.0.0" Manufacturer="Agamnentzar" UpgradeCode="cb88ff56-355c-48fd-8343-8d3f40ef02ce">
3+
<Product Id="*" Name="PSD Thumbnail Provider" Language="1033" Version="1.6.0.0" Manufacturer="Agamnentzar" UpgradeCode="cb88ff56-355c-48fd-8343-8d3f40ef02ce">
44
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
55
<Condition Message="You need to be an administrator to install this product.">Privileged</Condition>
66
<MajorUpgrade Schedule="afterInstallInitialize" DowngradeErrorMessage="A newer version of PSD Thumbnail Provider is already installed." />
@@ -31,6 +31,9 @@
3131
<RegistryKey Root="HKCR" Key=".psd\shellex\{e357fccd-a995-4576-b01f-234630154e96}" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
3232
<RegistryValue Type="string" Value="{5BB45D32-AF01-414F-B60A-5E999B986681}" />
3333
</RegistryKey>
34+
<RegistryKey Root="HKCR" Key=".psb\shellex\{e357fccd-a995-4576-b01f-234630154e96}" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
35+
<RegistryValue Type="string" Value="{5BB45D32-AF01-414F-B60A-5E999B986681}" />
36+
</RegistryKey>
3437
</Component>
3538
</DirectoryRef>
3639

Test/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LRESULT CALLBACK windowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
99
switch (message) {
1010
case WM_CREATE: {
1111
IStream* stream;
12-
SHCreateStreamOnFileEx(L"test4.psd", STGM_READ, FILE_ATTRIBUTE_NORMAL, false, NULL, &stream);
12+
SHCreateStreamOnFileEx(L"test7.psb", STGM_READ, FILE_ATTRIBUTE_NORMAL, false, NULL, &stream);
1313
bitmap = GetPSDThumbnail(stream);
1414
BITMAP bm = {};
1515
GetObject(bitmap, sizeof(bm), &bm);

Test/test7.psb

132 KB
Binary file not shown.

0 commit comments

Comments
 (0)