github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/webp/libwebp/examples/wicdec.c (about) 1 // Copyright 2013 Google Inc. All Rights Reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the COPYING file in the root of the source 5 // tree. An additional intellectual property rights grant can be found 6 // in the file PATENTS. All contributing project authors may 7 // be found in the AUTHORS file in the root of the source tree. 8 // ----------------------------------------------------------------------------- 9 // 10 // Windows Imaging Component (WIC) decode. 11 12 #include "./wicdec.h" 13 14 #ifdef HAVE_CONFIG_H 15 #include "config.h" 16 #endif 17 18 #include <stdio.h> 19 20 #ifdef HAVE_WINCODEC_H 21 #ifdef __MINGW32__ 22 #define INITGUID // Without this GUIDs are declared extern and fail to link 23 #endif 24 #define CINTERFACE 25 #define COBJMACROS 26 #define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ 27 // code with COBJMACROS. 28 #include <shlwapi.h> 29 #include <windows.h> 30 #include <wincodec.h> 31 32 #include "webp/encode.h" 33 #include "./metadata.h" 34 35 #define IFS(fn) \ 36 do { \ 37 if (SUCCEEDED(hr)) { \ 38 hr = (fn); \ 39 if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \ 40 } \ 41 } while (0) 42 43 // modified version of DEFINE_GUID from guiddef.h. 44 #define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 45 static const GUID name = \ 46 { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 47 48 #ifdef __cplusplus 49 #define MAKE_REFGUID(x) (x) 50 #else 51 #define MAKE_REFGUID(x) &(x) 52 #endif 53 54 typedef struct WICFormatImporter { 55 const GUID* pixel_format; 56 int bytes_per_pixel; 57 int (*import)(WebPPicture* const, const uint8_t* const, int); 58 } WICFormatImporter; 59 60 // From Microsoft SDK 7.0a -- wincodec.h 61 // Create local copies for compatibility when building against earlier 62 // versions of the SDK. 63 WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_, 64 0x6fddc324, 0x4e03, 0x4bfe, 65 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); 66 WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_, 67 0x6fddc324, 0x4e03, 0x4bfe, 68 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); 69 WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_, 70 0x6fddc324, 0x4e03, 0x4bfe, 71 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); 72 WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_, 73 0xf5c7ad2d, 0x6a8d, 0x43dd, 74 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); 75 76 static HRESULT OpenInputStream(const char* filename, IStream** stream) { 77 HRESULT hr = S_OK; 78 IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream)); 79 if (FAILED(hr)) { 80 fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr); 81 } 82 return hr; 83 } 84 85 // ----------------------------------------------------------------------------- 86 // Metadata processing 87 88 // Stores the first non-zero sized color profile from 'frame' to 'iccp'. 89 // Returns an HRESULT to indicate success or failure. The caller is responsible 90 // for freeing 'iccp->bytes' in either case. 91 static HRESULT ExtractICCP(IWICImagingFactory* const factory, 92 IWICBitmapFrameDecode* const frame, 93 MetadataPayload* const iccp) { 94 HRESULT hr = S_OK; 95 UINT i, count; 96 IWICColorContext** color_contexts; 97 98 IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count)); 99 if (FAILED(hr) || count == 0) return hr; 100 101 color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts)); 102 if (color_contexts == NULL) return E_OUTOFMEMORY; 103 for (i = 0; SUCCEEDED(hr) && i < count; ++i) { 104 IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i])); 105 } 106 107 if (SUCCEEDED(hr)) { 108 UINT num_color_contexts; 109 IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 110 count, color_contexts, 111 &num_color_contexts)); 112 for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) { 113 WICColorContextType type; 114 IFS(IWICColorContext_GetType(color_contexts[i], &type)); 115 if (SUCCEEDED(hr) && type == WICColorContextProfile) { 116 UINT size; 117 IFS(IWICColorContext_GetProfileBytes(color_contexts[i], 118 0, NULL, &size)); 119 if (size > 0) { 120 iccp->bytes = (uint8_t*)malloc(size); 121 if (iccp->bytes == NULL) { 122 hr = E_OUTOFMEMORY; 123 break; 124 } 125 iccp->size = size; 126 IFS(IWICColorContext_GetProfileBytes(color_contexts[i], 127 (UINT)iccp->size, iccp->bytes, 128 &size)); 129 if (SUCCEEDED(hr) && size != iccp->size) { 130 fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n", 131 size, (uint32_t)iccp->size); 132 iccp->size = size; 133 } 134 break; 135 } 136 } 137 } 138 } 139 for (i = 0; i < count; ++i) { 140 if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]); 141 } 142 free(color_contexts); 143 return hr; 144 } 145 146 static HRESULT ExtractMetadata(IWICImagingFactory* const factory, 147 IWICBitmapFrameDecode* const frame, 148 Metadata* const metadata) { 149 // TODO(jzern): add XMP/EXIF extraction. 150 const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp); 151 if (FAILED(hr)) MetadataFree(metadata); 152 return hr; 153 } 154 155 // ----------------------------------------------------------------------------- 156 157 static int HasPalette(GUID pixel_format) { 158 return (IsEqualGUID(MAKE_REFGUID(pixel_format), 159 MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) || 160 IsEqualGUID(MAKE_REFGUID(pixel_format), 161 MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) || 162 IsEqualGUID(MAKE_REFGUID(pixel_format), 163 MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) || 164 IsEqualGUID(MAKE_REFGUID(pixel_format), 165 MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed))); 166 } 167 168 static int HasAlpha(IWICImagingFactory* const factory, 169 IWICBitmapDecoder* const decoder, 170 IWICBitmapFrameDecode* const frame, 171 GUID pixel_format) { 172 int has_alpha; 173 if (HasPalette(pixel_format)) { 174 IWICPalette* frame_palette = NULL; 175 IWICPalette* global_palette = NULL; 176 BOOL frame_palette_has_alpha = FALSE; 177 BOOL global_palette_has_alpha = FALSE; 178 179 // A palette may exist at the frame or container level, 180 // check IWICPalette::HasAlpha() for both if present. 181 if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) && 182 SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) { 183 IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha); 184 } 185 if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) && 186 SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) { 187 IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha); 188 } 189 has_alpha = frame_palette_has_alpha || global_palette_has_alpha; 190 191 if (frame_palette != NULL) IUnknown_Release(frame_palette); 192 if (global_palette != NULL) IUnknown_Release(global_palette); 193 } else { 194 has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format), 195 MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) || 196 IsEqualGUID(MAKE_REFGUID(pixel_format), 197 MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)); 198 } 199 return has_alpha; 200 } 201 202 int ReadPictureWithWIC(const char* const filename, 203 WebPPicture* const pic, int keep_alpha, 204 Metadata* const metadata) { 205 // From Microsoft SDK 6.0a -- ks.h 206 // Define a local copy to avoid link errors under mingw. 207 WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 208 static const WICFormatImporter kAlphaFormatImporters[] = { 209 { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA }, 210 { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA }, 211 { NULL, 0, NULL }, 212 }; 213 static const WICFormatImporter kNonAlphaFormatImporters[] = { 214 { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR }, 215 { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB }, 216 { NULL, 0, NULL }, 217 }; 218 HRESULT hr = S_OK; 219 IWICBitmapFrameDecode* frame = NULL; 220 IWICFormatConverter* converter = NULL; 221 IWICImagingFactory* factory = NULL; 222 IWICBitmapDecoder* decoder = NULL; 223 IStream* stream = NULL; 224 UINT frame_count = 0; 225 UINT width = 0, height = 0; 226 BYTE* rgb = NULL; 227 WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined; 228 const WICFormatImporter* importer = NULL; 229 GUID src_container_format = GUID_NULL_; 230 static const GUID* kAlphaContainers[] = { 231 &GUID_ContainerFormatBmp, 232 &GUID_ContainerFormatPng, 233 &GUID_ContainerFormatTiff, 234 NULL 235 }; 236 int has_alpha = 0; 237 int stride; 238 239 IFS(CoInitialize(NULL)); 240 IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, 241 CLSCTX_INPROC_SERVER, 242 MAKE_REFGUID(IID_IWICImagingFactory), 243 (LPVOID*)&factory)); 244 if (hr == REGDB_E_CLASSNOTREG) { 245 fprintf(stderr, 246 "Couldn't access Windows Imaging Component (are you running " 247 "Windows XP SP3 or newer?). Most formats not available. " 248 "Use -s for the available YUV input.\n"); 249 } 250 // Prepare for image decoding. 251 IFS(OpenInputStream(filename, &stream)); 252 IFS(IWICImagingFactory_CreateDecoderFromStream( 253 factory, stream, NULL, 254 WICDecodeMetadataCacheOnDemand, &decoder)); 255 IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count)); 256 if (SUCCEEDED(hr) && frame_count == 0) { 257 fprintf(stderr, "No frame found in input file.\n"); 258 hr = E_FAIL; 259 } 260 IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame)); 261 IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format)); 262 IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format)); 263 264 if (keep_alpha) { 265 const GUID** guid; 266 for (guid = kAlphaContainers; *guid != NULL; ++guid) { 267 if (IsEqualGUID(MAKE_REFGUID(src_container_format), 268 MAKE_REFGUID(**guid))) { 269 has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format); 270 break; 271 } 272 } 273 } 274 275 // Prepare for pixel format conversion (if necessary). 276 IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter)); 277 278 for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters; 279 hr == S_OK && importer->import != NULL; ++importer) { 280 BOOL can_convert; 281 const HRESULT cchr = IWICFormatConverter_CanConvert( 282 converter, 283 MAKE_REFGUID(src_pixel_format), 284 MAKE_REFGUID(*importer->pixel_format), 285 &can_convert); 286 if (SUCCEEDED(cchr) && can_convert) break; 287 } 288 if (importer->import == NULL) hr = E_FAIL; 289 290 IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame, 291 importer->pixel_format, 292 WICBitmapDitherTypeNone, 293 NULL, 0.0, WICBitmapPaletteTypeCustom)); 294 295 // Decode. 296 IFS(IWICFormatConverter_GetSize(converter, &width, &height)); 297 stride = importer->bytes_per_pixel * width * sizeof(*rgb); 298 if (SUCCEEDED(hr)) { 299 rgb = (BYTE*)malloc(stride * height); 300 if (rgb == NULL) 301 hr = E_OUTOFMEMORY; 302 } 303 IFS(IWICFormatConverter_CopyPixels(converter, NULL, 304 stride, stride * height, rgb)); 305 306 // WebP conversion. 307 if (SUCCEEDED(hr)) { 308 int ok; 309 pic->width = width; 310 pic->height = height; 311 pic->use_argb = 1; 312 ok = importer->import(pic, rgb, stride); 313 if (!ok) hr = E_FAIL; 314 } 315 if (SUCCEEDED(hr)) { 316 if (metadata != NULL) { 317 hr = ExtractMetadata(factory, frame, metadata); 318 if (FAILED(hr)) { 319 fprintf(stderr, "Error extracting image metadata using WIC!\n"); 320 } 321 } 322 } 323 324 // Cleanup. 325 if (converter != NULL) IUnknown_Release(converter); 326 if (frame != NULL) IUnknown_Release(frame); 327 if (decoder != NULL) IUnknown_Release(decoder); 328 if (factory != NULL) IUnknown_Release(factory); 329 if (stream != NULL) IUnknown_Release(stream); 330 free(rgb); 331 return SUCCEEDED(hr); 332 } 333 #else // !HAVE_WINCODEC_H 334 int ReadPictureWithWIC(const char* const filename, 335 struct WebPPicture* const pic, int keep_alpha, 336 struct Metadata* const metadata) { 337 (void)filename; 338 (void)pic; 339 (void)keep_alpha; 340 (void)metadata; 341 fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. " 342 "Visual Studio and mingw-w64 builds support WIC. Make sure " 343 "wincodec.h detection is working correctly if using autoconf " 344 "and HAVE_WINCODEC_H is defined before building.\n"); 345 return 0; 346 } 347 #endif // HAVE_WINCODEC_H 348 349 // -----------------------------------------------------------------------------