|
Packit |
9c6abc |
// Copyright 2013 Google Inc. All Rights Reserved.
|
|
Packit |
9c6abc |
//
|
|
Packit |
9c6abc |
// Use of this source code is governed by a BSD-style license
|
|
Packit |
9c6abc |
// that can be found in the COPYING file in the root of the source
|
|
Packit |
9c6abc |
// tree. An additional intellectual property rights grant can be found
|
|
Packit |
9c6abc |
// in the file PATENTS. All contributing project authors may
|
|
Packit |
9c6abc |
// be found in the AUTHORS file in the root of the source tree.
|
|
Packit |
9c6abc |
// -----------------------------------------------------------------------------
|
|
Packit |
9c6abc |
//
|
|
Packit |
9c6abc |
// Windows Imaging Component (WIC) decode.
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#include "./wicdec.h"
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#ifdef HAVE_CONFIG_H
|
|
Packit |
9c6abc |
#include "webp/config.h"
|
|
Packit |
9c6abc |
#endif
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#include <assert.h>
|
|
Packit |
9c6abc |
#include <stdio.h>
|
|
Packit |
9c6abc |
#include <string.h>
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#ifdef HAVE_WINCODEC_H
|
|
Packit |
9c6abc |
#ifdef __MINGW32__
|
|
Packit |
9c6abc |
#define INITGUID // Without this GUIDs are declared extern and fail to link
|
|
Packit |
9c6abc |
#endif
|
|
Packit |
9c6abc |
#define CINTERFACE
|
|
Packit |
9c6abc |
#define COBJMACROS
|
|
Packit |
9c6abc |
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
|
|
Packit |
9c6abc |
// code with COBJMACROS.
|
|
Packit |
9c6abc |
#include <ole2.h> // CreateStreamOnHGlobal()
|
|
Packit |
9c6abc |
#include <shlwapi.h>
|
|
Packit |
9c6abc |
#include <windows.h>
|
|
Packit |
9c6abc |
#include <wincodec.h>
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#include "webp/encode.h"
|
|
Packit |
9c6abc |
#include "./imageio_util.h"
|
|
Packit |
9c6abc |
#include "./metadata.h"
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#define IFS(fn) \
|
|
Packit |
9c6abc |
do { \
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr)) { \
|
|
Packit |
9c6abc |
hr = (fn); \
|
|
Packit |
9c6abc |
if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr); \
|
|
Packit |
9c6abc |
} \
|
|
Packit |
9c6abc |
} while (0)
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// modified version of DEFINE_GUID from guiddef.h.
|
|
Packit |
9c6abc |
#define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
|
Packit |
9c6abc |
static const GUID name = \
|
|
Packit |
9c6abc |
{ l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
#ifdef __cplusplus
|
|
Packit |
9c6abc |
#define MAKE_REFGUID(x) (x)
|
|
Packit |
9c6abc |
#else
|
|
Packit |
9c6abc |
#define MAKE_REFGUID(x) &(x)
|
|
Packit |
9c6abc |
#endif
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
typedef struct WICFormatImporter {
|
|
Packit |
9c6abc |
const GUID* pixel_format;
|
|
Packit |
9c6abc |
int bytes_per_pixel;
|
|
Packit |
9c6abc |
int (*import)(WebPPicture* const, const uint8_t* const, int);
|
|
Packit |
9c6abc |
} WICFormatImporter;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// From Microsoft SDK 7.0a -- wincodec.h
|
|
Packit |
9c6abc |
// Create local copies for compatibility when building against earlier
|
|
Packit |
9c6abc |
// versions of the SDK.
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_,
|
|
Packit |
9c6abc |
0x6fddc324, 0x4e03, 0x4bfe,
|
|
Packit |
9c6abc |
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
|
|
Packit |
9c6abc |
0x6fddc324, 0x4e03, 0x4bfe,
|
|
Packit |
9c6abc |
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
|
|
Packit |
9c6abc |
0x6fddc324, 0x4e03, 0x4bfe,
|
|
Packit |
9c6abc |
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
|
|
Packit |
9c6abc |
0xf5c7ad2d, 0x6a8d, 0x43dd,
|
|
Packit |
9c6abc |
0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppBGRA_,
|
|
Packit |
9c6abc |
0x1562ff7c, 0xd352, 0x46f9,
|
|
Packit |
9c6abc |
0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
|
|
Packit |
9c6abc |
0x6fddc324, 0x4e03, 0x4bfe,
|
|
Packit |
9c6abc |
0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
static HRESULT OpenInputStream(const char* filename, IStream** stream) {
|
|
Packit |
9c6abc |
HRESULT hr = S_OK;
|
|
Packit |
9c6abc |
if (!strcmp(filename, "-")) {
|
|
Packit |
9c6abc |
const uint8_t* data = NULL;
|
|
Packit |
9c6abc |
size_t data_size = 0;
|
|
Packit |
9c6abc |
const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
|
|
Packit |
9c6abc |
if (ok) {
|
|
Packit |
9c6abc |
HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
|
|
Packit |
9c6abc |
if (image != NULL) {
|
|
Packit |
9c6abc |
void* const image_mem = GlobalLock(image);
|
|
Packit |
9c6abc |
if (image_mem != NULL) {
|
|
Packit |
9c6abc |
memcpy(image_mem, data, data_size);
|
|
Packit |
9c6abc |
GlobalUnlock(image);
|
|
Packit |
9c6abc |
IFS(CreateStreamOnHGlobal(image, TRUE, stream));
|
|
Packit |
9c6abc |
} else {
|
|
Packit |
9c6abc |
hr = E_FAIL;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
} else {
|
|
Packit |
9c6abc |
hr = E_OUTOFMEMORY;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
free((void*)data);
|
|
Packit |
9c6abc |
} else {
|
|
Packit |
9c6abc |
hr = E_FAIL;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
} else {
|
|
Packit |
9c6abc |
IFS(SHCreateStreamOnFileA(filename, STGM_READ, stream));
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (FAILED(hr)) {
|
|
Packit |
9c6abc |
fprintf(stderr, "Error opening input file %s (%08lx)\n", filename, hr);
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
return hr;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// -----------------------------------------------------------------------------
|
|
Packit |
9c6abc |
// Metadata processing
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// Stores the first non-zero sized color profile from 'frame' to 'iccp'.
|
|
Packit |
9c6abc |
// Returns an HRESULT to indicate success or failure. The caller is responsible
|
|
Packit |
9c6abc |
// for freeing 'iccp->bytes' in either case.
|
|
Packit |
9c6abc |
static HRESULT ExtractICCP(IWICImagingFactory* const factory,
|
|
Packit |
9c6abc |
IWICBitmapFrameDecode* const frame,
|
|
Packit |
9c6abc |
MetadataPayload* const iccp) {
|
|
Packit |
9c6abc |
HRESULT hr = S_OK;
|
|
Packit |
9c6abc |
UINT i, count;
|
|
Packit |
9c6abc |
IWICColorContext** color_contexts;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
|
|
Packit |
9c6abc |
if (FAILED(hr) || count == 0) return hr;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
|
|
Packit |
9c6abc |
if (color_contexts == NULL) return E_OUTOFMEMORY;
|
|
Packit |
9c6abc |
for (i = 0; SUCCEEDED(hr) && i < count; ++i) {
|
|
Packit |
9c6abc |
IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i]));
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr)) {
|
|
Packit |
9c6abc |
UINT num_color_contexts;
|
|
Packit |
9c6abc |
IFS(IWICBitmapFrameDecode_GetColorContexts(frame,
|
|
Packit |
9c6abc |
count, color_contexts,
|
|
Packit |
9c6abc |
&num_color_contexts));
|
|
Packit |
9c6abc |
assert(FAILED(hr) || num_color_contexts <= count);
|
|
Packit |
9c6abc |
for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
|
|
Packit |
9c6abc |
WICColorContextType type;
|
|
Packit |
9c6abc |
IFS(IWICColorContext_GetType(color_contexts[i], &type));
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr) && type == WICColorContextProfile) {
|
|
Packit |
9c6abc |
UINT size;
|
|
Packit |
9c6abc |
IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
|
|
Packit |
9c6abc |
0, NULL, &size));
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr) && size > 0) {
|
|
Packit |
9c6abc |
iccp->bytes = (uint8_t*)malloc(size);
|
|
Packit |
9c6abc |
if (iccp->bytes == NULL) {
|
|
Packit |
9c6abc |
hr = E_OUTOFMEMORY;
|
|
Packit |
9c6abc |
break;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
iccp->size = size;
|
|
Packit |
9c6abc |
IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
|
|
Packit |
9c6abc |
(UINT)iccp->size, iccp->bytes,
|
|
Packit |
9c6abc |
&size));
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr) && size != iccp->size) {
|
|
Packit |
9c6abc |
fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n",
|
|
Packit |
9c6abc |
size, (uint32_t)iccp->size);
|
|
Packit |
9c6abc |
iccp->size = size;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
break;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
for (i = 0; i < count; ++i) {
|
|
Packit |
9c6abc |
if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]);
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
free(color_contexts);
|
|
Packit |
9c6abc |
return hr;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
static HRESULT ExtractMetadata(IWICImagingFactory* const factory,
|
|
Packit |
9c6abc |
IWICBitmapFrameDecode* const frame,
|
|
Packit |
9c6abc |
Metadata* const metadata) {
|
|
Packit |
9c6abc |
// TODO(jzern): add XMP/EXIF extraction.
|
|
Packit |
9c6abc |
const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp);
|
|
Packit |
9c6abc |
if (FAILED(hr)) MetadataFree(metadata);
|
|
Packit |
9c6abc |
return hr;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// -----------------------------------------------------------------------------
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
static int HasPalette(GUID pixel_format) {
|
|
Packit |
9c6abc |
return (IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed)));
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
static int HasAlpha(IWICImagingFactory* const factory,
|
|
Packit |
9c6abc |
IWICBitmapDecoder* const decoder,
|
|
Packit |
9c6abc |
IWICBitmapFrameDecode* const frame,
|
|
Packit |
9c6abc |
GUID pixel_format) {
|
|
Packit |
9c6abc |
int has_alpha;
|
|
Packit |
9c6abc |
if (HasPalette(pixel_format)) {
|
|
Packit |
9c6abc |
IWICPalette* frame_palette = NULL;
|
|
Packit |
9c6abc |
IWICPalette* global_palette = NULL;
|
|
Packit |
9c6abc |
BOOL frame_palette_has_alpha = FALSE;
|
|
Packit |
9c6abc |
BOOL global_palette_has_alpha = FALSE;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// A palette may exist at the frame or container level,
|
|
Packit |
9c6abc |
// check IWICPalette::HasAlpha() for both if present.
|
|
Packit |
9c6abc |
if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) &&
|
|
Packit |
9c6abc |
SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) {
|
|
Packit |
9c6abc |
IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha);
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) &&
|
|
Packit |
9c6abc |
SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) {
|
|
Packit |
9c6abc |
IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha);
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
has_alpha = frame_palette_has_alpha || global_palette_has_alpha;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (frame_palette != NULL) IUnknown_Release(frame_palette);
|
|
Packit |
9c6abc |
if (global_palette != NULL) IUnknown_Release(global_palette);
|
|
Packit |
9c6abc |
} else {
|
|
Packit |
9c6abc |
has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat64bppRGBA_)) ||
|
|
Packit |
9c6abc |
IsEqualGUID(MAKE_REFGUID(pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(GUID_WICPixelFormat64bppBGRA_));
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
return has_alpha;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
int ReadPictureWithWIC(const char* const filename,
|
|
Packit |
9c6abc |
WebPPicture* const pic, int keep_alpha,
|
|
Packit |
9c6abc |
Metadata* const metadata) {
|
|
Packit |
9c6abc |
// From Microsoft SDK 6.0a -- ks.h
|
|
Packit |
9c6abc |
// Define a local copy to avoid link errors under mingw.
|
|
Packit |
9c6abc |
WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
Packit |
9c6abc |
static const WICFormatImporter kAlphaFormatImporters[] = {
|
|
Packit |
9c6abc |
{ &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA },
|
|
Packit |
9c6abc |
{ &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA },
|
|
Packit |
9c6abc |
{ NULL, 0, NULL },
|
|
Packit |
9c6abc |
};
|
|
Packit |
9c6abc |
static const WICFormatImporter kNonAlphaFormatImporters[] = {
|
|
Packit |
9c6abc |
{ &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR },
|
|
Packit |
9c6abc |
{ &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB },
|
|
Packit |
9c6abc |
{ NULL, 0, NULL },
|
|
Packit |
9c6abc |
};
|
|
Packit |
9c6abc |
HRESULT hr = S_OK;
|
|
Packit |
9c6abc |
IWICBitmapFrameDecode* frame = NULL;
|
|
Packit |
9c6abc |
IWICFormatConverter* converter = NULL;
|
|
Packit |
9c6abc |
IWICImagingFactory* factory = NULL;
|
|
Packit |
9c6abc |
IWICBitmapDecoder* decoder = NULL;
|
|
Packit |
9c6abc |
IStream* stream = NULL;
|
|
Packit |
9c6abc |
UINT frame_count = 0;
|
|
Packit |
9c6abc |
UINT width = 0, height = 0;
|
|
Packit |
9c6abc |
BYTE* rgb = NULL;
|
|
Packit |
9c6abc |
WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
|
|
Packit |
9c6abc |
const WICFormatImporter* importer = NULL;
|
|
Packit |
9c6abc |
GUID src_container_format = GUID_NULL_;
|
|
Packit |
9c6abc |
static const GUID* kAlphaContainers[] = {
|
|
Packit |
9c6abc |
&GUID_ContainerFormatBmp,
|
|
Packit |
9c6abc |
&GUID_ContainerFormatPng,
|
|
Packit |
9c6abc |
&GUID_ContainerFormatTiff,
|
|
Packit |
9c6abc |
NULL
|
|
Packit |
9c6abc |
};
|
|
Packit |
9c6abc |
int has_alpha = 0;
|
|
Packit |
9c6abc |
int64_t stride;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (filename == NULL || pic == NULL) return 0;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
IFS(CoInitialize(NULL));
|
|
Packit |
9c6abc |
IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
|
|
Packit |
9c6abc |
CLSCTX_INPROC_SERVER,
|
|
Packit |
9c6abc |
MAKE_REFGUID(IID_IWICImagingFactory),
|
|
Packit |
9c6abc |
(LPVOID*)&factory));
|
|
Packit |
9c6abc |
if (hr == REGDB_E_CLASSNOTREG) {
|
|
Packit |
9c6abc |
fprintf(stderr,
|
|
Packit |
9c6abc |
"Couldn't access Windows Imaging Component (are you running "
|
|
Packit |
9c6abc |
"Windows XP SP3 or newer?). Most formats not available. "
|
|
Packit |
9c6abc |
"Use -s for the available YUV input.\n");
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
// Prepare for image decoding.
|
|
Packit |
9c6abc |
IFS(OpenInputStream(filename, &stream));
|
|
Packit |
9c6abc |
IFS(IWICImagingFactory_CreateDecoderFromStream(
|
|
Packit |
9c6abc |
factory, stream, NULL,
|
|
Packit |
9c6abc |
WICDecodeMetadataCacheOnDemand, &decoder));
|
|
Packit |
9c6abc |
IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr) && frame_count == 0) {
|
|
Packit |
9c6abc |
fprintf(stderr, "No frame found in input file.\n");
|
|
Packit |
9c6abc |
hr = E_FAIL;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
|
|
Packit |
9c6abc |
IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
|
|
Packit |
9c6abc |
IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format));
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr) && keep_alpha) {
|
|
Packit |
9c6abc |
const GUID** guid;
|
|
Packit |
9c6abc |
for (guid = kAlphaContainers; *guid != NULL; ++guid) {
|
|
Packit |
9c6abc |
if (IsEqualGUID(MAKE_REFGUID(src_container_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(**guid))) {
|
|
Packit |
9c6abc |
has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format);
|
|
Packit |
9c6abc |
break;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// Prepare for pixel format conversion (if necessary).
|
|
Packit |
9c6abc |
IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter));
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters;
|
|
Packit |
9c6abc |
hr == S_OK && importer->import != NULL; ++importer) {
|
|
Packit |
9c6abc |
BOOL can_convert;
|
|
Packit |
9c6abc |
const HRESULT cchr = IWICFormatConverter_CanConvert(
|
|
Packit |
9c6abc |
converter,
|
|
Packit |
9c6abc |
MAKE_REFGUID(src_pixel_format),
|
|
Packit |
9c6abc |
MAKE_REFGUID(*importer->pixel_format),
|
|
Packit |
9c6abc |
&can_convert);
|
|
Packit |
9c6abc |
if (SUCCEEDED(cchr) && can_convert) break;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
if (importer->import == NULL) hr = E_FAIL;
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame,
|
|
Packit |
9c6abc |
importer->pixel_format,
|
|
Packit |
9c6abc |
WICBitmapDitherTypeNone,
|
|
Packit |
9c6abc |
NULL, 0.0, WICBitmapPaletteTypeCustom));
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// Decode.
|
|
Packit |
9c6abc |
IFS(IWICFormatConverter_GetSize(converter, &width, &height));
|
|
Packit |
9c6abc |
stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb);
|
|
Packit |
9c6abc |
if (stride != (int)stride ||
|
|
Packit |
9c6abc |
!ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
|
|
Packit |
9c6abc |
hr = E_FAIL;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr)) {
|
|
Packit |
9c6abc |
rgb = (BYTE*)malloc((size_t)stride * height);
|
|
Packit |
9c6abc |
if (rgb == NULL)
|
|
Packit |
9c6abc |
hr = E_OUTOFMEMORY;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
IFS(IWICFormatConverter_CopyPixels(converter, NULL,
|
|
Packit |
9c6abc |
(UINT)stride, (UINT)stride * height, rgb));
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// WebP conversion.
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr)) {
|
|
Packit |
9c6abc |
int ok;
|
|
Packit |
9c6abc |
pic->width = width;
|
|
Packit |
9c6abc |
pic->height = height;
|
|
Packit |
9c6abc |
pic->use_argb = 1; // For WIC, we always force to argb
|
|
Packit |
9c6abc |
ok = importer->import(pic, rgb, (int)stride);
|
|
Packit |
9c6abc |
if (!ok) hr = E_FAIL;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
if (SUCCEEDED(hr)) {
|
|
Packit |
9c6abc |
if (metadata != NULL) {
|
|
Packit |
9c6abc |
hr = ExtractMetadata(factory, frame, metadata);
|
|
Packit |
9c6abc |
if (FAILED(hr)) {
|
|
Packit |
9c6abc |
fprintf(stderr, "Error extracting image metadata using WIC!\n");
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// Cleanup.
|
|
Packit |
9c6abc |
if (converter != NULL) IUnknown_Release(converter);
|
|
Packit |
9c6abc |
if (frame != NULL) IUnknown_Release(frame);
|
|
Packit |
9c6abc |
if (decoder != NULL) IUnknown_Release(decoder);
|
|
Packit |
9c6abc |
if (factory != NULL) IUnknown_Release(factory);
|
|
Packit |
9c6abc |
if (stream != NULL) IUnknown_Release(stream);
|
|
Packit |
9c6abc |
free(rgb);
|
|
Packit |
9c6abc |
return SUCCEEDED(hr);
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
#else // !HAVE_WINCODEC_H
|
|
Packit |
9c6abc |
int ReadPictureWithWIC(const char* const filename,
|
|
Packit |
9c6abc |
struct WebPPicture* const pic, int keep_alpha,
|
|
Packit |
9c6abc |
struct Metadata* const metadata) {
|
|
Packit |
9c6abc |
(void)filename;
|
|
Packit |
9c6abc |
(void)pic;
|
|
Packit |
9c6abc |
(void)keep_alpha;
|
|
Packit |
9c6abc |
(void)metadata;
|
|
Packit |
9c6abc |
fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. "
|
|
Packit |
9c6abc |
"Visual Studio and mingw-w64 builds support WIC. Make sure "
|
|
Packit |
9c6abc |
"wincodec.h detection is working correctly if using autoconf "
|
|
Packit |
9c6abc |
"and HAVE_WINCODEC_H is defined before building.\n");
|
|
Packit |
9c6abc |
return 0;
|
|
Packit |
9c6abc |
}
|
|
Packit |
9c6abc |
#endif // HAVE_WINCODEC_H
|
|
Packit |
9c6abc |
|
|
Packit |
9c6abc |
// -----------------------------------------------------------------------------
|