SkImageEncoder_WIC.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. /*
  2. * Copyright 2011 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkTypes.h"
  8. #if defined(SK_BUILD_FOR_WIN)
  9. #include "include/core/SkBitmap.h"
  10. #include "include/core/SkImageEncoder.h"
  11. #include "include/core/SkStream.h"
  12. #include "include/core/SkUnPreMultiply.h"
  13. #include "include/private/SkTemplates.h"
  14. #include "src/core/SkAutoMalloc.h"
  15. #include "src/images/SkImageEncoderPriv.h"
  16. #include "src/utils/win/SkAutoCoInitialize.h"
  17. #include "src/utils/win/SkIStream.h"
  18. #include "src/utils/win/SkTScopedComPtr.h"
  19. #include <wincodec.h>
  20. //All Windows SDKs back to XPSP2 export the CLSID_WICImagingFactory symbol.
  21. //In the Windows8 SDK the CLSID_WICImagingFactory symbol is still exported
  22. //but CLSID_WICImagingFactory is then #defined to CLSID_WICImagingFactory2.
  23. //Undo this #define if it has been done so that we link against the symbols
  24. //we intended to link against on all SDKs.
  25. #if defined(CLSID_WICImagingFactory)
  26. #undef CLSID_WICImagingFactory
  27. #endif
  28. bool SkEncodeImageWithWIC(SkWStream* stream, const SkPixmap& pixmap,
  29. SkEncodedImageFormat format, int quality) {
  30. GUID type;
  31. switch (format) {
  32. case SkEncodedImageFormat::kJPEG:
  33. type = GUID_ContainerFormatJpeg;
  34. break;
  35. case SkEncodedImageFormat::kPNG:
  36. type = GUID_ContainerFormatPng;
  37. break;
  38. default:
  39. return false;
  40. }
  41. SkBitmap bitmapOrig;
  42. if (!bitmapOrig.installPixels(pixmap)) {
  43. return false;
  44. }
  45. bitmapOrig.setImmutable();
  46. // First convert to BGRA if necessary.
  47. SkBitmap bitmap;
  48. if (!bitmap.tryAllocPixels(bitmapOrig.info().makeColorType(kBGRA_8888_SkColorType)) ||
  49. !bitmapOrig.readPixels(bitmap.info(), bitmap.getPixels(), bitmap.rowBytes(), 0, 0))
  50. {
  51. return false;
  52. }
  53. // WIC expects unpremultiplied pixels. Unpremultiply if necessary.
  54. if (kPremul_SkAlphaType == bitmap.alphaType()) {
  55. uint8_t* pixels = reinterpret_cast<uint8_t*>(bitmap.getPixels());
  56. for (int y = 0; y < bitmap.height(); ++y) {
  57. for (int x = 0; x < bitmap.width(); ++x) {
  58. uint8_t* bytes = pixels + y * bitmap.rowBytes() + x * bitmap.bytesPerPixel();
  59. SkPMColor* src = reinterpret_cast<SkPMColor*>(bytes);
  60. SkColor* dst = reinterpret_cast<SkColor*>(bytes);
  61. *dst = SkUnPreMultiply::PMColorToColor(*src);
  62. }
  63. }
  64. }
  65. // Finally, if we are performing a jpeg encode, we must convert to BGR.
  66. void* pixels = bitmap.getPixels();
  67. size_t rowBytes = bitmap.rowBytes();
  68. SkAutoMalloc pixelStorage;
  69. WICPixelFormatGUID formatDesired = GUID_WICPixelFormat32bppBGRA;
  70. if (SkEncodedImageFormat::kJPEG == format) {
  71. formatDesired = GUID_WICPixelFormat24bppBGR;
  72. rowBytes = SkAlign4(bitmap.width() * 3);
  73. pixelStorage.reset(rowBytes * bitmap.height());
  74. for (int y = 0; y < bitmap.height(); y++) {
  75. uint8_t* dstRow = SkTAddOffset<uint8_t>(pixelStorage.get(), y * rowBytes);
  76. for (int x = 0; x < bitmap.width(); x++) {
  77. uint32_t bgra = *bitmap.getAddr32(x, y);
  78. dstRow[0] = (uint8_t) ((bgra >> 0) & 0xFF);
  79. dstRow[1] = (uint8_t) ((bgra >> 8) & 0xFF);
  80. dstRow[2] = (uint8_t) ((bgra >> 16) & 0xFF);
  81. dstRow += 3;
  82. }
  83. }
  84. pixels = pixelStorage.get();
  85. }
  86. //Initialize COM.
  87. SkAutoCoInitialize scopedCo;
  88. if (!scopedCo.succeeded()) {
  89. return false;
  90. }
  91. HRESULT hr = S_OK;
  92. //Create Windows Imaging Component ImagingFactory.
  93. SkTScopedComPtr<IWICImagingFactory> piImagingFactory;
  94. if (SUCCEEDED(hr)) {
  95. hr = CoCreateInstance(
  96. CLSID_WICImagingFactory
  97. , nullptr
  98. , CLSCTX_INPROC_SERVER
  99. , IID_PPV_ARGS(&piImagingFactory)
  100. );
  101. }
  102. //Convert the SkWStream to an IStream.
  103. SkTScopedComPtr<IStream> piStream;
  104. if (SUCCEEDED(hr)) {
  105. hr = SkWIStream::CreateFromSkWStream(stream, &piStream);
  106. }
  107. //Create an encode of the appropriate type.
  108. SkTScopedComPtr<IWICBitmapEncoder> piEncoder;
  109. if (SUCCEEDED(hr)) {
  110. hr = piImagingFactory->CreateEncoder(type, nullptr, &piEncoder);
  111. }
  112. if (SUCCEEDED(hr)) {
  113. hr = piEncoder->Initialize(piStream.get(), WICBitmapEncoderNoCache);
  114. }
  115. //Create a the frame.
  116. SkTScopedComPtr<IWICBitmapFrameEncode> piBitmapFrameEncode;
  117. SkTScopedComPtr<IPropertyBag2> piPropertybag;
  118. if (SUCCEEDED(hr)) {
  119. hr = piEncoder->CreateNewFrame(&piBitmapFrameEncode, &piPropertybag);
  120. }
  121. if (SUCCEEDED(hr)) {
  122. PROPBAG2 name;
  123. memset(&name, 0, sizeof(name));
  124. name.dwType = PROPBAG2_TYPE_DATA;
  125. name.vt = VT_R4;
  126. name.pstrName = const_cast<LPOLESTR>(L"ImageQuality");
  127. VARIANT value;
  128. VariantInit(&value);
  129. value.vt = VT_R4;
  130. value.fltVal = (FLOAT)(quality / 100.0);
  131. //Ignore result code.
  132. // This returns E_FAIL if the named property is not in the bag.
  133. //TODO(bungeman) enumerate the properties,
  134. // write and set hr iff property exists.
  135. piPropertybag->Write(1, &name, &value);
  136. }
  137. if (SUCCEEDED(hr)) {
  138. hr = piBitmapFrameEncode->Initialize(piPropertybag.get());
  139. }
  140. //Set the size of the frame.
  141. const UINT width = bitmap.width();
  142. const UINT height = bitmap.height();
  143. if (SUCCEEDED(hr)) {
  144. hr = piBitmapFrameEncode->SetSize(width, height);
  145. }
  146. //Set the pixel format of the frame. If native encoded format cannot match BGRA,
  147. //it will choose the closest pixel format that it supports.
  148. WICPixelFormatGUID formatGUID = formatDesired;
  149. if (SUCCEEDED(hr)) {
  150. hr = piBitmapFrameEncode->SetPixelFormat(&formatGUID);
  151. }
  152. if (SUCCEEDED(hr)) {
  153. //Be sure the image format is the one requested.
  154. hr = IsEqualGUID(formatGUID, formatDesired) ? S_OK : E_FAIL;
  155. }
  156. //Write the pixels into the frame.
  157. if (SUCCEEDED(hr)) {
  158. hr = piBitmapFrameEncode->WritePixels(height,
  159. (UINT) rowBytes,
  160. (UINT) rowBytes * height,
  161. reinterpret_cast<BYTE*>(pixels));
  162. }
  163. if (SUCCEEDED(hr)) {
  164. hr = piBitmapFrameEncode->Commit();
  165. }
  166. if (SUCCEEDED(hr)) {
  167. hr = piEncoder->Commit();
  168. }
  169. return SUCCEEDED(hr);
  170. }
  171. #endif // defined(SK_BUILD_FOR_WIN)