wicdec: add ICC profile extraction

Change-Id: I4522cdd5a529f802f1eb566b6d94539612e0976b
This commit is contained in:
James Zern 2013-01-24 15:37:49 -08:00
parent 522e9d6108
commit e83ff7decd
3 changed files with 86 additions and 8 deletions

View File

@ -79,7 +79,6 @@ static int ReadYUV(FILE* in_file, WebPPicture* const pic) {
static int ReadPicture(const char* const filename, WebPPicture* const pic, static int ReadPicture(const char* const filename, WebPPicture* const pic,
int keep_alpha, Metadata* const metadata) { int keep_alpha, Metadata* const metadata) {
int ok; int ok;
(void)metadata; // TODO(jzern): add metadata extraction using WIC
if (pic->width != 0 && pic->height != 0) { if (pic->width != 0 && pic->height != 0) {
// If image size is specified, infer it as YUV format. // If image size is specified, infer it as YUV format.
FILE* in_file = fopen(filename, "rb"); FILE* in_file = fopen(filename, "rb");
@ -91,7 +90,7 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic,
fclose(in_file); fclose(in_file);
} else { } else {
// If no size specified, try to decode it using WIC. // If no size specified, try to decode it using WIC.
ok = ReadPictureWithWIC(filename, pic, keep_alpha); ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
} }
if (!ok) { if (!ok) {
fprintf(stderr, "Error! Could not process file %s\n", filename); fprintf(stderr, "Error! Could not process file %s\n", filename);
@ -826,10 +825,10 @@ int main(int argc, const char *argv[]) {
start = token + 1; start = token + 1;
} }
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
if (keep_metadata != 0) { if (keep_metadata != 0 && keep_metadata != METADATA_ICCP) {
// TODO(jzern): remove when -metadata is supported on all platforms. // TODO(jzern): remove when -metadata is supported on all platforms.
fprintf(stderr, "Warning: -metadata is currently unsupported on this" fprintf(stderr, "Warning: only ICC profile extraction is currently"
" platform. Ignoring this option!\n"); " supported on this platform!\n");
} }
#endif #endif
} else if (!strcmp(argv[c], "-v")) { } else if (!strcmp(argv[c], "-v")) {

View File

@ -28,6 +28,7 @@
#include <wincodec.h> #include <wincodec.h>
#include "webp/encode.h" #include "webp/encode.h"
#include "./metadata.h"
#define IFS(fn) \ #define IFS(fn) \
do { \ do { \
@ -61,8 +62,76 @@ static HRESULT OpenInputStream(const char* filename, IStream** ppStream) {
return hr; return hr;
} }
// Stores the first non-zero sized color profile from 'pFrame' to 'iccp'.
// Returns an HRESULT to indicate success or failure. The caller is responsible
// for freeing 'iccp->bytes' in either case.
static HRESULT ExtractICCP(IWICImagingFactory* const pFactory,
IWICBitmapFrameDecode* const pFrame,
MetadataPayload* const iccp) {
HRESULT hr = S_OK;
UINT i, count;
IWICColorContext** ppColorContext;
IFS(IWICBitmapFrameDecode_GetColorContexts(pFrame, 0, NULL, &count));
if (FAILED(hr) || count == 0) return hr;
ppColorContext = (IWICColorContext**)calloc(count, sizeof(*ppColorContext));
if (ppColorContext == NULL) return E_OUTOFMEMORY;
for (i = 0; SUCCEEDED(hr) && i < count; ++i) {
IFS(IWICImagingFactory_CreateColorContext(pFactory, &ppColorContext[i]));
}
if (SUCCEEDED(hr)) {
UINT num_color_contexts;
IFS(IWICBitmapFrameDecode_GetColorContexts(pFrame,
count, ppColorContext,
&num_color_contexts));
for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
WICColorContextType type;
IFS(IWICColorContext_GetType(ppColorContext[i], &type));
if (SUCCEEDED(hr) && type == WICColorContextProfile) {
UINT size;
IFS(IWICColorContext_GetProfileBytes(ppColorContext[i],
0, NULL, &size));
if (size > 0) {
iccp->bytes = (uint8_t*)malloc(size);
if (iccp->bytes == NULL) {
hr = E_OUTOFMEMORY;
break;
}
iccp->size = size;
IFS(IWICColorContext_GetProfileBytes(ppColorContext[i],
(UINT)iccp->size, iccp->bytes,
&size));
if (SUCCEEDED(hr) && size != iccp->size) {
fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n",
size, iccp->size);
iccp->size = size;
}
break;
}
}
}
}
for (i = 0; i < count; ++i) {
if (ppColorContext[i] != NULL) IUnknown_Release(ppColorContext[i]);
}
free(ppColorContext);
return hr;
}
static HRESULT ExtractMetadata(IWICImagingFactory* const pFactory,
IWICBitmapFrameDecode* const pFrame,
Metadata* const metadata) {
// TODO(jzern): add XMP/EXIF extraction.
const HRESULT hr = ExtractICCP(pFactory, pFrame, &metadata->iccp);
if (FAILED(hr)) MetadataFree(metadata);
return hr;
}
int ReadPictureWithWIC(const char* const filename, int ReadPictureWithWIC(const char* const filename,
WebPPicture* const pic, int keep_alpha) { WebPPicture* const pic, int keep_alpha,
Metadata* const metadata) {
// From Microsoft SDK 7.0a -- wincodec.h // From Microsoft SDK 7.0a -- wincodec.h
// Create local copies for compatibility when building against earlier // Create local copies for compatibility when building against earlier
// versions of the SDK. // versions of the SDK.
@ -191,6 +260,12 @@ int ReadPictureWithWIC(const char* const filename,
if (has_alpha && keep_alpha == 2) { if (has_alpha && keep_alpha == 2) {
WebPCleanupTransparentArea(pic); WebPCleanupTransparentArea(pic);
} }
if (metadata != NULL) {
hr = ExtractMetadata(pFactory, pFrame, metadata);
if (FAILED(hr)) {
fprintf(stderr, "Error extracting image metadata using WIC!\n");
}
}
} }
// Cleanup. // Cleanup.
@ -204,10 +279,12 @@ int ReadPictureWithWIC(const char* const filename,
} }
#else // !HAVE_WINCODEC_H #else // !HAVE_WINCODEC_H
int ReadPictureWithWIC(const char* const filename, int ReadPictureWithWIC(const char* const filename,
struct WebPPicture* const pic, int keep_alpha) { struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata) {
(void)filename; (void)filename;
(void)pic; (void)pic;
(void)keep_alpha; (void)keep_alpha;
(void)metadata;
fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. " fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. "
"Visual Studio and mingw-w64 builds support WIC. Make sure " "Visual Studio and mingw-w64 builds support WIC. Make sure "
"wincodec.h detection is working correctly if using autoconf " "wincodec.h detection is working correctly if using autoconf "

View File

@ -14,6 +14,7 @@
extern "C" { extern "C" {
#endif #endif
struct Metadata;
struct WebPPicture; struct WebPPicture;
// Reads an image from 'filename', returning the decoded output in 'pic'. // Reads an image from 'filename', returning the decoded output in 'pic'.
@ -21,7 +22,8 @@ struct WebPPicture;
// RGBA otherwise it will be RGB. // RGBA otherwise it will be RGB.
// Returns true on success. // Returns true on success.
int ReadPictureWithWIC(const char* const filename, int ReadPictureWithWIC(const char* const filename,
struct WebPPicture* const pic, int keep_alpha); struct WebPPicture* const pic, int keep_alpha,
struct Metadata* const metadata);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"