├── .gitignore
├── .gitmodules
├── FlifWICCodec.sln
├── FlifWICCodec
├── FlifWICCodec.cpp
├── FlifWICCodec.vcxproj
├── FlifWICCodec.vcxproj.filters
├── autoreg.inf
├── decode_container.cpp
├── decode_container.h
├── decode_frame.cpp
├── decode_frame.h
├── dllmain.cpp
├── dllmain.h
├── encode_container.cpp
├── encode_container.h
├── encode_frame.cpp
├── encode_frame.h
├── flif_wic_codec.def
├── flif_wic_codec.rc
├── metadata_store.cpp
├── metadata_store.h
├── pixel_converter.cpp
├── pixel_converter.h
├── resids.h
├── stopwatch.h
├── targetver.h
├── utils.h
├── uuid.h
└── version.h
├── README.md
└── libflif
├── libflif.vcxproj
└── libflif.vcxproj.filters
/.gitignore:
--------------------------------------------------------------------------------
1 | *.opendb
2 | *.db
3 | /Release
4 | /x64
5 | /FlifWICCodec/Debug
6 | /FlifWICCodec/Release
7 | /FlifWICCodec/x64
8 | /Debug
9 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "FLIF"]
2 | path = FLIF
3 | url=https://github.com/FLIF-hub/FLIF.git
--------------------------------------------------------------------------------
/FlifWICCodec.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FlifWICCodec", "FlifWICCodec\FlifWICCodec.vcxproj", "{7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libflif", "libflif\libflif.vcxproj", "{56871ADF-ABF5-414B-8872-BCF0E200B95D}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{5ED12E51-C7C7-4486-ABB2-4808F9A4EA94}"
11 | ProjectSection(SolutionItems) = preProject
12 | README.md = README.md
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|x64 = Debug|x64
18 | Debug|x86 = Debug|x86
19 | Release|x64 = Release|x64
20 | Release|x86 = Release|x86
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Debug|x64.ActiveCfg = Debug|x64
24 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Debug|x64.Build.0 = Debug|x64
25 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Debug|x86.ActiveCfg = Debug|Win32
26 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Debug|x86.Build.0 = Debug|Win32
27 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Release|x64.ActiveCfg = Release|x64
28 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Release|x64.Build.0 = Release|x64
29 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Release|x86.ActiveCfg = Release|Win32
30 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}.Release|x86.Build.0 = Release|Win32
31 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Debug|x64.ActiveCfg = Debug|x64
32 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Debug|x64.Build.0 = Debug|x64
33 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Debug|x86.ActiveCfg = Debug|Win32
34 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Debug|x86.Build.0 = Debug|Win32
35 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Release|x64.ActiveCfg = Release|x64
36 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Release|x64.Build.0 = Release|x64
37 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Release|x86.ActiveCfg = Release|Win32
38 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}.Release|x86.Build.0 = Release|Win32
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/FlifWICCodec/FlifWICCodec.cpp:
--------------------------------------------------------------------------------
1 | // FlifWICCodec.cpp : Defines the exported functions for the DLL application.
2 | //
3 |
4 | #include "stdafx.h"
5 |
6 |
7 |
--------------------------------------------------------------------------------
/FlifWICCodec/FlifWICCodec.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {7BC431E9-6C4B-4E03-97B6-2DBF1AD4A3D1}
23 | Win32Proj
24 | FlifWICCodec
25 | 8.1
26 |
27 |
28 |
29 | DynamicLibrary
30 | true
31 | v140
32 | Unicode
33 |
34 |
35 | DynamicLibrary
36 | false
37 | v140
38 | true
39 | Unicode
40 |
41 |
42 | DynamicLibrary
43 | true
44 | v140
45 | Unicode
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v140
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 | $(SolutionDir)FLIF\src\library;$(VC_IncludePath);$(WindowsSDK_IncludePath)
75 |
76 |
77 | true
78 | $(SolutionDir)FLIF\src\library;$(VC_IncludePath);$(WindowsSDK_IncludePath)
79 |
80 |
81 | false
82 | $(SolutionDir)FLIF\src\library;$(VC_IncludePath);$(WindowsSDK_IncludePath)
83 |
84 |
85 | false
86 | $(SolutionDir)FLIF\src\library;$(VC_IncludePath);$(WindowsSDK_IncludePath)
87 |
88 |
89 |
90 | NotUsing
91 | Level3
92 | Disabled
93 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32;_DEBUG;_WINDOWS;_USRDLL;FLIFWICCODEC_EXPORTS;%(PreprocessorDefinitions)
94 | MultiThreadedDebug
95 | Fast
96 |
97 |
98 | Windows
99 | true
100 | flif_wic_codec.def
101 | shlwapi.lib;windowscodecs.lib;ole32.lib;OleAut32.lib;Propsys.lib
102 |
103 |
104 | true
105 |
106 |
107 |
108 |
109 | NotUsing
110 | Level3
111 | Disabled
112 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;_DEBUG;_WINDOWS;_USRDLL;FLIFWICCODEC_EXPORTS;%(PreprocessorDefinitions)
113 | MultiThreadedDebug
114 | Fast
115 |
116 |
117 | Windows
118 | true
119 | flif_wic_codec.def
120 | shlwapi.lib;windowscodecs.lib;ole32.lib;OleAut32.lib;Propsys.lib
121 |
122 |
123 | true
124 |
125 |
126 |
127 |
128 | Level3
129 | NotUsing
130 | Full
131 | true
132 | true
133 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32;NDEBUG;_WINDOWS;_USRDLL;FLIFWICCODEC_EXPORTS;%(PreprocessorDefinitions)
134 | MultiThreaded
135 | true
136 | true
137 | true
138 | Fast
139 | false
140 |
141 |
142 | Windows
143 | true
144 | true
145 | true
146 | flif_wic_codec.def
147 | shlwapi.lib;windowscodecs.lib;ole32.lib;OleAut32.lib;Propsys.lib
148 | UseLinkTimeCodeGeneration
149 |
150 |
151 | true
152 |
153 |
154 |
155 |
156 | Level3
157 | NotUsing
158 | Full
159 | true
160 | true
161 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;NDEBUG;_WINDOWS;_USRDLL;FLIFWICCODEC_EXPORTS;%(PreprocessorDefinitions)
162 | MultiThreaded
163 | true
164 | true
165 | Fast
166 | true
167 | false
168 |
169 |
170 | Windows
171 | true
172 | true
173 | true
174 | flif_wic_codec.def
175 | shlwapi.lib;windowscodecs.lib;ole32.lib;OleAut32.lib;Propsys.lib
176 | UseLinkTimeCodeGeneration
177 |
178 |
179 | true
180 |
181 |
182 |
183 |
184 |
185 |
186 | false
187 |
188 |
189 | false
190 |
191 |
192 | false
193 |
194 |
195 | false
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 | Document
232 |
233 |
234 |
235 |
236 |
237 | {56871adf-abf5-414b-8872-bcf0e200b95d}
238 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/FlifWICCodec/FlifWICCodec.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hh;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 | Source Files
26 |
27 |
28 | Source Files
29 |
30 |
31 | Source Files
32 |
33 |
34 | Source Files
35 |
36 |
37 | Source Files
38 |
39 |
40 |
41 |
42 | Resource Files
43 |
44 |
45 |
46 |
47 | Header Files
48 |
49 |
50 | Header Files
51 |
52 |
53 | Header Files
54 |
55 |
56 | Header Files
57 |
58 |
59 | Header Files
60 |
61 |
62 | Header Files
63 |
64 |
65 | Header Files
66 |
67 |
68 | Header Files
69 |
70 |
71 | Header Files
72 |
73 |
74 | Header Files
75 |
76 |
77 | Header Files
78 |
79 |
80 | Header Files
81 |
82 |
83 |
84 |
85 | Source Files
86 |
87 |
88 | Source Files
89 |
90 |
91 |
--------------------------------------------------------------------------------
/FlifWICCodec/autoreg.inf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peirick/FlifWICCodec/e42164e90ec300ae7396b6f06365ae0d7dcb651b/FlifWICCodec/autoreg.inf
--------------------------------------------------------------------------------
/FlifWICCodec/decode_container.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "dllmain.h"
3 | #include "uuid.h"
4 | #include "utils.h"
5 | #include "decode_container.h"
6 | #include "decode_frame.h"
7 |
8 | DecodeContainer::DecodeContainer()
9 | : has_been_decoded_(false),
10 | has_only_infos_decoded_(false),
11 | last_decode_desult(0),
12 | info_(nullptr),
13 | decoder_(nullptr)
14 | {
15 | TRACE("()\n");
16 | InitializeCriticalSection(&cs_);
17 | }
18 |
19 | DecodeContainer::~DecodeContainer()
20 | {
21 | TRACE("()\n");
22 | if (info_) {
23 | flif_destroy_info(info_);
24 | info_ = nullptr;
25 | }
26 | if (decoder_) {
27 | flif_destroy_decoder(decoder_);
28 | decoder_ = nullptr;
29 | }
30 | }
31 |
32 | HRESULT DecodeContainer::QueryInterface(REFIID riid, void** ppvObject) {
33 | TRACE2("(%s, %p)\n", debugstr_guid(riid), ppvObject);
34 |
35 | if (ppvObject == nullptr)
36 | return E_INVALIDARG;
37 | *ppvObject = nullptr;
38 |
39 | if (!IsEqualGUID(riid, IID_IUnknown) &&
40 | !IsEqualGUID(riid, IID_IWICBitmapDecoder))
41 | return E_NOINTERFACE;
42 | this->AddRef();
43 | *ppvObject = static_cast(this);
44 | return S_OK;
45 | }
46 |
47 | HRESULT DecodeContainer::ReadInfo(IStream* pIStream)
48 | {
49 | const int header_size_bytes = 100;
50 | uint8_t header[header_size_bytes];
51 | HRESULT ret;
52 | ULONG read;
53 |
54 | if (FAILED(ret = pIStream->Read(header, sizeof(header), &read)))
55 | return ret;
56 |
57 | if (info_) {
58 | flif_destroy_info(info_);
59 | info_ = nullptr;
60 | }
61 | info_ = flif_read_info_from_memory(header, read);
62 | if (!info_) {
63 | return WINCODEC_ERR_BADHEADER;
64 | }
65 |
66 | // reset pIStream
67 | LARGE_INTEGER zero;
68 | zero.QuadPart = 0;
69 | pIStream->Seek(zero, STREAM_SEEK_SET, nullptr);
70 | return S_OK;
71 | }
72 |
73 | HRESULT DecodeContainer::QueryCapability(IStream* pIStream, DWORD* pdwCapability) {
74 | TRACE2("(%p, %x)\n", pIStream, pdwCapability);
75 | if (pdwCapability == nullptr)
76 | return E_INVALIDARG;
77 |
78 | HRESULT ret = ReadInfo(pIStream);
79 | if (ret == WINCODEC_ERR_BADHEADER)
80 | return WINCODEC_ERR_WRONGSTATE; // That's what Win7 jpeg codec returns.
81 |
82 | if (ret == S_OK)
83 | *pdwCapability =
84 | WICBitmapDecoderCapabilityCanDecodeSomeImages
85 | | WICBitmapDecoderCapabilityCanDecodeAllImages
86 | //| WICBitmapDecoderCapabilityCanDecodeThumbnail
87 | | WICBitmapDecoderCapabilityCanEnumerateMetadata;
88 | return ret;
89 | }
90 |
91 | HRESULT DecodeContainer::Initialize(IStream* pIStream, WICDecodeOptions cacheOptions) {
92 | TRACE2("(%p, %x)\n", pIStream, cacheOptions);
93 |
94 | if (pIStream == nullptr)
95 | return E_INVALIDARG;
96 |
97 | SectionLock l(&cs_);
98 |
99 | HRESULT ret;
100 | ret = ReadInfo(pIStream);
101 | if (FAILED(ret)) {
102 | return ret;
103 | }
104 |
105 | if (has_been_decoded_) {
106 | has_been_decoded_ = false;
107 | frames_.clear();
108 | }
109 | // Save stream for later use
110 | return pIStream->QueryInterface(stream_.get_out_storage());
111 | }
112 |
113 | HRESULT DecodeContainer::DecodeCached(bool decode_only_infos)
114 | {
115 | SectionLock l(&cs_);
116 | if (!has_been_decoded_
117 | || (decode_only_infos == false && has_only_infos_decoded_))
118 | {
119 | last_decode_desult = Decode(decode_only_infos);
120 | has_been_decoded_ = true;
121 | has_only_infos_decoded_ = decode_only_infos;
122 | }
123 | return last_decode_desult;
124 | }
125 |
126 | HRESULT DecodeContainer::Decode(bool onlyInfos)
127 | {
128 | if (stream_.get() == nullptr)
129 | return WINCODEC_ERR_NOTINITIALIZED;
130 |
131 | HRESULT ret;
132 | STATSTG stats;
133 | ret = stream_->Stat(&stats, STATFLAG_NONAME);
134 | if (FAILED(ret))
135 | return ret;
136 | ULONG stream_size = stats.cbSize.QuadPart;
137 | TRACE1("stream_size %d\n", stream_size);
138 | ULONG bytes_read;
139 | scoped_buffer file_data(stream_size);
140 | if (file_data.get() == nullptr)
141 | return WINCODEC_ERR_OUTOFMEMORY;
142 |
143 | LARGE_INTEGER zero;
144 | zero.QuadPart = 0;
145 | ret = stream_->Seek(zero, STREAM_SEEK_SET, nullptr);
146 | if (FAILED(ret))
147 | return ret;
148 |
149 | ret = stream_->Read(file_data.get(), stream_size, &bytes_read);
150 | TRACE1("bytes_read %d\n", bytes_read);
151 | if (FAILED(ret)) {
152 | TRACE("pIStream->Read failed\n");
153 | return ret;
154 | }
155 |
156 | if (bytes_read != stream_size) {
157 | return WINCODEC_ERR_WRONGSTATE;
158 | }
159 |
160 | if (!decoder_) {
161 | decoder_ = flif_create_decoder();
162 | }
163 |
164 | if (onlyInfos) {
165 | flif_decoder_set_scale(decoder_, -2);
166 | }
167 | else {
168 | flif_decoder_set_scale(decoder_, 1);
169 | }
170 |
171 | if (flif_decoder_decode_memory(decoder_, file_data.get(), bytes_read) != 0)
172 | {
173 | size_t num_images = flif_decoder_num_images(decoder_);
174 | frames_.resize(num_images);
175 | for (int i = 0; i < num_images; ++i) {
176 | FLIF_IMAGE* image = flif_decoder_get_image(decoder_, i);
177 | if (image)
178 | {
179 | if (frames_[i].get() == nullptr) {
180 | frames_[i].reset(new (std::nothrow) DecodeFrame());
181 | if (frames_[i].get() == nullptr)
182 | return E_OUTOFMEMORY;
183 | }
184 | frames_[i]->SetFlifImage(image, num_images);
185 | }
186 | else {
187 | frames_[i].reset(nullptr);
188 | }
189 | }
190 | }
191 | else {
192 | TRACE("decode failed\n");
193 | ret = WINCODEC_ERR_WRONGSTATE;
194 | }
195 | if (FAILED(ret))
196 | return ret;
197 | return S_OK;
198 | }
199 |
200 | HRESULT DecodeContainer::GetContainerFormat(GUID* pguidContainerFormat) {
201 | TRACE1("(%p)\n", pguidContainerFormat);
202 | if (pguidContainerFormat == nullptr)
203 | return E_INVALIDARG;
204 | *pguidContainerFormat = GUID_ContainerFormatFLIF;
205 | return S_OK;
206 | }
207 |
208 | HRESULT DecodeContainer::InitializeFactory()
209 | {
210 | SectionLock l(&cs_);
211 | HRESULT result = S_OK;
212 | if (factory_.get() == nullptr) {
213 | result = CoCreateInstance(CLSID_WICImagingFactory,
214 | nullptr,
215 | CLSCTX_INPROC_SERVER,
216 | IID_IWICImagingFactory,
217 | (LPVOID*)factory_.get_out_storage());
218 | }
219 | return result;
220 | }
221 |
222 | HRESULT DecodeContainer::GetDecoderInfo(IWICBitmapDecoderInfo** ppIDecoderInfo) {
223 | TRACE1("(%p)\n", ppIDecoderInfo);
224 | HRESULT result;
225 |
226 | result = InitializeFactory();
227 | if (FAILED(result))
228 | return result;
229 |
230 | ComPtr compInfo;
231 | result = factory_->CreateComponentInfo(CLSID_FLIFWICDecoder, compInfo.get_out_storage());
232 | if (FAILED(result))
233 | return result;
234 |
235 | result = compInfo->QueryInterface(IID_IWICBitmapDecoderInfo, (void**)ppIDecoderInfo);
236 | if (FAILED(result))
237 | return result;
238 |
239 | return S_OK;
240 | }
241 |
242 | HRESULT DecodeContainer::CopyPalette(IWICPalette* pIPalette) {
243 | TRACE1("(%p)\n", pIPalette);
244 | return WINCODEC_ERR_PALETTEUNAVAILABLE;
245 | }
246 |
247 | HRESULT DecodeContainer::GetMetadataQueryReader(IWICMetadataQueryReader** ppIMetadataQueryReader) {
248 | TRACE1("(%p)\n", ppIMetadataQueryReader);
249 | if (ppIMetadataQueryReader == nullptr)
250 | return E_INVALIDARG;
251 |
252 | HRESULT result = DecodeCached(true);
253 | if (FAILED(result))
254 | return result;
255 |
256 | return frames_[0].get()->GetMetadataQueryReader(ppIMetadataQueryReader);
257 | }
258 |
259 | HRESULT DecodeContainer::GetPreview(IWICBitmapSource** ppIBitmapSource) {
260 | TRACE1("(%p)\n", ppIBitmapSource);
261 | if (ppIBitmapSource == nullptr)
262 | return E_INVALIDARG;
263 |
264 | HRESULT result = DecodeCached(false);
265 | if (FAILED(result))
266 | return result;
267 |
268 | *ppIBitmapSource = frames_[0].new_ref();
269 | return S_OK;
270 | }
271 |
272 | HRESULT DecodeContainer::GetColorContexts(UINT cCount, IWICColorContext** ppIColorContexts, UINT* pcActualCount) {
273 | TRACE3("(%d, %p, %p)\n", cCount, ppIColorContexts, pcActualCount);
274 | return S_OK;
275 | }
276 |
277 | HRESULT DecodeContainer::GetThumbnail(IWICBitmapSource** ppIThumbnail)
278 | {
279 | TRACE1("(%p)\n", ppIThumbnail);
280 | if (ppIThumbnail == nullptr)
281 | return E_INVALIDARG;
282 |
283 | HRESULT result = DecodeCached(false);
284 | if (FAILED(result))
285 | return result;
286 |
287 | *ppIThumbnail = frames_[0].new_ref();
288 | return S_OK;
289 | }
290 |
291 | HRESULT DecodeContainer::GetFrameCount(UINT* pCount) {
292 | TRACE1("(%p)\n", pCount);
293 | if (pCount == nullptr)
294 | return E_INVALIDARG;
295 |
296 | if (info_ == nullptr)
297 | return WINCODEC_ERR_NOTINITIALIZED;
298 |
299 | *pCount = GetFrameCount();
300 | return S_OK;
301 | }
302 |
303 | HRESULT DecodeContainer::GetFrame(UINT index, IWICBitmapFrameDecode** ppIBitmapFrame) {
304 | TRACE2("(%d, %p)\n", index, ppIBitmapFrame);
305 | if (ppIBitmapFrame == nullptr)
306 | return E_INVALIDARG;
307 |
308 | HRESULT result = DecodeCached(false);
309 | if (FAILED(result))
310 | return result;
311 |
312 | SectionLock l(&cs_);
313 | *ppIBitmapFrame = frames_[index].new_ref();
314 | return S_OK;
315 | }
316 |
317 | UINT DecodeContainer::GetWidth() const
318 | {
319 | return info_ ? flif_info_get_width(info_) : 0;
320 | }
321 |
322 | UINT DecodeContainer::GetHeight() const
323 | {
324 | return info_ ? flif_info_get_height(info_) : 0;
325 | }
326 |
327 | UINT DecodeContainer::GetBitDepth() const
328 | {
329 | return info_ ? flif_info_get_depth(info_) : 0;
330 | }
331 |
332 | UINT DecodeContainer::GetFrameCount() const
333 | {
334 | return info_ ? flif_info_num_images(info_) : 0;
335 | }
336 |
337 |
338 |
339 |
--------------------------------------------------------------------------------
/FlifWICCodec/decode_container.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "decode_frame.h"
7 | #include "utils.h"
8 |
9 | class DecodeContainer : public ComObjectBase {
10 | public:
11 | DecodeContainer();
12 | ~DecodeContainer();
13 | // Inherited via IUnknown:
14 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
15 | ULONG STDMETHODCALLTYPE AddRef() override { return ComObjectBase::AddRef(); }
16 | ULONG STDMETHODCALLTYPE Release() override { return ComObjectBase::Release(); }
17 | // Inherited via IWICBitmapDecoder:
18 | HRESULT STDMETHODCALLTYPE QueryCapability(IStream *pIStream, DWORD *pdwCapability) override;
19 | HRESULT STDMETHODCALLTYPE Initialize(IStream *pIStream, WICDecodeOptions cacheOptions) override;
20 | HRESULT STDMETHODCALLTYPE GetContainerFormat(GUID *pguidContainerFormat) override;
21 | HRESULT STDMETHODCALLTYPE GetDecoderInfo(IWICBitmapDecoderInfo **ppIDecoderInfo) override;
22 | HRESULT STDMETHODCALLTYPE CopyPalette(IWICPalette *pIPalette)override;
23 | HRESULT STDMETHODCALLTYPE GetMetadataQueryReader(IWICMetadataQueryReader **ppIMetadataQueryReader)override;
24 | HRESULT STDMETHODCALLTYPE GetPreview(IWICBitmapSource **ppIBitmapSource)override;
25 | HRESULT STDMETHODCALLTYPE GetColorContexts(UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)override;
26 | HRESULT STDMETHODCALLTYPE GetThumbnail(IWICBitmapSource **ppIThumbnail)override;
27 | HRESULT STDMETHODCALLTYPE GetFrameCount(UINT *pCount)override;
28 | HRESULT STDMETHODCALLTYPE GetFrame(UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)override;
29 | public:
30 | UINT GetWidth() const;
31 | UINT GetHeight() const;
32 | UINT GetBitDepth() const;
33 | UINT GetFrameCount() const;
34 | private:
35 | // No copy and assign.
36 | DecodeContainer(const DecodeContainer&) = delete;
37 | void operator=(const DecodeContainer&) = delete;
38 | HRESULT InitializeFactory();
39 | HRESULT ReadInfo(IStream * pIStream);
40 | HRESULT DecodeCached(bool onlyInfos);
41 | HRESULT Decode(bool onlyInfos);
42 | bool has_been_decoded_;
43 | bool has_only_infos_decoded_;
44 | HRESULT last_decode_desult;
45 |
46 | FLIF_INFO* info_;
47 |
48 | FLIF_DECODER* decoder_;
49 | ComPtr stream_;
50 | std::deque> frames_;
51 | ComPtr factory_;
52 | CRITICAL_SECTION cs_;
53 | };
54 |
--------------------------------------------------------------------------------
/FlifWICCodec/decode_frame.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include "decode_frame.h"
7 | #include "dllmain.h"
8 | #include "uuid.h"
9 |
10 | #ifdef FLIF_DEBUG_LOGGING
11 | #include "stopwatch.h"
12 | #endif // FLIF_DEBUG_LOGGING
13 |
14 |
15 |
16 | DecodeFrame::DecodeFrame()
17 | : metadataBlockReader_(*this),
18 | image_(nullptr),
19 | totalNumberOfImages_(0)
20 | {
21 | TRACE("()\n");
22 | InitializeCriticalSection(&cs_);
23 | }
24 |
25 | void DecodeFrame::SetFlifImage(FLIF_IMAGE * image, UINT totalNumberOfImages)
26 | {
27 | SectionLock l(&cs_);
28 | image_ = image;
29 | totalNumberOfImages_ = totalNumberOfImages;
30 | }
31 |
32 | DecodeFrame::~DecodeFrame()
33 | {
34 | TRACE("()\n");
35 | DeleteCriticalSection(&cs_);
36 | }
37 |
38 |
39 | HRESULT DecodeFrame::QueryInterface(REFIID riid, void **ppvObject) {
40 | TRACE2("(%s, %p)\n", debugstr_guid(riid), ppvObject);
41 |
42 | if (ppvObject == nullptr)
43 | return E_INVALIDARG;
44 | *ppvObject = nullptr;
45 |
46 | if (IsEqualGUID(riid, IID_IUnknown) ||
47 | IsEqualGUID(riid, IID_IWICBitmapFrameDecode) ||
48 | IsEqualGUID(riid, IID_IWICBitmapSource))
49 | {
50 | this->AddRef();
51 | *ppvObject = static_cast(this);
52 | return S_OK;
53 | }
54 |
55 | if (IsEqualGUID(riid, IID_IWICMetadataBlockReader))
56 | {
57 | this->AddRef();
58 | *ppvObject = static_cast(&this->metadataBlockReader_);
59 | return S_OK;
60 | }
61 |
62 | return E_NOINTERFACE;
63 | }
64 |
65 | HRESULT DecodeFrame::GetSize(UINT *puiWidth, UINT *puiHeight) {
66 | TRACE2("(%p, %p)\n", puiWidth, puiHeight);
67 | if (puiWidth == nullptr || puiHeight == nullptr)
68 | return E_INVALIDARG;
69 | *puiWidth = GetWidth();
70 | *puiHeight = GetHeight();
71 | TRACE2("ret: %u x %u\n", *puiWidth, *puiHeight);
72 | return S_OK;
73 | }
74 |
75 | HRESULT DecodeFrame::GetPixelFormat(WICPixelFormatGUID *pPixelFormat) {
76 | TRACE1("(%p)\n", pPixelFormat);
77 | if (pPixelFormat == nullptr)
78 | return E_INVALIDARG;
79 | //if (nb_channels >= 4) {
80 | *pPixelFormat = GUID_WICPixelFormat32bppRGBA;
81 | return S_OK;
82 | }
83 |
84 | HRESULT DecodeFrame::GetResolution(double *pDpiX, double *pDpiY) {
85 | TRACE2("(%p, %p)\n", pDpiX, pDpiY);
86 | if (pDpiX == nullptr)
87 | return E_INVALIDARG;
88 | if (pDpiY == nullptr)
89 | return E_INVALIDARG;
90 | // Let's assume square pixels. 96dpi seems to be a reasonable default.
91 | *pDpiX = 96;
92 | *pDpiY = 96;
93 | return S_OK;
94 | }
95 |
96 | HRESULT DecodeFrame::CopyPalette(IWICPalette *pIPalette) {
97 | TRACE1("(%p)\n", pIPalette);
98 | return WINCODEC_ERR_PALETTEUNAVAILABLE;
99 | }
100 |
101 | HRESULT DecodeFrame::CopyPixels(const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) {
102 | TRACE4("(%p, %u, %u, %p)\n", prc, cbStride, cbBufferSize, pbBuffer);
103 | if (pbBuffer == nullptr)
104 | return E_INVALIDARG;
105 | uint32_t image_width = GetWidth();
106 | uint32_t image_height = GetHeight();
107 | uint8_t nb_channels = 4; // flif_image_get_nb_channels(image_);
108 |
109 | WICRect rect = { 0, 0, image_width, image_height };
110 | if (prc)
111 | rect = *prc;
112 | if (rect.Width < 0 || rect.Height < 0 || rect.X < 0 || rect.Y < 0)
113 | return E_INVALIDARG;
114 | if (rect.X + rect.Width > image_width ||
115 | rect.Y + rect.Height > image_height)
116 | return E_INVALIDARG;
117 |
118 | // Divisions instead of multiplications to avoid integer overflows:
119 | if (cbStride / nb_channels < static_cast(rect.Width))
120 | return E_INVALIDARG;
121 | if (cbBufferSize / cbStride < static_cast(rect.Height))
122 | return WINCODEC_ERR_INSUFFICIENTBUFFER;
123 |
124 | if (rect.Width == 0 || rect.Height == 0)
125 | return S_OK;
126 |
127 | size_t buffer_size = image_width*nb_channels;
128 | scoped_buffer temp_row(buffer_size);
129 | if (temp_row.alloc_failed()) {
130 | return WINCODEC_ERR_OUTOFMEMORY;
131 | }
132 |
133 | BYTE* dst_buffer = pbBuffer;
134 | const int x_offset = rect.X * nb_channels;
135 | const int width = rect.Width * nb_channels;
136 |
137 | for (int src_y = rect.Y; src_y < rect.Y + rect.Height; ++src_y) {
138 | flif_image_read_row_RGBA8(image_, src_y, temp_row.get(), buffer_size);
139 | memcpy(dst_buffer, temp_row.get() + x_offset, width);
140 | dst_buffer += cbStride;
141 | }
142 | return S_OK;
143 | }
144 |
145 | HRESULT DecodeFrame::GetMetadataQueryReader(IWICMetadataQueryReader **ppIMetadataQueryReader) {
146 | TRACE1("(%p)\n", ppIMetadataQueryReader);
147 | if (ppIMetadataQueryReader == nullptr)
148 | return E_INVALIDARG;
149 |
150 | HRESULT result = S_OK;
151 | //Create factory
152 | result = InitializeFactory();
153 | if (FAILED(result))
154 | return result;
155 |
156 | return componentFactory_->CreateQueryReaderFromBlockReader(static_cast(&this->metadataBlockReader_), ppIMetadataQueryReader);
157 | }
158 |
159 | HRESULT DecodeFrame::GetColorContexts(UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) {
160 | TRACE3("(%d, %p, %p)\n", cCount, ppIColorContexts, pcActualCount);
161 | if (pcActualCount == nullptr)
162 | return E_INVALIDARG;
163 | *pcActualCount = 0;
164 | return S_OK;
165 | }
166 |
167 | HRESULT DecodeFrame::GetThumbnail(IWICBitmapSource **ppIThumbnail) {
168 | TRACE1("(%p)\n", ppIThumbnail);
169 | return WINCODEC_ERR_CODECNOTHUMBNAIL;
170 | }
171 |
172 |
173 |
174 | HRESULT DecodeFrame::InitializeFactory()
175 | {
176 | SectionLock l(&cs_);
177 | HRESULT result = S_OK;
178 | if (factory_.get() == nullptr)
179 | {
180 | result = CoCreateInstance(CLSID_WICImagingFactory,
181 | nullptr,
182 | CLSCTX_INPROC_SERVER,
183 | IID_IWICImagingFactory,
184 | (LPVOID*)factory_.get_out_storage());
185 | if (FAILED(result))
186 | return result;
187 | }
188 | if (factory_.get() != nullptr &&
189 | componentFactory_.get() == nullptr)
190 | {
191 | result = factory_->QueryInterface(componentFactory_.get_out_storage());
192 | if (FAILED(result)) {
193 | return result;
194 | }
195 | }
196 | return result;
197 | }
198 |
199 | UINT DecodeFrame::GetWidth() const
200 | {
201 | return flif_image_get_width(image_);
202 | }
203 |
204 | UINT DecodeFrame::GetHeight() const
205 | {
206 | return flif_image_get_height(image_);
207 | }
208 |
209 | UINT DecodeFrame::GetDelay() const
210 | {
211 | return flif_image_get_frame_delay(image_);
212 | }
213 |
214 | HRESULT DecodeFrame::MetadataBlockReader::GetContainerFormat(GUID * pguidContainerFormat)
215 | {
216 | TRACE1("(%p)\n", pguidContainerFormat);
217 | if (pguidContainerFormat == nullptr)
218 | return E_INVALIDARG;
219 | //Return container format of Jpeg so that "Photo Metadata Policies" will work.
220 | //https://msdn.microsoft.com/en-us/library/windows/desktop/ee872003(v=vs.85).aspx
221 | *pguidContainerFormat = GUID_ContainerFormatJpeg;
222 | //*pguidContainerFormat = GUID_ContainerFormatFLIF;
223 | return S_OK;
224 | }
225 |
226 | HRESULT DecodeFrame::MetadataBlockReader::GetCount(UINT * pcCount)
227 | {
228 | TRACE1("(%p)\n", pcCount);
229 | if (pcCount == nullptr)
230 | return E_INVALIDARG;
231 |
232 | HRESULT result;
233 |
234 | //Create factory
235 | result = decodeFrame_.InitializeFactory();
236 | if (FAILED(result))
237 | return result;
238 |
239 | ReadAllMetadata();
240 | *pcCount = metadataReader_.size();
241 | return S_OK;
242 | }
243 |
244 | HRESULT DecodeFrame::MetadataBlockReader::GetReaderByIndex(UINT nIndex, IWICMetadataReader ** ppIMetadataReader)
245 | {
246 | TRACE2("(%d, %p)\n", nIndex, ppIMetadataReader);
247 | if (ppIMetadataReader == nullptr)
248 | return E_INVALIDARG;
249 | if (nIndex >= metadataReader_.size())
250 | return E_INVALIDARG;
251 |
252 | *ppIMetadataReader = metadataReader_[nIndex].new_ref();
253 | return S_OK;
254 | }
255 |
256 | HRESULT DecodeFrame::MetadataBlockReader::GetEnumerator(IEnumUnknown ** ppIEnumMetadata)
257 | {
258 | TRACE1("(%p)\n", ppIEnumMetadata);
259 | return E_NOTIMPL;
260 | }
261 |
262 | static
263 | inline HRESULT InitPropVariantFromUInt8(_In_ UCHAR uiVal, _Out_ PROPVARIANT *ppropvar)
264 | {
265 | ppropvar->vt = VT_UI1;
266 | ppropvar->bVal = uiVal;
267 | return S_OK;
268 | }
269 |
270 | void DecodeFrame::MetadataBlockReader::ReadAllMetadata()
271 | {
272 | TRACE("()\n");
273 | ReadMetadata(GUID_MetadataFormatExif, "eXif");
274 | ReadMetadata(GUID_MetadataFormatXMP, "eXmp");
275 | ReadMetadata(GUID_MetadataFormatChunkiCCP, "iCCP");
276 |
277 | if (decodeFrame_.totalNumberOfImages_ > 1)
278 | {
279 | ComPtr writer;
280 |
281 | if (SUCCEEDED(decodeFrame_.componentFactory_->CreateMetadataWriter(
282 | GUID_MetadataFormatIMD,
283 | nullptr,
284 | WICPersistOptionDefault,
285 | writer.get_out_storage())))
286 | {
287 | PROPVARIANT key;
288 | PROPVARIANT value;
289 |
290 | InitPropVariantFromString(L"Left", &key);
291 | InitPropVariantFromUInt16(0, &value);
292 | writer->SetValue(nullptr, &key, &value);
293 | PropVariantClear(&key);
294 | PropVariantClear(&value);
295 |
296 | InitPropVariantFromString(L"Top", &key);
297 | InitPropVariantFromUInt16(0, &value);
298 | writer->SetValue(nullptr, &key, &value);
299 | PropVariantClear(&key);
300 | PropVariantClear(&value);
301 |
302 | InitPropVariantFromString(L"Width", &key);
303 | InitPropVariantFromUInt16(decodeFrame_.GetWidth(), &value);
304 | writer->SetValue(nullptr, &key, &value);
305 | PropVariantClear(&key);
306 | PropVariantClear(&value);
307 |
308 | InitPropVariantFromString(L"Height", &key);
309 | InitPropVariantFromUInt16(decodeFrame_.GetHeight(), &value);
310 | writer->SetValue(nullptr, &key, &value);
311 | PropVariantClear(&key);
312 | PropVariantClear(&value);
313 |
314 | // Store for later use
315 | ComPtr reader;
316 | if (SUCCEEDED(writer->QueryInterface(reader.get_out_storage())))
317 | metadataReader_.emplace_back(reader.new_ref());
318 | }
319 |
320 | if (SUCCEEDED(decodeFrame_.componentFactory_->CreateMetadataWriter(
321 | GUID_MetadataFormatGCE,
322 | nullptr,
323 | WICPersistOptionDefault,
324 | writer.get_out_storage())))
325 | {
326 | PROPVARIANT key;
327 | PROPVARIANT value;
328 |
329 | InitPropVariantFromString(L"Disposal", &key);
330 | InitPropVariantFromUInt8(0, &value);
331 | writer->SetValue(nullptr, &key, &value);
332 | PropVariantClear(&key);
333 | PropVariantClear(&value);
334 |
335 | InitPropVariantFromString(L"Delay", &key);
336 | InitPropVariantFromUInt16(decodeFrame_.GetDelay() / 10, &value);
337 | writer->SetValue(nullptr, &key, &value);
338 | PropVariantClear(&key);
339 | PropVariantClear(&value);
340 |
341 | InitPropVariantFromString(L"TransparencyFlag", &key);
342 | InitPropVariantFromBoolean(FALSE, &value);
343 | writer->SetValue(nullptr, &key, &value);
344 | PropVariantClear(&key);
345 | PropVariantClear(&value);
346 |
347 | // Store for later use
348 | ComPtr reader;
349 | if (SUCCEEDED(writer->QueryInterface(reader.get_out_storage())))
350 | metadataReader_.emplace_back(reader.new_ref());
351 | }
352 | }
353 | }
354 |
355 | void DecodeFrame::MetadataBlockReader::ReadMetadata(GUID metadataFormat, const char* name)
356 | {
357 | TRACE("()\n");
358 | uint8_t* data = nullptr;
359 | size_t length = 0;
360 | flif_image_get_metadata(decodeFrame_.image_, name, &data, &length);
361 | if (data && length > 0)
362 | {
363 | //Create stream
364 | ComPtr stream(SHCreateMemStream(data, length));
365 |
366 | // Create reader of stream
367 | ComPtr reader;
368 | if (SUCCEEDED(decodeFrame_.componentFactory_->CreateMetadataReader(
369 | metadataFormat,
370 | nullptr,
371 | WICPersistOptionDefault,
372 | stream.get(),
373 | reader.get_out_storage()))) {
374 | // Store Reader for later use
375 | metadataReader_.emplace_back(reader.new_ref());
376 | }
377 | }
378 | flif_image_free_metadata(decodeFrame_.image_, data);
379 | }
380 |
381 |
382 |
--------------------------------------------------------------------------------
/FlifWICCodec/decode_frame.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "utils.h"
9 |
10 | class DecodeFrame : public ComObjectBase {
11 | public:
12 | DecodeFrame();
13 | ~DecodeFrame();
14 | // Inherited via IUnknown:
15 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
16 | ULONG STDMETHODCALLTYPE AddRef() override { return ComObjectBase::AddRef(); }
17 | ULONG STDMETHODCALLTYPE Release() override { return ComObjectBase::Release(); }
18 | // Inherited via IWICBitmapSource:
19 | HRESULT STDMETHODCALLTYPE GetSize(UINT *puiWidth, UINT *puiHeight) override;
20 | HRESULT STDMETHODCALLTYPE GetPixelFormat(WICPixelFormatGUID *pPixelFormat) override;
21 | HRESULT STDMETHODCALLTYPE GetResolution(double *pDpiX, double *pDpiY) override;
22 | HRESULT STDMETHODCALLTYPE CopyPalette(IWICPalette *pIPalette) override;
23 | HRESULT STDMETHODCALLTYPE CopyPixels(const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) override;
24 | // Inherited via IWICBitmapFrameDecode:
25 | HRESULT STDMETHODCALLTYPE GetMetadataQueryReader(IWICMetadataQueryReader **ppIMetadataQueryReader) override;
26 | HRESULT STDMETHODCALLTYPE GetColorContexts(UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) override;
27 | HRESULT STDMETHODCALLTYPE GetThumbnail(IWICBitmapSource **ppIThumbnail) override;
28 |
29 | void SetFlifImage(FLIF_IMAGE* image, UINT totalNumberImages);
30 | private:
31 |
32 | class MetadataBlockReader : public IWICMetadataBlockReader {
33 | public:
34 | MetadataBlockReader(DecodeFrame& decodeFrame) : decodeFrame_(decodeFrame) {}
35 | // Inherited via IUnknown:
36 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override { return decodeFrame_.QueryInterface(riid, ppvObject); };
37 | ULONG STDMETHODCALLTYPE AddRef() override { return decodeFrame_.AddRef(); }
38 | ULONG STDMETHODCALLTYPE Release() override { return decodeFrame_.Release(); }
39 | // Inherited via IWICMetadataBlockReader
40 | HRESULT STDMETHODCALLTYPE GetContainerFormat(GUID * pguidContainerFormat) override;
41 | HRESULT STDMETHODCALLTYPE GetCount(UINT * pcCount) override;
42 | HRESULT STDMETHODCALLTYPE GetReaderByIndex(UINT nIndex, IWICMetadataReader ** ppIMetadataReader) override;
43 | HRESULT STDMETHODCALLTYPE GetEnumerator(IEnumUnknown ** ppIEnumMetadata) override;
44 | private:
45 | void ReadAllMetadata();
46 | void ReadMetadata(GUID metadataFormat, const char* name);
47 |
48 | DecodeFrame& decodeFrame_;
49 | std::deque> metadataReader_;
50 | };
51 |
52 | // No copy and assign.
53 | DecodeFrame(const DecodeFrame&) = delete;
54 | void operator=(const DecodeFrame&) = delete;
55 | HRESULT InitializeFactory();
56 | private:
57 | UINT GetWidth() const;
58 | UINT GetHeight() const;
59 | UINT GetDelay() const;
60 |
61 | CRITICAL_SECTION cs_;
62 | ComPtr factory_;
63 | ComPtr componentFactory_;
64 | MetadataBlockReader metadataBlockReader_;
65 | FLIF_IMAGE* image_;
66 | UINT totalNumberOfImages_;
67 | };
68 |
--------------------------------------------------------------------------------
/FlifWICCodec/dllmain.cpp:
--------------------------------------------------------------------------------
1 | #define INITGUID
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "dllmain.h"
11 | #include "decode_container.h"
12 | #include "encode_container.h"
13 | #include "metadata_store.h"
14 | #include "utils.h"
15 | #include "uuid.h"
16 |
17 | // Logging in debug mode.
18 | #ifdef FLIF_DEBUG_LOGGING
19 |
20 | #include
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | static CRITICAL_SECTION debug_file_section;
27 |
28 | void MAIN_debug_printf(const char* prefix, const char* func, const char* fmt, ...) {
29 | va_list ap;
30 | va_start(ap, fmt);
31 | EnterCriticalSection(&debug_file_section);
32 | fprintf(stdout, "%s:%s ", prefix, func);
33 | fflush(stdout);
34 | vfprintf(stdout, fmt, ap);
35 | fflush(stdout);
36 | LeaveCriticalSection(&debug_file_section);
37 | va_end(ap);
38 | }
39 |
40 | static void init_logging() {
41 | InitializeCriticalSection(&debug_file_section);
42 |
43 | WCHAR path[MAX_PATH];
44 | DWORD path_size = MAX_PATH;
45 | DWORD err;
46 | if ((err = SHRegGetValueW(HKEY_LOCAL_MACHINE, L"Software\\FLIF\\FLIF Codec",
47 | L"DebugPath", SRRF_RT_REG_SZ, NULL, path, &path_size)) != ERROR_SUCCESS) {
48 | StringCchCopyW(path, MAX_PATH, L"C:\\DebugOut");
49 | }
50 |
51 | WCHAR filename[MAX_PATH];
52 | StringCchPrintfW(filename, MAX_PATH, L"%s\\flif-stdout.txt", path);
53 | _wfreopen(filename, L"a", stdout);
54 | StringCchPrintfW(filename, MAX_PATH, L"%s\\flif-stderr.txt", path);
55 | _wfreopen(filename, L"a", stderr);
56 | }
57 |
58 | // Returns a pointer to a string representation of a GUID. The results are
59 | // stored in 32 static buffer - the 33rd call to this methods will overwrite
60 | // the first result.
61 | char *debugstr_guid(REFGUID guid)
62 | {
63 | static char guidbuf[32][128];
64 | static int pos = 0;
65 | pos %= 32;
66 | StringCchPrintfA(guidbuf[pos], 128,
67 | "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
68 | guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1],
69 | guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5],
70 | guid.Data4[6], guid.Data4[7]);
71 | return guidbuf[pos++];
72 | }
73 |
74 | WCHAR *debugstr_var(REFPROPVARIANT var)
75 | {
76 | static WCHAR buf[32][128];
77 | static int pos = 0;
78 | pos %= 32;
79 | HRESULT result = PropVariantToString(var, buf[pos], ARRAYSIZE(buf[pos]));
80 | if (SUCCEEDED(result) || result == STRSAFE_E_INSUFFICIENT_BUFFER)
81 | {
82 | return buf[pos++];
83 | }
84 | else {
85 | return L"error";
86 | }
87 | }
88 | #endif
89 |
90 | // Object and server locks counters
91 | LONG volatile MAIN_nObjects = 0;
92 | LONG volatile MAIN_nServerLocks = 0;
93 | HINSTANCE MAIN_hSelf;
94 |
95 |
96 | // Class factory
97 |
98 | typedef HRESULT(*ObjectConstructor)(IUnknown** ppvObject);
99 |
100 | // A default constructor. Creates and instance of T. T should be a subclass of
101 | // IUnknown with a parameter-less constructor.
102 | template
103 | HRESULT CreateComObject(IUnknown** output) {
104 | T* result = new (std::nothrow) T();
105 | if (result == nullptr)
106 | return E_OUTOFMEMORY;
107 | *output = static_cast(result);
108 | return S_OK;
109 | }
110 |
111 | class MyClassFactory : public ComObjectBase
112 | {
113 | public:
114 | MyClassFactory(ObjectConstructor ctor);
115 | // IUnknown:
116 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
117 | ULONG STDMETHODCALLTYPE AddRef() override { return ComObjectBase::AddRef(); }
118 | ULONG STDMETHODCALLTYPE Release() override { return ComObjectBase::Release(); }
119 | // IClassFactory:
120 | HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppvObject) override;
121 | HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override;
122 |
123 | private:
124 | volatile LONG ref_count_;
125 | ObjectConstructor ctor_;
126 | };
127 |
128 | MyClassFactory::MyClassFactory(ObjectConstructor ctor) {
129 | InterlockedIncrement(&MAIN_nObjects);
130 | ref_count_ = 0;
131 | ctor_ = ctor;
132 | }
133 |
134 | HRESULT MyClassFactory::QueryInterface(REFIID riid, void **ppvObject)
135 | {
136 | if (ppvObject == nullptr)
137 | return E_INVALIDARG;
138 | *ppvObject = nullptr;
139 |
140 | if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IClassFactory))
141 | return E_NOINTERFACE;
142 | this->AddRef();
143 | *ppvObject = static_cast(this);
144 | return S_OK;
145 | }
146 |
147 | HRESULT MyClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppvObject)
148 | {
149 | IUnknown* output;
150 | HRESULT ret;
151 | TRACE3("(%p, %s, %p)\n", pUnkOuter, debugstr_guid(riid), ppvObject);
152 |
153 | if (ppvObject == nullptr)
154 | return E_INVALIDARG;
155 | *ppvObject = nullptr;
156 |
157 | if (pUnkOuter != nullptr)
158 | return CLASS_E_NOAGGREGATION;
159 |
160 | ret = ctor_(&output);
161 | if (FAILED(ret))
162 | return ret;
163 | ret = output->QueryInterface(riid, ppvObject);
164 | output->Release();
165 | if (FAILED(ret)) {
166 | *ppvObject = nullptr;
167 | }
168 | TRACE1("ret=%08x\n", ret);
169 | return ret;
170 | }
171 |
172 | HRESULT MyClassFactory::LockServer(BOOL fLock)
173 | {
174 | if (fLock)
175 | InterlockedIncrement(&MAIN_nServerLocks);
176 | else
177 | InterlockedDecrement(&MAIN_nServerLocks);
178 | return S_OK;
179 | }
180 |
181 | typedef HRESULT(WINAPI *RegInstallFuncA)(HMODULE hm, LPCSTR pszSection, const STRTABLEA* pstTable);
182 | typedef void (STDAPICALLTYPE *SHChangeNotifyFunc)(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID dwItem2);
183 |
184 |
185 | static HRESULT RegisterServer(BOOL fInstall) {
186 | // Manual loading of advpack not to load it when DLL used in normal opertion.
187 | HMODULE hAdvPack = LoadLibraryExW(L"advpack.dll", nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
188 | if (hAdvPack == nullptr) {
189 | TRACE("Couldn't load advpack.dll\n");
190 | return E_UNEXPECTED;
191 | }
192 |
193 | // Note: RegInstallA/W not available on Windows XP with MSIE6.
194 | // Using ANSI version doesn't matter, as the "unicodeness" of the _MOD_PATH
195 | // depends only on the "unicodeness" of the *.inf file, while other
196 | // substitutions are ASCII.
197 | RegInstallFuncA pRegInstallA = (RegInstallFuncA)GetProcAddress(hAdvPack, "RegInstall");
198 | if (!pRegInstallA) {
199 | TRACE("Couldn't find RegInstall in advpack.dll\n");
200 | return E_UNEXPECTED;
201 | }
202 |
203 | STRENTRYA entries[1] = {
204 | { "PhotoDir", "Windows Photo Viewer" }
205 | };
206 | STRTABLEA strings;
207 | strings.cEntries = sizeof(entries) / sizeof(entries[0]);
208 | strings.pse = entries;
209 | if (LOWORD(GetVersion()) == 0x0006)
210 | entries[0].pszValue = "Windows Photo Gallery";
211 |
212 | LPCSTR section;
213 | if (LOBYTE(GetVersion()) < 6) {
214 | section = (fInstall ? "PrevistaInstall" : "PrevistaUninstall");
215 | }
216 | else {
217 | section = (fInstall ? "DefaultInstall" : "DefaultUninstall");
218 | }
219 | TRACE3("Registering install=%d (using %ws) v=%x\n", fInstall, section, GetVersion());
220 | if (FAILED(pRegInstallA(MAIN_hSelf, section, &strings)))
221 | return E_UNEXPECTED;
222 |
223 | // Invalidate caches.
224 | HMODULE hShell32 = LoadLibraryExW(L"shell32.dll", nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
225 | if (!hShell32) {
226 | TRACE("Couldn't load shell32.dll\n");
227 | return E_UNEXPECTED;
228 | }
229 | SHChangeNotifyFunc pSHChangeNotify = (SHChangeNotifyFunc)GetProcAddress(hShell32, "SHChangeNotify");
230 | if (pSHChangeNotify)
231 | pSHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
232 | return S_OK;
233 | }
234 |
235 | STDAPI DllRegisterServer() {
236 | return RegisterServer(TRUE);
237 | }
238 |
239 | STDAPI DllUnregisterServer() {
240 | return RegisterServer(FALSE);
241 | }
242 |
243 | _Check_return_
244 | STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID iid, _Outptr_ LPVOID FAR* ppv)
245 | {
246 | if (ppv == nullptr)
247 | return E_INVALIDARG;
248 | *ppv = nullptr;
249 | TRACE3("(%s, %s, %p)\n", debugstr_guid(clsid), debugstr_guid(iid), ppv);
250 | if (!IsEqualGUID(iid, IID_IClassFactory))
251 | return E_INVALIDARG;
252 |
253 | if (IsEqualGUID(clsid, CLSID_FLIFWICDecoder)) {
254 | *ppv = (LPVOID)(new (std::nothrow) MyClassFactory(CreateComObject));
255 | }
256 | else if (IsEqualGUID(clsid, CLSID_FLIFWICEncoder)) {
257 | *ppv = (LPVOID)(new (std::nothrow) MyClassFactory(CreateComObject));
258 | }
259 | else if (IsEqualGUID(clsid, GUID_FLIFPropertyStore)) {
260 | *ppv = (LPVOID)(new (std::nothrow) MyClassFactory(CreateComObject));
261 | }
262 | else {
263 | return CLASS_E_CLASSNOTAVAILABLE;
264 | }
265 |
266 | if (*ppv == nullptr)
267 | return E_OUTOFMEMORY;
268 | return S_OK;
269 | }
270 |
271 | STDAPI DllCanUnloadNow() {
272 | if (MAIN_nObjects == 0 && MAIN_nServerLocks == 0)
273 | return S_OK;
274 | else
275 | return S_FALSE;
276 | }
277 |
278 | BOOL APIENTRY DllMain(HMODULE hModule,
279 | DWORD ul_reason_for_call,
280 | LPVOID lpReserved)
281 | {
282 | if (ul_reason_for_call == DLL_PROCESS_ATTACH) {
283 | DisableThreadLibraryCalls(hModule);
284 | MAIN_hSelf = hModule;
285 | #ifdef FLIF_DEBUG_LOGGING
286 | init_logging();
287 | #endif
288 | }
289 | TRACE1("(%d)\n", ul_reason_for_call);
290 | return TRUE;
291 | }
292 |
--------------------------------------------------------------------------------
/FlifWICCodec/dllmain.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef _DEBUG
4 | #define FLIF_DEBUG_LOGGING
5 | #endif // DEBUG
6 |
7 | #ifdef FLIF_DEBUG_LOGGING
8 | // debug functions
9 | void MAIN_debug_printf(_In_z_ const char* prefix, _In_z_ const char* func, _In_z_ _Printf_format_string_ const char* fmt, ...);
10 | #define TRACE(fmt) MAIN_debug_printf("trace", __FUNCTION__, fmt)
11 | #define TRACE1(fmt, a) MAIN_debug_printf("trace", __FUNCTION__, fmt, a)
12 | #define TRACE2(fmt, a, b) MAIN_debug_printf("trace", __FUNCTION__, fmt, a, b)
13 | #define TRACE3(fmt, a, b, c) MAIN_debug_printf("trace", __FUNCTION__, fmt, a, b, c)
14 | #define TRACE4(fmt, a, b, c, d) MAIN_debug_printf("trace", __FUNCTION__, fmt, a, b, c, d)
15 |
16 | char *debugstr_guid(REFGUID guid);
17 | WCHAR *debugstr_var(REFPROPVARIANT var);
18 | #else
19 | #define TRACE(fmt)
20 | #define TRACE1(fmt, a)
21 | #define TRACE2(fmt, a, b)
22 | #define TRACE3(fmt, a, b, c)
23 | #define TRACE4(fmt, a, b, c, d)
24 | #endif
25 |
26 | // Number of COM objects created.
27 | extern LONG volatile MAIN_nObjects;
--------------------------------------------------------------------------------
/FlifWICCodec/encode_container.cpp:
--------------------------------------------------------------------------------
1 | #include "encode_container.h"
2 | #include "encode_frame.h"
3 | #include "uuid.h"
4 | #include "pixel_converter.h"
5 |
6 | EncodeContainer::EncodeContainer()
7 | : current_frame_(nullptr), encoder_(nullptr), pIStream_(nullptr)
8 | {
9 | TRACE("()\n");
10 | InitializeCriticalSection(&cs_);
11 | }
12 |
13 | EncodeContainer::~EncodeContainer()
14 | {
15 | TRACE("()\n");
16 | DeleteCriticalSection(&cs_);
17 | if (encoder_) {
18 | flif_destroy_encoder(encoder_);
19 | encoder_ = nullptr;
20 | }
21 | }
22 |
23 | HRESULT EncodeContainer::QueryInterface(REFIID riid, void ** ppvObject)
24 | {
25 | TRACE2("(%s, %p)\n", debugstr_guid(riid), ppvObject);
26 |
27 | if (ppvObject == nullptr)
28 | return E_INVALIDARG;
29 | *ppvObject = nullptr;
30 |
31 | if (!IsEqualGUID(riid, IID_IUnknown) && !IsEqualGUID(riid, IID_IWICBitmapEncoder))
32 | return E_NOINTERFACE;
33 | this->AddRef();
34 | *ppvObject = static_cast(this);
35 | return S_OK;
36 | }
37 |
38 | HRESULT EncodeContainer::Initialize(IStream * pIStream, WICBitmapEncoderCacheOption cacheOptions)
39 | {
40 | TRACE2("(%p, %x)\n", pIStream, cacheOptions);
41 | if (pIStream == nullptr)
42 | return E_INVALIDARG;
43 | pIStream_ = pIStream;
44 |
45 | //reset encoder
46 | if (encoder_) {
47 | flif_destroy_encoder(encoder_);
48 | encoder_ = nullptr;
49 | }
50 | encoder_ = flif_create_encoder();
51 | return S_OK;
52 | }
53 |
54 | HRESULT EncodeContainer::GetContainerFormat(GUID * pguidContainerFormat)
55 | {
56 | TRACE1("(%p)\n", pguidContainerFormat);
57 | if (pguidContainerFormat == nullptr)
58 | return E_INVALIDARG;
59 | *pguidContainerFormat = GUID_ContainerFormatFLIF;
60 | return S_OK;
61 | }
62 |
63 | HRESULT EncodeContainer::InitializeFactory()
64 | {
65 | SectionLock l(&cs_);
66 | HRESULT result = S_OK;
67 | if (factory_.get() == nullptr) {
68 | result = CoCreateInstance(CLSID_WICImagingFactory,
69 | nullptr,
70 | CLSCTX_INPROC_SERVER,
71 | IID_IWICImagingFactory,
72 | (LPVOID*)factory_.get_out_storage());
73 | }
74 | return result;
75 | }
76 |
77 | HRESULT EncodeContainer::GetEncoderInfo(IWICBitmapEncoderInfo ** ppIEncoderInfo)
78 | {
79 | TRACE1("(%p)\n", ppIEncoderInfo);
80 | HRESULT result;
81 |
82 | result = InitializeFactory();
83 | if (FAILED(result))
84 | return result;
85 |
86 | ComPtr compInfo;
87 | result = factory_->CreateComponentInfo(CLSID_FLIFWICEncoder, compInfo.get_out_storage());
88 | if (FAILED(result))
89 | return result;
90 |
91 | result = compInfo->QueryInterface(IID_IWICBitmapEncoderInfo, (void**)ppIEncoderInfo);
92 | if (FAILED(result))
93 | return result;
94 |
95 | return S_OK;
96 | }
97 |
98 | HRESULT EncodeContainer::SetColorContexts(UINT cCount, IWICColorContext ** ppIColorContext)
99 | {
100 | TRACE2("(%d, %p)\n", cCount, ppIColorContext);
101 | return WINCODEC_ERR_UNSUPPORTEDOPERATION;;
102 | }
103 |
104 | HRESULT EncodeContainer::SetPalette(IWICPalette * pIPalette)
105 | {
106 | TRACE1("(%p)\n", pIPalette);
107 | return WINCODEC_ERR_UNSUPPORTEDOPERATION;
108 | }
109 |
110 | HRESULT EncodeContainer::SetThumbnail(IWICBitmapSource * pIThumbnail)
111 | {
112 | TRACE1("(%p)\n", pIThumbnail);
113 | return WINCODEC_ERR_UNSUPPORTEDOPERATION;
114 | }
115 |
116 | HRESULT EncodeContainer::SetPreview(IWICBitmapSource * pIPreview)
117 | {
118 | TRACE1("(%p)\n", pIPreview);
119 | return WINCODEC_ERR_UNSUPPORTEDOPERATION;
120 | }
121 |
122 | HRESULT EncodeContainer::CreateNewFrame(IWICBitmapFrameEncode ** ppIFrameEncode, IPropertyBag2 ** ppIEncoderOptions)
123 | {
124 | TRACE2("(%p, %p)\n", ppIFrameEncode, ppIEncoderOptions);
125 | if (ppIFrameEncode == nullptr)
126 | return E_INVALIDARG;
127 |
128 | if (encoder_ == nullptr) {
129 | return WINCODEC_ERR_NOTINITIALIZED;
130 | }
131 |
132 | SectionLock l(&cs_);
133 |
134 | ComPtr output;
135 | output.reset(new (std::nothrow) EncodeFrame(this));
136 | *ppIFrameEncode = output.new_ref();
137 | return S_OK;
138 | }
139 |
140 | HRESULT EncodeContainer::Commit(void)
141 | {
142 | TRACE("()\n");
143 | if (encoder_ == nullptr) {
144 | return WINCODEC_ERR_NOTINITIALIZED;
145 | }
146 |
147 | if (current_frame_.get())
148 | {
149 | uint8_t* buffer = nullptr;
150 | size_t buffer_size = 0;
151 | if (flif_encoder_encode_memory(encoder_, reinterpret_cast(&buffer), &buffer_size) != 0) {
152 | ULONG written = 0;
153 | do {
154 | pIStream_->Write(buffer, buffer_size, &written);
155 | buffer_size -= written;
156 | buffer += written;
157 | } while (buffer_size > 0);
158 | }
159 | }
160 | return S_OK;
161 | }
162 |
163 | HRESULT EncodeContainer::GetMetadataQueryWriter(IWICMetadataQueryWriter ** ppIMetadataQueryWriter)
164 | {
165 | TRACE1("(%p)\n", ppIMetadataQueryWriter);
166 | if (ppIMetadataQueryWriter == nullptr)
167 | return E_INVALIDARG;
168 | return E_NOTIMPL;
169 | }
170 |
171 | HRESULT EncodeContainer::AddImage(std::shared_ptr frame, AnimationInformation animation_information, std::deque> metadata)
172 | {
173 | if (encoder_ == nullptr) {
174 | return WINCODEC_ERR_NOTINITIALIZED;
175 | }
176 |
177 | //Merge current frame
178 | if (current_frame_.get()) {
179 | if (current_frame_->NumberComponents != frame->NumberComponents) {
180 | return WINCODEC_ERR_INTERNALERROR;
181 | }
182 |
183 | if (animation_information.TransparencyFlag && frame->NumberComponents == 4) {
184 | //Must be RGBA and Alpha channel has only values 0 or FF
185 | assert(frame->NumberComponents == 4);
186 | for (UINT i = 0; i < frame->Height; ++i) {
187 | BYTE* srcrow = frame->Buffer + i * frame->Stride;
188 | BYTE* destrow = current_frame_->Buffer + (i + animation_information.Top) * current_frame_->Stride;
189 | BYTE* destrowstart = destrow + animation_information.Left * current_frame_->NumberComponents;
190 | CopyAllButTransparentPixelRGBA8(frame->Width, srcrow, destrowstart);
191 | }
192 | }
193 | else {
194 | //Must be RGB or Gray
195 | assert(frame->NumberComponents < 4);
196 | for (UINT i = 0; i < frame->Height; ++i) {
197 | BYTE* srcrow = frame->Buffer + i * frame->Stride;
198 | BYTE* destrow = current_frame_->Buffer + (i + animation_information.Top) * current_frame_->Stride;
199 | BYTE* destrowstart = destrow + animation_information.Left * current_frame_->NumberComponents;
200 | memcpy(destrowstart, srcrow, frame->Width*frame->NumberComponents);
201 | }
202 | }
203 | }
204 | else
205 | {
206 | current_frame_ = frame;
207 | }
208 |
209 | //Write and encode rows
210 | FLIF_IMAGE* image = nullptr;
211 | if (current_frame_->NumberComponents == 1) {
212 | image = flif_import_image_GRAY(current_frame_->Width, current_frame_->Height, current_frame_->Buffer, current_frame_->Stride);
213 | }
214 | else if (current_frame_->NumberComponents == 3) {
215 | image = flif_import_image_RGB(current_frame_->Width, current_frame_->Height, current_frame_->Buffer, current_frame_->Stride);
216 | }
217 | else if (current_frame_->NumberComponents == 4) {
218 | image = flif_import_image_RGBA(current_frame_->Width, current_frame_->Height, current_frame_->Buffer, current_frame_->Stride);
219 | }
220 |
221 | if (image == nullptr)
222 | return WINCODEC_ERR_INTERNALERROR;
223 |
224 | //Animation
225 | if (animation_information.Delay > 0) {
226 | flif_image_set_frame_delay(image, animation_information.Delay);
227 | }
228 |
229 | //Metadata
230 | if (metadata.size() > 0) {
231 | for (int i = 0; i < metadata.size(); ++i) {
232 | flif_image_set_metadata(image, metadata[i]->Chunkname.c_str(), metadata[i]->Buffer, metadata[i]->BufferSize);
233 | }
234 | }
235 |
236 | flif_encoder_add_image(encoder_, image);
237 | flif_destroy_image(image);
238 |
239 | return S_OK;
240 | }
241 |
--------------------------------------------------------------------------------
/FlifWICCodec/encode_container.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "utils.h"
10 |
11 | struct AnimationInformation {
12 | uint32_t Left;
13 | uint32_t Top;
14 | uint8_t Disposal;
15 | bool TransparencyFlag;
16 | uint32_t Delay;
17 | };
18 |
19 | class EncodeContainer : public ComObjectBase {
20 | public:
21 | EncodeContainer();
22 | ~EncodeContainer();
23 | // IUnknown:
24 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
25 | ULONG STDMETHODCALLTYPE AddRef() override { return ComObjectBase::AddRef(); }
26 | ULONG STDMETHODCALLTYPE Release() override { return ComObjectBase::Release(); }
27 | // Inherited via IWICBitmapEncoder
28 | HRESULT STDMETHODCALLTYPE Initialize(IStream * pIStream, WICBitmapEncoderCacheOption cacheOption) override;
29 | HRESULT STDMETHODCALLTYPE GetContainerFormat(GUID* pguidContainerFormat) override;
30 | HRESULT STDMETHODCALLTYPE GetEncoderInfo(IWICBitmapEncoderInfo ** ppIEncoderInfo) override;
31 | HRESULT STDMETHODCALLTYPE SetColorContexts(UINT cCount, IWICColorContext ** ppIColorContext) override;
32 | HRESULT STDMETHODCALLTYPE SetPalette(IWICPalette * pIPalette) override;
33 | HRESULT STDMETHODCALLTYPE SetThumbnail(IWICBitmapSource * pIThumbnail) override;
34 | HRESULT STDMETHODCALLTYPE SetPreview(IWICBitmapSource * pIPreview) override;
35 | HRESULT STDMETHODCALLTYPE CreateNewFrame(IWICBitmapFrameEncode ** ppIFrameEncode, IPropertyBag2 ** ppIEncoderOptions) override;
36 | HRESULT STDMETHODCALLTYPE Commit(void) override;
37 | HRESULT STDMETHODCALLTYPE GetMetadataQueryWriter(IWICMetadataQueryWriter ** ppIMetadataQueryWriter) override;
38 | public:
39 | HRESULT AddImage(std::shared_ptr frame, AnimationInformation animationInformation, std::deque> metadata);
40 | private:
41 | // No copy and assign.
42 | EncodeContainer(const EncodeContainer&) = delete;
43 | void operator=(const EncodeContainer&) = delete;
44 | HRESULT InitializeFactory();
45 |
46 | std::shared_ptr current_frame_;
47 | FLIF_ENCODER* encoder_;
48 | IStream* pIStream_;
49 | ComPtr factory_;
50 | CRITICAL_SECTION cs_;
51 |
52 | };
53 |
--------------------------------------------------------------------------------
/FlifWICCodec/encode_frame.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "encode_frame.h"
3 | #include "uuid.h"
4 |
5 | EncodeFrame::EncodeFrame(EncodeContainer* container)
6 | : container_(container), frame_(nullptr), metadataBlockWriter_(*this)
7 | {
8 | TRACE("()\n");
9 | container_->AddRef();
10 | InitializeCriticalSection(&cs_);
11 | }
12 |
13 | EncodeFrame::~EncodeFrame()
14 | {
15 | TRACE("()\n");
16 | container_->Release();
17 | DeleteCriticalSection(&cs_);
18 | }
19 |
20 |
21 | HRESULT EncodeFrame::QueryInterface(REFIID riid, void ** ppvObject)
22 | {
23 | TRACE2("(%s, %p)\n", debugstr_guid(riid), ppvObject);
24 |
25 | if (ppvObject == nullptr)
26 | return E_INVALIDARG;
27 | *ppvObject = nullptr;
28 |
29 | if (IsEqualGUID(riid, IID_IUnknown) ||
30 | IsEqualGUID(riid, IID_IWICBitmapFrameEncode))
31 | {
32 | this->AddRef();
33 | *ppvObject = static_cast(this);
34 | return S_OK;
35 | }
36 |
37 | // Multiple inheritence needs explicit cast
38 | if (IsEqualGUID(riid, IID_IWICMetadataBlockWriter) ||
39 | IsEqualGUID(riid, IID_IWICMetadataBlockReader))
40 | {
41 | this->AddRef();
42 | *ppvObject = static_cast(&this->metadataBlockWriter_);
43 | return S_OK;
44 | }
45 | return E_NOINTERFACE;
46 | }
47 |
48 | HRESULT EncodeFrame::Initialize(IPropertyBag2 * pIEncoderOptions)
49 | {
50 | TRACE1("(%p)\n", pIEncoderOptions);
51 | return S_OK;
52 | }
53 |
54 | HRESULT EncodeFrame::SetSize(UINT uiWidth, UINT uiHeight)
55 | {
56 | TRACE2("(%d, %d)\n", uiWidth, uiHeight);
57 | return S_OK;
58 | }
59 |
60 | HRESULT EncodeFrame::SetResolution(double dpiX, double dpiY)
61 | {
62 | TRACE2("(%f, %f)\n", dpiX, dpiY);
63 | return S_OK;
64 | }
65 |
66 | HRESULT EncodeFrame::SetPixelFormat(WICPixelFormatGUID * pPixelFormat)
67 | {
68 | TRACE1("(%p)\n", pPixelFormat);
69 | if (pPixelFormat == nullptr)
70 | return E_INVALIDARG;
71 |
72 | //supported nativly
73 | if (*pPixelFormat == GUID_WICPixelFormat32bppRGBA ||
74 | *pPixelFormat == GUID_WICPixelFormat24bppRGB ||
75 | *pPixelFormat == GUID_WICPixelFormat8bppGray)
76 | {
77 | return S_OK;
78 | }
79 |
80 | //supported through converter
81 | if (*pPixelFormat == GUID_WICPixelFormatBlackWhite ||
82 | *pPixelFormat == GUID_WICPixelFormat2bppGray ||
83 | *pPixelFormat == GUID_WICPixelFormat4bppGray ||
84 | *pPixelFormat == GUID_WICPixelFormat32bppBGRA ||
85 | *pPixelFormat == GUID_WICPixelFormat16bppBGRA5551 ||
86 | *pPixelFormat == GUID_WICPixelFormat16bppBGR555 ||
87 | *pPixelFormat == GUID_WICPixelFormat16bppBGR565 ||
88 | *pPixelFormat == GUID_WICPixelFormat24bppBGR ||
89 | *pPixelFormat == GUID_WICPixelFormat32bppRGB ||
90 | *pPixelFormat == GUID_WICPixelFormat32bppBGR ||
91 | *pPixelFormat == GUID_WICPixelFormat1bppIndexed ||
92 | *pPixelFormat == GUID_WICPixelFormat2bppIndexed ||
93 | *pPixelFormat == GUID_WICPixelFormat4bppIndexed ||
94 | *pPixelFormat == GUID_WICPixelFormat8bppIndexed)
95 | {
96 | return S_OK;
97 | }
98 |
99 | *pPixelFormat = GUID_WICPixelFormatUndefined;
100 | return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
101 | }
102 |
103 | HRESULT EncodeFrame::SetColorContexts(UINT cCount, IWICColorContext ** ppIColorContext)
104 | {
105 | TRACE2("(%d, %p)\n", cCount, ppIColorContext);
106 | return E_NOTIMPL;
107 | }
108 |
109 | HRESULT EncodeFrame::SetPalette(IWICPalette * pIPalette)
110 | {
111 | TRACE1("(%p)\n", pIPalette);
112 | return E_NOTIMPL;
113 | }
114 |
115 | HRESULT EncodeFrame::SetThumbnail(IWICBitmapSource * pIThumbnail)
116 | {
117 | TRACE1("(%p)\n", pIThumbnail);
118 | return E_NOTIMPL;
119 | }
120 |
121 | HRESULT EncodeFrame::WritePixels(UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE * pbPixels)
122 | {
123 | TRACE4("(%d, %d, %d, %p)\n", lineCount, cbStride, cbBufferSize, pbPixels);
124 | return E_NOTIMPL;
125 | }
126 |
127 | HRESULT EncodeFrame::WriteSource(IWICBitmapSource* pIBitmapSource, WICRect * prc)
128 | {
129 | TRACE2("(%p, %p)\n", pIBitmapSource, prc);
130 | if (pIBitmapSource == nullptr)
131 | return E_INVALIDARG;
132 |
133 | HRESULT result = S_OK;
134 |
135 | //For GIFs get animation information
136 | animation_information_ = {};
137 | ComPtr decodeframe;
138 | if (SUCCEEDED(pIBitmapSource->QueryInterface(decodeframe.get_out_storage()))) {
139 | ComPtr metadataReader;
140 | if (SUCCEEDED(decodeframe->GetMetadataQueryReader(metadataReader.get_out_storage())))
141 | {
142 | PROPVARIANT propValue;
143 | PropVariantInit(&propValue);
144 |
145 | if (SUCCEEDED(metadataReader->GetMetadataByName(L"/imgdesc/Left", &propValue))) {
146 | if (propValue.vt == VT_UI2) {
147 | animation_information_.Left = propValue.uiVal;
148 | }
149 | }
150 | PropVariantClear(&propValue);
151 |
152 | if (SUCCEEDED(metadataReader->GetMetadataByName(L"/imgdesc/Top", &propValue))) {
153 | if (propValue.vt == VT_UI2) {
154 | animation_information_.Top = propValue.uiVal;
155 | }
156 | }
157 | PropVariantClear(&propValue);
158 |
159 | if (SUCCEEDED(metadataReader->GetMetadataByName(L"/grctlext/Disposal", &propValue))) {
160 | if (propValue.vt == VT_UI1) {
161 | animation_information_.Disposal = propValue.bVal;
162 | }
163 | }
164 | PropVariantClear(&propValue);
165 |
166 | if (SUCCEEDED(metadataReader->GetMetadataByName(L"/grctlext/Delay", &propValue))) {
167 | if (propValue.vt == VT_UI2) {
168 | // From 10th ms to ms
169 | animation_information_.Delay = propValue.uiVal * 10;
170 | }
171 | }
172 | PropVariantClear(&propValue);
173 |
174 | if (SUCCEEDED(metadataReader->GetMetadataByName(L"/grctlext/TransparencyFlag", &propValue))) {
175 | if (propValue.vt == VT_BOOL) {
176 | animation_information_.TransparencyFlag = propValue.boolVal;
177 | }
178 | }
179 | PropVariantClear(&propValue);
180 | }
181 | }
182 |
183 | //Check Rect
184 | UINT image_width = 0;
185 | UINT image_height = 0;
186 | result = pIBitmapSource->GetSize(&image_width, &image_height);
187 | if (FAILED(result)) {
188 | return result;
189 | }
190 | WICRect rect = { 0, 0, image_width, image_height };
191 | if (prc)
192 | rect = *prc;
193 | if (rect.Width < 0 || rect.Height < 0 || rect.X < 0 || rect.Y < 0)
194 | return E_INVALIDARG;
195 | if (rect.X + rect.Width > image_width ||
196 | rect.Y + rect.Height > image_height)
197 | return E_INVALIDARG;
198 |
199 | //Convert Image
200 | WICPixelFormatGUID source_pixel_format = { 0 };
201 | result = pIBitmapSource->GetPixelFormat(&source_pixel_format);
202 | if (FAILED(result)) {
203 | return result;
204 | }
205 | IWICBitmapSource* source_image = pIBitmapSource;
206 | ComPtr converter;
207 | if (source_pixel_format != GUID_WICPixelFormat32bppRGBA &&
208 | source_pixel_format != GUID_WICPixelFormat24bppRGB &&
209 | source_pixel_format != GUID_WICPixelFormat8bppGray)
210 | {
211 | //Create factory
212 | result = InitializeFactory();
213 | if (FAILED(result)) {
214 | return result;
215 | }
216 |
217 | //Set destination pixelformat
218 | WICPixelFormatGUID dest_pixel_format = { 0 };
219 | if (source_pixel_format == GUID_WICPixelFormatBlackWhite ||
220 | source_pixel_format == GUID_WICPixelFormat2bppGray ||
221 | source_pixel_format == GUID_WICPixelFormat4bppGray)
222 | {
223 | dest_pixel_format = GUID_WICPixelFormat8bppGray;
224 | }
225 | else if (source_pixel_format == GUID_WICPixelFormat32bppBGRA ||
226 | source_pixel_format == GUID_WICPixelFormat16bppBGRA5551)
227 | {
228 | dest_pixel_format = GUID_WICPixelFormat32bppRGBA;
229 | }
230 | else if (
231 | source_pixel_format == GUID_WICPixelFormat16bppBGR555 ||
232 | source_pixel_format == GUID_WICPixelFormat16bppBGR565 ||
233 | source_pixel_format == GUID_WICPixelFormat24bppBGR ||
234 | source_pixel_format == GUID_WICPixelFormat32bppBGR ||
235 | source_pixel_format == GUID_WICPixelFormat32bppRGB)
236 | {
237 | dest_pixel_format = GUID_WICPixelFormat24bppRGB;
238 | }
239 | else if (source_pixel_format == GUID_WICPixelFormat1bppIndexed ||
240 | source_pixel_format == GUID_WICPixelFormat2bppIndexed ||
241 | source_pixel_format == GUID_WICPixelFormat4bppIndexed ||
242 | source_pixel_format == GUID_WICPixelFormat8bppIndexed)
243 | {
244 | //Set destination pixelformat from palette info
245 | ComPtr palette;
246 | result = factory_->CreatePalette(palette.get_out_storage());
247 | if (FAILED(result)) {
248 | return result;
249 | }
250 | result = pIBitmapSource->CopyPalette(palette.get());
251 | if (FAILED(result)) {
252 | return result;
253 | }
254 | dest_pixel_format = GUID_WICPixelFormat24bppRGB;
255 | BOOL HasAlpha = false;
256 | result = palette->HasAlpha(&HasAlpha);
257 | if (FAILED(result)) {
258 | return result;
259 | }
260 | if (HasAlpha) {
261 | dest_pixel_format = GUID_WICPixelFormat32bppRGBA;
262 | }
263 | else
264 | {
265 | BOOL is_grayscale = false;
266 | result = palette->IsGrayscale(&is_grayscale);
267 | if (FAILED(result)) {
268 | return result;
269 | }
270 | BOOL is_blackwhite = false;
271 | result = palette->IsBlackWhite(&is_blackwhite);
272 | if (FAILED(result)) {
273 | return result;
274 | }
275 | if (is_grayscale || is_blackwhite) {
276 | dest_pixel_format = GUID_WICPixelFormat8bppGray;
277 | }
278 | }
279 | }
280 | else
281 | {
282 | return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
283 | }
284 |
285 | //Create Converter
286 | result = factory_->CreateFormatConverter(converter.get_out_storage());
287 | if (FAILED(result)) {
288 | return result;
289 | }
290 | BOOL can_convert = false;
291 | result = converter->CanConvert(source_pixel_format, dest_pixel_format, &can_convert);
292 | if (FAILED(result))
293 | {
294 | return result;
295 | }
296 | if (!can_convert) {
297 | return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
298 | }
299 | result = converter->Initialize(
300 | pIBitmapSource, dest_pixel_format,
301 | WICBitmapDitherTypeNone, nullptr, 0.f,
302 | WICBitmapPaletteTypeMedianCut);
303 | if (FAILED(result)) {
304 | return result;
305 | }
306 | source_image = converter.get();
307 | }
308 |
309 | //Create raw frame
310 | result = source_image->GetPixelFormat(&source_pixel_format);
311 | if (FAILED(result)) {
312 | return result;
313 | }
314 | assert(source_pixel_format == GUID_WICPixelFormat32bppRGBA ||
315 | source_pixel_format == GUID_WICPixelFormat24bppRGB ||
316 | source_pixel_format == GUID_WICPixelFormat8bppGray);
317 |
318 | if (source_pixel_format == GUID_WICPixelFormat32bppRGBA)
319 | {
320 | uint32_t stride = rect.Width * 4;
321 | frame_.reset(new RawFrame(rect.Width, rect.Height, 4, stride));
322 | }
323 | else if (source_pixel_format == GUID_WICPixelFormat24bppRGB)
324 | {
325 | uint32_t stride = 4 * ((24 * (UINT)rect.Width + 31) / 32);
326 | frame_.reset(new RawFrame(rect.Width, rect.Height, 3, stride));
327 | }
328 | else if (source_pixel_format == GUID_WICPixelFormat8bppGray)
329 | {
330 | uint32_t stride = rect.Width;
331 | frame_.reset(new RawFrame(rect.Width, rect.Height, 1, stride));
332 | }
333 | else
334 | {
335 | return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
336 | }
337 | if (frame_->Buffer == nullptr)
338 | {
339 | frame_.reset();
340 | return E_OUTOFMEMORY;
341 | }
342 |
343 | //Read Source Pixel
344 | result = source_image->CopyPixels(&rect, frame_->Stride, frame_->BufferSize, frame_->Buffer);
345 | if (FAILED(result))
346 | {
347 | frame_.reset();
348 | return result;
349 | }
350 |
351 |
352 | return S_OK;
353 |
354 | }
355 |
356 | HRESULT EncodeFrame::Commit(void)
357 | {
358 | TRACE("()\n");
359 | if (!frame_.get())
360 | return WINCODEC_ERR_NOTINITIALIZED;
361 |
362 | HRESULT result = S_OK;
363 |
364 | std::deque> metadatas;
365 | result = metadataBlockWriter_.GetMetadatas(metadatas);
366 | if (FAILED(result))
367 | return result;
368 |
369 | result = container_->AddImage(frame_, animation_information_, metadatas);
370 | frame_.reset();
371 | return result;
372 | }
373 |
374 | HRESULT EncodeFrame::InitializeFactory()
375 | {
376 | SectionLock l(&cs_);
377 | HRESULT result = S_OK;
378 |
379 | if (factory_.get() == nullptr)
380 | {
381 | result = CoCreateInstance(CLSID_WICImagingFactory,
382 | nullptr,
383 | CLSCTX_INPROC_SERVER,
384 | IID_IWICImagingFactory,
385 | (LPVOID*)factory_.get_out_storage());
386 | if (FAILED(result))
387 | return result;
388 |
389 | }
390 |
391 | if (factory_.get() != nullptr &&
392 | componentFactory_.get() == nullptr)
393 | {
394 | result = factory_->QueryInterface(componentFactory_.get_out_storage());
395 | if (FAILED(result)) {
396 | return result;
397 | }
398 | }
399 |
400 | return result;
401 | }
402 |
403 | HRESULT EncodeFrame::GetMetadataQueryWriter(IWICMetadataQueryWriter ** ppIMetadataQueryWriter)
404 | {
405 | TRACE1("(%p)\n", ppIMetadataQueryWriter);
406 | if (ppIMetadataQueryWriter == nullptr)
407 | return E_INVALIDARG;
408 |
409 | HRESULT result;
410 |
411 | //Create factory
412 | result = InitializeFactory();
413 | if (FAILED(result))
414 | return result;
415 |
416 | return componentFactory_->CreateQueryWriterFromBlockWriter(static_cast(&this->metadataBlockWriter_), ppIMetadataQueryWriter);
417 | }
418 |
419 | HRESULT EncodeFrame::MetadataBlockWriter::GetContainerFormat(GUID * pguidContainerFormat)
420 | {
421 | TRACE1("(%p)\n", pguidContainerFormat);
422 | if (pguidContainerFormat == nullptr)
423 | return E_INVALIDARG;
424 | *pguidContainerFormat = GUID_ContainerFormatFLIF;
425 | return S_OK;
426 | }
427 |
428 | HRESULT EncodeFrame::MetadataBlockWriter::GetCount(UINT * pcCount)
429 | {
430 | TRACE1("(%p)\n", pcCount);
431 | if (pcCount == nullptr)
432 | return E_INVALIDARG;
433 | *pcCount = metadataWriter_.size();
434 | return S_OK;
435 | }
436 |
437 | HRESULT EncodeFrame::MetadataBlockWriter::GetEnumerator(IEnumUnknown ** ppIEnumMetadata)
438 | {
439 | TRACE1("(%p)\n", ppIEnumMetadata);
440 | return E_NOTIMPL;
441 | }
442 |
443 | HRESULT EncodeFrame::MetadataBlockWriter::InitializeFromBlockReader(IWICMetadataBlockReader * pIMDBlockReader)
444 | {
445 | TRACE1("(%p)\n", pIMDBlockReader);
446 | if (pIMDBlockReader == nullptr)
447 | return E_INVALIDARG;
448 |
449 | HRESULT result;
450 |
451 | UINT blockCount = 0;
452 | result = pIMDBlockReader->GetCount(&blockCount);
453 | if (FAILED(result))
454 | return result;
455 |
456 | if (blockCount > 0)
457 | {
458 | //Create factory
459 | result = encodeFrame_.InitializeFactory();
460 | if (FAILED(result))
461 | return result;
462 |
463 | for (UINT i = 0; i < blockCount; ++i)
464 | {
465 | IWICMetadataReader* metadataReader;
466 | if (SUCCEEDED(pIMDBlockReader->GetReaderByIndex(i, &metadataReader)))
467 | {
468 | ComPtr metadataWriter;
469 | if (SUCCEEDED(encodeFrame_.componentFactory_->CreateMetadataWriterFromReader(metadataReader, NULL, metadataWriter.get_out_storage())))
470 | {
471 | metadataWriter_.emplace_back(metadataWriter.new_ref());
472 | }
473 | }
474 | }
475 | }
476 | return S_OK;
477 | }
478 |
479 | HRESULT EncodeFrame::MetadataBlockWriter::GetReaderByIndex(UINT nIndex, IWICMetadataReader ** ppIMetadataReader)
480 | {
481 | TRACE2("(%d, %p)\n", nIndex, ppIMetadataReader);
482 | if (ppIMetadataReader == nullptr)
483 | return E_INVALIDARG;
484 | if (nIndex >= metadataWriter_.size())
485 | return E_INVALIDARG;
486 | *ppIMetadataReader = static_cast(metadataWriter_[nIndex].new_ref());
487 | return S_OK;
488 | }
489 |
490 | HRESULT EncodeFrame::MetadataBlockWriter::GetWriterByIndex(UINT nIndex, IWICMetadataWriter ** ppIMetadataWriter)
491 | {
492 | TRACE2("(%d, %p)\n", nIndex, ppIMetadataWriter);
493 | if (ppIMetadataWriter == nullptr)
494 | return E_INVALIDARG;
495 | if (nIndex >= metadataWriter_.size())
496 | return E_INVALIDARG;
497 | *ppIMetadataWriter = metadataWriter_[nIndex].new_ref();
498 | return S_OK;
499 | }
500 |
501 | HRESULT EncodeFrame::MetadataBlockWriter::AddWriter(IWICMetadataWriter * pIMetadataWriter)
502 | {
503 | TRACE1("(%p)\n", pIMetadataWriter);
504 | if (pIMetadataWriter == nullptr)
505 | return E_INVALIDARG;
506 | metadataWriter_.emplace_back(pIMetadataWriter);
507 | return S_OK;
508 | }
509 |
510 | HRESULT EncodeFrame::MetadataBlockWriter::SetWriterByIndex(UINT nIndex, IWICMetadataWriter * pIMetadataWriter)
511 | {
512 | TRACE2("(%d, %p)\n", nIndex, pIMetadataWriter);
513 | if (pIMetadataWriter == nullptr)
514 | return E_INVALIDARG;
515 | if (nIndex >= metadataWriter_.size())
516 | return E_INVALIDARG;
517 | metadataWriter_[nIndex].reset(pIMetadataWriter);
518 | return S_OK;
519 | }
520 |
521 | HRESULT EncodeFrame::MetadataBlockWriter::RemoveWriterByIndex(UINT nIndex)
522 | {
523 | TRACE1("(%d)\n", nIndex);
524 | if (nIndex >= metadataWriter_.size())
525 | return E_INVALIDARG;
526 | //metadataWriter_.erase(metadataWriter_.begin() + nIndex);
527 | return S_OK;
528 | }
529 |
530 |
531 | static
532 | HRESULT SaveMetadata(IWICMetadataReader* reader,
533 | const std::string metadataName,
534 | std::deque>& metadatas)
535 | {
536 | ComPtr persistStream;
537 | if (SUCCEEDED(reader->QueryInterface(persistStream.get_out_storage())))
538 | {
539 | IStream* stream = SHCreateMemStream(nullptr, 0);
540 | if (SUCCEEDED(persistStream->SaveEx(stream, WICMetadataCreationAllowUnknown | WICPersistOptionDefault, FALSE))) {
541 | // Allocates enough memeory for the content.
542 | STATSTG ssStreamData = {};
543 | if (SUCCEEDED(stream->Stat(&ssStreamData, STATFLAG_NONAME))) {
544 | SIZE_T cbSize = ssStreamData.cbSize.LowPart;
545 | std::shared_ptr metadata(new (std::nothrow) Metadata(metadataName, cbSize));
546 | if (!metadata->Buffer)
547 | return E_OUTOFMEMORY;
548 |
549 | // Copies the content from the stream to the buffer.
550 | LARGE_INTEGER position;
551 | position.QuadPart = 0;
552 | if (SUCCEEDED((stream->Seek(position, STREAM_SEEK_SET, NULL)))) {
553 | ULONG cbRead;
554 | if (SUCCEEDED(stream->Read(metadata->Buffer, cbSize, &cbRead))) {
555 | metadatas.emplace_back(metadata);
556 | }
557 | }
558 | }
559 | }
560 | }
561 | return S_OK;
562 | }
563 |
564 | static
565 | void ReadMetadataReqursive(IWICMetadataReader* reader, std::deque>& metadatas)
566 | {
567 | HRESULT result = S_OK;
568 |
569 | GUID metadataFormat;
570 | if (SUCCEEDED(reader->GetMetadataFormat(&metadataFormat)))
571 | {
572 | if (IsEqualGUID(metadataFormat, GUID_MetadataFormatExif))
573 | {
574 | SaveMetadata(reader, "eXif", metadatas);
575 | return;
576 | }
577 | else if (IsEqualGUID(metadataFormat, GUID_MetadataFormatXMP)) {
578 | SaveMetadata(reader, "eXmp", metadatas);
579 | return;
580 | }
581 | else if (IsEqualGUID(metadataFormat, GUID_MetadataFormatChunkiCCP))
582 | {
583 | SaveMetadata(reader, "iCCP", metadatas);
584 | return;
585 | }
586 | }
587 |
588 | UINT count = 0;
589 | result = reader->GetCount(&count);
590 | if (FAILED(result))
591 | return;
592 | for (UINT i = 0; i < count; ++i)
593 | {
594 | PROPVARIANT id, value;
595 |
596 | PropVariantInit(&id);
597 | PropVariantInit(&value);
598 | result = reader->GetValueByIndex(i, nullptr, &id, &value);
599 | if (SUCCEEDED(result)) {
600 | if (VT_UNKNOWN == value.vt)
601 | {
602 | ComPtr subReader;
603 | result = value.punkVal->QueryInterface(subReader.get_out_storage());
604 | if (SUCCEEDED(result))
605 | {
606 | ReadMetadataReqursive(subReader.get(), metadatas);
607 | }
608 | }
609 | PropVariantClear(&id);
610 | PropVariantClear(&value);
611 | }
612 | }
613 | }
614 |
615 | HRESULT EncodeFrame::MetadataBlockWriter::GetMetadatas(std::deque>& metadatas)
616 | {
617 | TRACE("()\n");
618 | for (int i = 0; i < metadataWriter_.size(); ++i)
619 | {
620 | ReadMetadataReqursive(metadataWriter_[i].get(), metadatas);
621 | }
622 | return S_OK;
623 | }
624 |
--------------------------------------------------------------------------------
/FlifWICCodec/encode_frame.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "utils.h"
8 | #include "encode_container.h"
9 |
10 | class EncodeFrame : public ComObjectBase {
11 | public:
12 | explicit EncodeFrame(EncodeContainer* container);
13 | ~EncodeFrame();
14 |
15 | // Inherited via IUnknown:
16 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
17 | ULONG STDMETHODCALLTYPE AddRef() { return ComObjectBase::AddRef(); }
18 | ULONG STDMETHODCALLTYPE Release() { return ComObjectBase::Release(); }
19 | // Inherited via IWICBitmapFrameEncode
20 | HRESULT STDMETHODCALLTYPE Initialize(IPropertyBag2 * pIEncoderOptions) override;
21 | HRESULT STDMETHODCALLTYPE SetSize(UINT uiWidth, UINT uiHeight) override;
22 | HRESULT STDMETHODCALLTYPE SetResolution(double dpiX, double dpiY) override;
23 | HRESULT STDMETHODCALLTYPE SetPixelFormat(WICPixelFormatGUID * pPixelFormat) override;
24 | HRESULT STDMETHODCALLTYPE SetColorContexts(UINT cCount, IWICColorContext ** ppIColorContext) override;
25 | HRESULT STDMETHODCALLTYPE SetPalette(IWICPalette * pIPalette) override;
26 | HRESULT STDMETHODCALLTYPE SetThumbnail(IWICBitmapSource * pIThumbnail) override;
27 | HRESULT STDMETHODCALLTYPE WritePixels(UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE * pbPixels) override;
28 | HRESULT STDMETHODCALLTYPE WriteSource(IWICBitmapSource * pIBitmapSource, WICRect * prc) override;
29 | HRESULT STDMETHODCALLTYPE Commit(void) override;
30 | HRESULT STDMETHODCALLTYPE GetMetadataQueryWriter(IWICMetadataQueryWriter ** ppIMetadataQueryWriter) override;
31 |
32 | private:
33 | class MetadataBlockWriter : public IWICMetadataBlockWriter {
34 | public:
35 | MetadataBlockWriter(EncodeFrame& encodeFrame) : encodeFrame_(encodeFrame) {}
36 | // Inherited via IUnknown:
37 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override { return encodeFrame_.QueryInterface(riid, ppvObject); };
38 | ULONG STDMETHODCALLTYPE AddRef() override { return encodeFrame_.AddRef(); }
39 | ULONG STDMETHODCALLTYPE Release() override { return encodeFrame_.Release(); }
40 | // Inherited via IWICMetadataBlockWriter
41 | HRESULT STDMETHODCALLTYPE GetContainerFormat(GUID * pguidContainerFormat) override;
42 | HRESULT STDMETHODCALLTYPE GetCount(UINT * pcCount) override;
43 | HRESULT STDMETHODCALLTYPE GetReaderByIndex(UINT nIndex, IWICMetadataReader ** ppIMetadataReader) override;
44 | HRESULT STDMETHODCALLTYPE GetEnumerator(IEnumUnknown ** ppIEnumMetadata) override;
45 | HRESULT STDMETHODCALLTYPE InitializeFromBlockReader(IWICMetadataBlockReader * pIMDBlockReader) override;
46 | HRESULT STDMETHODCALLTYPE GetWriterByIndex(UINT nIndex, IWICMetadataWriter ** ppIMetadataWriter) override;
47 | HRESULT STDMETHODCALLTYPE AddWriter(IWICMetadataWriter * pIMetadataWriter) override;
48 | HRESULT STDMETHODCALLTYPE SetWriterByIndex(UINT nIndex, IWICMetadataWriter * pIMetadataWriter) override;
49 | HRESULT STDMETHODCALLTYPE RemoveWriterByIndex(UINT nIndex) override;
50 | HRESULT GetMetadatas(std::deque>& metadatas);
51 | private:
52 | EncodeFrame& encodeFrame_;
53 | std::deque> metadataWriter_;
54 | };
55 |
56 | // No copy and assign.
57 | EncodeFrame(const EncodeFrame&) = delete;
58 | void operator=(const EncodeFrame&) = delete;
59 | HRESULT InitializeFactory();
60 |
61 | EncodeContainer* container_;
62 | std::shared_ptr frame_;
63 | AnimationInformation animation_information_;
64 | MetadataBlockWriter metadataBlockWriter_;
65 | ComPtr factory_;
66 | ComPtr componentFactory_;
67 | CRITICAL_SECTION cs_;
68 | };
69 |
70 |
--------------------------------------------------------------------------------
/FlifWICCodec/flif_wic_codec.def:
--------------------------------------------------------------------------------
1 | LIBRARY FLIFWICCodec
2 | EXPORTS
3 | DllCanUnloadNow PRIVATE
4 | DllGetClassObject PRIVATE
5 | DllRegisterServer PRIVATE
6 | DllUnregisterServer PRIVATE
7 |
--------------------------------------------------------------------------------
/FlifWICCodec/flif_wic_codec.rc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/peirick/FlifWICCodec/e42164e90ec300ae7396b6f06365ae0d7dcb651b/FlifWICCodec/flif_wic_codec.rc
--------------------------------------------------------------------------------
/FlifWICCodec/metadata_store.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include "metadata_store.h"
4 | #include "decode_frame.h"
5 |
6 |
7 | struct SupportedMetadata {
8 | SupportedMetadata(const PROPERTYKEY& key, LPCWSTR photo_metadata_policy, LPCWSTR xmp_metadata_query, bool is_writable)
9 | : key(key),
10 | photoMetadataPolicy(photo_metadata_policy),
11 | xmpMetadataQuery(xmp_metadata_query),
12 | isWritable(is_writable)
13 | {
14 | }
15 |
16 | const PROPERTYKEY& key;
17 | LPCWSTR photoMetadataPolicy;
18 | LPCWSTR xmpMetadataQuery;
19 | //LPCWSTR exifMetadataQuery;
20 | const bool isWritable;
21 | };
22 |
23 | static const
24 | SupportedMetadata supported_metadatas[] = {
25 | // Using "Photo Metadata Policies" of Jpeg container.
26 | // See also DecodeFrame::MetadataBlockReader::GetContainerFormat
27 | { PKEY_Title, L"System.Title", L"/xmp/dc:title", false },
28 | { PKEY_Copyright, L"System.Copyright", L"/xmp/dc:rights", false },
29 | { PKEY_Author, L"System.Author", L"/xmp/dc:creator", false },
30 | { PKEY_Subject, L"System.Subject", L"/ifd/{ushort=40095} ", false },
31 | { PKEY_Image_BitDepth, nullptr, nullptr, false },
32 | { PKEY_Image_HorizontalSize, nullptr, nullptr, false },
33 | { PKEY_Image_VerticalSize, nullptr, nullptr, false },
34 | { PKEY_Image_Dimensions, nullptr, nullptr, false },
35 | { PKEY_Rating, L"System.Rating", L"/xmp/xmp:Rating", false },
36 | { PKEY_Photo_CameraModel, L"System.Photo.CameraModel", L"/xmp/tiff:Model", false },
37 | { PKEY_Photo_CameraManufacturer, L"System.Photo.CameraManufacturer", L"/xmp/tiff:Make", false },
38 | { PKEY_Photo_CameraSerialNumber, L"System.Photo.CameraSerialNumber", L"/xmp/MicrosoftPhoto:CameraSerialNumber", false },
39 |
40 | { PKEY_Photo_Aperture, L"System.Photo.Aperture", L"/xmp/exif:ApertureValue", false },
41 | { PKEY_Photo_Brightness, L"System.Photo.Brightness", L"/xmp/exif:BrightnessValue", false },
42 | { PKEY_Photo_Contrast, L"System.Photo.Contrast", L"/xmp/exif:Contrast", false },
43 | { PKEY_Photo_DateTaken, L"System.Photo.DateTaken", L"/xmp/xmp:CreateDate", false },
44 | { PKEY_Photo_DigitalZoom, L"System.Photo.DigitalZoom", L"/xmp/exif:DigitalZoomRatio", false },
45 | { PKEY_Photo_EXIFVersion, L"System.Photo.EXIFVersion", L"/xmp/exif:ExifVersion", false },
46 | { PKEY_Photo_ExposureBias, L"System.Photo.ExposureBias", L"/xmp/exif:ExposureBiasValue", false },
47 | { PKEY_Photo_ExposureTime, L"System.Photo.ExposureTime", L"/xmp/exif:ExposureTime", false },
48 |
49 | { PKEY_GPS_Altitude, L"System.GPS.Altitude", L"/xmp/exif:GPSAltitude", false },
50 | { PKEY_GPS_Latitude, L"System.GPS.Latitude", L"/xmp/exif:GPSLatitude", false },
51 | { PKEY_GPS_Longitude, L"System.GPS.Longitude" , L"/xmp/exif:GPSLongitude", false },
52 | };
53 |
54 | MetadataStore::MetadataStore()
55 | : initializeWithStream_(*this)
56 | , propertyStoreCapabilities_(*this)
57 | {
58 | TRACE("()\n");
59 | }
60 |
61 | MetadataStore::~MetadataStore()
62 | {
63 | TRACE("()\n");
64 | }
65 |
66 | HRESULT MetadataStore::QueryInterface(REFIID riid, void ** ppvObject)
67 | {
68 | TRACE2("(%s, %p)\n", debugstr_guid(riid), ppvObject);
69 |
70 | if (ppvObject == nullptr)
71 | return E_INVALIDARG;
72 | *ppvObject = nullptr;
73 |
74 | if (IsEqualGUID(riid, IID_IUnknown) ||
75 | IsEqualGUID(riid, IID_IPropertyStore))
76 | {
77 | this->AddRef();
78 | *ppvObject = static_cast(this);
79 | return S_OK;
80 | }
81 |
82 | if (IsEqualGUID(riid, IID_IInitializeWithStream))
83 | {
84 | this->AddRef();
85 | *ppvObject = static_cast(&this->initializeWithStream_);
86 | return S_OK;
87 | }
88 |
89 | if (IsEqualGUID(riid, IID_IPropertyStoreCapabilities))
90 | {
91 | this->AddRef();
92 | *ppvObject = static_cast(&this->propertyStoreCapabilities_);
93 | return S_OK;
94 | }
95 |
96 | return E_NOINTERFACE;
97 | }
98 |
99 | HRESULT MetadataStore::GetCount(DWORD * cProps)
100 | {
101 | TRACE1("(%p)\n", cProps);
102 | return propertyStoreCache_.get() ? propertyStoreCache_->GetCount(cProps) : E_UNEXPECTED;
103 | }
104 |
105 | HRESULT MetadataStore::GetAt(DWORD iProp, PROPERTYKEY * pkey)
106 | {
107 | TRACE2("(%d %p)\n", iProp, pkey);
108 | return propertyStoreCache_.get() ? propertyStoreCache_->GetAt(iProp, pkey) : E_UNEXPECTED;
109 | }
110 |
111 | HRESULT MetadataStore::GetValue(REFPROPERTYKEY key, PROPVARIANT * pv)
112 | {
113 | TRACE2("(%s, %p)\n", debugstr_guid(key.fmtid), pv);
114 | return propertyStoreCache_.get() ? propertyStoreCache_->GetValue(key, pv) : E_UNEXPECTED;
115 | }
116 |
117 | HRESULT MetadataStore::SetValue(REFPROPERTYKEY key, REFPROPVARIANT propvar)
118 | {
119 | TRACE2("(%s, %ls)\n", debugstr_guid(key.fmtid), debugstr_var(propvar));
120 | return propertyStoreCache_.get() ? propertyStoreCache_->SetValue(key, propvar) : E_UNEXPECTED;
121 | }
122 |
123 | HRESULT MetadataStore::Commit(void)
124 | {
125 | TRACE("()\n");
126 | return S_OK;
127 | }
128 |
129 | HRESULT MetadataStore::InitializeWithStream::Initialize(IStream * pstream, DWORD grfMode)
130 | {
131 | TRACE2("(%p, %d)\n", pstream, grfMode);
132 | HRESULT result;
133 | result = PSCreateMemoryPropertyStore(IID_PPV_ARGS(metadataStore_.propertyStoreCache_.get_out_storage()));
134 | if (FAILED(result))
135 | return result;
136 |
137 | DecodeContainer container;
138 | result = container.Initialize(pstream, WICDecodeMetadataCacheOnDemand);
139 | if (FAILED(result))
140 | return result;
141 |
142 | PROPVARIANT propvar;
143 | PropVariantInit(&propvar);
144 |
145 | // bitdepth
146 | InitPropVariantFromUInt32(container.GetBitDepth(), &propvar);
147 | metadataStore_.propertyStoreCache_->SetValueAndState(PKEY_Image_BitDepth, &propvar, PSC_NORMAL);
148 | PropVariantClear(&propvar);
149 |
150 | // width
151 | ULONG width = container.GetWidth();
152 | InitPropVariantFromUInt32(width, &propvar);
153 | metadataStore_.propertyStoreCache_->SetValueAndState(PKEY_Image_HorizontalSize, &propvar, PSC_NORMAL);
154 | PropVariantClear(&propvar);
155 |
156 | // height
157 | ULONG height = container.GetHeight();
158 | InitPropVariantFromUInt32(height, &propvar);
159 | metadataStore_.propertyStoreCache_->SetValueAndState(PKEY_Image_VerticalSize, &propvar, PSC_NORMAL);
160 | PropVariantClear(&propvar);
161 |
162 | // dimensions
163 | WCHAR buffer[64] = {};
164 | swprintf_s(buffer, L"%u \u00D7 %u", width, height);
165 | InitPropVariantFromString(buffer, &propvar);
166 | metadataStore_.propertyStoreCache_->SetValueAndState(PKEY_Image_Dimensions, &propvar, PSC_NORMAL);
167 | PropVariantClear(&propvar);
168 |
169 |
170 | ComPtr queryReader;
171 | result = container.GetMetadataQueryReader(queryReader.get_out_storage());
172 | if (FAILED(result))
173 | return result;
174 | for (const SupportedMetadata& supportedMetadata : supported_metadatas)
175 | {
176 | if (supportedMetadata.photoMetadataPolicy)
177 | {
178 | if (SUCCEEDED(queryReader->GetMetadataByName(supportedMetadata.photoMetadataPolicy, &propvar))
179 | && (propvar.vt != VT_EMPTY))
180 | {
181 | result = metadataStore_.propertyStoreCache_->SetValueAndState(supportedMetadata.key, &propvar, PSC_NORMAL);
182 | }
183 | PropVariantClear(&propvar);
184 | }
185 | }
186 | return S_OK;
187 | }
188 |
189 | HRESULT MetadataStore::PropertyStoreCapabilities::IsPropertyWritable(REFPROPERTYKEY key)
190 | {
191 | TRACE1("(%s)\n", debugstr_guid(key.fmtid));
192 | for (const SupportedMetadata& supportedMetadata : supported_metadatas)
193 | {
194 | if (IsEqualGUID(supportedMetadata.key.fmtid, key.fmtid))
195 | {
196 | return supportedMetadata.isWritable
197 | ? S_OK
198 | : S_FALSE;
199 | }
200 | }
201 | return S_FALSE;
202 | }
203 |
--------------------------------------------------------------------------------
/FlifWICCodec/metadata_store.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "decode_container.h"
9 | #include "utils.h"
10 |
11 | class MetadataStore : public ComObjectBase {
12 | public:
13 | explicit MetadataStore();
14 | ~MetadataStore();
15 | // Inherited via IUnknown:
16 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override;
17 | ULONG STDMETHODCALLTYPE AddRef() override { return ComObjectBase::AddRef(); }
18 | ULONG STDMETHODCALLTYPE Release() override { return ComObjectBase::Release(); }
19 | // Inherited via ComObjectBase
20 | HRESULT STDMETHODCALLTYPE GetCount(DWORD * cProps) override;
21 | HRESULT STDMETHODCALLTYPE GetAt(DWORD iProp, PROPERTYKEY * pkey) override;
22 | HRESULT STDMETHODCALLTYPE GetValue(REFPROPERTYKEY key, PROPVARIANT * pv) override;
23 | HRESULT STDMETHODCALLTYPE SetValue(REFPROPERTYKEY key, REFPROPVARIANT propvar) override;
24 | HRESULT STDMETHODCALLTYPE Commit(void) override;
25 | private:
26 | class InitializeWithStream : public IInitializeWithStream
27 | {
28 | public:
29 | InitializeWithStream(MetadataStore& metadataStore) : metadataStore_(metadataStore) { InitializeCriticalSection(&cs_); }
30 | ~InitializeWithStream() { DeleteCriticalSection(&cs_); }
31 | // Inherited via IUnknown:
32 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override { return metadataStore_.QueryInterface(riid, ppvObject); };
33 | ULONG STDMETHODCALLTYPE AddRef() override { return metadataStore_.AddRef(); }
34 | ULONG STDMETHODCALLTYPE Release() override { return metadataStore_.Release(); }
35 | // Inherited via IInitializeWithStream
36 | HRESULT STDMETHODCALLTYPE Initialize(IStream * pstream, DWORD grfMode) override;
37 | private:
38 | MetadataStore& metadataStore_;
39 | CRITICAL_SECTION cs_;
40 | };
41 |
42 | class PropertyStoreCapabilities : public IPropertyStoreCapabilities
43 | {
44 | public:
45 | PropertyStoreCapabilities(MetadataStore& metadataStore) : metadataStore_(metadataStore) {}
46 | // Inherited via IUnknown:
47 | HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override { return metadataStore_.QueryInterface(riid, ppvObject); };
48 | ULONG STDMETHODCALLTYPE AddRef() override { return metadataStore_.AddRef(); }
49 | ULONG STDMETHODCALLTYPE Release() override { return metadataStore_.Release(); }
50 | // Inherited via IPropertyStoreCapabilities
51 | virtual HRESULT STDMETHODCALLTYPE IsPropertyWritable(REFPROPERTYKEY key) override;
52 | private:
53 | MetadataStore& metadataStore_;
54 | };
55 |
56 | ComPtr propertyStoreCache_;
57 | InitializeWithStream initializeWithStream_;
58 | PropertyStoreCapabilities propertyStoreCapabilities_;
59 | };
--------------------------------------------------------------------------------
/FlifWICCodec/pixel_converter.cpp:
--------------------------------------------------------------------------------
1 | #include "pixel_converter.h"
2 |
3 | #pragma pack(push, 1)
4 | struct RGBA {
5 | unsigned char r, g, b, a;
6 | };
7 | #pragma pack(pop)
8 |
9 | void CopyAllButTransparentPixelRGBA8(size_t width, const void* sourceRow, const void* destRow) {
10 | RGBA* src = (RGBA*)sourceRow;
11 | RGBA* dst = (RGBA*)destRow;
12 | for (size_t i = 0; i < width; ++i) {
13 | const RGBA temp = src[i];
14 | //Don't copy fully transparent pixel
15 | if (temp.a == 0)
16 | continue;
17 | dst[i].r = temp.r;
18 | dst[i].g = temp.g;
19 | dst[i].b = temp.b;
20 | dst[i].a = temp.a;
21 | }
22 | }
--------------------------------------------------------------------------------
/FlifWICCodec/pixel_converter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | void CopyAllButTransparentPixelRGBA8(size_t width, const void* sourceRow, const void* destRow);
--------------------------------------------------------------------------------
/FlifWICCodec/resids.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Used by flif_wic_codec.rc
3 |
4 | #pragma once
5 |
6 | #define IDS_MUI_FILE_TYPE_NAME 1025 // Referenced from the registry - file type.
7 |
--------------------------------------------------------------------------------
/FlifWICCodec/stopwatch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | typedef LARGE_INTEGER Stopwatch;
6 |
7 | static inline double StopwatchReadAndReset(Stopwatch* watch) {
8 | const LARGE_INTEGER old_value = *watch;
9 | LARGE_INTEGER freq;
10 | if (!QueryPerformanceCounter(watch))
11 | return 0.0;
12 | if (!QueryPerformanceFrequency(&freq))
13 | return 0.0;
14 | if (freq.QuadPart == 0)
15 | return 0.0;
16 | return (watch->QuadPart - old_value.QuadPart) / (double)freq.QuadPart;
17 | }
18 |
--------------------------------------------------------------------------------
/FlifWICCodec/targetver.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Including SDKDDKVer.h defines the highest available Windows platform.
4 |
5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
7 |
8 | #include
9 |
--------------------------------------------------------------------------------
/FlifWICCodec/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "dllmain.h"
8 |
9 | struct RawFrame {
10 | const uint32_t Width;
11 | const uint32_t Height;
12 | const uint32_t NumberComponents;
13 | const uint32_t Stride;
14 | const size_t BufferSize;
15 | uint8_t* const Buffer;
16 |
17 | RawFrame(uint32_t width, uint32_t height, uint32_t numberComponents, uint32_t stride)
18 | : Width(width), Height(height), NumberComponents(numberComponents), Stride(stride),
19 | BufferSize(stride*height), Buffer((uint8_t*)CoTaskMemAlloc(BufferSize))
20 | {
21 | }
22 | ~RawFrame()
23 | {
24 | if (Buffer) {
25 | CoTaskMemFree(Buffer);
26 | }
27 | }
28 | private:
29 | // No copy and assign.
30 | RawFrame(const RawFrame&) = delete;
31 | void operator=(const RawFrame&) = delete;
32 | };
33 |
34 | struct Metadata {
35 | std::string Chunkname;
36 | const size_t BufferSize;
37 | uint8_t* const Buffer;
38 | Metadata(std::string chunkname, size_t bufferSize)
39 | : Chunkname(chunkname), BufferSize(bufferSize), Buffer((uint8_t*)CoTaskMemAlloc(BufferSize))
40 | {
41 | }
42 | ~Metadata()
43 | {
44 | if (Buffer) {
45 | CoTaskMemFree(Buffer);
46 | }
47 | }
48 | private:
49 | // No copy and assign.
50 | Metadata(const Metadata&) = delete;
51 | void operator=(const Metadata&) = delete;
52 | };
53 |
54 |
55 | class SectionLock {
56 | public:
57 | SectionLock(CRITICAL_SECTION* cs) :cs_(cs) { EnterCriticalSection(cs_); }
58 | ~SectionLock() { LeaveCriticalSection(cs_); }
59 | private:
60 | CRITICAL_SECTION* cs_;
61 | // No copy and assign.
62 | SectionLock(const SectionLock&) = delete;
63 | void operator=(const SectionLock&) = delete;
64 | };
65 |
66 | // A wrapper around a pointer to a COM object that does a Release on
67 | // descruction. T should be a subclass of IUnknown.
68 | template
69 | class ComPtr {
70 | public:
71 | ComPtr() :ptr_(NULL) { }
72 | // ptr should be already AddRef'ed for this reference.
73 | ComPtr(T* ptr) :ptr_(ptr) { }
74 | ~ComPtr() { if (ptr_) ptr_->Release(); }
75 |
76 | T* get() { return ptr_; }
77 | T* new_ref() { ptr_->AddRef(); return ptr_; }
78 | // new_ptr should be already AddRef'ed for this new reference.
79 | void reset(T* new_ptr) { if (ptr_ != NULL) ptr_->Release(); ptr_ = new_ptr; }
80 | // Allows to pass the the pointer as an 'out' parameter. If a non-NULL value
81 | // is written to it, it should be a valid pointer and already AddRef'ed for
82 | // this new reference.
83 | T** get_out_storage() { reset(NULL); return &ptr_; }
84 | T* operator->() { return ptr_; }
85 | T& operator*() { return *ptr_; }
86 | private:
87 | T* ptr_;
88 |
89 | // No copy and assign.
90 | ComPtr(const ComPtr&) = delete;
91 | void operator=(const ComPtr&) = delete;
92 | };
93 |
94 | // Implements handling of object's and DLL's COM reference counts.
95 | // T should be a subinterface of IUnknown. Templating used to avoid unnecessary
96 | // mulitple inheritance.
97 | template
98 | class ComObjectBase : public T {
99 | public:
100 | ComObjectBase() {
101 | TRACE1("(%p)\n", this);
102 | InterlockedIncrement(&MAIN_nObjects);
103 | ref_count_ = 1;
104 | }
105 | virtual ~ComObjectBase() {
106 | TRACE1("(%p)\n", this);
107 | InterlockedDecrement(&MAIN_nObjects);
108 | }
109 |
110 | // IUnknown methods:
111 | virtual ULONG STDMETHODCALLTYPE AddRef() override {
112 | return InterlockedIncrement(&ref_count_);
113 | }
114 |
115 | virtual ULONG STDMETHODCALLTYPE Release() override {
116 | ULONG ret = InterlockedDecrement(&ref_count_);
117 | if (ret == 0)
118 | delete this;
119 | return ret;
120 | }
121 | protected:
122 | volatile ULONG ref_count_;
123 | };
124 |
125 | // Can't use e.g., auto_ptr because it's using delete and not delete[].
126 | class scoped_buffer {
127 | public:
128 | scoped_buffer(SIZE_T size) { ptr_ = (BYTE*)CoTaskMemAlloc(size); }
129 | ~scoped_buffer() { CoTaskMemFree(ptr_); }
130 |
131 | // Did the allocation succeed.
132 | bool alloc_failed() { return ptr_ == NULL; }
133 | BYTE* get() { assert(ptr_ != NULL); return ptr_; }
134 | private:
135 | // No copy and assign.
136 | scoped_buffer(const scoped_buffer&) = delete;
137 | void operator=(const scoped_buffer&) = delete;
138 | BYTE* ptr_;
139 | };
140 |
141 |
--------------------------------------------------------------------------------
/FlifWICCodec/uuid.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Class ID of the decoder class (DecodeContainer)
4 | // {688C2007-3185-4BB1-8075-00BEE4657DE2}
5 | DEFINE_GUID(CLSID_FLIFWICDecoder,
6 | 0x688c2007, 0x3185, 0x4bb1, 0x80, 0x75, 0x0, 0xbe, 0xe4, 0x65, 0x7d, 0xe2);
7 |
8 | // GUID of the FLIF container format.
9 | // {CB7F4B31-8638-41B2-A7B6-E5CB230DD56B}
10 | DEFINE_GUID(GUID_ContainerFormatFLIF,
11 | 0xcb7f4b31, 0x8638, 0x41b2, 0xa7, 0xb6, 0xe5, 0xcb, 0x23, 0xd, 0xd5, 0x6b);
12 |
13 | // GUID used as the vendor of this DLL.
14 | // {DD10E737-3366-4703-B75F-F9C66DFED5EE}
15 | DEFINE_GUID(GUID_FLIFCodecVendor,
16 | 0xdd10e737, 0x3366, 0x4703, 0xb7, 0x5f, 0xf9, 0xc6, 0x6d, 0xfe, 0xd5, 0xee);
17 |
18 | // GUID for IPropertyStore implementation.
19 | // {30186A1B-E4D3-4781-B3A3-2F54E271ED5A}
20 | DEFINE_GUID(GUID_FLIFPropertyStore,
21 | 0x30186a1b, 0xe4d3, 0x4781, 0xb3, 0xa3, 0x2f, 0x54, 0xe2, 0x71, 0xed, 0x5a);
22 |
23 | // Class ID of the encoder class (EncodeContainer)
24 | // {9C21723C-6748-4BCA-AB32-C2BB7EE02471}
25 | DEFINE_GUID(CLSID_FLIFWICEncoder,
26 | 0x9c21723c, 0x6748, 0x4bca, 0xab, 0x32, 0xc2, 0xbb, 0x7e, 0xe0, 0x24, 0x71);
27 |
--------------------------------------------------------------------------------
/FlifWICCodec/version.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define PRODUCT_NAME "FLIF Codec for Windows"
4 | #define PRODUCT_COMPANY "Private open source build"
5 |
6 | #define FILE_VERSION_MAJOR 0
7 | #define FILE_VERSION_MINOR 1
8 | #define FILE_VERSION_MAJOR_STR "0"
9 | #define FILE_VERSION_MINOR_STR "1"
10 | #define PRODUCT_VERSION_MAJOR 0
11 | #define PRODUCT_VERSION_MINOR 1
12 | #define PRODUCT_VERSION_MAJOR_STR "0"
13 | #define PRODUCT_VERSION_MINOR_STR "1"
14 |
15 | #define FILE_VERSION_BUILD 0
16 | #define FILE_VERSION_BUILD_STR "0"
17 | #define PRODUCT_VERSION_BUILD 0
18 | #define PRODUCT_VERSION_BUILD_STR "0"
19 |
20 | // Builds with a set build id are considered non-private.
21 | #if FILE_VERSION_BUILD
22 | #define VER_PRIVATE 0
23 | #else
24 | #define VER_PRIVATE VS_FF_PRIVATEBUILD
25 | #endif
26 |
27 | #ifdef _DEBUG
28 | #define VER_DEBUG VS_FF_DEBUG
29 | #else
30 | #define VER_DEBUG 0
31 | #endif
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://ci.appveyor.com/project/peirick/flifwiccodec)
2 |
3 | # FLIF Windows Codec
4 | This plugin allows to **decode** and **encode** [FLIF](http://flif.com) files in Windows aplications using the Windows Imaging Component (WIC) API. That allows e.g., to see the files
5 | in Windows PhotoViewer and Windows Explorer.
6 |
7 | ## Build Instructions
8 | 1. Open Visual Studio 2015 and open FlifWICCodec.sln
9 | 2. Compile
10 |
11 | ## Installation
12 | 1. open an administrative command prompt
13 | 2. navigate to folder with the FlifWICCodec.dll
14 | 3. execute:
15 | ```
16 | regsvr32 FlifWICCodec.dll
17 | ```
18 |
19 | ## Uninstall
20 | 1. open an administrative command prompt
21 | 2. navigate to folder with the FlifWICCodec.dll
22 | 3. execute:
23 | ```
24 | regsvr32 -u FlifWICCodec.dll
25 | ```
26 |
27 | ## Used Repositories
28 | * [https://github.com/FLIF-hub/FLIF](https://github.com/FLIF-hub/FLIF)
29 |
--------------------------------------------------------------------------------
/libflif/libflif.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | false
89 | false
90 | false
91 | false
92 |
93 |
94 | true
95 | true
96 | true
97 | true
98 |
99 |
100 | Default
101 | Default
102 | Default
103 | Default
104 | true
105 | true
106 | true
107 | true
108 |
109 |
110 | Default
111 | Default
112 | Default
113 | Default
114 | true
115 | true
116 | true
117 | true
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | {56871ADF-ABF5-414B-8872-BCF0E200B95D}
126 | Win32Proj
127 | libflif
128 | 8.1
129 | libflif
130 |
131 |
132 |
133 | StaticLibrary
134 | true
135 | v140
136 | Unicode
137 |
138 |
139 | StaticLibrary
140 | false
141 | v140
142 | true
143 | Unicode
144 |
145 |
146 | StaticLibrary
147 | true
148 | v140
149 | Unicode
150 |
151 |
152 | StaticLibrary
153 | false
154 | v140
155 | true
156 | Unicode
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | NotUsing
183 | Level3
184 | Disabled
185 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
186 | true
187 | MultiThreadedDebug
188 | Fast
189 |
190 |
191 | Windows
192 |
193 |
194 |
195 |
196 | NotUsing
197 | Level3
198 | Disabled
199 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;_DEBUG;_LIB;%(PreprocessorDefinitions)
200 | true
201 | MultiThreadedDebug
202 | Fast
203 | %(AdditionalOptions)
204 |
205 |
206 | Windows
207 |
208 |
209 |
210 |
211 | Level3
212 | NotUsing
213 | Full
214 | true
215 | true
216 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
217 | true
218 | MultiThreaded
219 | true
220 | Fast
221 | false
222 | true
223 | true
224 |
225 |
226 | Windows
227 | true
228 | true
229 |
230 |
231 |
232 |
233 | Level3
234 | NotUsing
235 | Full
236 | true
237 | true
238 | FLIF_USE_STB_IMAGE;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;NOMINMAX;NDEBUG;_LIB;%(PreprocessorDefinitions)
239 | true
240 | MultiThreaded
241 | true
242 | Fast
243 | false
244 | true
245 | true
246 | /Qpar-report:1 /Qvec-report:1 %(AdditionalOptions)
247 |
248 |
249 | Windows
250 | true
251 | true
252 |
253 |
254 |
255 |
256 |
257 |
--------------------------------------------------------------------------------
/libflif/libflif.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {45d6fccd-46d8-4d0c-8e9c-59bde0f3fa56}
6 |
7 |
8 | {0e8f55d4-ac57-4cb7-97f6-35914f60c803}
9 |
10 |
11 | {e7722c4e-9787-4ac4-b175-b2505df06706}
12 |
13 |
14 | {6be9adf2-782a-493e-ad12-3955c989587e}
15 |
16 |
17 | {5aa93bd9-1709-4937-a867-7a5169a68230}
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | transform
31 |
32 |
33 | transform
34 |
35 |
36 | transform
37 |
38 |
39 | transform
40 |
41 |
42 | transform
43 |
44 |
45 | transform
46 |
47 |
48 | transform
49 |
50 |
51 | transform
52 |
53 |
54 | transform
55 |
56 |
57 | transform
58 |
59 |
60 | transform
61 |
62 |
63 | transform
64 |
65 |
66 | transform
67 |
68 |
69 | maniac
70 |
71 |
72 | maniac
73 |
74 |
75 | maniac
76 |
77 |
78 | maniac
79 |
80 |
81 | maniac
82 |
83 |
84 | maniac
85 |
86 |
87 | maniac
88 |
89 |
90 | maniac
91 |
92 |
93 | maniac
94 |
95 |
96 | image
97 |
98 |
99 | image
100 |
101 |
102 | image
103 |
104 |
105 | image
106 |
107 |
108 | image
109 |
110 |
111 | image
112 |
113 |
114 | image
115 |
116 |
117 | image
118 |
119 |
120 | image
121 |
122 |
123 | library
124 |
125 |
126 | library
127 |
128 |
129 | library
130 |
131 |
132 | library
133 |
134 |
135 | library
136 |
137 |
138 | library
139 |
140 |
141 | library
142 |
143 |
144 | library
145 |
146 |
147 | extern
148 |
149 |
150 | extern
151 |
152 |
153 | extern
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | transform
163 |
164 |
165 | maniac
166 |
167 |
168 | maniac
169 |
170 |
171 | maniac
172 |
173 |
174 | image
175 |
176 |
177 | image
178 |
179 |
180 | image
181 |
182 |
183 | image
184 |
185 |
186 | image
187 |
188 |
189 | image
190 |
191 |
192 | image
193 |
194 |
195 | image
196 |
197 |
198 | library
199 |
200 |
201 | library
202 |
203 |
204 | library
205 |
206 |
207 | library
208 |
209 |
210 | extern
211 |
212 |
213 |
--------------------------------------------------------------------------------