chromium/third_party/libwebp/src/imageio/image_enc.c

// Copyright 2016 Google Inc. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the COPYING file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Save image

#include "./image_enc.h"

#include <assert.h>
#include <string.h>

#ifdef WEBP_HAVE_PNG
#include <png.h>
#include <setjmp.h>   // note: this must be included *after* png.h
#endif

#ifdef HAVE_WINCODEC_H
#ifdef __MINGW32__
#define INITGUID
#endif
#define CINTERFACE
#define COBJMACROS
#define _WIN32_IE
                         // code with COBJMACROS.
#include <ole2.h>  // CreateStreamOnHGlobal()
#include <shlwapi.h>
#include <tchar.h>
#include <windows.h>
#include <wincodec.h>
#endif

#include "./imageio_util.h"
#include "../examples/unicode.h"

//------------------------------------------------------------------------------
// PNG

#ifdef HAVE_WINCODEC_H

#define IFS

#ifdef __cplusplus
#define MAKE_REFGUID
#else
#define MAKE_REFGUID
#endif

static HRESULT CreateOutputStream(const char* out_file_name,
                                  int write_to_mem, IStream** stream) {
  HRESULT hr = S_OK;
  if (write_to_mem) {
    // Output to a memory buffer. This is freed when 'stream' is released.
    IFS(CreateStreamOnHGlobal(NULL, TRUE, stream));
  } else {
    IFS(SHCreateStreamOnFile((const LPTSTR)out_file_name,
                             STGM_WRITE | STGM_CREATE, stream));
  }
  if (FAILED(hr)) {
    _ftprintf(stderr, _T("Error opening output file %s (%08lx)\n"),
              (const LPTSTR)out_file_name, hr);
  }
  return hr;
}

static HRESULT WriteUsingWIC(const char* out_file_name, int use_stdout,
                             REFGUID container_guid,
                             uint8_t* rgb, int stride,
                             uint32_t width, uint32_t height, int has_alpha) {
  HRESULT hr = S_OK;
  IWICImagingFactory* factory = NULL;
  IWICBitmapFrameEncode* frame = NULL;
  IWICBitmapEncoder* encoder = NULL;
  IStream* stream = NULL;
  WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
                                              : GUID_WICPixelFormat24bppBGR;

  if (out_file_name == NULL || rgb == NULL) return E_INVALIDARG;

  IFS(CoInitialize(NULL));
  IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
                       CLSCTX_INPROC_SERVER,
                       MAKE_REFGUID(IID_IWICImagingFactory),
                       (LPVOID*)&factory));
  if (hr == REGDB_E_CLASSNOTREG) {
    fprintf(stderr,
            "Couldn't access Windows Imaging Component (are you running "
            "Windows XP SP3 or newer?). PNG support not available. "
            "Use -ppm or -pgm for available PPM and PGM formats.\n");
  }
  IFS(CreateOutputStream(out_file_name, use_stdout, &stream));
  IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
                                       &encoder));
  IFS(IWICBitmapEncoder_Initialize(encoder, stream,
                                   WICBitmapEncoderNoCache));
  IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
  IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
  IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
  IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
  IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
                                        height * stride, rgb));
  IFS(IWICBitmapFrameEncode_Commit(frame));
  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 (encoder != NULL) IUnknown_Release(encoder);
  if (factory != NULL) IUnknown_Release(factory);
  if (stream != NULL) IUnknown_Release(stream);
  return hr;
}

int WebPWritePNG(const char* out_file_name, int use_stdout,
                 const WebPDecBuffer* const buffer) {
  const uint32_t width = buffer->width;
  const uint32_t height = buffer->height;
  uint8_t* const rgb = buffer->u.RGBA.rgba;
  const int stride = buffer->u.RGBA.stride;
  const int has_alpha = WebPIsAlphaMode(buffer->colorspace);

  return SUCCEEDED(WriteUsingWIC(out_file_name, use_stdout,
                                 MAKE_REFGUID(GUID_ContainerFormatPng),
                                 rgb, stride, width, height, has_alpha));
}

