diff --git a/Makefile.vc b/Makefile.vc index a37febc2..32d2284d 100644 --- a/Makefile.vc +++ b/Makefile.vc @@ -176,6 +176,7 @@ EX_FORMAT_DEC_OBJS = \ $(DIROBJ)\examples/metadata.obj \ $(DIROBJ)\examples/pngdec.obj \ $(DIROBJ)\examples/tiffdec.obj \ + $(DIROBJ)\examples/wicdec.obj \ EX_UTIL_OBJS = \ $(DIROBJ)\examples\example_util.obj \ diff --git a/examples/Makefile.am b/examples/Makefile.am index 3cc106b9..d5916c70 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -31,6 +31,7 @@ cwebp_SOURCES = cwebp.c metadata.c metadata.h stopwatch.h cwebp_SOURCES += jpegdec.c jpegdec.h cwebp_SOURCES += pngdec.c pngdec.h cwebp_SOURCES += tiffdec.c tiffdec.h +cwebp_SOURCES += wicdec.c wicdec.h cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(USE_EXPERIMENTAL_CODE) cwebp_CPPFLAGS += $(JPEG_INCLUDES) $(PNG_INCLUDES) $(TIFF_INCLUDES) cwebp_LDADD = ../src/libwebp.la $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) diff --git a/examples/cwebp.c b/examples/cwebp.c index e33215d7..4902ae62 100644 --- a/examples/cwebp.c +++ b/examples/cwebp.c @@ -18,20 +18,6 @@ #include "config.h" #endif -#ifdef HAVE_WINCODEC_H -#ifdef __MINGW32__ -#define INITGUID // Without this GUIDs are declared extern and fail to link -#endif -#define CINTERFACE -#define COBJMACROS -#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ - // code with COBJMACROS. -#include -#include -#include -#endif /* HAVE_WINCODEC_H */ - - #include "webp/encode.h" #include "./metadata.h" @@ -40,6 +26,7 @@ #include "./jpegdec.h" #include "./pngdec.h" #include "./tiffdec.h" +#include "./wicdec.h" #ifndef WEBP_DLL #if defined(__cplusplus) || defined(c_plusplus) @@ -89,180 +76,6 @@ static int ReadYUV(FILE* in_file, WebPPicture* const pic) { #ifdef HAVE_WINCODEC_H -#define IFS(fn) \ - do { \ - if (SUCCEEDED(hr)) { \ - hr = (fn); \ - if (FAILED(hr)) fprintf(stderr, #fn " failed %08x\n", hr); \ - } \ - } while (0) - -// modified version of DEFINE_GUID from guiddef.h. -#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ - const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } - -#ifdef __cplusplus -#define MAKE_REFGUID(x) (x) -#else -#define MAKE_REFGUID(x) &(x) -#endif - -typedef struct WICFormatImporter { - const GUID* pixel_format; - int bytes_per_pixel; - int (*import)(WebPPicture* const, const uint8_t* const, int); -} WICFormatImporter; - -static HRESULT OpenInputStream(const char* filename, IStream** ppStream) { - HRESULT hr = S_OK; - IFS(SHCreateStreamOnFileA(filename, STGM_READ, ppStream)); - if (FAILED(hr)) - fprintf(stderr, "Error opening input file %s (%08x)\n", filename, hr); - return hr; -} - -static HRESULT ReadPictureWithWIC(const char* filename, - WebPPicture* const pic, int keep_alpha) { - // From Microsoft SDK 7.0a -- wincodec.h - // Create local copies for compatibility when building against earlier - // versions of the SDK. - WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); - WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); - WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_, - 0x6fddc324, 0x4e03, 0x4bfe, - 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); - WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_, - 0xf5c7ad2d, 0x6a8d, 0x43dd, - 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); - const WICFormatImporter alphaFormatImporters[] = { - { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA }, - { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA }, - { NULL, 0, NULL }, - }; - const WICFormatImporter nonAlphaFormatImporters[] = { - { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR }, - { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB }, - { NULL, 0, NULL }, - }; - HRESULT hr = S_OK; - IWICBitmapFrameDecode* pFrame = NULL; - IWICFormatConverter* pConverter = NULL; - IWICImagingFactory* pFactory = NULL; - IWICBitmapDecoder* pDecoder = NULL; - IStream* pStream = NULL; - UINT frameCount = 0; - UINT width = 0, height = 0; - BYTE* rgb = NULL; - WICPixelFormatGUID srcPixelFormat = { 0 }; - const WICFormatImporter* importer = NULL; - GUID srcContainerFormat = { 0 }; - const GUID* alphaContainers[] = { - &GUID_ContainerFormatBmp, - &GUID_ContainerFormatPng, - &GUID_ContainerFormatTiff - }; - int has_alpha = 0; - int i, stride; - - IFS(CoInitialize(NULL)); - IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, - CLSCTX_INPROC_SERVER, MAKE_REFGUID(IID_IWICImagingFactory), - (LPVOID*)&pFactory)); - if (hr == REGDB_E_CLASSNOTREG) { - fprintf(stderr, - "Couldn't access Windows Imaging Component (are you running " - "Windows XP SP3 or newer?). Most formats not available. " - "Use -s for the available YUV input.\n"); - } - // Prepare for image decoding. - IFS(OpenInputStream(filename, &pStream)); - IFS(IWICImagingFactory_CreateDecoderFromStream(pFactory, pStream, NULL, - WICDecodeMetadataCacheOnDemand, &pDecoder)); - IFS(IWICBitmapDecoder_GetFrameCount(pDecoder, &frameCount)); - if (SUCCEEDED(hr) && frameCount == 0) { - fprintf(stderr, "No frame found in input file.\n"); - hr = E_FAIL; - } - IFS(IWICBitmapDecoder_GetFrame(pDecoder, 0, &pFrame)); - IFS(IWICBitmapFrameDecode_GetPixelFormat(pFrame, &srcPixelFormat)); - IFS(IWICBitmapDecoder_GetContainerFormat(pDecoder, &srcContainerFormat)); - - if (keep_alpha) { - for (i = 0; - i < sizeof(alphaContainers) / sizeof(alphaContainers[0]); - ++i) { - if (IsEqualGUID(MAKE_REFGUID(srcContainerFormat), - MAKE_REFGUID(*alphaContainers[i]))) { - has_alpha = - IsEqualGUID(MAKE_REFGUID(srcPixelFormat), - MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) || - IsEqualGUID(MAKE_REFGUID(srcPixelFormat), - MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)); - break; - } - } - } - - // Prepare for pixel format conversion (if necessary). - IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter)); - - for (importer = has_alpha ? alphaFormatImporters : nonAlphaFormatImporters; - hr == S_OK && importer->import != NULL; ++importer) { - BOOL canConvert; - const HRESULT cchr = IWICFormatConverter_CanConvert( - pConverter, - MAKE_REFGUID(srcPixelFormat), - MAKE_REFGUID(*importer->pixel_format), - &canConvert); - if (SUCCEEDED(cchr) && canConvert) break; - } - if (importer->import == NULL) hr = E_FAIL; - - IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame, - importer->pixel_format, - WICBitmapDitherTypeNone, - NULL, 0.0, WICBitmapPaletteTypeCustom)); - - // Decode. - IFS(IWICFormatConverter_GetSize(pConverter, &width, &height)); - stride = importer->bytes_per_pixel * width * sizeof(*rgb); - if (SUCCEEDED(hr)) { - rgb = (BYTE*)malloc(stride * height); - if (rgb == NULL) - hr = E_OUTOFMEMORY; - } - IFS(IWICFormatConverter_CopyPixels(pConverter, NULL, stride, - stride * height, rgb)); - - // WebP conversion. - if (SUCCEEDED(hr)) { - int ok; - pic->width = width; - pic->height = height; - ok = importer->import(pic, rgb, stride); - if (!ok) - hr = E_FAIL; - } - if (SUCCEEDED(hr)) { - if (has_alpha && keep_alpha == 2) { - WebPCleanupTransparentArea(pic); - } - } - - // Cleanup. - if (pConverter != NULL) IUnknown_Release(pConverter); - if (pFrame != NULL) IUnknown_Release(pFrame); - if (pDecoder != NULL) IUnknown_Release(pDecoder); - if (pFactory != NULL) IUnknown_Release(pFactory); - if (pStream != NULL) IUnknown_Release(pStream); - free(rgb); - return hr; -} - static int ReadPicture(const char* const filename, WebPPicture* const pic, int keep_alpha, Metadata* const metadata) { int ok; @@ -278,7 +91,7 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic, fclose(in_file); } else { // If no size specified, try to decode it using WIC. - ok = SUCCEEDED(ReadPictureWithWIC(filename, pic, keep_alpha)); + ok = ReadPictureWithWIC(filename, pic, keep_alpha); } if (!ok) { fprintf(stderr, "Error! Could not process file %s\n", filename); diff --git a/examples/wicdec.c b/examples/wicdec.c new file mode 100644 index 00000000..619b959a --- /dev/null +++ b/examples/wicdec.c @@ -0,0 +1,219 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Windows Imaging Component (WIC) decode. + +#include "./wicdec.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef HAVE_WINCODEC_H +#ifdef __MINGW32__ +#define INITGUID // Without this GUIDs are declared extern and fail to link +#endif +#define CINTERFACE +#define COBJMACROS +#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ + // code with COBJMACROS. +#include +#include +#include + +#include "webp/encode.h" + +#define IFS(fn) \ + do { \ + if (SUCCEEDED(hr)) { \ + hr = (fn); \ + if (FAILED(hr)) fprintf(stderr, #fn " failed %08x\n", hr); \ + } \ + } while (0) + +// modified version of DEFINE_GUID from guiddef.h. +#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } + +#ifdef __cplusplus +#define MAKE_REFGUID(x) (x) +#else +#define MAKE_REFGUID(x) &(x) +#endif + +typedef struct WICFormatImporter { + const GUID* pixel_format; + int bytes_per_pixel; + int (*import)(WebPPicture* const, const uint8_t* const, int); +} WICFormatImporter; + +static HRESULT OpenInputStream(const char* filename, IStream** ppStream) { + HRESULT hr = S_OK; + IFS(SHCreateStreamOnFileA(filename, STGM_READ, ppStream)); + if (FAILED(hr)) + fprintf(stderr, "Error opening input file %s (%08x)\n", filename, hr); + return hr; +} + +int ReadPictureWithWIC(const char* const filename, + WebPPicture* const pic, int keep_alpha) { + // From Microsoft SDK 7.0a -- wincodec.h + // Create local copies for compatibility when building against earlier + // versions of the SDK. + WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_, + 0x6fddc324, 0x4e03, 0x4bfe, + 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); + WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_, + 0x6fddc324, 0x4e03, 0x4bfe, + 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); + WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_, + 0x6fddc324, 0x4e03, 0x4bfe, + 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); + WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_, + 0xf5c7ad2d, 0x6a8d, 0x43dd, + 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9); + const WICFormatImporter alphaFormatImporters[] = { + { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA }, + { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA }, + { NULL, 0, NULL }, + }; + const WICFormatImporter nonAlphaFormatImporters[] = { + { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR }, + { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB }, + { NULL, 0, NULL }, + }; + HRESULT hr = S_OK; + IWICBitmapFrameDecode* pFrame = NULL; + IWICFormatConverter* pConverter = NULL; + IWICImagingFactory* pFactory = NULL; + IWICBitmapDecoder* pDecoder = NULL; + IStream* pStream = NULL; + UINT frameCount = 0; + UINT width = 0, height = 0; + BYTE* rgb = NULL; + WICPixelFormatGUID srcPixelFormat = { 0 }; + const WICFormatImporter* importer = NULL; + GUID srcContainerFormat = { 0 }; + const GUID* alphaContainers[] = { + &GUID_ContainerFormatBmp, + &GUID_ContainerFormatPng, + &GUID_ContainerFormatTiff + }; + int has_alpha = 0; + int i, stride; + + IFS(CoInitialize(NULL)); + IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL, + CLSCTX_INPROC_SERVER, MAKE_REFGUID(IID_IWICImagingFactory), + (LPVOID*)&pFactory)); + if (hr == REGDB_E_CLASSNOTREG) { + fprintf(stderr, + "Couldn't access Windows Imaging Component (are you running " + "Windows XP SP3 or newer?). Most formats not available. " + "Use -s for the available YUV input.\n"); + } + // Prepare for image decoding. + IFS(OpenInputStream(filename, &pStream)); + IFS(IWICImagingFactory_CreateDecoderFromStream(pFactory, pStream, NULL, + WICDecodeMetadataCacheOnDemand, &pDecoder)); + IFS(IWICBitmapDecoder_GetFrameCount(pDecoder, &frameCount)); + if (SUCCEEDED(hr) && frameCount == 0) { + fprintf(stderr, "No frame found in input file.\n"); + hr = E_FAIL; + } + IFS(IWICBitmapDecoder_GetFrame(pDecoder, 0, &pFrame)); + IFS(IWICBitmapFrameDecode_GetPixelFormat(pFrame, &srcPixelFormat)); + IFS(IWICBitmapDecoder_GetContainerFormat(pDecoder, &srcContainerFormat)); + + if (keep_alpha) { + for (i = 0; + i < sizeof(alphaContainers) / sizeof(alphaContainers[0]); + ++i) { + if (IsEqualGUID(MAKE_REFGUID(srcContainerFormat), + MAKE_REFGUID(*alphaContainers[i]))) { + has_alpha = + IsEqualGUID(MAKE_REFGUID(srcPixelFormat), + MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) || + IsEqualGUID(MAKE_REFGUID(srcPixelFormat), + MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)); + break; + } + } + } + + // Prepare for pixel format conversion (if necessary). + IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter)); + + for (importer = has_alpha ? alphaFormatImporters : nonAlphaFormatImporters; + hr == S_OK && importer->import != NULL; ++importer) { + BOOL canConvert; + const HRESULT cchr = IWICFormatConverter_CanConvert( + pConverter, + MAKE_REFGUID(srcPixelFormat), + MAKE_REFGUID(*importer->pixel_format), + &canConvert); + if (SUCCEEDED(cchr) && canConvert) break; + } + if (importer->import == NULL) hr = E_FAIL; + + IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame, + importer->pixel_format, + WICBitmapDitherTypeNone, + NULL, 0.0, WICBitmapPaletteTypeCustom)); + + // Decode. + IFS(IWICFormatConverter_GetSize(pConverter, &width, &height)); + stride = importer->bytes_per_pixel * width * sizeof(*rgb); + if (SUCCEEDED(hr)) { + rgb = (BYTE*)malloc(stride * height); + if (rgb == NULL) + hr = E_OUTOFMEMORY; + } + IFS(IWICFormatConverter_CopyPixels(pConverter, NULL, stride, + stride * height, rgb)); + + // WebP conversion. + if (SUCCEEDED(hr)) { + int ok; + pic->width = width; + pic->height = height; + ok = importer->import(pic, rgb, stride); + if (!ok) + hr = E_FAIL; + } + if (SUCCEEDED(hr)) { + if (has_alpha && keep_alpha == 2) { + WebPCleanupTransparentArea(pic); + } + } + + // Cleanup. + if (pConverter != NULL) IUnknown_Release(pConverter); + if (pFrame != NULL) IUnknown_Release(pFrame); + if (pDecoder != NULL) IUnknown_Release(pDecoder); + if (pFactory != NULL) IUnknown_Release(pFactory); + if (pStream != NULL) IUnknown_Release(pStream); + free(rgb); + return SUCCEEDED(hr); +} +#else // !HAVE_WINCODEC_H +int ReadPictureWithWIC(const char* const filename, + struct WebPPicture* const pic, int keep_alpha) { + (void)filename; + (void)pic; + (void)keep_alpha; + fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. " + "Visual Studio and mingw-w64 builds support WIC. Make sure " + "wincodec.h detection is working correctly if using autoconf " + "and HAVE_WINCODEC_H is defined before building.\n"); + return 0; +} +#endif // HAVE_WINCODEC_H + +// ----------------------------------------------------------------------------- diff --git a/examples/wicdec.h b/examples/wicdec.h new file mode 100644 index 00000000..e94133bc --- /dev/null +++ b/examples/wicdec.h @@ -0,0 +1,30 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Windows Imaging Component (WIC) decode. + +#ifndef WEBP_EXAMPLES_WICDEC_H_ +#define WEBP_EXAMPLES_WICDEC_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +struct WebPPicture; + +// Reads an image from 'filename', returning the decoded output in 'pic'. +// If 'keep_alpha' is true and the image has an alpha channel, the output is +// RGBA otherwise it will be RGB. +// Returns true on success. +int ReadPictureWithWIC(const char* const filename, + struct WebPPicture* const pic, int keep_alpha); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBP_EXAMPLES_WICDEC_H_