dwebp: enable stdout output with WIC

Change-Id: Ieb73a414784480945bba6cb2687468517e24e755
This commit is contained in:
James Zern 2013-08-20 15:01:23 -07:00
parent 6eabb88637
commit 61405a143d
2 changed files with 45 additions and 17 deletions

View File

@ -32,6 +32,7 @@
#define COBJMACROS #define COBJMACROS
#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++ #define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
// code with COBJMACROS. // code with COBJMACROS.
#include <ole2.h> // CreateStreamOnHGlobal()
#include <shlwapi.h> #include <shlwapi.h>
#include <windows.h> #include <windows.h>
#include <wincodec.h> #include <wincodec.h>
@ -89,9 +90,15 @@ typedef enum {
#define MAKE_REFGUID(x) &(x) #define MAKE_REFGUID(x) &(x)
#endif #endif
static HRESULT CreateOutputStream(const char* out_file_name, IStream** stream) { static HRESULT CreateOutputStream(const char* out_file_name,
int write_to_mem, IStream** stream) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream)); if (write_to_mem) {
// Output to a memory buffer. This is freed when 'stream' is released.
IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
} else {
IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
}
if (FAILED(hr)) { if (FAILED(hr)) {
fprintf(stderr, "Error opening output file %s (%08lx)\n", fprintf(stderr, "Error opening output file %s (%08lx)\n",
out_file_name, hr); out_file_name, hr);
@ -99,7 +106,8 @@ static HRESULT CreateOutputStream(const char* out_file_name, IStream** stream) {
return hr; return hr;
} }
static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid, static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
REFGUID container_guid,
uint8_t* rgb, int stride, uint8_t* rgb, int stride,
uint32_t width, uint32_t height, int has_alpha) { uint32_t width, uint32_t height, int has_alpha) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
@ -121,7 +129,7 @@ static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
"Windows XP SP3 or newer?). PNG support not available. " "Windows XP SP3 or newer?). PNG support not available. "
"Use -ppm or -pgm for available PPM and PGM formats.\n"); "Use -ppm or -pgm for available PPM and PGM formats.\n");
} }
IFS(CreateOutputStream(out_file_name, &stream)); IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL, IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
&encoder)); &encoder));
IFS(IWICBitmapEncoder_Initialize(encoder, stream, IFS(IWICBitmapEncoder_Initialize(encoder, stream,
@ -135,6 +143,28 @@ static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
IFS(IWICBitmapFrameEncode_Commit(frame)); IFS(IWICBitmapFrameEncode_Commit(frame));
IFS(IWICBitmapEncoder_Commit(encoder)); IFS(IWICBitmapEncoder_Commit(encoder));
if (SUCCEEDED(hr) && use_stdout) {
HGLOBAL image;
IFS(GetHGlobalFromStream(stream, &image));
if (SUCCEEDED(hr)) {
HANDLE std_output = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
const BOOL update_mode = GetConsoleMode(std_output, &mode);
const void* const image_mem = GlobalLock(image);
DWORD bytes_written = 0;
// Clear output processing if necessary, then output the image.
if (update_mode) SetConsoleMode(std_output, 0);
if (!WriteFile(std_output, image_mem, (DWORD)GlobalSize(image),
&bytes_written, NULL) ||
bytes_written != GlobalSize(image)) {
hr = E_FAIL;
}
if (update_mode) SetConsoleMode(std_output, mode);
GlobalUnlock(image);
}
}
if (frame != NULL) IUnknown_Release(frame); if (frame != NULL) IUnknown_Release(frame);
if (encoder != NULL) IUnknown_Release(encoder); if (encoder != NULL) IUnknown_Release(encoder);
if (factory != NULL) IUnknown_Release(factory); if (factory != NULL) IUnknown_Release(factory);
@ -142,7 +172,7 @@ static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
return hr; return hr;
} }
static int WritePNG(const char* out_file_name, static int WritePNG(const char* out_file_name, int use_stdout,
const WebPDecBuffer* const buffer) { const WebPDecBuffer* const buffer) {
const uint32_t width = buffer->width; const uint32_t width = buffer->width;
const uint32_t height = buffer->height; const uint32_t height = buffer->height;
@ -150,7 +180,7 @@ static int WritePNG(const char* out_file_name,
const int stride = buffer->u.RGBA.stride; const int stride = buffer->u.RGBA.stride;
const int has_alpha = (buffer->colorspace == MODE_BGRA); const int has_alpha = (buffer->colorspace == MODE_BGRA);
return SUCCEEDED(WriteUsingWIC(out_file_name, return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
MAKE_REFGUID(GUID_ContainerFormatPng), MAKE_REFGUID(GUID_ContainerFormatPng),
rgb, stride, width, height, has_alpha)); rgb, stride, width, height, has_alpha));
} }
@ -440,7 +470,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
OutputFileFormat format, const char* const out_file) { OutputFileFormat format, const char* const out_file) {
FILE* fout = NULL; FILE* fout = NULL;
int needs_open_file = 1; int needs_open_file = 1;
int use_stdout = !strcmp(out_file, "-"); const int use_stdout = !strcmp(out_file, "-");
int ok = 1; int ok = 1;
Stopwatch stop_watch; Stopwatch stop_watch;
@ -450,7 +480,6 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
needs_open_file = (format != PNG); needs_open_file = (format != PNG);
#endif #endif
use_stdout &= needs_open_file;
#if defined(_WIN32) #if defined(_WIN32)
if (use_stdout && _setmode(_fileno(stdout), _O_BINARY) == -1) { if (use_stdout && _setmode(_fileno(stdout), _O_BINARY) == -1) {
@ -469,7 +498,7 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
if (format == PNG) { if (format == PNG) {
#ifdef HAVE_WINCODEC_H #ifdef HAVE_WINCODEC_H
ok &= WritePNG(out_file, buffer); ok &= WritePNG(out_file, use_stdout, buffer);
#else #else
ok &= WritePNG(fout, buffer); ok &= WritePNG(fout, buffer);
#endif #endif
@ -490,20 +519,20 @@ static int SaveOutput(const WebPDecBuffer* const buffer,
fclose(fout); fclose(fout);
} }
if (ok) { if (ok) {
if (fout != stdout) { if (use_stdout) {
fprintf(stderr, "Saved file %s\n", out_file);
} else {
fprintf(stderr, "Saved to stdout\n"); fprintf(stderr, "Saved to stdout\n");
} else {
fprintf(stderr, "Saved file %s\n", out_file);
} }
if (verbose) { if (verbose) {
const double write_time = StopwatchReadAndReset(&stop_watch); const double write_time = StopwatchReadAndReset(&stop_watch);
fprintf(stderr, "Time to write output: %.3fs\n", write_time); fprintf(stderr, "Time to write output: %.3fs\n", write_time);
} }
} else { } else {
if (fout != stdout) { if (use_stdout) {
fprintf(stderr, "Error writing file %s !!\n", out_file);
} else {
fprintf(stderr, "Error writing to stdout !!\n"); fprintf(stderr, "Error writing to stdout !!\n");
} else {
fprintf(stderr, "Error writing file %s !!\n", out_file);
} }
} }
return ok; return ok;

View File

@ -23,8 +23,7 @@ Print the version number (as major.minor.revision) and exit.
.TP .TP
.BI \-o " string .BI \-o " string
Specify the name of the output file (as PNG format by default). Specify the name of the output file (as PNG format by default).
Using "-" as output name will direct output to 'stdout' (this feature Using "-" as output name will direct output to 'stdout'.
is not available when using WIC under Windows).
.TP .TP
.B \-bmp .B \-bmp
Change the output format to uncompressed BMP. Change the output format to uncompressed BMP.