#elif defined(WEBP_HAVE_PNG)    // !HAVE_WINCODEC_H
static void PNGAPI PNGErrorFunction(png_structp png, png_const_charp unused) {
  (void)unused;  // remove variable-unused warning
  longjmp(png_jmpbuf(png), 1);
}

int WebPWritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
  volatile png_structp png;
  volatile png_infop info;

  if (out_file == NULL || buffer == NULL) return 0;

  png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                                NULL, PNGErrorFunction, NULL);
  if (png == NULL) {
    return 0;
  }
  info = png_create_info_struct(png);
  if (info == NULL) {
    png_destroy_write_struct((png_structpp)&png, NULL);
    return 0;
  }
  if (setjmp(png_jmpbuf(png))) {
    png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
    return 0;
  }
  png_init_io(png, out_file);
  {
    const uint32_t width = buffer->width;
    const uint32_t height = buffer->height;
    png_bytep row = buffer->u.RGBA.rgba;
    const int stride = buffer->u.RGBA.stride;
    const int has_alpha = WebPIsAlphaMode(buffer->colorspace);
    uint32_t y;

    png_set_IHDR(png, info, width, height, 8,
                 has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
                 PNG_FILTER_TYPE_DEFAULT);
    png_write_info(png, info);
    for (y = 0; y < height; ++y) {
      png_write_rows(png, &row, 1);
      row += stride;
    }
  }
  png_write_end(png, info);
  png_destroy_write_struct((png_structpp)&png, (png_infopp)&info);
  return 1;
}
#else    // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
int WebPWritePNG(FILE* fout, const WebPDecBuffer* const buffer) {}
#endif

//------------------------------------------------------------------------------
// PPM / PAM

static int WritePPMPAM(FILE* fout, const WebPDecBuffer* const buffer,
                       int alpha) {}

int WebPWritePPM(FILE* fout, const WebPDecBuffer* const buffer) {}

int WebPWritePAM(FILE* fout, const WebPDecBuffer* const buffer) {}

//------------------------------------------------------------------------------
// Raw PGM

// Save 16b mode (RGBA4444, RGB565, ...) for debugging purpose.
int WebPWrite16bAsPGM(FILE* fout, const WebPDecBuffer* const buffer) {}

//------------------------------------------------------------------------------
// BMP (see https://en.wikipedia.org/wiki/BMP_file_format#Pixel_storage)

static void PutLE16(uint8_t* const dst, uint32_t value) {}

static void PutLE32(uint8_t* const dst, uint32_t value) {}

#define BMP_HEADER_SIZE
#define BMP_HEADER_ALPHA_EXTRA_SIZE
int WebPWriteBMP(FILE* fout, const WebPDecBuffer* const buffer) {}
#undef BMP_HEADER_SIZE
#undef BMP_HEADER_ALPHA_EXTRA_SIZE

//------------------------------------------------------------------------------
// TIFF

#define NUM_IFD_ENTRIES
#define EXTRA_DATA_SIZE
// 10b for signature/header + n * 12b entries + 4b for IFD terminator:
#define EXTRA_DATA_OFFSET
#define TIFF_HEADER_SIZE

int WebPWriteTIFF(FILE* fout, const WebPDecBuffer* const buffer) {}

#undef TIFF_HEADER_SIZE
#undef EXTRA_DATA_OFFSET
#undef EXTRA_DATA_SIZE
#undef NUM_IFD_ENTRIES

//------------------------------------------------------------------------------
// Raw Alpha

int WebPWriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {}

//------------------------------------------------------------------------------
// PGM with IMC4 layout

int WebPWritePGM(FILE* fout, const WebPDecBuffer* const buffer) {}

//------------------------------------------------------------------------------
// Raw YUV(A) planes

int WebPWriteYUV(FILE* fout, const WebPDecBuffer* const buffer) {}

//------------------------------------------------------------------------------
// Generic top-level call

int WebPSaveImage(const WebPDecBuffer* const buffer,
                  WebPOutputFileFormat format,
                  const char* const out_file_name) {}